private static void exit_section_impl_()

in src/org/intellij/grammar/parser/GeneratedParserUtilBase.java [552:635]


  private static void exit_section_impl_(ErrorState state,
                                         Frame frame,
                                         PsiBuilder builder,
                                         @Nullable IElementType elementType,
                                         boolean result,
                                         boolean pinned,
                                         @Nullable Parser eatMore) {
    int initialPos = builder.rawTokenIndex();
    replace_variants_with_name_(state, frame, builder, elementType, result, pinned);
    int lastErrorPos = frame.lastVariantAt < 0 ? initialPos : frame.lastVariantAt;
    if (!state.suppressErrors && eatMore != null) {
      state.suppressErrors = true;
      final boolean eatMoreFlagOnce = !builder.eof() && eatMore.parse(builder, frame.level + 1);
      boolean eatMoreFlag = eatMoreFlagOnce || !result && frame.position == initialPos && lastErrorPos > frame.position;

      PsiBuilderImpl.ProductionMarker latestDoneMarker =
        (pinned || result) && (state.altMode || elementType != null) &&
        eatMoreFlagOnce ? getLatestExtensibleDoneMarker(builder) : null;
      // advance to the last error pos
      // skip tokens until lastErrorPos. parseAsTree might look better here...
      int parenCount = 0;
      while ((eatMoreFlag || parenCount > 0) && builder.rawTokenIndex() < lastErrorPos) {
        IElementType tokenType = builder.getTokenType();
        if (state.braces != null) {
          if (tokenType == state.braces[0].getLeftBraceType()) parenCount ++;
          else if (tokenType == state.braces[0].getRightBraceType()) parenCount --;
        }
        if (!(builder.rawTokenIndex() < lastErrorPos)) break;
        state.tokenAdvancer.parse(builder, frame.level + 1);
        eatMoreFlag = eatMore.parse(builder, frame.level + 1);
      }
      boolean errorReported = frame.errorReportedAt == initialPos || !result && frame.errorReportedAt >= frame.position;
      if (errorReported || eatMoreFlag) {
        if (!errorReported) {
          errorReported = reportError(builder, state, frame, false, true, true);
        }
        else if (eatMoreFlag) {
          state.tokenAdvancer.parse(builder, frame.level + 1);
        }
        if (eatMore.parse(builder, frame.level + 1)) {
          parseAsTree(state, builder, frame.level + 1, DUMMY_BLOCK, true, state.tokenAdvancer, eatMore);
        }
      }
      else if (eatMoreFlagOnce || !result && frame.position != builder.rawTokenIndex() || frame.errorReportedAt > initialPos) {
        errorReported = reportError(builder, state, frame, false, true, false);
      }
      else if (!result && pinned && frame.errorReportedAt < 0) {
        errorReported = reportError(builder, state, frame, elementType != null, false, false);
      }
      // whitespace prefix makes the very first frame offset bigger than marker start offset which is always 0
      if (latestDoneMarker != null &&
          frame.position >= latestDoneMarker.getStartIndex() &&
          frame.position <= latestDoneMarker.getEndIndex()) {
        extend_marker_impl((PsiBuilder.Marker)latestDoneMarker);
      }
      state.suppressErrors = false;
      if (errorReported || result) {
        state.clearVariants(true, 0);
        state.clearVariants(false, 0);
        frame.lastVariantAt = -1;
        for (Frame f = frame; f != null && f.variantCount > 0; f = f.parentFrame) f.variantCount = 0;
      }
    }
    else if (!result && pinned && frame.errorReportedAt < 0) {
      // do not report if there are errors beyond current position
      if (lastErrorPos == initialPos) {
        // do not force, inner recoverRoot might have skipped some tokens
        reportError(builder, state, frame, elementType != null && (frame.modifiers & _UPPER_) == 0, false, false);
      }
      else if (lastErrorPos > initialPos) {
        // set error pos here as if it is reported for future reference
        frame.errorReportedAt = lastErrorPos;
      }
    }
    // propagate errorReportedAt up the stack to avoid duplicate reporting
    if (state.currentFrame != null) {
      if (state.currentFrame.errorReportedAt < frame.errorReportedAt) {
        state.currentFrame.errorReportedAt = frame.errorReportedAt;
      }
      if (state.currentFrame.lastVariantAt < frame.lastVariantAt) {
        state.currentFrame.lastVariantAt = frame.lastVariantAt;
      }
    }
  }