blob: 1bd040e7fc2f8f7510748248b5a38de22cf2b9de [file] [log] [blame]
/*
* Copyright 2000-2014 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 org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arguments.CommandArguments;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.PathExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.UnaryExpressionNotPlusMinus;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.PrimaryExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
/**
* Main classdef for any general expression parsing
*
* http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/test/gls/syntax/Gep3Test.groovy
* @author ilyas
*/
public class ExpressionStatement {
private static IElementType parseExpressionStatement(PsiBuilder builder, GroovyParser parser) {
if (checkForTypeCast(builder, parser)) return GroovyElementTypes.CAST_EXPRESSION;
PsiBuilder.Marker marker = builder.mark();
final PathExpression.Result result = PathExpression.parsePathExprQualifierForExprStatement(builder, parser);
if (result != PathExpression.Result.WRONG_WAY &&
!TokenSets.SEPARATORS.contains(builder.getTokenType()) &&
!TokenSets.BINARY_OP_SET.contains(builder.getTokenType()) &&
!TokenSets.POSTFIX_UNARY_OP_SET.contains(builder.getTokenType())) {
if (result == PathExpression.Result.METHOD_CALL) {
marker.drop();
return GroovyElementTypes.PATH_METHOD_CALL;
}
if (result == PathExpression.Result.LITERAL) {
final PsiBuilder.Marker newMarker = marker.precede();
marker.rollbackTo();
marker = newMarker;
PrimaryExpression.parsePrimaryExpression(builder, parser, true);
}
if (CommandArguments.parseCommandArguments(builder, parser)) {
marker.done(GroovyElementTypes.CALL_EXPRESSION);
return GroovyElementTypes.CALL_EXPRESSION;
}
}
marker.drop();
return GroovyElementTypes.WRONGWAY;
}
private static boolean checkForTypeCast(PsiBuilder builder, GroovyParser parser) {
return UnaryExpressionNotPlusMinus.parse(builder, parser, false);
}
/**
* Use for parse expressions in Argument position
*
* @param builder - Given builder
* @return type of parsing result
*/
public static boolean argParse(PsiBuilder builder, GroovyParser parser) {
return AssignmentExpression.parse(builder, parser);
}
enum Result {
WRONG_WAY, EXPR_STATEMENT, EXPRESSION
}
public static Result parse(PsiBuilder builder, GroovyParser parser) {
PsiBuilder.Marker marker = builder.mark();
final IElementType result = parseExpressionStatement(builder, parser);
if (result != GroovyElementTypes.CALL_EXPRESSION && result != GroovyElementTypes.PATH_METHOD_CALL) {
marker.drop();
return result == GroovyElementTypes.WRONGWAY ? Result.WRONG_WAY : Result.EXPRESSION;
}
boolean isExprStatement = result == GroovyElementTypes.CALL_EXPRESSION;
while (true) {
boolean nameParsed = namePartParse(builder, parser) == GroovyElementTypes.REFERENCE_EXPRESSION;
PsiBuilder.Marker exprStatement;
if (nameParsed) {
exprStatement = marker.precede();
marker.done(GroovyElementTypes.REFERENCE_EXPRESSION);
}
else {
exprStatement = marker;
}
if (builder.getTokenType() == GroovyTokenTypes.mLPAREN) {
PrimaryExpression.methodCallArgsParse(builder, parser);
exprStatement.done(GroovyElementTypes.PATH_METHOD_CALL);
}
else if (GroovyTokenTypes.mLBRACK.equals(builder.getTokenType()) &&
!ParserUtils.lookAhead(builder, GroovyTokenTypes.mLBRACK, GroovyTokenTypes.mCOLON) &&
!ParserUtils.lookAhead(builder, GroovyTokenTypes.mLBRACK, GroovyTokenTypes.mNLS, GroovyTokenTypes.mCOLON)) {
PathExpression.indexPropertyArgsParse(builder, parser);
exprStatement.done(GroovyElementTypes.PATH_INDEX_PROPERTY);
if (GroovyTokenTypes.mLPAREN.equals(builder.getTokenType())) {
PrimaryExpression.methodCallArgsParse(builder, parser);
}
else if (GroovyTokenTypes.mLCURLY.equals(builder.getTokenType())) {
PsiBuilder.Marker argsMarker = builder.mark();
argsMarker.done(GroovyElementTypes.ARGUMENTS);
}
while (GroovyTokenTypes.mLCURLY.equals(builder.getTokenType())) {
OpenOrClosableBlock.parseClosableBlock(builder, parser);
}
exprStatement = exprStatement.precede();
exprStatement.done(GroovyElementTypes.PATH_METHOD_CALL);
}
else if (nameParsed && CommandArguments.parseCommandArguments(builder, parser)) {
isExprStatement = true;
exprStatement.done(GroovyElementTypes.CALL_EXPRESSION);
}
else {
exprStatement.drop();
break;
}
marker = exprStatement.precede();
}
return isExprStatement ? Result.EXPR_STATEMENT : Result.EXPRESSION;
}
private static GroovyElementType namePartParse(PsiBuilder builder, GroovyParser parser) {
if (TokenSets.BINARY_OP_SET.contains(builder.getTokenType())) return GroovyElementTypes.WRONGWAY;
if (TokenSets.KEYWORDS.contains(builder.getTokenType())) return GroovyElementTypes.WRONGWAY;
final GroovyElementType type = PathExpression.namePartParse(builder, parser);
if (type == GroovyElementTypes.WRONGWAY && TokenSets.NUMBERS.contains(builder.getTokenType())) {
builder.advanceLexer();
return GroovyElementTypes.REFERENCE_EXPRESSION;
}
return type;
}
}