All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.plugins.groovy.lang.parser.parsing.statements.declaration.VariableDefinitions Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition groovy-psi library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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.declaration;

import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.ThrowClause;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.annotations.AnnotationArguments;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.parameters.ParameterList;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.TupleParse;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.constructor.ConstructorBody;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.AssignmentExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;

/**
 * @autor: Dmitry.Krasilschikov
 * @date: 16.03.2007
 */

public class VariableDefinitions {

  public static IElementType parseDefinitions(@NotNull PsiBuilder builder,
                                              boolean isInClass,
                                              boolean isInAnnotation,
                                              @Nullable String typeDefinitionName,
                                              boolean hasModifiers,
                                              boolean canBeTuple,
                                              @NotNull GroovyParser parser) {
    boolean isLParenth = builder.getTokenType() == GroovyTokenTypes.mLPAREN;

    boolean isStringName = builder.getTokenType() == GroovyTokenTypes.mSTRING_LITERAL || builder.getTokenType() ==
                                                                                         GroovyTokenTypes.mGSTRING_LITERAL;

    if (builder.getTokenType() != GroovyTokenTypes.mIDENT && !isStringName && !isLParenth) {
      builder.error(GroovyBundle.message("indentifier.or.string.or.left.parenth.literal.expected"));
      return GroovyElementTypes.WRONGWAY;
    }

    if (isLParenth && !canBeTuple) {
      builder.error(GroovyBundle.message("indentifier.or.string.or.left.parenth.literal.expected"));
      return GroovyElementTypes.WRONGWAY;
    }

    if (isInAnnotation && isStringName) {
      builder.error(GroovyBundle.message("string.name.unexpected"));
    }

    if (!isLParenth) { //id or string => method name
      PsiBuilder.Marker varMarker = builder.mark();

      final boolean isConstructor = isInClass &&
                                    !isInAnnotation &&
                                    typeDefinitionName != null &&
                                    builder.getTokenType() == GroovyTokenTypes.mIDENT &&
                                    typeDefinitionName.equals(builder.getTokenText());
      builder.advanceLexer();

      if (GroovyTokenTypes.mLPAREN != builder.getTokenType()) {
        varMarker.rollbackTo();
      }
      else {
        varMarker.drop();
        return parseMethod(builder, isInAnnotation, hasModifiers, parser, isConstructor);
      }
    }

    return parseVar(builder, isInClass, hasModifiers, parser, isLParenth);
  }

  private static IElementType parseVar(PsiBuilder builder, boolean isInClass, boolean hasModifiers, GroovyParser parser, boolean LParenth) {
    // a = b, c = d
    PsiBuilder.Marker varAssMarker = builder.mark();

    final IElementType declarator = parseDeclarator(builder, LParenth);

    if (declarator != GroovyElementTypes.WRONGWAY) {
      final boolean wasAssignment = parseAssignment(builder, parser);

      if (declarator == GroovyElementTypes.TUPLE_DECLARATION) {
        varAssMarker.drop();
        if (!wasAssignment && !hasModifiers) {
          builder.error(GroovyBundle.message("assignment.expected"));
          return GroovyElementTypes.WRONGWAY;
        }
      }
      else if (isInClass) { // a = b, c = d
        varAssMarker.done(GroovyElementTypes.FIELD);
      }
      else {
        varAssMarker.done(GroovyElementTypes.VARIABLE);
      }

      while (ParserUtils.getToken(builder, GroovyTokenTypes.mCOMMA)) {
        ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);

        if (GroovyElementTypes.WRONGWAY.equals(parseVariableOrField(builder, isInClass, parser)) && declarator == GroovyTokenTypes.mIDENT) {
          return GroovyElementTypes.VARIABLE_DEFINITION_ERROR; //parse b = d
        }
      }

      if (isInClass && declarator == GroovyElementTypes.TUPLE_DECLARATION) {
        builder.error(GroovyBundle.message("tuple.cant.be.placed.in.class"));
      }
      return GroovyElementTypes.VARIABLE_DEFINITION;
    }
    else {
      varAssMarker.drop();
      builder.error(GroovyBundle.message("identifier.expected"));
      return GroovyElementTypes.WRONGWAY;
    }
  }

  private static IElementType parseMethod(PsiBuilder builder,
                                          boolean isAnnotationMember,
                                          boolean hasModifiers,
                                          GroovyParser parser,
                                          boolean constructor) {
    //if we have no modifiers and current method is not constructor there is something wrong
    if (!hasModifiers && !constructor) {
      builder.error(GroovyBundle.message("method.definition.without.modifier"));
      return GroovyElementTypes.WRONGWAY;
    }

    builder.advanceLexer();

    ParameterList.parse(builder, GroovyTokenTypes.mRPAREN, parser);

    ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
    if (!ParserUtils.getToken(builder, GroovyTokenTypes.mRPAREN)) {
      builder.error(GroovyBundle.message("rparen.expected"));
      ThrowClause.parse(builder);
      return methodType(isAnnotationMember, constructor);
    }

    if (isAnnotationMember && builder.getTokenType() == GroovyTokenTypes.kDEFAULT) {
      ParserUtils.getToken(builder, GroovyTokenTypes.kDEFAULT);
      ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);

      if (!AnnotationArguments.parseAnnotationMemberValueInitializer(builder, parser)) {
        builder.error(GroovyBundle.message("annotation.initializer.expected"));
      }
    }

    if (ParserUtils.lookAhead(builder, GroovyTokenTypes.mNLS, GroovyTokenTypes.kTHROWS) || ParserUtils.lookAhead(builder,
                                                                                                                 GroovyTokenTypes.mNLS,
                                                                                                                 GroovyTokenTypes.mLCURLY)) {
      ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
    }

    if (isAnnotationMember && builder.getTokenType() == GroovyTokenTypes.kTHROWS) {
      builder.error(GroovyBundle.message("throws.clause.is.not.allowed.in.at.interface"));
    }
    ThrowClause.parse(builder);

    if (builder.getTokenType() == GroovyTokenTypes.mLCURLY || ParserUtils.lookAhead(builder, GroovyTokenTypes.mNLS,
                                                                                    GroovyTokenTypes.mLCURLY)) {
      ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
      if (isAnnotationMember) {
        builder.error(GroovyBundle.message("separator.or.rcurly.expected"));
      }
      if (constructor) {
        ConstructorBody.parseConstructorBody(builder, parser);
      }
      else {
        OpenOrClosableBlock.parseOpenBlock(builder, parser);
      }
    }

    return methodType(isAnnotationMember, constructor);
  }

  private static IElementType methodType(boolean isAnnotationMember, final boolean isConstructor) {
    return isAnnotationMember ? GroovyElementTypes.ANNOTATION_METHOD :
           isConstructor ? GroovyElementTypes.CONSTRUCTOR_DEFINITION :
           GroovyElementTypes.METHOD_DEFINITION;
  }

  //a, a = b

  private static IElementType parseVariableOrField(PsiBuilder builder, boolean isInClass, GroovyParser parser) {
    PsiBuilder.Marker varAssMarker = builder.mark();
    if (ParserUtils.getToken(builder, GroovyTokenTypes.mIDENT)) {
      parseAssignment(builder, parser);
      if (isInClass) {
        varAssMarker.done(GroovyElementTypes.FIELD);
        return GroovyElementTypes.FIELD;
      }
      else {
        varAssMarker.done(GroovyElementTypes.VARIABLE);
        return GroovyElementTypes.VARIABLE;
      }
    }
    else {
      varAssMarker.drop();
      builder.error("Identifier expected");
      return GroovyElementTypes.WRONGWAY;
    }
  }

  private static IElementType parseDeclarator(PsiBuilder builder, boolean isTuple) {
    if (isTuple && builder.getTokenType() == GroovyTokenTypes.mLPAREN && TupleParse.parseTupleForVariableDeclaration(builder)) {
      return GroovyElementTypes.TUPLE_DECLARATION;
    }
    if (!isTuple && ParserUtils.getToken(builder, GroovyTokenTypes.mIDENT)) {
      return GroovyTokenTypes.mIDENT;
    }
    return GroovyElementTypes.WRONGWAY;
  }


  private static boolean parseAssignment(PsiBuilder builder, GroovyParser parser) {
    if (ParserUtils.getToken(builder, GroovyTokenTypes.mASSIGN)) {
      PsiBuilder.Marker marker = builder.mark();
      ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);

      if (!AssignmentExpression.parse(builder, parser, true)) {
        marker.rollbackTo();
        builder.error(GroovyBundle.message("expression.expected"));
        return false;
      }
      else {
        marker.drop();
        return true;
      }
    }
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy