コード例 #1
0
  /**
   * Named list operators
   *
   * @param b PerlBuilder
   * @param l Parsing level
   * @return parsing result
   */
  public static boolean isListOperator(PsiBuilder b, int l) {
    PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1);

    if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE) return false;

    IElementType tokenType = b.getTokenType();
    IElementType nextTokenType = b.lookAhead(1);

    if (CONVERTABLE_TOKENS.contains(tokenType)
        && nextTokenType != LEFT_PAREN // not function call
        && !PACKAGE_TOKENS.contains(nextTokenType) // not method Package::
        && !(nextTokenType == IDENTIFIER
            && ((PerlBuilder) b)
                .isKnownPackage(
                    ((PerlBuilder) b).lookupToken(1).getTokenText())) // not Method Package
    )
      // todo we should check current namespace here
      return !PerlSubUtil.BUILT_IN_UNARY.contains(b.getTokenText());
    else if (PACKAGE_TOKENS.contains(tokenType)
        && CONVERTABLE_TOKENS.contains(nextTokenType)
        && b.lookAhead(2) != LEFT_PAREN)
      return !PerlSubUtil.isUnary(
          b.getTokenText(), ((PerlBuilder) b).lookupToken(1).getTokenText());

    return false;
  }
コード例 #2
0
 private static boolean reportError(ErrorState state, PsiBuilder builder_, boolean force) {
   String expectedText = state.getExpectedText(builder_);
   boolean notEmpty = StringUtil.isNotEmpty(expectedText);
   if (force || notEmpty) {
     final String gotText =
         builder_.eof()
             ? "unexpected end of file"
             : notEmpty
                 ? "got '" + builder_.getTokenText() + "'"
                 : "'" + builder_.getTokenText() + "' unexpected";
     builder_.error(expectedText + gotText);
     return true;
   }
   return false;
 }
コード例 #3
0
 private void getNextTokenValue(PsiBuilder builder) {
   PsiBuilder.Marker rb = builder.mark();
   builder.advanceLexer();
   nextToken = builder.getTokenType();
   nextTokenText = builder.getTokenText();
   rb.rollbackTo();
 }
コード例 #4
0
 private static boolean reportError(
     PsiBuilder builder,
     ErrorState state,
     Frame frame,
     IElementType elementType,
     boolean force,
     boolean advance) {
   String expectedText = state.getExpectedText(builder);
   boolean notEmpty = StringUtil.isNotEmpty(expectedText);
   if (force || notEmpty || advance) {
     String gotText =
         builder.eof()
             ? "unexpected end of file"
             : notEmpty
                 ? "got '" + builder.getTokenText() + "'"
                 : "'" + builder.getTokenText() + "' unexpected";
     String message = expectedText + gotText;
     if (advance) {
       PsiBuilder.Marker mark = builder.mark();
       builder.advanceLexer();
       mark.error(message);
     } else if (!force) {
       PsiBuilder.Marker extensionMarker = null;
       IElementType extensionTokenType = null;
       PsiBuilderImpl.ProductionMarker latestDoneMarker =
           elementType == null
               ? null
               : (PsiBuilderImpl.ProductionMarker) builder.getLatestDoneMarker();
       if (latestDoneMarker != null
           && frame.position >= latestDoneMarker.getStartIndex()
           && frame.position <= latestDoneMarker.getEndIndex()) {
         extensionMarker = ((PsiBuilder.Marker) latestDoneMarker).precede();
         extensionTokenType = latestDoneMarker.getTokenType();
         ((PsiBuilder.Marker) latestDoneMarker).drop();
       }
       builder.error(message);
       if (extensionMarker != null) extensionMarker.done(extensionTokenType);
     } else {
       builder.error(message);
     }
     builder.eof(); // skip whitespaces
     frame.errorReportedAt = builder.rawTokenIndex();
     return true;
   }
   return false;
 }
コード例 #5
0
 @NotNull
 protected String getTokenText() {
   String result = myBuilder.getTokenText();
   if (result == null) {
     result = "";
   }
   return result;
 }
コード例 #6
0
  /**
   * Named unary operators
   *
   * @param b PerlBuilder
   * @param l parsing level
   * @return parsing result
   */
  public static boolean isUnaryOperator(PsiBuilder b, int l) {
    assert b instanceof PerlBuilder;
    PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1);

    if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE) return false;

    IElementType tokenType = b.getTokenType();
    IElementType nextTokenType = b.lookAhead(1);

    if (CONVERTABLE_TOKENS.contains(tokenType)
        && nextTokenType != LEFT_PAREN
        && !PACKAGE_TOKENS.contains(nextTokenType))
      // todo we should check current namespace here
      return PerlSubUtil.BUILT_IN_UNARY.contains(b.getTokenText());
    else if (PACKAGE_TOKENS.contains(tokenType)
        && CONVERTABLE_TOKENS.contains(SUB)
        && b.lookAhead(2) != LEFT_PAREN) {
      PerlTokenData nextToken = ((PerlBuilder) b).lookupToken(1);
      if (nextToken != null) return PerlSubUtil.isUnary(b.getTokenText(), nextToken.getTokenText());
    }

    return false;
  }
コード例 #7
0
  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);
  }
コード例 #8
0
  public void advance() {
    final String tokenText = myBuilder.getTokenText();
    final int tokenLength = tokenText == null ? 0 : tokenText.length();

    final int whiteSpaceStart = getCurrentOffset() + tokenLength;
    myBuilder.advanceLexer();
    final int whiteSpaceEnd = getCurrentOffset();
    final String whiteSpaceText =
        myBuilder.getOriginalText().subSequence(whiteSpaceStart, whiteSpaceEnd).toString();

    int i = whiteSpaceText.lastIndexOf('\n');
    if (i >= 0) {
      myCurrentIndent = whiteSpaceText.length() - i - 1;
      myNewLine = true;
    } else {
      myNewLine = false;
    }
  }
コード例 #9
0
  /**
   * parser for print/say/printf filehandle
   *
   * @param b PerlBuilder
   * @param l parsing level
   * @return parsing result
   */
  public static boolean parsePrintHandle(PsiBuilder b, int l) {
    IElementType currentTokenType = b.getTokenType();
    IElementType nextTokenType = b.lookAhead(1);
    assert b instanceof PerlBuilder;

    if (CONVERTABLE_TOKENS.contains(currentTokenType) // it's identifier
        && !PRINT_HANDLE_NEGATE_SUFFIX.contains(nextTokenType) // no negation tokens
        && !PerlSubUtil.BUILT_IN.contains(
            b.getTokenText()) // it's not built in. crude, probably we should check any known sub
    ) {
      PsiBuilder.Marker m = b.mark();
      b.advanceLexer();
      m.collapse(HANDLE);
      return true;
    }

    return false;
  }
コード例 #10
0
  @NotNull
  public ASTNode parse(final IElementType root, final PsiBuilder builder) {
    final PsiBuilder.Marker fileMarker = builder.mark();

    final Stack<Pair<Integer, PsiBuilder.Marker>> stack =
        new Stack<Pair<Integer, PsiBuilder.Marker>>();
    stack.push(Pair.create(0, builder.mark()));

    PsiBuilder.Marker startLineMarker = null;
    int currentIndent = 0;
    boolean eolSeen = false;

    while (!builder.eof()) {
      final IElementType type = builder.getTokenType();
      // EOL
      if (type == myEolTokenType) {
        // Handle variant with several EOLs
        if (startLineMarker == null) {
          startLineMarker = builder.mark();
        }
        eolSeen = true;
      } else

      // Indent
      {
        if (type == myIndentTokenType) {
          //noinspection ConstantConditions
          currentIndent = builder.getTokenText().length();
        } else if (eolSeen) {
          if (startLineMarker != null) {
            startLineMarker.rollbackTo();
            startLineMarker = null;
          }
          // Close indentation blocks
          while (!stack.isEmpty() && currentIndent < stack.peek().first) {
            stack.pop().second.done(myBlockElementType);
          }

          if (!stack.isEmpty()) {
            final Pair<Integer, PsiBuilder.Marker> pair = stack.peek();
            if (currentIndent == pair.first) {
              stack.pop().second.done(myBlockElementType);
              passEOLsAndIndents(builder);
              stack.push(Pair.create(currentIndent, builder.mark()));
            }
            if (currentIndent > pair.first) {
              passEOLsAndIndents(builder);
              stack.push(Pair.create(currentIndent, builder.mark()));
            }
          }
          eolSeen = false;
          currentIndent = 0;
        }
      }
      advanceLexer(builder);
    }

    // Close all left opened markers
    if (startLineMarker != null) {
      startLineMarker.drop();
    }
    while (!stack.isEmpty()) {
      stack.pop().second.done(myBlockElementType);
    }

    return buildTree(fileMarker, builder, root);
  }
コード例 #11
0
  @Nullable
  public static IElementType parseAfterModifiers(
      PsiBuilder builder,
      boolean isInClass,
      boolean isInAnnotation,
      GroovyParser parser,
      PsiBuilder.Marker declMarker,
      boolean modifiersParsed) {
    if (modifiersParsed && mLT == builder.getTokenType()) {
      TypeParameters.parse(builder);
      PsiBuilder.Marker checkMarker = builder.mark(); // point to begin of type or variable

      if (TypeSpec.parse(builder, true)
          == fail) { // if type wasn't recognized trying parse VariableDeclaration
        checkMarker.rollbackTo();
      } else {
        checkMarker.drop();
      }
      IElementType decl =
          VariableDefinitions.parseDefinitions(
              builder, isInClass, false, false, true, modifiersParsed, false, parser);

      if (WRONGWAY.equals(decl)) {
        return WRONGWAY;
      }

      return METHOD_DEFINITION;
    }

    if (modifiersParsed) {

      PsiBuilder.Marker checkMarker = builder.mark(); // point to begin of type or variable

      if (TypeSpec.parse(builder, false)
          == fail) { // if type wasn't recognized trying parse VariableDeclaration
        checkMarker.rollbackTo();

        if (isInAnnotation) {
          builder.error(GroovyBundle.message("type.expected"));
        }

        // current token isn't identifier
        IElementType varDecl =
            VariableDefinitions.parse(builder, isInClass, modifiersParsed, parser);

        if (WRONGWAY.equals(varDecl)) {
          return WRONGWAY;
        }
        return varDecl;
      } else { // type was recognized, identifier here
        // starts after type
        IElementType varDeclarationTop =
            VariableDefinitions.parse(builder, isInClass, modifiersParsed, false, parser);

        if (WRONGWAY.equals(varDeclarationTop)) {
          checkMarker.rollbackTo();

          if (isInAnnotation) {
            builder.error(GroovyBundle.message("type.expected"));
          }

          // starts before "type" identifier, here can't be tuple, because next token is identifier
          // (we are in "type recognized" branch)
          IElementType varDecl =
              VariableDefinitions.parse(builder, isInClass, modifiersParsed, false, parser);

          if (WRONGWAY.equals(varDecl)) {
            return WRONGWAY;
          } else {
            return varDecl;
          }
        } else {
          checkMarker.drop();
          return varDeclarationTop;
        }
      }
    } else {

      // if definition starts with lower case letter than it can be just call expression

      String text = builder.getTokenText();
      if (!builder.eof()
          && !TokenSets.BUILT_IN_TYPE.contains(builder.getTokenType())
          && text != null
          && (Character.isLowerCase((text.charAt(0))) || !Character.isLetter(text.charAt(0)))
          && (ParserUtils.lookAhead(builder, mIDENT, mIDENT)
              || ParserUtils.lookAhead(builder, mIDENT, mLPAREN))) {
        // call expression
        return WRONGWAY;
      }

      boolean typeParsed = false;
      if (!ParserUtils.lookAhead(builder, mIDENT, mLPAREN)) {
        typeParsed = TypeSpec.parse(builder, true) != fail;
        // type specification starts with upper case letter
        if (!typeParsed) {
          builder.error(GroovyBundle.message("type.specification.expected"));
          return WRONGWAY;
        }
      }

      IElementType varDef =
          VariableDefinitions.parseDefinitions(
              builder, isInClass, false, false, false, typeParsed, false, parser);
      if (varDef != WRONGWAY) {
        return varDef;
      } else if (isInClass && typeParsed) {
        return typeParsed ? null : WRONGWAY;
      }

      return WRONGWAY;
    }
  }
コード例 #12
0
  public static boolean exitErrorRecordingSection(
      PsiBuilder builder_,
      int level,
      boolean result,
      boolean pinned,
      @NotNull String sectionType,
      @Nullable Parser eatMore) {
    ErrorState state = ErrorState.get(builder_);

    Frame frame = state.levelCheck.pollLast();
    int initialOffset = builder_.getCurrentOffset();
    if (frame == null || level != frame.level || !sectionType.equals(frame.section)) {
      LOG.error(
          "Unbalanced error section: got "
              + new Frame().init(initialOffset, level, sectionType, "", 0)
              + ", expected "
              + frame);
      if (frame != null) state.FRAMES.recycle(frame);
      return result;
    }
    if (sectionType == _SECTION_AND_ || sectionType == _SECTION_NOT_) {
      state.predicateCount--;
      if (sectionType == _SECTION_NOT_) state.predicateSign = !state.predicateSign;
      state.FRAMES.recycle(frame);
      return result;
    }
    if (!result
        && !pinned
        && initialOffset == frame.offset
        && state.lastExpectedVariantOffset == frame.offset
        && frame.name != null
        && state.variants.size() - frame.variantCount > 1) {
      state.clearVariants(true, frame.variantCount);
      addVariantInner(state, initialOffset, frame.name);
    }
    if (sectionType == _SECTION_RECOVER_ && !state.suppressErrors && eatMore != null) {
      state.suppressErrors = true;
      final boolean eatMoreFlagOnce = !builder_.eof() && eatMore.parse(builder_, frame.level + 1);
      final int lastErrorPos = getLastVariantOffset(state, initialOffset);
      boolean eatMoreFlag =
          eatMoreFlagOnce || frame.offset == initialOffset && lastErrorPos > frame.offset;

      final LighterASTNode latestDoneMarker =
          (pinned || result) && (state.altMode || lastErrorPos > initialOffset) && eatMoreFlagOnce
              ? builder_.getLatestDoneMarker()
              : null;
      PsiBuilder.Marker extensionMarker = null;
      IElementType extensionTokenType = null;
      if (latestDoneMarker instanceof PsiBuilder.Marker) {
        extensionMarker = ((PsiBuilder.Marker) latestDoneMarker).precede();
        extensionTokenType = latestDoneMarker.getTokenType();
        ((PsiBuilder.Marker) latestDoneMarker).drop();
      }
      // advance to the last error pos
      // skip tokens until lastErrorPos. parseAsTree might look better here...
      int parenCount = 0;
      while (eatMoreFlag && builder_.getCurrentOffset() < lastErrorPos) {
        if (state.braces != null) {
          if (builder_.getTokenType() == state.braces[0].getLeftBraceType()) parenCount++;
          else if (builder_.getTokenType() == state.braces[0].getRightBraceType()) parenCount--;
        }
        builder_.advanceLexer();
        eatMoreFlag = parenCount != 0 || eatMore.parse(builder_, frame.level + 1);
      }
      boolean errorReported = frame.errorReportedAt == initialOffset;
      if (errorReported) {
        if (eatMoreFlag) {
          builder_.advanceLexer();
          parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore);
        }
      } else if (eatMoreFlag) {
        String tokenText = builder_.getTokenText();
        String expectedText = state.getExpectedText(builder_);
        PsiBuilder.Marker mark = builder_.mark();
        builder_.advanceLexer();
        final String gotText =
            !expectedText.isEmpty() ? "got '" + tokenText + "'" : "'" + tokenText + "' unexpected";
        mark.error(expectedText + gotText);
        parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore);
        errorReported = true;
      } else if (eatMoreFlagOnce || (!result && frame.offset != builder_.getCurrentOffset())) {
        reportError(state, builder_, true);
        errorReported = true;
      }
      if (extensionMarker != null) {
        extensionMarker.done(extensionTokenType);
      }
      state.suppressErrors = false;
      if (errorReported || result) {
        state.clearVariants(true, 0);
        state.clearVariants(false, 0);
        state.lastExpectedVariantOffset = -1;
      }
      if (!result && eatMoreFlagOnce && frame.offset != builder_.getCurrentOffset()) result = true;
    } else if (!result && pinned && frame.errorReportedAt < 0) {
      // do not report if there're errors after current offset
      if (getLastVariantOffset(state, initialOffset) == initialOffset) {
        // do not force, inner recoverRoot might have skipped some tokens
        if (reportError(state, builder_, false)) {
          frame.errorReportedAt = initialOffset;
        }
      }
    }
    // propagate errorReportedAt up the stack to avoid duplicate reporting
    Frame prevFrame = state.levelCheck.isEmpty() ? null : state.levelCheck.getLast();
    if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt)
      prevFrame.errorReportedAt = frame.errorReportedAt;
    state.FRAMES.recycle(frame);
    return result;
  }
コード例 #13
0
  /**
   * Parses invocable method As input we may have: PACKAGE_IDENTIFIER IDENTIFIER Foo::sub IDENTIFIER
   * PACKAGE_IDENTIFIER sub Foo:: IDENTIFIER IDENTIFIER sub Foo
   *
   * @param b PerlBuilder
   * @param l parsing level
   * @return parsing result
   */
  public static boolean parseMethod(PsiBuilder b, int l) {
    IElementType currentTokenType = b.getTokenType();
    IElementType nextTokenType = b.lookAhead(1);

    assert b instanceof PerlBuilder;

    // can be
    // 	Foo::method
    //  Foo::Bar
    if (PACKAGE_TOKENS.contains(currentTokenType) && CONVERTABLE_TOKENS.contains(nextTokenType)) {
      PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);
      PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2);

      IElementType nextNextTokenType =
          nextNextTokenData == null ? null : nextNextTokenData.getTokenType();

      String canonicalPackageName = PerlPackageUtil.getCanonicalPackageName(b.getTokenText());
      String potentialSubName = canonicalPackageName + "::" + nextTokenData.getTokenText();

      if (nextNextTokenType == LEFT_PAREN // Package::Identifier( - what can it be?
          || ((PerlBuilder) b).isKnownSub(potentialSubName) // we know this sub
          || !((PerlBuilder) b).isKnownPackage(potentialSubName)) // we don't know such package
      return convertPackageIdentifier(b, l) && convertIdentifier(b, l, SUB);
      else return false;
    }
    // 	method
    else if (CONVERTABLE_TOKENS.contains(currentTokenType)) {
      PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1);

      // ->sub
      if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE)
        return convertIdentifier(b, l, SUB);
      // may be
      // 	method Foo::
      //	method Foo::Bar
      //  method Foo::othermethod
      else if (PACKAGE_TOKENS.contains(nextTokenType)) {
        IElementType nextNextTokenType = b.lookAhead(2);

        // sub Foo::->method
        if (nextNextTokenType == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB);
        // identifier Package::identifier
        else if (CONVERTABLE_TOKENS.contains(nextNextTokenType)) {

          // identifier Package::identifier->
          if (b.lookAhead(3) == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB);

          PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);
          PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2);

          String packageOrSub =
              PerlPackageUtil.getCanonicalPackageName(nextTokenData.getTokenText())
                  + "::"
                  + nextNextTokenData.getTokenText();

          if (((PerlBuilder) b).isKnownSub(packageOrSub)) return convertIdentifier(b, l, SUB);
          else if (((PerlBuilder) b).isKnownPackage(packageOrSub))
            return convertIdentifier(b, l, SUB) && mergePackageName(b, l);
          return convertIdentifier(b, l, SUB);
        } else
          // it's method Package::
          return convertIdentifier(b, l, SUB) && convertPackageIdentifier(b, l);
      }
      // may be
      // 	method Foo
      else if (CONVERTABLE_TOKENS.contains(nextTokenType)
          && b.lookAhead(2) != OPERATOR_DEREFERENCE) {
        PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);

        String potentialSubName = nextTokenData.getTokenText() + "::" + b.getTokenText();
        if (((PerlBuilder) b).isKnownSub(potentialSubName))
          return convertIdentifier(b, l, SUB) && convertIdentifier(b, l, PACKAGE);
        else return convertIdentifier(b, l, SUB);
      }
      // KnownPackage->
      else if (nextTokenType == OPERATOR_DEREFERENCE
          && ((PerlBuilder) b).isKnownPackage(b.getTokenText())) return false;
      // it's just sub
      else return convertIdentifier(b, l, SUB);
    }

    return false;
  }