/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.coldFusion.model.parsers;
import com.intellij.coldFusion.CfmlBundle;
import com.intellij.coldFusion.model.lexer.CfmlTokenTypes;
import com.intellij.coldFusion.model.lexer.CfscriptTokenTypes;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import static com.intellij.coldFusion.model.lexer.CfscriptTokenTypes.*;
/**
* Created by Lera Nikolaenko
* Date: 10.12.2008
*/
public class CfmlExpressionParser {
private PsiBuilder myBuilder = null;
public CfmlExpressionParser(final PsiBuilder builder) {
myBuilder = builder;
}
/*
EXPRESSION := VALUE | VALUE BOP VALUE
*/
/*
public boolean parseExpression() {
boolean ifComplex = false;
if (closeExpressionToken()) return false;
PsiBuilder.Marker expressionMarker = myBuilder.mark();
parseOperand();
while (!closeExpressionToken()) {
int offset = myBuilder.getCurrentOffset();
ifComplex = true;
if (BINARY_OPERATIONS.contains(getTokenType())) {
advance();
if (closeExpressionToken()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.right.operand.missed"));
break;
}
} else {
myBuilder.error(CfmlBundle.message("cfml.parsing.binary.op.expected"));
}
parseOperand();
if (myBuilder.getCurrentOffset() == offset) {
myBuilder.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
advance();
}
}
if (ifComplex) {
expressionMarker.done(CfmlCompositeElementTypes.NONE);
} else {
expressionMarker.drop();
}
return true;
}
*/
public boolean parseExpression() {
if (myBuilder.getTokenType() == FUNCTION_KEYWORD) {
new CfscriptParser().parseFunctionExpression(myBuilder, true);
}
PsiBuilder.Marker expr = myBuilder.mark();
if (!parseBinaryExpression()) {
expr.drop();
return false;
}
if (getTokenType() == QUESTION) {
advance();
if (!parseExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
expr.drop();
return true;
}
if (getTokenType() == DOTDOT) {
advance();
if (!parseExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
expr.drop();
return true;
}
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.dot.dot.expected"));
expr.drop();
return true;
}
expr.done(CfmlElementTypes.TERNARY_EXPRESSION);
} else if (myBuilder.getTokenType() == ELVIS) {
advance();
if (!parseExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
expr.drop();
return true;
}
expr.done(CfmlElementTypes.BINARY_EXPRESSION);
}
else {
expr.drop();
}
return true;
}
private boolean parseBinaryExpression() {
PsiBuilder.Marker expr = myBuilder.mark();
if (!parseRelationalExpression()) {
expr.drop();
return false;
}
while (LOGICAL_OPERATIONS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
if (!parseRelationalExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
}
expr.done(CfmlElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
}
expr.drop();
return true;
}
private boolean parseRelationalExpression() {
PsiBuilder.Marker expr = myBuilder.mark();
if (!parseAdditiveExpression()) {
expr.drop();
return false;
}
while (RELATIONAL_OPERATIONS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
if (!parseAdditiveExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
}
expr.done(CfmlElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
}
expr.drop();
return true;
}
private boolean parseAdditiveExpression() {
PsiBuilder.Marker expr = myBuilder.mark();
if (!parseMultiplicativeExpression()) {
expr.drop();
return false;
}
while (ADDITIVE_OPERATIONS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
if (!parseMultiplicativeExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
}
expr.done(CfmlElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
}
expr.drop();
return true;
}
private boolean parseMultiplicativeExpression() {
PsiBuilder.Marker expr = myBuilder.mark();
if (parseAssignmentIfValid()) {
expr.drop();
return true;
}
if (!parseUnaryExpression()) {
expr.drop();
return false;
}
while (MULTIPLICATIVE_OPERATIONS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
if (!parseUnaryExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
}
expr.done(CfmlElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
}
expr.drop();
return true;
}
private boolean parseAssignmentIfValid() {
PsiBuilder.Marker marker = myBuilder.mark();
if (!parseAssignmentExpression(false)) {
marker.rollbackTo();
return false;
}
marker.drop();
return true;
}
private boolean parseUnaryExpression() {
final IElementType tokenType = myBuilder.getTokenType();
if (UNARY_OPERATIONS.contains(tokenType)) {
final PsiBuilder.Marker expr = myBuilder.mark();
myBuilder.advanceLexer();
if (!parseUnaryExpression()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.expression.expected"));
}
expr.done(CfmlElementTypes.UNARY_EXPRESSION);
return true;
}
else {
parseOperand();
return true;
}
}
private boolean parseAssignmentExpression(boolean allowDotDot) {
PsiBuilder.Marker statementMarker = myBuilder.mark();
int statementMarkerPosition = myBuilder.getCurrentOffset();
if (getTokenType() == VAR_KEYWORD) {
advance();
}
if (!parseLValue()) {
statementMarker.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.l.value.expected"));
return false;
}
IElementType tokenType = getTokenType();
if (tokenType != CfmlTokenTypes.ASSIGN && (!allowDotDot || tokenType != DOTDOT)) {
statementMarker.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.assignment.expected"));
return false;
}
else {
advance();
}
if (!parseRValue()) {
statementMarker.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.right.operand.missed"));
return false;
}
if (statementMarkerPosition != myBuilder.getCurrentOffset()) {
statementMarker.done(CfmlElementTypes.ASSIGNMENT);
}
else {
statementMarker.drop();
}
return true;
}
public boolean parseRValue() {
if (!parseStructureDefinition()) {
PsiBuilder.Marker referenceExpression = myBuilder.mark();
if (!parseNewExpression()) {
referenceExpression.rollbackTo();
if (!parseArrayDefinition()) {
if (!parseExpression()) {
return false;
}
}
}
else if (myBuilder.getTokenType() == POINT) {
referenceExpression.rollbackTo();
parseReference(false);
}
else {
referenceExpression.drop();
}
}
return true;
}
public void parsePrefixOperationExpression() {
if (!PREFIX_OPERATIONS.contains(getTokenType())) {
return;
}
PsiBuilder.Marker prefixExpressionMarker = myBuilder.mark();
advance();
if (!parseLValue()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.l.value.expected"));
}
prefixExpressionMarker.done(CfmlElementTypes.NONE);
}
/**
* STATEMENT := ASSIGN | FUNCTION_CALL_NAME | MODIFICATION_EXPRESSION
* ASSIGN := LVALUE ASSIGN_OP (STRUCT_DEF | ARRAY_DEF | EXPRESSION)
* MODIFICATION_EXPRESSION := PREFIX_OP LVALUE
* ASSIGN_OP := = | += | *= ...
*/
public void parseStatement() {
if (myBuilder.eof() || closeExpressionToken()) {
return;
}
int offset = myBuilder.getCurrentOffset();
// parse prefix operation with value
if (PREFIX_OPERATIONS.contains(getTokenType())) {
parsePrefixOperationExpression();
return;
}
PsiBuilder.Marker statementMarker = myBuilder.mark();
if (getTokenType() == VAR_KEYWORD) {
// advance();
parseAssignmentExpression(false);
statementMarker.drop();
return;
}
// parse function call
if (!parseLValue()) {
statementMarker.drop();
return;
}
boolean isClearAssign = false;
boolean isProbableVariableDef = false;
if (POSTFIX_OPERATIONS.contains(getTokenType())) {
advance();
statementMarker.done(CfmlElementTypes.NONE);
return;
}
else if (!ASSIGN_OPERATORS.contains(getTokenType())) {
myBuilder.error(CfmlBundle.message("cfml.parsing.statement.expected"));
if (OPERATIONS.contains(getTokenType())) {
advance();
myBuilder.error(CfmlBundle.message("cfml.parsing.assignment.expected"));
// TODO: test code
isClearAssign = true;
}
}
else {
isProbableVariableDef = isClearAssign = (getTokenType() == CfmlTokenTypes.ASSIGN);
if (myBuilder.eof()) {
statementMarker.drop();
return;
}
advance();
}
if (!isClearAssign || !parseStructureDefinition()) {
if (!isClearAssign || !parseNewExpression()) {
if (!isClearAssign || !parseArrayDefinition()) {
if (!parseExpression()) {
if (offset == myBuilder.getCurrentOffset()) {
statementMarker.drop();
myBuilder.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
advance();
return;
}
myBuilder.error(CfmlBundle.message("cfml.parsing.right.operand.missed"));
statementMarker.drop();
return;
}
}
}
}
if (offset == myBuilder.getCurrentOffset()) {
statementMarker.drop();
myBuilder.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
advance();
return;
}
if (isProbableVariableDef) {
statementMarker.done(CfmlElementTypes.ASSIGNMENT);
}
else {
statementMarker.drop();
}
}
// TODO: think about whether I can make this code more cfml independent (using CLOSER or ANGLEBRACKET keywords)
private boolean closeExpressionToken() {
return getTokenType() == CfmlTokenTypes.END_EXPRESSION ||
getTokenType() == CLOSESHARP ||
getTokenType() == CfmlTokenTypes.CLOSER ||
getTokenType() == CfmlTokenTypes.R_ANGLEBRACKET ||
myBuilder.eof() ||
getTokenType() == R_BRACKET ||
getTokenType() == R_SQUAREBRACKET ||
getTokenType() == COMMA ||
getTokenType() == CfmlTokenTypes.ASSIGN ||
getTokenType() == CfmlTokenTypes.OPENER ||
getTokenType() == CfmlTokenTypes.LSLASH_ANGLEBRACKET ||
getTokenType() == SEMICOLON ||
getTokenType() == R_CURLYBRACKET ||
getTokenType() == L_CURLYBRACKET/* ||
getTokenTYpe() == CfmlTokenTypes.R*/;
}
// parse ([EXPRESSION])*
private void parseArrayAccess() {
if (getTokenType() != L_SQUAREBRACKET) {
return;
}
advance();
parseExpression();
if (getTokenType() != R_SQUAREBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.square.bracket.expected"));
}
else {
advance();
}
}
private boolean parseID(boolean ifSharpsInIDs) {
if (!ifSharpsInIDs) {
if (getTokenType() == IDENTIFIER || CfscriptTokenTypes.KEYWORDS.contains(getTokenType())) {
advance();
return true;
}
}
else {
// SHARPED_ID := (#EXPRESSION#)*IDENTIFIER(#EXPRESSION#)*
if (getTokenType() != OPENSHARP && getTokenType() != IDENTIFIER) {
return false;
}
while (getTokenType() == OPENSHARP || getTokenType() == IDENTIFIER) {
while (getTokenType() == OPENSHARP) {
parseSharpExpr();
}
if (getTokenType() == IDENTIFIER) {
advance();
}
while (getTokenType() == OPENSHARP) {
parseSharpExpr();
}
}
return true;
}
return false;
}
public void parseComponentReference() {
assert myBuilder.getTokenType() == IDENTIFIER;
PsiBuilder.Marker componentReferenceMarker = myBuilder.mark();
while (myBuilder.getTokenType() == IDENTIFIER || KEYWORDS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() != POINT) {
break;
}
myBuilder.advanceLexer();
}
componentReferenceMarker.done(CfmlElementTypes.COMPONENT_REFERENCE);
}
// TODO: add flag "if component reference"
public boolean parseReference(boolean ifSharpsInIDs) {
boolean isReference = false;
PsiBuilder.Marker referenceExpression = myBuilder.mark();
boolean start = true;
while (getTokenType() == POINT || start) {
if (start) {
if (getTokenType() == SCOPE_KEYWORD) {
advance();
if (getTokenType() == POINT) {
advance();
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.dot.expected"));
}
}
else if (parseNewExpression()) {
if (getTokenType() == POINT) {
advance();
}
}
}
if (!start && getTokenType() == POINT) {
advance();
}
start = false;
if (!parseID(ifSharpsInIDs)) {
break;
}
isReference = true;
referenceExpression.done(CfmlElementTypes.REFERENCE_EXPRESSION);
do {
if (getTokenType() == L_BRACKET) {
isReference = false;
referenceExpression = referenceExpression.precede();
parseArgumentsList();
referenceExpression.done(CfmlElementTypes.FUNCTION_CALL_EXPRESSION);
}
// parse ([])*
int arrayAccessNumber = 0;
while (getTokenType() == L_SQUAREBRACKET) {
isReference = true;
referenceExpression = referenceExpression.precede();
parseArrayAccess();
// referenceExpression.done(CfmlElementTypes.ARRAY_ACCESS);
referenceExpression.done(CfmlElementTypes.NONE);
arrayAccessNumber++;
}
if (arrayAccessNumber != 1) {
break;
}
}
while (getTokenType() == L_BRACKET);
referenceExpression = referenceExpression.precede();
}
referenceExpression.drop();
return isReference;
}
// Parsing up to the first error the left value of assignment in cfset tag
// it differs from parseReferenceOrMethodCall just in:
// 1) it must check if it is not a method call
// 2) if value is inside quotes than dynamic variable naming available
private boolean parseLValue() {
boolean isReference;
if (getTokenType() == CfmlTokenTypes.DOUBLE_QUOTE || getTokenType() == CfmlTokenTypes.SINGLE_QUOTE) {
advance();
/*if (myBuilder.getTokenType() == STRING_TEXT) {
advance();
}*/
PsiBuilder.Marker lValueMarker = myBuilder.mark();
isReference = (parseReference(true) || parseStringReference(true));
if (!isReference) {
lValueMarker.error(CfmlBundle.message("cfml.parsing.l.value.expected"));
}
else {
lValueMarker.drop();
}
if (getTokenType() == OPENSHARP) {
parseSharpExpr();
}
if (getTokenType() != CfmlTokenTypes.DOUBLE_QUOTE_CLOSER && getTokenType() != CfmlTokenTypes.SINGLE_QUOTE_CLOSER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.quote.expected"));
// doneBefore(lValueMarker, "Quote expected");
}
else {
// lValueMarker.drop();
advance();
}
return true;
}
else {
boolean result = parseReference(false);
if (POSTFIX_OPERATIONS.contains(getTokenType())) {
advance();
return false;
}
return result;
}
}
public boolean parseStringReference(boolean isLValueInQuotes) {
boolean isReference = false;
if (isLValueInQuotes) {
PsiBuilder.Marker stringReferenceExpression = myBuilder.mark();
advance();
stringReferenceExpression.drop();
isReference = true; //it is not exactly a reference, it is a String_Text type as new Field name in create structure expression;
}
return isReference;
}
private boolean parseArgumentsList() {
if (getTokenType() == L_BRACKET) {
PsiBuilder.Marker argumentList = myBuilder.mark();
advance();
if (getTokenType() != R_BRACKET) {
boolean first = true;
while (first || getTokenType() == COMMA) {
if (!first) {
advance();
}
first = false;
PsiBuilder.Marker markArgumentName = myBuilder.mark();
if (getTokenType() == IDENTIFIER) {
advance();
if (getTokenType() == CfmlTokenTypes.ASSIGN) {
PsiBuilder.Marker assignment = markArgumentName.precede();
markArgumentName.done(CfmlElementTypes.ARGUMENT_NAME);
advance();
parseExpression();
assignment.done(CfmlElementTypes.ASSIGNMENT);
continue;
}
else if (getTokenType() == COMMA || getTokenType() == R_BRACKET) {
markArgumentName.done(CfmlElementTypes.ARGUMENT_NAME);
continue;
}
}
else if (parseRValue()) {
markArgumentName.drop();
continue;
}
markArgumentName.rollbackTo();
parseExpression();
}
}
if (getTokenType() != R_BRACKET) {
argumentList.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return true;
}
advance();
argumentList.done(CfmlElementTypes.ARGUMENT_LIST);
return true;
}
return false;
}
/*
ASSIGNLIST := LVALUE (=|:) EXPRESSION, ASSIGNLIST | LVALUE (=|:) EXPRESSION
*/
private void parseAssignsList() {
while(true) {
parseAssignmentExpression(true);
if (getTokenType() != COMMA) break;
advance();
}
}
public boolean parseNewExpression() {
if (getTokenType() != IDENTIFIER) {
return false;
}
if (!"new".equalsIgnoreCase(getTokenText())) {
return false;
}
PsiBuilder.Marker newExpression = mark();
advance();
PsiBuilder.Marker constructorCall = mark();
if (getTokenType() == CfmlTokenTypes.DOUBLE_QUOTE) {
parseString();
}
else if (getTokenType() == CfscriptTokenTypes.IDENTIFIER) {
parseComponentReference();
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.identifier.expected"));
}
parseArgumentsList();
constructorCall.done(CfmlElementTypes.COMPONENT_CONSTRUCTOR_CALL);
newExpression.done(CfmlElementTypes.NEW_EXPRESSION);
return true;
}
/*
STRUCTURE_DEFINITION := {ASSIGNLIST}
*/
public boolean parseStructureDefinition() {
PsiBuilder.Marker structDefMarker = mark();
IElementType tokenType = getTokenType();
if (tokenType == L_CURLYBRACKET) {
advance();
if (getTokenType() != R_CURLYBRACKET) {
parseAssignsList();
}
}
else {
structDefMarker.drop();
return false;
}
if (getTokenType() != R_CURLYBRACKET) {
structDefMarker.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return true;
}
advance();
structDefMarker.drop();
return true;
}
/*
ARRAY_DEFINITION := [EXPRESSION_LIST]
*/
public boolean parseArrayDefinition() {
IElementType tokenType = getTokenType();
if (tokenType != L_SQUAREBRACKET) {
return false;
}
PsiBuilder.Marker arrayDefMarker = mark();
getTokenType();
advance();
if (getTokenType() != R_SQUAREBRACKET) {
parseRValuesList();
}
if (getTokenType() != R_SQUAREBRACKET) {
arrayDefMarker.done(CfmlElementTypes.SCRIPT_EXPRESSION);
myBuilder.error(CfmlBundle.message("cfml.parsing.square.bracket.expected"));
return true;
}
advance();
arrayDefMarker.drop();
return true;
}
public void parseString() {
IElementType tokenType = getTokenType();
assert tokenType == CfmlTokenTypes.SINGLE_QUOTE || tokenType == CfmlTokenTypes.DOUBLE_QUOTE;
PsiBuilder.Marker stringLiteral = myBuilder.mark();
advance();
if (getTokenType() != CfmlTokenTypes.SINGLE_QUOTE_CLOSER && getTokenType() != CfmlTokenTypes.DOUBLE_QUOTE_CLOSER && !myBuilder.eof()) {
parseStringText();
}
if (getTokenType() != CfmlTokenTypes.SINGLE_QUOTE_CLOSER && getTokenType() != CfmlTokenTypes.DOUBLE_QUOTE_CLOSER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.quote.expected"));
stringLiteral.done(CfmlElementTypes.STRING_LITERAL);
return;
}
advance();
stringLiteral.done(CfmlElementTypes.STRING_LITERAL);
}
/*
VALUE := (EXPRESSION) | SMART_IDENTIFIER | "STRING" | 'STRING' |
FUNCTION_DEFINITION(EXPR_LIST) | INTEGER | DOUBLE | SHARP_EXPRESSION |
PREFIX_OP IDENTIFIER | IDENTIFIER POSTFIX_OP | ARRAY_DEFINITION | STRUCTURE_DEFINITION
*/
private void parseOperand() {
// PsiBuilder.Marker valueMarker = mark();
IElementType tokenType = getTokenType();
if (tokenType == L_BRACKET) {
advance();
parseExpression();
if (getTokenType() != R_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return;
}
advance();
}
if (parseArrayDefinition() || parseStructureDefinition()) {
}
else if (tokenType == CfmlTokenTypes.SINGLE_QUOTE || tokenType == CfmlTokenTypes.DOUBLE_QUOTE) {
parseString();
}
else if (tokenType == INTEGER) {
PsiBuilder.Marker integerLiteral = myBuilder.mark();
advance();
integerLiteral.done(CfmlElementTypes.INTEGER_LITERAL);
}
else if (tokenType == BOOLEAN) {
PsiBuilder.Marker integerLiteral = myBuilder.mark();
advance();
integerLiteral.done(CfmlElementTypes.BOOLEAN_LITERAL);
}
else if (tokenType == DOUBLE) {
PsiBuilder.Marker integerLiteral = myBuilder.mark();
advance();
integerLiteral.done(CfmlElementTypes.DOUBLE_LITERAL);
}
else if (tokenType == OPENSHARP) {
parseSharpExpr();
}
else if (PREFIX_OPERATIONS.contains(tokenType)) {
advance();
parseOperand();
// parseReference(false, false);
}
else if (tokenType == BAD_CHARACTER) {
PsiBuilder.Marker badCharMark = myBuilder.mark();
while (getTokenType() == BAD_CHARACTER) {
advance();
}
badCharMark.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
}
else {
parseReference(false);
if (POSTFIX_OPERATIONS.contains(getTokenType())) {
advance();
}
}
}
/*
SHARP_EXPRESSION := #EXPRESSION#
*/
private void parseSharpExpr() {
// PsiBuilder.Marker sharpExprMarker = mark();
if (getTokenType() != OPENSHARP) {
myBuilder.error(CfmlBundle.message("cfml.parsing.sharp.expected"));
return;
}
advance();
parseExpression();
if (getTokenType() != CLOSESHARP) {
myBuilder.error(CfmlBundle.message("cfml.parsing.sharp.expected"));
}
else {
advance();
}
// sharpExprMarker.done(CfmlElementTypes.SHARPS_EXPRESSION);
}
/*
STRING_TEXT := Eps | CfscriptTokenTypes.STRING_TEXT | STRING_TEXT SHARP_EXPRESSION STRING_TEXT;
*/
private void parseStringText() {
IElementType tokenType = getTokenType();
if ((tokenType != CfmlTokenTypes.STRING_TEXT && tokenType != OPENSHARP) ||
tokenType == CfmlTokenTypes.DOUBLE_QUOTE_CLOSER ||
tokenType == CfmlTokenTypes.SINGLE_QUOTE_CLOSER) {
return;
}
if (tokenType == CfmlTokenTypes.STRING_TEXT) {
advance();
parseStringText();
}
else {/*if (tokenType == OPENSHARP) {*/
parseSharpExpr();
parseStringText();
}
}
/*
EXPRESSION_LIST := EXPRESSION | EXPRESSION, EXPRESSION_LIST
*/
private void parseRValuesList() {
if (!parseStructureDefinition()) {
if (!parseArrayDefinition()) {
parseExpression();
}
}
if (getTokenType() == COMMA) {
advance();
parseRValuesList();
}
}
// util methods
@Nullable
private String getTokenText() {
return myBuilder.getTokenText();
}
@Nullable
private IElementType getTokenType() {
return myBuilder.getTokenType();
}
private void advance() {
myBuilder.advanceLexer();
}
private PsiBuilder.Marker mark() {
return myBuilder.mark();
}
}