public static boolean parseAmbiguousSigil(PsiBuilder b, int l, IElementType sigilTokenType) {
    IElementType tokenType = b.getTokenType();
    if (tokenType == sigilTokenType) {
      if (PerlParserDefinition.WHITE_SPACE_AND_COMMENTS.contains(b.rawLookup(1))
          && b.lookAhead(1) != LEFT_BRACE) // space disallowed after * or % if it's not a cast
      return false;

      b.advanceLexer();
      return true;
    }

    return false;
  }
  @Nullable
  private static IElementType getGtTokenType(final PsiBuilder builder) {
    IElementType tokenType = builder.getTokenType();
    if (tokenType != JavaTokenType.GT) return tokenType;

    if (builder.rawLookup(1) == JavaTokenType.GT) {
      if (builder.rawLookup(2) == JavaTokenType.GT) {
        if (builder.rawLookup(3) == JavaTokenType.EQ) {
          tokenType = JavaTokenType.GTGTGTEQ;
        } else {
          tokenType = JavaTokenType.GTGTGT;
        }
      } else if (builder.rawLookup(2) == JavaTokenType.EQ) {
        tokenType = JavaTokenType.GTGTEQ;
      } else {
        tokenType = JavaTokenType.GTGT;
      }
    } else if (builder.rawLookup(1) == JavaTokenType.EQ) {
      tokenType = JavaTokenType.GE;
    }

    return tokenType;
  }
 private static void addCompletionVariant(
     ErrorState state,
     CompletionState completionState,
     PsiBuilder builder_,
     Object o,
     int offset) {
   boolean add = false;
   int diff = completionState.offset - offset;
   String text = completionState.convertItem(o);
   int length = text == null ? 0 : text.length();
   if (length == 0) return;
   if (diff == 0) {
     add = true;
   } else if (diff > 0 && diff <= length) {
     CharSequence fragment =
         builder_.getOriginalText().subSequence(offset, completionState.offset);
     add = StringUtil.startsWithIgnoreCase(text, fragment.toString());
   } else if (diff < 0) {
     for (int i = -1; ; i--) {
       IElementType type = builder_.rawLookup(i);
       int tokenStart = builder_.rawTokenTypeStart(i);
       if (state.whitespaceTokens.contains(type) || state.commentTokens.contains(type)) {
         diff = completionState.offset - tokenStart;
       } else if (type != null && tokenStart < completionState.offset) {
         CharSequence fragment =
             builder_.getOriginalText().subSequence(tokenStart, completionState.offset);
         if (StringUtil.startsWithIgnoreCase(text, fragment.toString())) {
           diff = completionState.offset - tokenStart;
         }
         break;
       } else break;
     }
     add = diff >= 0 && diff < length;
   }
   add =
       add
           && length > 1
           && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>')
           && !(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5);
   if (add) {
     completionState.items.add(text);
   }
 }
  private static void addCompletionVariant(
      @NotNull PsiBuilder builder, @NotNull CompletionState completionState, Object o) {
    int offset = builder.getCurrentOffset();
    if (!builder.eof() && offset == builder.rawTokenTypeStart(1))
      return; // suppress for zero-length tokens

    boolean add = false;
    int diff = completionState.offset - offset;
    String text = completionState.convertItem(o);
    int length = text == null ? 0 : text.length();
    if (length == 0) return;
    if (diff == 0) {
      add = true;
    } else if (diff > 0 && diff <= length) {
      CharSequence fragment = builder.getOriginalText().subSequence(offset, completionState.offset);
      add = completionState.prefixMatches(fragment.toString(), text);
    } else if (diff < 0) {
      for (int i = -1; ; i--) {
        IElementType type = builder.rawLookup(i);
        int tokenStart = builder.rawTokenTypeStart(i);
        if (isWhitespaceOrComment(builder, type)) {
          diff = completionState.offset - tokenStart;
        } else if (type != null && tokenStart < completionState.offset) {
          CharSequence fragment =
              builder.getOriginalText().subSequence(tokenStart, completionState.offset);
          if (completionState.prefixMatches(fragment.toString(), text)) {
            diff = completionState.offset - tokenStart;
          }
          break;
        } else break;
      }
      add = diff >= 0 && diff < length;
    }
    add =
        add
            && length > 1
            && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>')
            && !(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5);
    if (add) {
      completionState.addItem(builder, text);
    }
  }
  public static boolean parseAsTree(
      ErrorState state,
      final PsiBuilder builder,
      int level,
      final IElementType chunkType,
      boolean checkBraces,
      final Parser parser,
      final Parser eatMoreCondition) {
    final LinkedList<Pair<PsiBuilder.Marker, PsiBuilder.Marker>> parenList =
        new LinkedList<Pair<PsiBuilder.Marker, PsiBuilder.Marker>>();
    final LinkedList<Pair<PsiBuilder.Marker, Integer>> siblingList =
        new LinkedList<Pair<PsiBuilder.Marker, Integer>>();
    PsiBuilder.Marker marker = null;

    final Runnable checkSiblingsRunnable =
        new Runnable() {
          @Override
          public void run() {
            main:
            while (!siblingList.isEmpty()) {
              final Pair<PsiBuilder.Marker, PsiBuilder.Marker> parenPair = parenList.peek();
              final int rating = siblingList.getFirst().second;
              int count = 0;
              for (Pair<PsiBuilder.Marker, Integer> pair : siblingList) {
                if (pair.second != rating || parenPair != null && pair.first == parenPair.second)
                  break main;
                if (++count >= MAX_CHILDREN_IN_TREE) {
                  PsiBuilder.Marker parentMarker = pair.first.precede();
                  parentMarker.setCustomEdgeTokenBinders(
                      WhitespacesBinders.GREEDY_LEFT_BINDER, null);
                  while (count-- > 0) {
                    siblingList.removeFirst();
                  }
                  parentMarker.done(chunkType);
                  siblingList.addFirst(Pair.create(parentMarker, rating + 1));
                  continue main;
                }
              }
              break;
            }
          }
        };
    boolean checkParens = state.braces != null && checkBraces;
    int totalCount = 0;
    int tokenCount = 0;
    if (checkParens) {
      int tokenIdx = -1;
      while (builder.rawLookup(tokenIdx) == TokenType.WHITE_SPACE) tokenIdx--;
      LighterASTNode doneMarker =
          builder.rawLookup(tokenIdx) == state.braces[0].getLeftBraceType()
              ? builder.getLatestDoneMarker()
              : null;
      if (doneMarker != null
          && doneMarker.getStartOffset() == builder.rawTokenTypeStart(tokenIdx)
          && doneMarker.getTokenType() == TokenType.ERROR_ELEMENT) {
        parenList.add(
            Pair.create(((PsiBuilder.Marker) doneMarker).precede(), (PsiBuilder.Marker) null));
      }
    }
    while (true) {
      final IElementType tokenType = builder.getTokenType();
      if (checkParens
          && (tokenType == state.braces[0].getLeftBraceType()
              || tokenType == state.braces[0].getRightBraceType() && !parenList.isEmpty())) {
        if (marker != null) {
          marker.done(chunkType);
          siblingList.addFirst(Pair.create(marker, 1));
          marker = null;
          tokenCount = 0;
        }
        if (tokenType == state.braces[0].getLeftBraceType()) {
          final Pair<PsiBuilder.Marker, Integer> prev = siblingList.peek();
          parenList.addFirst(Pair.create(builder.mark(), prev == null ? null : prev.first));
        }
        checkSiblingsRunnable.run();
        builder.advanceLexer();
        if (tokenType == state.braces[0].getRightBraceType()) {
          final Pair<PsiBuilder.Marker, PsiBuilder.Marker> pair = parenList.removeFirst();
          pair.first.done(chunkType);
          // drop all markers inside parens
          while (!siblingList.isEmpty() && siblingList.getFirst().first != pair.second) {
            siblingList.removeFirst();
          }
          siblingList.addFirst(Pair.create(pair.first, 1));
          checkSiblingsRunnable.run();
        }
      } else {
        if (marker == null) {
          marker = builder.mark();
          marker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, null);
        }
        final boolean result =
            (!parenList.isEmpty() || eatMoreCondition.parse(builder, level + 1))
                && parser.parse(builder, level + 1);
        if (result) {
          tokenCount++;
          totalCount++;
        }
        if (!result) {
          break;
        }
      }

      if (tokenCount >= MAX_CHILDREN_IN_TREE && marker != null) {
        marker.done(chunkType);
        siblingList.addFirst(Pair.create(marker, 1));
        checkSiblingsRunnable.run();
        marker = null;
        tokenCount = 0;
      }
    }
    if (marker != null) {
      marker.drop();
    }
    for (Pair<PsiBuilder.Marker, PsiBuilder.Marker> pair : parenList) {
      pair.first.drop();
    }
    return totalCount != 0;
  }
 @Nullable
 public IElementType rawLookup(int step) {
   return myBuilder.rawLookup(step);
 }
  /**
   * Parses tokens as variables name; replaces:
   *
   * @param b PerlBuilder
   * @param l parsing level
   * @return parsing result
   */
  public static boolean parseVariableName(PsiBuilder b, int l) {
    IElementType currentTokenType = b.getTokenType();
    IElementType nextTokenType = b.rawLookup(1);

    PsiBuilder.Marker m;

    //		while (currentTokenType == SIGIL_SCALAR                                // sigil is here
    //				&& POST_SIGILS_SUFFIXES.contains(nextTokenType)            // next can be variable name
    //				)
    //		{
    //			if (m == null)
    //				m = b.mark();
    //			b.advanceLexer();
    //			currentTokenType = nextTokenType;
    //			nextTokenType = b.rawLookup(1);
    //		}
    //
    //		if (m != null)
    //			m.collapse(SCALAR_SIGILS);

    // checking for scalar cast
    if (currentTokenType == SIGIL_SCALAR && POST_SIGILS_SUFFIXES.contains(b.lookAhead(1)))
      return false;

    // $package::
    // $package::var
    if (PACKAGE_TOKENS.contains(currentTokenType)) {
      PsiBuilder.Marker mp = b.mark();
      b.advanceLexer();
      mp.collapse(PACKAGE);
      if (CONVERTABLE_TOKENS.contains(nextTokenType)) {
        PsiBuilder.Marker mv = b.mark();
        b.advanceLexer();
        mv.collapse(VARIABLE_NAME);
      }
      return true;
    }
    // $var
    else if (POSSIBLE_VARIABLE_NAME.contains(currentTokenType)) {
      if (currentTokenType == OPERATOR_BITWISE_XOR
          && CONTROL_VARIABLE_NAMES.contains(nextTokenType)) // branch for $^]
      {
        m = b.mark();
        b.advanceLexer();
        b.advanceLexer();
        m.collapse(VARIABLE_NAME);
      } else {
        PsiBuilder.Marker mv = b.mark();
        b.advanceLexer();
        mv.collapse(VARIABLE_NAME);
      }

      return true;
    }
    // ${var}
    else if (currentTokenType == LEFT_BRACE) {
      b.advanceLexer();
      currentTokenType = nextTokenType;
      nextTokenType = b.lookAhead(1);

      // ${package::}
      // ${package::var}
      if (PACKAGE_TOKENS.contains(currentTokenType)) {
        PsiBuilder.Marker mp = b.mark();
        b.advanceLexer();
        mp.collapse(PACKAGE);
        if (CONVERTABLE_TOKENS.contains(nextTokenType) && b.lookAhead(1) == RIGHT_BRACE) {
          PsiBuilder.Marker mv = b.mark();
          b.advanceLexer();
          mv.collapse(VARIABLE_NAME);
          b.advanceLexer();
          return true;
        } else if (nextTokenType == RIGHT_BRACE) {
          b.advanceLexer();
          return true;
        }
      }
      // ${var}
      else if (POSSIBLE_VARIABLE_NAME.contains(currentTokenType) && nextTokenType == RIGHT_BRACE) {
        PsiBuilder.Marker mv = b.mark();
        b.advanceLexer();
        mv.collapse(VARIABLE_NAME);
        b.advanceLexer();
        return true;
      }
    }

    return false;
  }