/* *preamble * : namespaceHeader? import* * ; */ private void parsePreamble(boolean imports) { /* * namespaceHeader * : modifiers "namespace" SimpleName{"."} SEMI? * ; */ PsiBuilder.Marker namespaceHeader = mark(); PsiBuilder.Marker firstEntry = mark(); parseModifierList(MODIFIER_LIST, true); if (at(PACKAGE_KEYWORD)) { advance(); // PACKAGE_KEYWORD parseNamespaceName(); if (at(LBRACE)) { // Because it's blocked namespace and it will be parsed as one of top level objects firstEntry.rollbackTo(); namespaceHeader.done(NAMESPACE_HEADER); return; } firstEntry.drop(); consumeIf(SEMICOLON); } else { firstEntry.rollbackTo(); } namespaceHeader.done(NAMESPACE_HEADER); if (imports) parseImportDirectives(); }
@Nullable private PsiBuilder.Marker parseUnary(final PsiBuilder builder) { final IElementType tokenType = builder.getTokenType(); if (PREFIX_OPS.contains(tokenType)) { final PsiBuilder.Marker unary = builder.mark(); builder.advanceLexer(); final PsiBuilder.Marker operand = parseUnary(builder); if (operand == null) { error(builder, JavaErrorMessages.message("expected.expression")); } unary.done(JavaElementType.PREFIX_EXPRESSION); return unary; } else if (tokenType == JavaTokenType.LPARENTH) { final PsiBuilder.Marker typeCast = builder.mark(); builder.advanceLexer(); ReferenceParser.TypeInfo typeInfo = myParser .getReferenceParser() .parseTypeInfo( builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD | ReferenceParser.CONJUNCTIONS | ReferenceParser.INCOMPLETE_ANNO); if (typeInfo == null || !expect(builder, JavaTokenType.RPARENTH)) { typeCast.rollbackTo(); return parsePostfix(builder); } if (PREF_ARITHMETIC_OPS.contains(builder.getTokenType()) && !typeInfo.isPrimitive) { typeCast.rollbackTo(); return parsePostfix(builder); } final PsiBuilder.Marker expr = parseUnary(builder); if (expr == null) { if (!typeInfo .isParameterized) { // cannot parse correct parenthesized expression after correct // parameterized type typeCast.rollbackTo(); return parsePostfix(builder); } else { error(builder, JavaErrorMessages.message("expected.expression")); } } typeCast.done(JavaElementType.TYPE_CAST_EXPRESSION); return typeCast; } else { return parsePostfix(builder); } }
/* * "this" ("<" type ">")? label? */ private void parseSuperExpression() { assert _at(SUPER_KEYWORD); PsiBuilder.Marker mark = mark(); PsiBuilder.Marker superReference = mark(); advance(); // SUPER_KEYWORD superReference.done(REFERENCE_EXPRESSION); if (at(LT)) { // This may be "super < foo" or "super<foo>", thus the backtracking PsiBuilder.Marker supertype = mark(); myBuilder.disableNewlines(); advance(); // LT myJetParsing.parseTypeRef(); if (at(GT)) { advance(); // GT supertype.drop(); } else { supertype.rollbackTo(); } myBuilder.restoreNewlinesState(); } parseLabelOnTheSameLine(); mark.done(SUPER_EXPRESSION); }
/* * callableReference * : (userType "?"*)? "::" SimpleName * ; */ private boolean parseDoubleColonExpression() { PsiBuilder.Marker expression = mark(); if (!at(COLONCOLON)) { PsiBuilder.Marker typeReference = mark(); myJetParsing.parseUserType(); typeReference = myJetParsing.parseNullableTypeSuffix(typeReference); typeReference.done(TYPE_REFERENCE); if (!at(COLONCOLON)) { expression.rollbackTo(); return false; } } advance(); // COLONCOLON if (at(CLASS_KEYWORD)) { advance(); // CLASS_KEYWORD expression.done(CLASS_LITERAL_EXPRESSION); } else { parseSimpleNameExpression(); expression.done(CALLABLE_REFERENCE_EXPRESSION); } return true; }
protected boolean parseTupleExpression( boolean stopOnIn, boolean isTargetExpression, final boolean oldTest) { PsiBuilder.Marker expr = myBuilder.mark(); boolean exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression); if (!exprParseResult) { expr.drop(); return false; } if (myBuilder.getTokenType() == PyTokenTypes.COMMA) { while (myBuilder.getTokenType() == PyTokenTypes.COMMA) { myBuilder.advanceLexer(); PsiBuilder.Marker expr2 = myBuilder.mark(); exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression); if (!exprParseResult) { expr2.rollbackTo(); break; } expr2.drop(); } expr.done(PyElementTypes.TUPLE_EXPRESSION); } else { expr.drop(); } return true; }
public static void parse(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker annArgs = builder.mark(); if (!ParserUtils.getToken(builder, mLPAREN)) { annArgs.done(ANNOTATION_ARGUMENTS); return; } if (ParserUtils.lookAhead(builder, mIDENT, mASSIGN)) { if (!parseAnnotationMemberValuePairs(builder, parser)) { annArgs.rollbackTo(); return; } } else { PsiBuilder.Marker pairMarker = builder.mark(); if (!parseAnnotationMemberValueInitializer(builder, parser)) { pairMarker.drop(); } else { pairMarker.done(ANNOTATION_MEMBER_VALUE_PAIR); } } ParserUtils.getToken(builder, mNLS); if (!ParserUtils.getToken(builder, mRPAREN)) { builder.error(GroovyBundle.message("rparen.expected")); } annArgs.done(ANNOTATION_ARGUMENTS); }
public static boolean parse( PsiBuilder builder, boolean isInClass, boolean isInAnnotation, GroovyParser parser) { PsiBuilder.Marker declMarker = builder.mark(); // allows error messages boolean modifiersParsed = Modifiers.parse(builder, parser); final boolean methodStart = mLT == builder.getTokenType(); final IElementType type = parseAfterModifiers( builder, isInClass, isInAnnotation, parser, declMarker, modifiersParsed); if (type == WRONGWAY) { if (modifiersParsed && methodStart) { declMarker.error(GroovyBundle.message("method.definitions.expected")); return false; } declMarker.rollbackTo(); if (modifiersParsed) { builder.error(GroovyBundle.message("variable.definitions.expected")); } return false; } if (type != null) { declMarker.done(type); } else { declMarker.drop(); } return true; }
private void getNextTokenValue(PsiBuilder builder) { PsiBuilder.Marker rb = builder.mark(); builder.advanceLexer(); nextToken = builder.getTokenType(); nextTokenText = builder.getTokenText(); rb.rollbackTo(); }
@Nullable private static IElementType getGtTokenType(final PsiBuilder builder) { final PsiBuilder.Marker sp = builder.mark(); IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.GT) { builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.GT) { builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.GT) { builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.EQ) { tokenType = JavaTokenType.GTGTGTEQ; } else { tokenType = JavaTokenType.GTGTGT; } } else if (builder.getTokenType() == JavaTokenType.EQ) { tokenType = JavaTokenType.GTGTEQ; } else { tokenType = JavaTokenType.GTGT; } } else if (builder.getTokenType() == JavaTokenType.EQ) { tokenType = JavaTokenType.GE; } } sp.rollbackTo(); return tokenType; }
@Nullable private PsiBuilder.Marker parseLambdaExpression( final PsiBuilder builder, final boolean typed, @Nullable final PsiBuilder.Marker typeList) { final PsiBuilder.Marker start = typeList != null ? typeList.precede() : builder.mark(); myParser.getDeclarationParser().parseLambdaParameterList(builder, typed); if (!expect(builder, JavaTokenType.ARROW)) { start.rollbackTo(); return null; } final PsiBuilder.Marker body; if (builder.getTokenType() == JavaTokenType.LBRACE) { body = myParser.getStatementParser().parseCodeBlock(builder); } else { body = parse(builder); } if (body == null) { builder.error(JavaErrorMessages.message("expected.lbrace")); } start.done(JavaElementType.LAMBDA_EXPRESSION); return start; }
public static boolean parseMasonMethod( PsiBuilder b, int l, IElementType closeToken, IElementType statementTokenType) { boolean r = false; PsiBuilder.Marker methodMarker = b.mark(); b.advanceLexer(); PsiBuilder.Marker subMarker = b.mark(); if (PerlParserUtil.consumeToken(b, IDENTIFIER)) { subMarker.collapse(SUB); PerlParserImpl.method_signature(b, l); if (PerlParserUtil.consumeToken(b, MASON_TAG_CLOSER)) { PsiBuilder.Marker blockMarker = b.mark(); PerlParserImpl.block_content(b, l); if (b.getTokenType() == closeToken) { blockMarker.done(BLOCK); blockMarker.setCustomEdgeTokenBinders( WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER); b.advanceLexer(); methodMarker.done(statementTokenType); r = true; } } } if (!r) { methodMarker.rollbackTo(); } return r || recoverToGreedy(b, closeToken, "Error"); }
private static boolean tradForClauseParse(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); if (ParserUtils.getToken(builder, mSEMI) || (Declaration.parse(builder, false, parser) && ParserUtils.getToken(builder, mSEMI))) { StrictContextExpression.parse(builder, parser); ParserUtils.getToken(builder, mSEMI, GroovyBundle.message("semi.expected")); ParserUtils.getToken(builder, mNLS); if (!mRPAREN.equals(builder.getTokenType())) { controlExpressionListParse(builder, parser); } } else { marker.rollbackTo(); marker = builder.mark(); controlExpressionListParse(builder, parser); ParserUtils.getToken(builder, mSEMI, GroovyBundle.message("semi.expected")); StrictContextExpression.parse(builder, parser); ParserUtils.getToken(builder, mSEMI, GroovyBundle.message("semi.expected")); ParserUtils.getToken(builder, mNLS); if (!mRPAREN.equals(builder.getTokenType())) { controlExpressionListParse(builder, parser); } } marker.done(FOR_TRADITIONAL_CLAUSE); return true; }
public void parseArgumentList() { LOG.assertTrue(myBuilder.getTokenType() == PyTokenTypes.LPAR); final PsiBuilder.Marker arglist = myBuilder.mark(); myBuilder.advanceLexer(); PsiBuilder.Marker genexpr = myBuilder.mark(); int argNumber = 0; while (myBuilder.getTokenType() != PyTokenTypes.RPAR) { argNumber++; if (argNumber > 1) { if (argNumber == 2 && atToken(PyTokenTypes.FOR_KEYWORD) && genexpr != null) { parseComprehension(genexpr, null, PyElementTypes.GENERATOR_EXPRESSION); genexpr = null; continue; } else if (matchToken(PyTokenTypes.COMMA)) { if (atToken(PyTokenTypes.RPAR)) { break; } } else { myBuilder.error(message("PARSE.expected.comma.or.rpar")); break; } } if (myBuilder.getTokenType() == PyTokenTypes.MULT || myBuilder.getTokenType() == PyTokenTypes.EXP) { final PsiBuilder.Marker starArgMarker = myBuilder.mark(); myBuilder.advanceLexer(); if (!parseSingleExpression(false)) { myBuilder.error(message("PARSE.expected.expression")); } starArgMarker.done(PyElementTypes.STAR_ARGUMENT_EXPRESSION); } else { if (myBuilder.getTokenType() == PyTokenTypes.IDENTIFIER) { final PsiBuilder.Marker keywordArgMarker = myBuilder.mark(); myBuilder.advanceLexer(); if (myBuilder.getTokenType() == PyTokenTypes.EQ) { myBuilder.advanceLexer(); if (!parseSingleExpression(false)) { myBuilder.error(message("PARSE.expected.expression")); } keywordArgMarker.done(PyElementTypes.KEYWORD_ARGUMENT_EXPRESSION); continue; } keywordArgMarker.rollbackTo(); } if (!parseSingleExpression(false)) { myBuilder.error(message("PARSE.expected.expression")); break; } } } if (genexpr != null) { genexpr.drop(); } checkMatches(PyTokenTypes.RPAR, message("PARSE.expected.rpar")); arglist.done(PyElementTypes.ARGUMENT_LIST); }
@Nullable private PsiBuilder.Marker parseLambdaAfterParenth( final PsiBuilder builder, @Nullable final PsiBuilder.Marker typeList) { final boolean isLambda; final boolean isTyped; final IElementType nextToken1 = builder.lookAhead(1); final IElementType nextToken2 = builder.lookAhead(2); if (nextToken1 == JavaTokenType.RPARENTH && nextToken2 == JavaTokenType.ARROW) { isLambda = true; isTyped = false; } else if (nextToken1 == JavaTokenType.AT || ElementType.MODIFIER_BIT_SET.contains(nextToken1) || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(nextToken1)) { isLambda = true; isTyped = true; } else if (nextToken1 == JavaTokenType.IDENTIFIER) { if (nextToken2 == JavaTokenType.COMMA || nextToken2 == JavaTokenType.RPARENTH && builder.lookAhead(3) == JavaTokenType.ARROW) { isLambda = true; isTyped = false; } else if (nextToken2 == JavaTokenType.ARROW) { isLambda = false; isTyped = false; } else { boolean arrow = false; final PsiBuilder.Marker marker = builder.mark(); while (!builder.eof()) { builder.advanceLexer(); final IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.ARROW) { arrow = true; break; } if (tokenType == JavaTokenType.RPARENTH) { arrow = builder.lookAhead(1) == JavaTokenType.ARROW; break; } else if (tokenType == JavaTokenType.LPARENTH || tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.LBRACE || tokenType == JavaTokenType.RBRACE) { break; } } marker.rollbackTo(); isLambda = arrow; isTyped = true; } } else { isLambda = false; isTyped = false; } return isLambda ? parseLambdaExpression(builder, isTyped, typeList) : null; }
private static boolean parseHasArgumentsBare(PerlBuilder b, int l) { PsiBuilder.Marker m = b.mark(); if (parseHasArgumentsSequenceContent(b, l)) { m.done(COMMA_SEQUENCE_EXPR); return true; } m.rollbackTo(); return false; }
private boolean rollbackOrDropAt(PsiBuilder.Marker rollbackMarker, IElementType dropAt) { if (at(dropAt)) { advance(); // dropAt rollbackMarker.drop(); return true; } rollbackMarker.rollbackTo(); return false; }
public static boolean parseTokens( PsiBuilder builder, boolean smart, int pin, IElementType... tokens) { PsiBuilder.Marker marker = builder.mark(); boolean result = consumeTokens(builder, smart, pin, tokens); if (!result) { marker.rollbackTo(); } else { marker.drop(); } return result; }
private static boolean parseAnnotationMemberValuePairs(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker annmvps = builder.mark(); if (!parseAnnotationMemberValueSinglePair(builder, parser)) { annmvps.rollbackTo(); return false; } while (ParserUtils.getToken(builder, mCOMMA)) { ParserUtils.getToken(builder, mNLS); if (!parseAnnotationMemberValueSinglePair(builder, parser)) { annmvps.rollbackTo(); return false; } } annmvps.done(ANNOTATION_MEMBER_VALUE_PAIRS); return true; }
protected void rollbackTo(@NotNull final PsiBuilder.Marker marker) { if (myIndents.get(marker) == null) { throw new RuntimeException( "Parser can't rollback marker that was created by mark() method, use mark(true) instead"); } myCurrentIndent = myIndents.get(marker); myNewLine = myNewLines.get(marker); myIndents.remove(marker); myNewLines.remove(marker); marker.rollbackTo(); }
private static boolean parseHasArgumentsSequenceContent(PerlBuilder b, int l) { PsiBuilder.Marker m = b.mark(); if (parseHasAttributeDefinitions(b, l) && (PerlParserUtil.consumeToken(b, OPERATOR_COMMA) || PerlParserUtil.consumeToken(b, OPERATOR_COMMA_ARROW)) && PerlParserImpl.expr(b, l, -1)) { m.drop(); return true; } m.rollbackTo(); return false; }
private boolean parseEllipsis() { if (atToken(PyTokenTypes.DOT)) { final PsiBuilder.Marker maybeEllipsis = myBuilder.mark(); myBuilder.advanceLexer(); if (matchToken(PyTokenTypes.DOT) && matchToken(PyTokenTypes.DOT)) { maybeEllipsis.done(PyElementTypes.NONE_LITERAL_EXPRESSION); return true; } maybeEllipsis.rollbackTo(); } return false; }
@Nullable private PsiBuilder.Marker parseClassAccessOrMethodReference(final PsiBuilder builder) { final PsiBuilder.Marker expr = builder.mark(); final boolean primitive = ElementType.PRIMITIVE_TYPE_BIT_SET.contains(builder.getTokenType()); if (myParser.getReferenceParser().parseType(builder, 0) == null) { expr.drop(); return null; } final PsiBuilder.Marker result = continueClassAccessOrMethodReference(builder, expr, primitive); if (result == null) expr.rollbackTo(); return result; }
private static boolean parseAnnotationMemberValueSinglePair( PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker annmvp = builder.mark(); if (!ParserUtils.getToken(builder, mIDENT)) { annmvp.rollbackTo(); return false; } if (!ParserUtils.getToken(builder, mASSIGN)) { annmvp.rollbackTo(); return false; } ParserUtils.getToken(builder, mNLS); if (!parseAnnotationMemberValueInitializer(builder, parser)) { builder.error(GroovyBundle.message("annotation.member.value.initializer.expected")); } annmvp.done(ANNOTATION_MEMBER_VALUE_PAIR); return true; }
/* * callableReference * : (userType "?"*)? "::" SimpleName typeArguments? * ; */ private boolean parseDoubleColonExpression() { PsiBuilder.Marker expression = mark(); if (!at(COLONCOLON)) { PsiBuilder.Marker typeReference = mark(); myJetParsing.parseUserType(); typeReference = myJetParsing.parseNullableTypeSuffix(typeReference); typeReference.done(TYPE_REFERENCE); if (!at(COLONCOLON)) { expression.rollbackTo(); return false; } } advance(); // COLONCOLON if (at(CLASS_KEYWORD)) { advance(); // CLASS_KEYWORD expression.done(CLASS_LITERAL_EXPRESSION); } else { parseSimpleNameExpression(); if (at(LT)) { PsiBuilder.Marker typeArgumentList = mark(); if (myJetParsing.tryParseTypeArgumentList(TYPE_ARGUMENT_LIST_STOPPERS)) { typeArgumentList.error("Type arguments are not allowed"); } else { typeArgumentList.rollbackTo(); } } expression.done(CALLABLE_REFERENCE_EXPRESSION); } return true; }
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); }
/* * class * : modifiers ("class" | "trait") SimpleName * typeParameters? * modifiers ("(" primaryConstructorParameter{","} ")")? * (":" attributes delegationSpecifier{","})? * typeConstraints * (classBody? | enumClassBody) * ; */ IElementType parseClass(boolean enumClass) { assert _atSet(CLASS_KEYWORD, TRAIT_KEYWORD); advance(); // CLASS_KEYWORD or TRAIT_KEYWORD if (!parseIdeTemplate()) { expect(IDENTIFIER, "Class name expected", CLASS_NAME_RECOVERY_SET); } boolean typeParametersDeclared = parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); PsiBuilder.Marker beforeConstructorModifiers = mark(); boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false); // Some modifiers found, but no parentheses following: class has already ended, and we are // looking at something else if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON)) { beforeConstructorModifiers.rollbackTo(); return CLASS; } // We are still inside a class declaration beforeConstructorModifiers.drop(); if (at(LPAR)) { parseValueParameterList(false, TokenSet.create(COLON, LBRACE)); } else if (hasConstructorModifiers) { // A comprehensive error message for cases like: // class A private : Foo // or // class A private { error("Expecting primary constructor parameter list"); } if (at(COLON)) { advance(); // COLON parseDelegationSpecifierList(); } parseTypeConstraintsGuarded(typeParametersDeclared); if (at(LBRACE)) { if (enumClass) { parseEnumClassBody(); } else { parseClassBody(); } } return CLASS; }
@Nullable private static PsiBuilder.Marker parseClassObjectAccess(final PsiBuilder builder) { final PsiBuilder.Marker expr = builder.mark(); if (ReferenceParser.parseType(builder, 0) == null) { expr.drop(); return null; } if (builder.getTokenType() != JavaTokenType.DOT) { expr.rollbackTo(); return null; } builder.advanceLexer(); if (builder.getTokenType() != JavaTokenType.CLASS_KEYWORD) { expr.rollbackTo(); return null; } builder.advanceLexer(); expr.done(JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION); return expr; }
private static boolean singleDeclNoInitParse( PsiBuilder builder, PsiBuilder.Marker marker, PsiBuilder.Marker declMarker, GroovyParser parser) { if (ParserUtils.getToken(builder, mIDENT)) { if (kIN.equals(builder.getTokenType()) || mCOLON.equals(builder.getTokenType())) { declMarker.done(PARAMETER); builder.advanceLexer(); if (!ShiftExpression.parse(builder, parser)) { builder.error(GroovyBundle.message("expression.expected")); } marker.done(FOR_IN_CLAUSE); return true; } else { marker.rollbackTo(); return false; } } else { declMarker.drop(); marker.rollbackTo(); return false; } }
private static boolean parseAssignment(PsiBuilder builder, GroovyParser parser) { if (ParserUtils.getToken(builder, GroovyTokenTypes.mASSIGN)) { PsiBuilder.Marker marker = builder.mark(); ParserUtils.getToken(builder, GroovyTokenTypes.mNLS); if (!AssignmentExpression.parse(builder, parser, true)) { marker.rollbackTo(); builder.error(GroovyBundle.message("expression.expected")); return false; } else { marker.drop(); return true; } } return false; }
@Nullable private static PsiBuilder.Marker parseClassObjectAccess( PsiBuilder builder, PsiBuilder.Marker expr, boolean optionalClassKeyword) { final PsiBuilder.Marker mark = builder.mark(); builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.CLASS_KEYWORD) { mark.drop(); builder.advanceLexer(); } else { if (!optionalClassKeyword) return null; mark.rollbackTo(); builder.error(".class expected"); } expr.done(JavaElementType.CLASS_OBJECT_ACCESS_EXPRESSION); return expr; }