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

org.jetbrains.plugins.groovy.lang.parser.parsing.statements.typeDefinitions.ReferenceElement 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.typeDefinitions;

import com.intellij.codeInsight.completion.CompletionUtilCore;
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.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.parsing.types.TypeArguments;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
import org.jetbrains.plugins.groovy.lang.psi.stubs.elements.GrReferenceListElementType;

/**
 * @author: Dmitry.Krasilschikov
 * @date: 20.03.2007
 */

public class ReferenceElement {
  public static final String DUMMY_IDENTIFIER = CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED; //inserted by completion

  @NotNull
  public static IElementType parseReferenceList(@NotNull PsiBuilder builder,
                                                @NotNull final IElementType startElement,
                                                @NotNull final GrReferenceListElementType clauseType,
                                                @NotNull ClassType type) {
    PsiBuilder.Marker isMarker = builder.mark();

    if (!ParserUtils.getToken(builder, startElement)) {
      if (clauseType == GroovyElementTypes.IMPLEMENTS_CLAUSE && (type == ClassType.INTERFACE || type == ClassType.ANNOTATION) ||
          clauseType == GroovyElementTypes.EXTENDS_CLAUSE && type == ClassType.ENUM ||
          type == ClassType.ANNOTATION) {
        isMarker.rollbackTo();
        return GroovyElementTypes.NONE;
      }

      return finish(builder, clauseType, isMarker, null, null);
    }

    PsiBuilder.Marker space = builder.mark();
    ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);

    if (parseReferenceElement(builder) == ReferenceElementResult.FAIL) {
      return finish(builder, clauseType, isMarker, space, GroovyBundle.message("identifier.expected"));
    }
    else {
      space.drop();
    }

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

      if (parseReferenceElement(builder) == ReferenceElementResult.FAIL) {
        return finish(builder, clauseType, isMarker, space, GroovyBundle.message("identifier.expected"));
      }
      else {
        space.drop();
      }
    }

    return finish(builder, clauseType, isMarker, null, null);
  }

  @NotNull
  private static GrReferenceListElementType finish(@NotNull PsiBuilder builder,
                                                      @NotNull GrReferenceListElementType clauseType,
                                                      @NotNull PsiBuilder.Marker isMarker,
                                                      @Nullable PsiBuilder.Marker space,
                                                      @Nullable String error) {
    if (space != null) space.rollbackTo();
    if (error != null) builder.error(error);
    isMarker.done(clauseType);
    return clauseType;
  }

  public enum ReferenceElementResult {
    IDENTIFIER, PATH_REF, REF_WITH_TYPE_PARAMS, FAIL
  }

  public static ReferenceElementResult parseForImport(@NotNull PsiBuilder builder) {
    return parse(builder, false, false, true, false, false);
  }

  public static ReferenceElementResult parseForPackage(@NotNull PsiBuilder builder) {
    return parse(builder, false, false, true, false, false);
  }

  //it doesn't important first letter of identifier of ThrowClause, of Annotation, of new Expression, of implements, extends, superclass clauses
  public static ReferenceElementResult parseReferenceElement(@NotNull PsiBuilder builder) {
    return parseReferenceElement(builder, false, true);
  }

  public static ReferenceElementResult parseReferenceElement(@NotNull PsiBuilder builder, boolean isUpperCase, final boolean expressionPossible) {
    return parse(builder, isUpperCase, true, false, false, expressionPossible);
  }

  public static ReferenceElementResult parse(@NotNull PsiBuilder builder,
                                             boolean checkUpperCase,
                                             boolean parseTypeArgs,
                                             boolean lineFeedAllowed,
                                             boolean allowDiamond,
                                             boolean expressionPossible) {
    PsiBuilder.Marker internalTypeMarker = builder.mark();

    String lastIdentifier = builder.getTokenText();

    if (!ParserUtils.getToken(builder, TokenSets.CODE_REFERENCE_ELEMENT_NAME_TOKENS)) {
      internalTypeMarker.rollbackTo();
      return ReferenceElementResult.FAIL;
    }

    boolean hasTypeArguments = false;
    if (parseTypeArgs && TypeArguments.parseTypeArguments(builder, expressionPossible, allowDiamond)) {
      hasTypeArguments = true;
    }

    internalTypeMarker.done(GroovyElementTypes.REFERENCE_ELEMENT);
    internalTypeMarker = internalTypeMarker.precede();

    boolean hasDots = builder.getTokenType() == GroovyTokenTypes.mDOT;

    while (builder.getTokenType() == GroovyTokenTypes.mDOT) {

      if ((ParserUtils.lookAhead(builder, GroovyTokenTypes.mDOT, GroovyTokenTypes.mSTAR) || ParserUtils.lookAhead(builder,
                                                                                                                  GroovyTokenTypes.mDOT,
                                                                                                                  GroovyTokenTypes.mNLS,
                                                                                                                  GroovyTokenTypes.mSTAR)) && lineFeedAllowed) {
        internalTypeMarker.drop();
        return ReferenceElementResult.PATH_REF;
      }

      ParserUtils.getToken(builder, GroovyTokenTypes.mDOT);

      if (lineFeedAllowed) {
        ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
      }

      lastIdentifier = builder.getTokenText();

      if (!ParserUtils.getToken(builder, TokenSets.CODE_REFERENCE_ELEMENT_NAME_TOKENS)) {
        if (TokenSets.REFERENCE_NAME_PREFIXES.contains(builder.getTokenType())) {
          internalTypeMarker.rollbackTo();
          return ReferenceElementResult.FAIL;
        }
        builder.error(GroovyBundle.message("identifier.expected"));
        internalTypeMarker.done(GroovyElementTypes.REFERENCE_ELEMENT);
        return ReferenceElementResult.PATH_REF;
      }

      if (parseTypeArgs && TypeArguments.parseTypeArguments(builder, expressionPossible, allowDiamond)) {
        hasTypeArguments = true;
      }

      internalTypeMarker.done(GroovyElementTypes.REFERENCE_ELEMENT);
      internalTypeMarker = internalTypeMarker.precede();
    }

    if (lastIdentifier == null) {
      //eof
      return ReferenceElementResult.FAIL;
    }

    char firstChar = lastIdentifier.charAt(0);
    if (checkUpperCase) {
      if (!Character.isUpperCase(firstChar) || DUMMY_IDENTIFIER.equals(lastIdentifier)) { //hack to make completion work
        internalTypeMarker.rollbackTo();
        return ReferenceElementResult.FAIL;
      }
    }

    internalTypeMarker.drop();

    return hasTypeArguments ? ReferenceElementResult.REF_WITH_TYPE_PARAMS :
           hasDots ? ReferenceElementResult.PATH_REF :
           ReferenceElementResult.IDENTIFIER;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy