in grails-gsp/core/src/main/groovy/org/grails/gsp/compiler/GroovyPageExpressionParser.java [61:121]
int parse() {
int currentPos = startPos;
char previousChar = 0;
char previousPreviousChar = 0;
while(currentPos < scriptTokens.length() && terminationCharPos==-1) {
ParsingState parsingState = parsingStateStack.peek();
char ch = scriptTokens.charAt(currentPos++);
char nextChar = (currentPos < scriptTokens.length()) ? scriptTokens.charAt(currentPos) : 0;
if (parsingStateStack.size()==1 && ch==terminationChar && (nextTerminationChar==0 || nextTerminationChar==nextChar)) {
terminationCharPos = currentPos-1;
} else if (parsingState==ParsingState.EXPRESSION || parsingState==ParsingState.NORMAL) {
switch(ch) {
case '{':
if (previousChar=='$' && parsingState==ParsingState.EXPRESSION) {
// invalid expression, starting new ${} expression inside expression
return -1;
}
if (previousChar=='$' || parsingState==ParsingState.EXPRESSION) {
changeState(ParsingState.EXPRESSION);
}
break;
case '[':
if (relativeCharIndex==0 || parsingState==ParsingState.EXPRESSION) {
changeState(ParsingState.EXPRESSION);
}
break;
case '}':
case ']':
if (parsingState==ParsingState.EXPRESSION) {
parsingStateStack.pop();
}
break;
case '\'':
case '"':
if (parsingState==ParsingState.EXPRESSION) {
if (nextChar != ch && previousChar != ch) {
changeState(ch=='"' ? ParsingState.QUOTEDVALUE_DOUBLE : ParsingState.QUOTEDVALUE_SINGLE);
} else if (previousChar==ch && previousPreviousChar==ch) {
changeState(ch=='"' ? ParsingState.TRIPLEQUOTED_DOUBLE : ParsingState.TRIPLEQUOTED_SINGLE);
}
}
break;
}
} else if (ch=='"' || ch=='\'') {
if (nextChar != ch && (previousChar != ch || previousPreviousChar=='\\') && (previousChar != '\\' || (previousChar=='\\' && previousPreviousChar=='\\'))
&& ((parsingState == ParsingState.QUOTEDVALUE_DOUBLE && ch == '"') || (parsingState == ParsingState.QUOTEDVALUE_SINGLE && ch == '\''))) {
parsingStateStack.pop();
}
else if ((previousChar == ch && previousPreviousChar == ch)
&& ((parsingState == ParsingState.TRIPLEQUOTED_DOUBLE && ch == '"') || (parsingState == ParsingState.TRIPLEQUOTED_SINGLE && ch == '\''))) {
parsingStateStack.pop();
}
}
previousPreviousChar = previousChar;
previousChar=ch;
relativeCharIndex++;
}
return terminationCharPos;
}