/*
* 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.annotation.impl;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.util.TextRange;
import glslplugin.annotation.Annotator;
import glslplugin.lang.elements.GLSLIdentifier;
import glslplugin.lang.elements.expressions.GLSLExpression;
import glslplugin.lang.elements.expressions.GLSLFieldSelectionExpression;
import glslplugin.lang.elements.types.GLSLType;
import glslplugin.lang.elements.types.GLSLVectorType;
import org.jetbrains.annotations.NotNull;
/**
* Checks if vector components are correct.
* - all of the same type (no mixing)
* - within range (<= number of components)
*/
public class VectorComponentsAnnotation extends Annotator<GLSLFieldSelectionExpression> {
private static final char[] xyzw = {'x', 'y', 'z', 'w'};
private static final char[] rgba = {'r', 'g', 'b', 'a'};
private static final char[] stpq = {'s', 't', 'p', 'q'};
public void annotate(GLSLFieldSelectionExpression expr, AnnotationHolder holder) {
GLSLExpression leftHandExpression = expr.getLeftHandExpression();
if(leftHandExpression == null)return;
GLSLType leftHandType = leftHandExpression.getType();
if (leftHandType instanceof GLSLVectorType) {
GLSLVectorType type = (GLSLVectorType) leftHandType;
GLSLIdentifier memberIdentifier = expr.getMemberIdentifier();
if(memberIdentifier == null)return;
String member = memberIdentifier.getName();
if (member != null && !type.hasMember(member) && member.length() > 0) {
//It has no member like that, why?
TextRange mitr = memberIdentifier.getTextRange();
char[] basePattern = getPattern(member.charAt(0));
int numComponents = type.getNumComponents();
if (basePattern == null) {
TextRange tr = new TextRange(mitr.getStartOffset(), mitr.getStartOffset() + 1);
holder.createErrorAnnotation(tr, "'" + member.charAt(0) + "' is not one of: " + getAllAlternatives(numComponents));
} else {
for (int i = 0; i < member.length(); i++) {
char cm = member.charAt(i);
char[] pattern = getPattern(cm);
TextRange tr = new TextRange(mitr.getStartOffset() + i, mitr.getStartOffset() + i + 1);
if (pattern == null) {
holder.createErrorAnnotation(tr, "'" + cm + "' is not one of: " + getAlternatives(basePattern, numComponents));
} else {
if (basePattern != pattern) {
holder.createErrorAnnotation(tr, "Can not mix " + getAlternatives(pattern, numComponents) + " with " + getAlternatives(basePattern, numComponents));
} else if (!checkRange(pattern, numComponents, cm)) {
holder.createErrorAnnotation(tr, "'" + cm + "' is out of range of: " + getAlternatives(basePattern, numComponents));
}
}
}
}
}
}
}
private String getAllAlternatives(int numComponents) {
return getAlternatives(xyzw, numComponents) + ", " + getAlternatives(rgba, numComponents) + " or " + getAlternatives(stpq, numComponents);
}
private String getAlternatives(char[] chars, int numComponents) {
String result = "";
for (int i = 0; i < numComponents; i++) {
result += chars[i];
}
return result;
}
private boolean checkRange(char[] pattern, int numComponents, char c) {
for (int i = 0; i < numComponents; i++) {
if (pattern[i] == c) {
return true;
}
}
return false;
}
private char[] getPattern(char c) {
for (int i = 0; i < 4; i++) {
if (xyzw[i] == c) {
return xyzw;
} else if (rgba[i] == c) {
return rgba;
} else if (stpq[i] == c) {
return stpq;
}
}
return null;
}
@NotNull
@Override
public Class<GLSLFieldSelectionExpression> getElementType() {
return GLSLFieldSelectionExpression.class;
}
}