@Nullable
  public PsiBuilder.Marker parse(final @NotNull PsiBuilder builder, final BaseContext context) {
    IElementType tokenType = builder.getTokenType();
    if (tokenType == null) return null;

    if (tokenType == JavaTokenType.LBRACE) {
      if (context == BaseContext.FILE || context == BaseContext.CODE_BLOCK) return null;
    }
    else if (!isRecordToken(builder, tokenType) && !isSealedToken(builder, tokenType) && !isNonSealedToken(builder, tokenType)) {
      if (!TYPE_START.contains(tokenType) || tokenType == JavaTokenType.AT) {
        if (tokenType instanceof ILazyParseableElementType) {
          builder.advanceLexer();
          return null;
        }
        else if (!BASIC_MODIFIER_BIT_SET.contains(tokenType) &&
                 !BASIC_CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
                 tokenType != JavaTokenType.AT &&
                 (context == BaseContext.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
          return null;
        }
      }
    }

    final PsiBuilder.Marker declaration = builder.mark();
    final int declarationStart = builder.getCurrentOffset();

    final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
    final PsiBuilder.Marker modList = modListInfo.first;

    if (expect(builder, JavaTokenType.AT)) {
      if (builder.getTokenType() == JavaTokenType.INTERFACE_KEYWORD) {
        final PsiBuilder.Marker result = parseClassFromKeyword(builder, declaration, true, context);
        return result != null ? result : modList;
      }
      else {
        declaration.rollbackTo();
        return null;
      }
    }
    if (BASIC_CLASS_KEYWORD_BIT_SET.contains(builder.getTokenType()) || isRecordToken(builder, builder.getTokenType())) {
      final PsiBuilder.Marker result = parseClassFromKeyword(builder, declaration, false, context);
      return result != null ? result : modList;
    }

    PsiBuilder.Marker typeParams = null;
    if (builder.getTokenType() == JavaTokenType.LT && context != BaseContext.CODE_BLOCK) {
      typeParams = myParser.getReferenceParser().parseTypeParameters(builder);
    }

    if (builder.getTokenType() == JavaTokenType.LBRACE) {
      if (context == BaseContext.CODE_BLOCK) {
        error(builder, JavaPsiBundle.message("expected.identifier.or.type"), null);
        declaration.drop();
        return modList;
      }

      PsiBuilder.Marker codeBlock = myParser.getStatementParser().parseCodeBlock(builder);
      assert codeBlock != null : builder.getOriginalText();

      if (typeParams != null) {
        PsiBuilder.Marker error = typeParams.precede();
        error.errorBefore(JavaPsiBundle.message("unexpected.token"), codeBlock);
      }

      done(declaration, myJavaElementTypeContainer.CLASS_INITIALIZER, myWhiteSpaceAndCommentSetHolder);
      return declaration;
    }

    BasicReferenceParser.TypeInfo type = null;

    if (TYPE_START.contains(builder.getTokenType())) {
      PsiBuilder.Marker pos = builder.mark();

      int flags = BasicReferenceParser.EAT_LAST_DOT | BasicReferenceParser.WILDCARD;
      if (context == BaseContext.CODE_BLOCK) flags |= BasicReferenceParser.VAR_TYPE;
      type = myParser.getReferenceParser().parseTypeInfo(builder, flags);

      if (type == null) {
        pos.rollbackTo();
      }
      else if (builder.getTokenType() == JavaTokenType.LPARENTH || builder.getTokenType() == JavaTokenType.LBRACE) {  // constructor
        if (context == BaseContext.CODE_BLOCK) {
          declaration.rollbackTo();
          return null;
        }

        pos.rollbackTo();

        if (typeParams == null) {
          emptyElement(builder, myJavaElementTypeContainer.TYPE_PARAMETER_LIST);
        }
        parseAnnotations(builder);

        if (!expect(builder, JavaTokenType.IDENTIFIER)) {
          PsiBuilder.Marker primitive = builder.mark();
          builder.advanceLexer();
          primitive.error(JavaPsiBundle.message("expected.identifier"));
        }

        if (builder.getTokenType() == JavaTokenType.LPARENTH) {
          return parseMethodFromLeftParenth(builder, declaration, false, true);
        }
        else if (builder.getTokenType() == JavaTokenType.LBRACE) { // compact constructor
          emptyElement(builder, myJavaElementTypeContainer.THROWS_LIST);
          return parseMethodBody(builder, declaration, false);
        }
        else {
          declaration.rollbackTo();
          return null;
        }
      }
      else {
        pos.drop();
      }
    }

    if (type == null) {
      PsiBuilder.Marker error = typeParams != null ? typeParams.precede() : builder.mark();
      error.error(JavaPsiBundle.message("expected.identifier.or.type"));
      declaration.drop();
      return modList;
    }

    if (!expect(builder, JavaTokenType.IDENTIFIER)) {
      if (context != BaseContext.CODE_BLOCK ||
          Boolean.FALSE.equals(modListInfo.second) ||
          (type.isPrimitive && builder.getTokenType() != JavaTokenType.DOT)) {
        if (typeParams != null) {
          typeParams.precede().errorBefore(JavaPsiBundle.message("unexpected.token"), type.marker);
        }
        builder.error(JavaPsiBundle.message("expected.identifier"));
        declaration.drop();
        return modList;
      }
      else {
        declaration.rollbackTo();
        return null;
      }
    }

    if (builder.getTokenType() == JavaTokenType.LPARENTH) {
      if (context == BaseContext.CLASS || context == BaseContext.ANNOTATION_INTERFACE || context == BaseContext.FILE) {  // method
        if (typeParams == null) {
          emptyElement(type.marker, myJavaElementTypeContainer.TYPE_PARAMETER_LIST);
        }
        return parseMethodFromLeftParenth(builder, declaration, (context == BaseContext.ANNOTATION_INTERFACE), false);
      }
    }

    if (typeParams != null) {
      typeParams.precede().errorBefore(JavaPsiBundle.message("unexpected.token"), type.marker);
    }
    return parseFieldOrLocalVariable(builder, declaration, declarationStart, context);
  }
@Nullable
  public PsiBuilder.Marker parse(final @NotNull PsiBuilder builder, final BaseContext context)