public static void exit_section_(
      PsiBuilder builder,
      int level,
      PsiBuilder.Marker marker,
      @Nullable IElementType elementType,
      boolean result,
      boolean pinned,
      @Nullable Parser eatMore) {
    ErrorState state = ErrorState.get(builder);

    Frame frame = state.frameStack.pollLast();
    if (frame == null || level != frame.level) {
      LOG.error("Unbalanced error section: got " + frame + ", expected level " + level);
      if (frame != null) state.FRAMES.recycle(frame);
      close_marker_impl_(frame, marker, elementType, result);
      return;
    }

    if (((frame.modifiers & _AND_) | (frame.modifiers & _NOT_)) != 0) {
      close_marker_impl_(frame, marker, null, false);
      state.predicateCount--;
      if ((frame.modifiers & _NOT_) != 0) state.predicateSign = !state.predicateSign;
      state.FRAMES.recycle(frame);
      return;
    }
    close_frame_impl_(state, frame, builder, marker, elementType, result, pinned);
    exit_section_impl_(state, frame, builder, elementType, result, pinned, eatMore);
    state.FRAMES.recycle(frame);
  }
 private static void enter_section_impl_(
     PsiBuilder builder, int level, int modifiers, @Nullable String frameName) {
   ErrorState state = ErrorState.get(builder);
   Frame frame = state.FRAMES.alloc().init(builder, state, level, modifiers, frameName);
   Frame prevFrame = state.frameStack.peekLast();
   if (prevFrame != null && prevFrame.errorReportedAt > frame.position) {
     // report error for previous unsuccessful frame
     reportError(builder, state, frame, null, true, false);
   }
   if (((frame.modifiers & _LEFT_) | (frame.modifiers & _LEFT_INNER_)) != 0) {
     PsiBuilder.Marker left = (PsiBuilder.Marker) builder.getLatestDoneMarker();
     if (invalid_left_marker_guard_(builder, left, frameName)) {
       frame.leftMarker = left;
     }
   }
   state.frameStack.add(frame);
   if ((modifiers & _AND_) != 0) {
     if (state.predicateCount == 0 && !state.predicateSign) {
       throw new AssertionError("Incorrect false predicate sign");
     }
     state.predicateCount++;
   } else if ((modifiers & _NOT_) != 0) {
     if (state.predicateCount == 0) {
       state.predicateSign = false;
     } else {
       state.predicateSign = !state.predicateSign;
     }
     state.predicateCount++;
   }
 }
 public static void enterErrorRecordingSection(
     PsiBuilder builder_, int level, @NotNull String sectionType, @Nullable String frameName) {
   ErrorState state = ErrorState.get(builder_);
   Frame frame =
       state
           .FRAMES
           .alloc()
           .init(
               builder_.getCurrentOffset(), level, sectionType, frameName, state.variants.size());
   state.levelCheck.add(frame);
   if (sectionType == _SECTION_AND_) {
     if (state.predicateCount == 0 && !state.predicateSign) {
       throw new AssertionError("Incorrect false predicate sign");
     }
     state.predicateCount++;
   } else if (sectionType == _SECTION_NOT_) {
     if (state.predicateCount == 0) {
       state.predicateSign = false;
     } else {
       state.predicateSign = !state.predicateSign;
     }
     state.predicateCount++;
   }
 }
  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;
  }