/* * Copyright 2010 Jean-Paul Balabanian and Yngve Devik Hammersland * * This file is part of glsl4idea. * * Glsl4idea is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Glsl4idea is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glsl4idea. If not, see <http://www.gnu.org/licenses/>. */ package glslplugin.lang.elements.expressions; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import glslplugin.lang.elements.GLSLElement; import glslplugin.lang.elements.GLSLIdentifier; import glslplugin.lang.elements.GLSLReferenceElement; import glslplugin.lang.elements.declarations.GLSLDeclarator; import glslplugin.lang.elements.declarations.GLSLTypeDefinition; import glslplugin.lang.elements.reference.GLSLFieldReference; import glslplugin.lang.elements.types.GLSLType; import glslplugin.lang.elements.types.GLSLTypes; import glslplugin.lang.elements.types.GLSLVectorType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.logging.Logger; /** * GLSLMemberOperator is ... * * @author Yngve Devik Hammersland * Date: Jan 28, 2009 * Time: 4:40:28 PM */ public class GLSLFieldSelectionExpression extends GLSLSelectionExpressionBase implements GLSLReferenceElement { public GLSLFieldSelectionExpression(@NotNull ASTNode astNode) { super(astNode); } @Nullable public GLSLIdentifier getMemberIdentifier() { PsiElement last = getLastChild(); if (last instanceof GLSLIdentifier) { return (GLSLIdentifier) last; } else { return null; } } @Override public boolean isLValue() { // A member is L-Value only if its container also is L-Value GLSLExpression leftExpression = getLeftHandExpression(); //noinspection SimplifiableIfStatement if(leftExpression == null)return true; //It might be, but right now it is broken. else { if(isSwizzle()){ //It is a swizzle, so it may or may not be a L value //If any of the components are repeated, it is not a L value GLSLIdentifier memberIdentifier = getMemberIdentifier(); if(memberIdentifier == null)return true; //This should not happen String components = memberIdentifier.getName(); if(components == null)return true; // This absolutely shouldn't happen for (int i = 0; i < components.length(); i++) { char c = components.charAt(i); for (int j = i+1; j < components.length(); j++) { if(c == components.charAt(j)){ //When any component is repeated, it is not a L value return false; } } } return true; }else{ return leftExpression.isLValue(); } } } /** * Reports whether this selection operates on vector and selects more than one component. * Returns false if it failed to find out. */ public boolean isSwizzle(){ GLSLExpression leftHandExpression = getLeftHandExpression(); GLSLIdentifier memberIdentifier = getMemberIdentifier(); if(leftHandExpression == null || memberIdentifier == null)return false; GLSLType leftHandType = leftHandExpression.getType(); if(!leftHandType.isValidType())return false; if(!(leftHandType instanceof GLSLVectorType))return false; //If it got here, it is picking a component(s) from a vector. But how many? return memberIdentifier.getName().length() > 1; //Because all vector components are marked as only one letter, having more letters means swizzling } @NotNull public GLSLFieldReference getReferenceProxy() { return new GLSLFieldReference(this); } @NotNull @Override public GLSLType getType() { GLSLDeclarator declarator = getReferenceProxy().resolve(); if (declarator != null) { return declarator.getType(); } else { // No declarator, check for built-in type GLSLExpression left = getLeftHandExpression(); if(left == null)return GLSLTypes.UNKNOWN_TYPE; GLSLType type = left.getType(); if (type == GLSLTypes.UNKNOWN_TYPE) { return GLSLTypes.UNKNOWN_TYPE; } if (!type.hasMembers()) { return GLSLTypes.UNKNOWN_TYPE; } GLSLIdentifier memberIdentifier = getMemberIdentifier(); if(memberIdentifier == null)return GLSLTypes.UNKNOWN_TYPE; else return type.getMemberType(memberIdentifier.getName()); } } public String toString() { GLSLIdentifier memberIdentifier = getMemberIdentifier(); if(memberIdentifier == null){ return "Field selection: '(unknown)'"; }else{ return "Field selection: '" + memberIdentifier.getName() + "'"; } } }