/*
* 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.CfmlUtil;
import com.intellij.coldFusion.model.lexer.CfmlTokenTypes;
import com.intellij.coldFusion.model.psi.stubs.CfmlStubElementTypes;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import static com.intellij.coldFusion.model.lexer.CfscriptTokenTypes.*;
/**
* Created by Lera Nikolaenko
* Date: 13.01.2009
*/
public class CfscriptParser {
// parse statement or statements block in curly brackets
// if no curly brackets than parse only one statement
private static void parseExpression(PsiBuilder myBuilder) {
(new CfmlExpressionParser(myBuilder)).parseExpression();
}
private static void parseRValue(PsiBuilder myBuilder) {
(new CfmlExpressionParser(myBuilder)).parseRValue();
}
private static boolean parseOptionalIDAndTags_PropertyUtil(PsiBuilder myBuilder) {
PsiBuilder.Marker propertyBodyMarker = myBuilder.mark();
// parse Type ID attributes
// parse ID attributes
// parse attributes
if (myBuilder.getTokenType() == IDENTIFIER) {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) {
propertyBodyMarker.rollbackTo();
CfmlParser.parseAttributes(myBuilder, "cfproperty", IDENTIFIER, true);
return true;
}
else if (myBuilder.getTokenType() == IDENTIFIER) {
PsiBuilder.Marker attributesMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) {
attributesMarker.rollbackTo();
propertyBodyMarker.drop();
CfmlParser.parseAttributes(myBuilder, "cfproperty", IDENTIFIER, true);
return true;
}
else {
attributesMarker.drop();
propertyBodyMarker.rollbackTo();
return false;
}
}
//try to parse type in "property type name;" expression//
else if (myBuilder.getTokenType() == POINT) {
if (!parseType(myBuilder) || myBuilder.getTokenType() != IDENTIFIER) {
propertyBodyMarker.rollbackTo();
return false;
}
}
else if (myBuilder.getTokenType() == SEMICOLON) {
propertyBodyMarker.drop();
return true;
}
}
propertyBodyMarker.drop();
return false;
}
private boolean parseProperty(PsiBuilder myBuilder) {
assert myBuilder.getTokenType() == IDENTIFIER;
PsiBuilder.Marker propertyMarker = myBuilder.mark();
myBuilder.advanceLexer();
// parse Type ID attributes
// parse ID attributes
// parse attributes
if (!parseOptionalIDAndTags_PropertyUtil(myBuilder)) {
if (!parseType(myBuilder)) {
propertyMarker.drop();
return false;
}
if (!parseOptionalIDAndTags_PropertyUtil(myBuilder)) {
propertyMarker.drop();
return false;
}
else {
propertyMarker.done(CfmlElementTypes.PROPERTY);
return true;
}
}
else {
propertyMarker.done(CfmlElementTypes.PROPERTY);
return true;
}
}
private void parseAction(PsiBuilder myBuilder) {
// http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec0999c-7ffa.html
assert myBuilder.getTokenType() == IDENTIFIER;
final String actionName = myBuilder.getTokenText();
PsiBuilder.Marker actionMarker = myBuilder.mark();
myBuilder.remapCurrentToken(ACTION_NAME);
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) {
actionMarker.rollbackTo();
myBuilder.remapCurrentToken(IDENTIFIER);
(new CfmlExpressionParser(myBuilder)).parseStatement();
eatSemicolon(myBuilder);
}
else {
CfmlParser.parseAttributes(myBuilder, "cfproperty", IDENTIFIER, true);//it's not really property, but have same syntax rules
if ("param".equalsIgnoreCase(actionName)) {
// See link above.
eatSemicolon(myBuilder);
}
else {
parseFunctionBody(myBuilder);
}
actionMarker.done(CfmlElementTypes.ACTION);
}
}
private void parseStatement(PsiBuilder myBuilder) {
// PsiBuilder.Marker statement = myBuilder.mark();
if (myBuilder.getTokenType() == IDENTIFIER &&
"property".equalsIgnoreCase(myBuilder.getTokenText()) &&
parseProperty(myBuilder)) {
}
else {
(new CfmlExpressionParser(myBuilder)).parseStatement();
}
if(myBuilder.getTokenType() == L_CURLYBRACKET) {
parseScript(myBuilder, false);
} else {
eatSemicolon(myBuilder);
}
// statement.done(CfscriptElementTypes.STATEMENT);
}
private static void parseCondition(PsiBuilder myBuilder) {
(new CfmlExpressionParser(myBuilder)).parseExpression();
}
private static void parseInclude(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != INCLUDE_KEYWORD) {
return;
}
PsiBuilder.Marker marker = myBuilder.mark();
myBuilder.advanceLexer();
IElementType tokenType = myBuilder.getTokenType();
if (tokenType != CfmlTokenTypes.SINGLE_QUOTE && tokenType != CfmlTokenTypes.DOUBLE_QUOTE) {
marker.drop();
return;
}
(new CfmlExpressionParser(myBuilder)).parseString();
marker.done(CfmlElementTypes.INCLUDEEXPRESSION);
}
private static void parseImport(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != IMPORT_KEYWORD) {
return;
}
PsiBuilder.Marker marker = myBuilder.mark();
myBuilder.advanceLexer();
IElementType tokenType = myBuilder.getTokenType();
if (tokenType == CfmlTokenTypes.SINGLE_QUOTE || tokenType == CfmlTokenTypes.DOUBLE_QUOTE) {
(new CfmlExpressionParser(myBuilder)).parseString();
}
else if (tokenType == IDENTIFIER) {
(new CfmlExpressionParser(myBuilder)).parseComponentReference();
}
marker.done(CfmlElementTypes.IMPORTEXPRESSION);
}
// eating numeric or string
private static boolean parseConstant(PsiBuilder myBuilder) {
IElementType tokenType = myBuilder.getTokenType();
if (tokenType == INTEGER ||
tokenType == DOUBLE || tokenType == BOOLEAN) {
myBuilder.advanceLexer();
return true;
}
else if (tokenType == CfmlTokenTypes.SINGLE_QUOTE || tokenType == CfmlTokenTypes.DOUBLE_QUOTE) {
myBuilder.advanceLexer();
tokenType = myBuilder.getTokenType();
if (tokenType != CfmlTokenTypes.SINGLE_QUOTE_CLOSER && tokenType != CfmlTokenTypes.DOUBLE_QUOTE_CLOSER && !myBuilder.eof()) {
myBuilder.advanceLexer();
}
tokenType = myBuilder.getTokenType();
if (tokenType != CfmlTokenTypes.SINGLE_QUOTE_CLOSER && tokenType != CfmlTokenTypes.DOUBLE_QUOTE_CLOSER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.quote.expected"));
return true;
}
myBuilder.advanceLexer();
return true;
}
return false;
}
private boolean parseConditionInBrackets(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != L_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return false;
}
myBuilder.advanceLexer();
parseCondition(myBuilder);
if (myBuilder.getTokenType() != R_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return true;
}
myBuilder.advanceLexer();
return true;
}
private void parseComponentOrInterface(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != COMPONENT_KEYWORD &&
myBuilder.getTokenType() != INTERFACE_KEYWORD) {
return;
}
PsiBuilder.Marker componentMarker = myBuilder.mark();
boolean isComponent = myBuilder.getTokenType() == COMPONENT_KEYWORD;
myBuilder.advanceLexer();
/*
if (myBuilder.getTokenType() != IDENTIFIER) {
// myBuilder.error("cfml.parsing.identifier.expected");
} else {
final String nameOrAttribute = myBuilder.getTokenText();
final CfmlTagDescription componentTag = CfmlLangInfo.myTagAttributes.get("cfcomponent");
if (nameOrAttribute != null && !componentTag.hasAttribute(nameOrAttribute.toLowerCase())) {
myBuilder.advanceLexer();
}
}
*/
if (myBuilder.getTokenType() == FUNCTION_KEYWORD) {
componentMarker.rollbackTo();
parseFunctionExpression(myBuilder, false);
return;
}
CfmlParser.parseAttributes(myBuilder, isComponent ? "cfcomponent" : "cfinterface", IDENTIFIER, true);
if (myBuilder.getTokenType() != L_CURLYBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.open.curly.bracket.expected"));
componentMarker.drop();
return;
}
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == PAGEENCODING_KEYWORD) {
myBuilder.advanceLexer();
IElementType tokenType = myBuilder.getTokenType();
if (tokenType == CfmlTokenTypes.SINGLE_QUOTE || tokenType == CfmlTokenTypes.DOUBLE_QUOTE) {
(new CfmlExpressionParser(myBuilder)).parseString();
eatSemicolon(myBuilder);
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.string.expected"));
}
}
parseScript(myBuilder, false, false, true);
componentMarker.done(CfmlStubElementTypes.COMPONENT_DEFINITION);
}
private void parseIfExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != IF_KEYWORD) {
return;
}
PsiBuilder.Marker ifExprMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (!parseConditionInBrackets(myBuilder)) {
ifExprMarker.drop();
return;
}
parseScript(myBuilder, false);
if (myBuilder.getTokenType() == ELSE_KEYWORD) {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == IF_KEYWORD) {
parseIfExpression(myBuilder);
}
else {
parseScript(myBuilder, false);
}
}
ifExprMarker.done(CfmlElementTypes.IFEXPRESSION);
}
private void parseWhileExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != WHILE_KEYWORD) {
return;
}
PsiBuilder.Marker whileMarker = myBuilder.mark();
myBuilder.advanceLexer();
parseConditionInBrackets(myBuilder);
parseScript(myBuilder, false);
whileMarker.done(CfmlElementTypes.WHILEEXPRESSION);
}
private void parseDoWhileExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != DO_KEYWORD) {
return;
}
PsiBuilder.Marker doWhileMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (myBuilder.getTokenType() != L_CURLYBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.open.bracket.expected"));
doWhileMarker.drop();
return;
}
parseScript(myBuilder, false);
if (myBuilder.getTokenType() != WHILE_KEYWORD) {
myBuilder.error(CfmlBundle.message("cfml.parsing.keyword.expected", "while"));
doWhileMarker.done(CfmlElementTypes.DOWHILEEXPRESSION);
return;
}
myBuilder.advanceLexer();
parseConditionInBrackets(myBuilder);
if (myBuilder.getTokenType() != SEMICOLON) {
myBuilder.error(CfmlBundle.message("cfml.parsing.semicolon.expected"));
}
else {
myBuilder.advanceLexer();
}
doWhileMarker.done(CfmlElementTypes.DOWHILEEXPRESSION);
}
private static void eatSemicolon(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != SEMICOLON) {
myBuilder.error(CfmlBundle.message("cfml.parsing.semicolon.expected"));
}
else {
myBuilder.advanceLexer();
}
}
private void parseForExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != FOR_KEYWORD) {
return;
}
PsiBuilder.Marker forExpressionMarker = myBuilder.mark();
myBuilder.advanceLexer();
// eat opening bracket
if (myBuilder.getTokenType() != L_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
forExpressionMarker.drop();
return;
}
myBuilder.advanceLexer();
if (!tryParseForIn(myBuilder)) {
parseStatement(myBuilder);
parseCondition(myBuilder);
eatSemicolon(myBuilder);
(new CfmlExpressionParser(myBuilder)).parseStatement();
}
if (myBuilder.getTokenType() != R_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
forExpressionMarker.done(CfmlElementTypes.FOREXPRESSION);
return;
}
myBuilder.advanceLexer();
parseScript(myBuilder, false);
forExpressionMarker.done(CfmlElementTypes.FOREXPRESSION);
}
private static boolean tryParseForIn(PsiBuilder myBuilder) {
PsiBuilder.Marker startMarker = myBuilder.mark();
if (myBuilder.getTokenType() == VAR_KEYWORD) {
myBuilder.advanceLexer();
}
PsiBuilder.Marker definitionMarker = myBuilder.mark();
if (!(new CfmlExpressionParser(myBuilder)).parseReference(false)) {
startMarker.rollbackTo();
return false;
}
else {
definitionMarker.done(CfmlElementTypes.FORVARIABLE);
}
if (myBuilder.getTokenType() != IN_L) {
startMarker.rollbackTo();
return false;
}
myBuilder.advanceLexer();
if (!(new CfmlExpressionParser(myBuilder)).parseReference(false)) {
(new CfmlExpressionParser(myBuilder)).parseArrayDefinition();
}
startMarker.drop();
return true;
}
private void parseFunctionBody(PsiBuilder myBuilder) {
PsiBuilder.Marker functionBodyMarker = myBuilder.mark();
if (myBuilder.getTokenType() != L_CURLYBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.open.curly.bracket.expected"));
functionBodyMarker.drop();
return;
}
parseScript(myBuilder, false);
// TODO eat return keyword
functionBodyMarker.done(CfmlElementTypes.FUNCTIONBODY);
}
/**
* ColdFusion9: [required] [type] name [= default value (constant)], ...
*/
private void parseParametersList(PsiBuilder myBuilder) {
PsiBuilder.Marker argumentMarker = myBuilder.mark();
// parsing required keyword is present
if (myBuilder.getTokenType() == REQUIRED_KEYWORD) {
myBuilder.advanceLexer();
}
// try to parse type
final PsiBuilder.Marker marker = myBuilder.mark();
if (!parseType(myBuilder) || myBuilder.getTokenType() != IDENTIFIER) {
marker.rollbackTo();
}
else {
marker.drop();
}
// parse parameter name
if (myBuilder.getTokenType() == IDENTIFIER) {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) { // parse default value
// TODO: to find out whether it can be something different from a constant
myBuilder.advanceLexer();
final PsiBuilder.Marker defaultValueMarker = myBuilder.mark();
if (!parseConstant(myBuilder)) {
parseRValue(myBuilder);
}
defaultValueMarker.done(CfmlElementTypes.VALUE);
}
if (myBuilder.getTokenType() == IDENTIFIER) {
CfmlParser.parseAttributes(myBuilder, "cfparameter", IDENTIFIER, true);
}
argumentMarker.done(CfmlElementTypes.FUNCTION_ARGUMENT);
if (myBuilder.getTokenType() == COMMA) {
myBuilder.advanceLexer();
parseParametersList(myBuilder);
}
}
else {
argumentMarker.drop();
}
}
private void parseParametersListInBrackets(PsiBuilder myBuilder) {
PsiBuilder.Marker argumentsList = myBuilder.mark();
eatLeftBracket(myBuilder);
parseParametersList(myBuilder);
eatRightBracket(myBuilder);
argumentsList.done(CfmlElementTypes.PARAMETERS_LIST);
}
void parseFunctionExpression(PsiBuilder myBuilder, boolean anonymous) {
PsiBuilder.Marker functionMarker = myBuilder.mark();
if (!anonymous) {
if (ACCESS_KEYWORDS.contains(myBuilder.getTokenType())) {
myBuilder.advanceLexer();
}
if (myBuilder.getTokenType() != FUNCTION_KEYWORD) {
parseType(myBuilder);
}
}
if (myBuilder.getTokenType() != FUNCTION_KEYWORD) {
myBuilder.error(CfmlBundle.message("cfml.parsing.function.expected"));
functionMarker.drop();
return;
}
myBuilder.advanceLexer();
if (myBuilder.getTokenType() != IDENTIFIER &&
!(myBuilder.getTokenType() == DEFAULT_KEYWORD) && !anonymous) {
myBuilder.error(CfmlBundle.message("cfml.parsing.identifier.expected"));
}
else {
if (!anonymous) myBuilder.advanceLexer();
}
parseParametersListInBrackets(myBuilder);
CfmlParser.parseAttributes(myBuilder, "cffunction", IDENTIFIER, true);
parseFunctionBody(myBuilder);
functionMarker.done(CfmlElementTypes.FUNCTION_DEFINITION);
}
private void parseDOTDOTAndScript(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != DOTDOT) {
myBuilder.error(CfmlBundle.message("cfml.parsing.dot.dot.expected"));
}
else {
myBuilder.advanceLexer();
}
if (myBuilder.getTokenType() != L_CURLYBRACKET) {
if (myBuilder.getTokenType() == CASE_KEYWORD) {
return;
}
int offset = myBuilder.getCurrentOffset();
while (!myBuilder.eof() &&
myBuilder.getTokenType() != BREAK_KEYWORD &&
myBuilder.getTokenType() != DEFAULT_KEYWORD &&
myBuilder.getTokenType() != CASE_KEYWORD &&
myBuilder.getTokenType() != R_CURLYBRACKET && !isEndOfScript(myBuilder)) {
if (!parseScript(myBuilder, false)) {
break;
}
if (offset == myBuilder.getCurrentOffset()) {
break;
}
offset = myBuilder.getCurrentOffset();
}
if (myBuilder.getTokenType() == BREAK_KEYWORD) {
myBuilder.advanceLexer();
eatSemicolon(myBuilder);
}
}
else {
parseScript(myBuilder, false);
}
}
private void parseCaseExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != CASE_KEYWORD) {
return;
}
PsiBuilder.Marker caseExpressionMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (!parseConstant(myBuilder)) {
if (myBuilder.getTokenType() == IDENTIFIER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.constant.expected"));
myBuilder.advanceLexer();
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.constant.expected"));
}
}
parseDOTDOTAndScript(myBuilder);
caseExpressionMarker.done(CfmlElementTypes.CASEEXPRESSION);
}
private void parseSwitchExpression(PsiBuilder myBuilder) {
PsiBuilder.Marker switchMarker = myBuilder.mark();
if (myBuilder.getTokenType() != SWITCH_KEYWORD) {
return;
}
myBuilder.advanceLexer();
if (!this.eatLeftBracket(myBuilder)) {
switchMarker.drop();
return;
}
this.parseExpression(myBuilder);
this.eatRightBracket(myBuilder);
if (myBuilder.getTokenType() != L_CURLYBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.open.curly.bracket.expected"));
switchMarker.drop();
return;
}
myBuilder.advanceLexer();
while (myBuilder.getTokenType() == CASE_KEYWORD) {
parseCaseExpression(myBuilder);
}
if (myBuilder.getTokenType() == DEFAULT_KEYWORD) {
PsiBuilder.Marker caseExpressionMarker = myBuilder.mark();
myBuilder.advanceLexer();
parseDOTDOTAndScript(myBuilder);
caseExpressionMarker.done(CfmlElementTypes.CASEEXPRESSION);
}
while (myBuilder.getTokenType() == CASE_KEYWORD) {
parseCaseExpression(myBuilder);
}
if (myBuilder.getTokenType() != R_CURLYBRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.curly.bracket.expected"));
}
else {
myBuilder.advanceLexer();
}
switchMarker.done(CfmlElementTypes.SWITCHEXPRESSION);
}
private static boolean eatLeftBracket(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != L_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.open.bracket.expected"));
return false;
}
myBuilder.advanceLexer();
return true;
}
private static void eatRightBracket(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != R_BRACKET) {
myBuilder.error(CfmlBundle.message("cfml.parsing.close.bracket.expected"));
return;
}
myBuilder.advanceLexer();
}
private static boolean parseType(PsiBuilder myBuilder) {
if (TYPE_KEYWORDS.contains(myBuilder.getTokenType())) {
final PsiBuilder.Marker typeMarker = myBuilder.mark();
myBuilder.advanceLexer();
typeMarker.done(CfmlElementTypes.TYPE);
}
else {
if (myBuilder.getTokenType() != IDENTIFIER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.type.expected"));
return false;
}
final PsiBuilder.Marker typeMarker = myBuilder.mark();
myBuilder.advanceLexer();
while (myBuilder.getTokenType() == POINT) {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() != IDENTIFIER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.type.expected"));
typeMarker.done(CfmlElementTypes.TYPE);
return true;
}
myBuilder.advanceLexer();
}
typeMarker.done(CfmlElementTypes.TYPE);
}
return true;
}
private void parseCatchExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != CATCH_KEYWORD) {
return;
}
PsiBuilder.Marker catchExpressionMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (!eatLeftBracket(myBuilder)) {
catchExpressionMarker.drop();
return;
}
parseType(myBuilder);
if (myBuilder.getTokenType() != IDENTIFIER) {
myBuilder.error(CfmlBundle.message("cfml.parsing.identifier.expected"));
catchExpressionMarker.drop();
return;
}
myBuilder.advanceLexer();
eatRightBracket(myBuilder);
catchExpressionMarker.done(CfmlElementTypes.CATCHEXPRESSION);
parseScript(myBuilder, false);
}
private void parseTryCatchExpression(PsiBuilder myBuilder) {
if (myBuilder.getTokenType() != TRY_KEYWORD) {
return;
}
PsiBuilder.Marker tryCatchMarker = myBuilder.mark();
myBuilder.advanceLexer();
parseScript(myBuilder, false);
while (myBuilder.getTokenType() == CATCH_KEYWORD) {
parseCatchExpression(myBuilder);
}
if (myBuilder.getTokenType() == FINALLY_KEYWORD) {
myBuilder.advanceLexer();
parseScript(myBuilder, false);
}
tryCatchMarker.done(CfmlElementTypes.TRYCATCHEXPRESSION);
}
public boolean parseScript(PsiBuilder myBuilder, boolean betweenScriptTags) {
return parseScript(myBuilder, betweenScriptTags, true, false);
}
public boolean parseScript(PsiBuilder myBuilder, boolean betweenScriptTags, boolean createBlockOfStatments, boolean waitForRightBracket) {
PsiBuilder.Marker blockOfStatements = null;
if (myBuilder.getTokenType() == L_CURLYBRACKET) {
waitForRightBracket = true;
blockOfStatements = myBuilder.mark();
myBuilder.advanceLexer();
}
while (!isEndOfScript(myBuilder)) {
int lexerPosition = myBuilder.getCurrentOffset();
if (myBuilder.getTokenType() == INCLUDE_KEYWORD) {
parseInclude(myBuilder);
}
else if (myBuilder.getTokenType() == IMPORT_KEYWORD) {
parseImport(myBuilder);
}
else if (myBuilder.getTokenType() == COMPONENT_KEYWORD ||
myBuilder.getTokenType() == INTERFACE_KEYWORD) {
parseComponentOrInterface(myBuilder);
}
else if (ACCESS_KEYWORDS.contains(myBuilder.getTokenType()) ||
myBuilder.getTokenType() == FUNCTION_KEYWORD
) {
parseFunctionExpression(myBuilder, false);
}
else if (TYPE_KEYWORDS.contains(myBuilder.getTokenType())) {
if (!tryParseStatement(myBuilder)) {
parseFunctionExpression(myBuilder, false);
}
}
else if (myBuilder.getTokenType() == VAR_KEYWORD) {
parseStatement(myBuilder);
}
else if (myBuilder.getTokenType() == IF_KEYWORD) {
parseIfExpression(myBuilder);
}
else if (myBuilder.getTokenType() == WHILE_KEYWORD) {
parseWhileExpression(myBuilder);
}
else if (myBuilder.getTokenType() == DO_KEYWORD) {
parseDoWhileExpression(myBuilder);
}
else if (myBuilder.getTokenType() == FOR_KEYWORD) {
parseForExpression(myBuilder);
}
else if (myBuilder.getTokenType() == SWITCH_KEYWORD) {
parseSwitchExpression(myBuilder);
} else if (myBuilder.getTokenType() == RETHROW_KEYWORD) {
myBuilder.advanceLexer();
eatSemicolon(myBuilder);
}
else if (myBuilder.getTokenType() == RETURN_KEYWORD) {
parseReturnStatement(myBuilder);
}
else if (myBuilder.getTokenType() == BREAK_KEYWORD ||
myBuilder.getTokenType() == ABORT_KEYWORD) {
myBuilder.advanceLexer();
eatSemicolon(myBuilder);
}
else if (CfmlUtil.isActionName(myBuilder)) {
parseAction(myBuilder);
}
else if (myBuilder.getTokenType() == L_CURLYBRACKET) {
parseScript(myBuilder, false);
}
else if (myBuilder.getTokenType() == R_CURLYBRACKET) {
if (waitForRightBracket) {
myBuilder.advanceLexer();
if (blockOfStatements != null) {
if (createBlockOfStatments) {
blockOfStatements.done(CfmlElementTypes.BLOCK_OF_STATEMENTS);
}
else {
blockOfStatements.drop();
}
}
return true;
}
else {
myBuilder.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
myBuilder.advanceLexer();
return false;
}
}
else if (myBuilder.getTokenType() == TRY_KEYWORD) {
parseTryCatchExpression(myBuilder);
}
else if (KEYWORDS.contains(myBuilder.getTokenType())) {
if (myBuilder.getTokenType() == VAR_KEYWORD || myBuilder.getTokenType() == SCOPE_KEYWORD) {
parseStatement(myBuilder);
}
else if (myBuilder.getTokenType() != CONTINUE_KEYWORD &&
myBuilder.getTokenType() != RETURN_KEYWORD &&
myBuilder.getTokenType() != BREAK_KEYWORD) {
PsiBuilder.Marker errorMarker = myBuilder.mark();
myBuilder.advanceLexer();
errorMarker.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
}
else {
myBuilder.advanceLexer();
eatSemicolon(myBuilder);
}
}
else {
PsiBuilder.Marker marker = myBuilder.mark();
if (parseType(myBuilder) && myBuilder.getTokenType() == FUNCTION_KEYWORD) {
marker.rollbackTo();
parseFunctionExpression(myBuilder, false);
}
else {
marker.rollbackTo();
if (myBuilder.getTokenType() == IDENTIFIER) {
PsiBuilder.Marker assignMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) {
assignMarker.rollbackTo();
new CfmlExpressionParser(myBuilder).parseExpression();
eatSemicolon(myBuilder);
}
else {
assignMarker.rollbackTo();
parseStatement(myBuilder);
}
}
else {
parseStatement(myBuilder);
}
}
}
if (!betweenScriptTags && !waitForRightBracket) {
break;
}
if (lexerPosition == myBuilder.getCurrentOffset()) {
myBuilder.error(CfmlBundle.message("cfml.parsing.unexpected.token"));
myBuilder.advanceLexer();
if (blockOfStatements != null) {
blockOfStatements.drop();
}
return false;
}
/*
IN_KEYWORD,
VAR_KEYWORD,
*/
}
if (blockOfStatements != null) {
blockOfStatements.drop();
}
return true;
}
private boolean tryParseStatement(PsiBuilder myBuilder) {
PsiBuilder.Marker referenceMarker = myBuilder.mark();
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == CfmlTokenTypes.ASSIGN) {
referenceMarker.rollbackTo();
parseStatement(myBuilder);
return true;
}
referenceMarker.rollbackTo();
return false;
}
private static void parseReturnStatement(PsiBuilder myBuilder) {
myBuilder.advanceLexer();
if (!(new CfmlExpressionParser(myBuilder)).parseStructureDefinition()) {
if (!(new CfmlExpressionParser(myBuilder)).parseArrayDefinition()) {
(new CfmlExpressionParser(myBuilder)).parseExpression();
}
}
eatSemicolon(myBuilder);
}
private static boolean isEndOfScript(PsiBuilder myBuilder) {
return myBuilder.getTokenType() == null ||
myBuilder.getTokenType() == CfmlTokenTypes.OPENER ||
myBuilder.getTokenType() == CfmlTokenTypes.LSLASH_ANGLEBRACKET;
}
}