@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); } }
@NotNull private PsiBuilder.Marker parseMethodReference( final PsiBuilder builder, final PsiBuilder.Marker start) { builder.advanceLexer(); myParser.getReferenceParser().parseReferenceParameterList(builder, false, false); if (!expect(builder, JavaTokenType.IDENTIFIER) && !expect(builder, JavaTokenType.NEW_KEYWORD)) { error(builder, JavaErrorMessages.message("expected.identifier")); } start.done(JavaElementType.METHOD_REF_EXPRESSION); return start; }
@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; }
@Nullable private PsiBuilder.Marker parseExpression(final PsiBuilder builder, final ExprType type) { switch (type) { case CONDITIONAL_OR: return parseBinary(builder, ExprType.CONDITIONAL_AND, CONDITIONAL_OR_OPS); case CONDITIONAL_AND: return parseBinary(builder, ExprType.OR, CONDITIONAL_AND_OPS); case OR: return parseBinary(builder, ExprType.XOR, OR_OPS); case XOR: return parseBinary(builder, ExprType.AND, XOR_OPS); case AND: return parseBinary(builder, ExprType.EQUALITY, AND_OPS); case EQUALITY: return parseBinary(builder, ExprType.RELATIONAL, EQUALITY_OPS); case RELATIONAL: return parseRelational(builder); case SHIFT: return parseBinary(builder, ExprType.ADDITIVE, SHIFT_OPS); case ADDITIVE: return parseBinary(builder, ExprType.MULTIPLICATIVE, ADDITIVE_OPS); case MULTIPLICATIVE: return parseBinary(builder, ExprType.UNARY, MULTIPLICATIVE_OPS); case UNARY: return parseUnary(builder); case TYPE: return myParser .getReferenceParser() .parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD); default: assert false : "Unexpected type: " + type; return null; } }
@NotNull private PsiBuilder.Marker parseNew(PsiBuilder builder, @Nullable PsiBuilder.Marker start) { PsiBuilder.Marker newExpr = (start != null ? start.precede() : builder.mark()); builder.advanceLexer(); myParser.getReferenceParser().parseReferenceParameterList(builder, false, true); PsiBuilder.Marker refOrType; PsiBuilder.Marker anno = myParser.getDeclarationParser().parseAnnotations(builder); IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.IDENTIFIER) { if (anno != null) { anno.rollbackTo(); } refOrType = myParser.getReferenceParser().parseJavaCodeReference(builder, true, true, true, true); if (refOrType == null) { error(builder, JavaErrorMessages.message("expected.identifier")); newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } } else if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { refOrType = null; builder.advanceLexer(); } else { error(builder, JavaErrorMessages.message("expected.identifier")); newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } if (refOrType != null && builder.getTokenType() == JavaTokenType.LPARENTH) { parseArgumentList(builder); if (builder.getTokenType() == JavaTokenType.LBRACE) { final PsiBuilder.Marker classElement = refOrType.precede(); myParser.getDeclarationParser().parseClassBodyWithBraces(builder, false, false); classElement.done(JavaElementType.ANONYMOUS_CLASS); } newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } myParser.getDeclarationParser().parseAnnotations(builder); if (builder.getTokenType() != JavaTokenType.LBRACKET) { error( builder, refOrType == null ? JavaErrorMessages.message("expected.lbracket") : JavaErrorMessages.message("expected.lparen.or.lbracket")); newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } int bracketCount = 0; int dimCount = 0; while (true) { myParser.getDeclarationParser().parseAnnotations(builder); if (builder.getTokenType() != JavaTokenType.LBRACKET) break; builder.advanceLexer(); if (bracketCount == dimCount) { final PsiBuilder.Marker dimExpr = parse(builder); if (dimExpr != null) { dimCount++; } } bracketCount++; if (!expectOrError(builder, JavaTokenType.RBRACKET, "expected.rbracket")) { newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; } } if (dimCount == 0) { if (builder.getTokenType() == JavaTokenType.LBRACE) { parseArrayInitializer(builder); } else { error(builder, JavaErrorMessages.message("expected.array.initializer")); } } newExpr.done(JavaElementType.NEW_EXPRESSION); return newExpr; }
@Nullable private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder) { IElementType tokenType = builder.getTokenType(); if (LITERALS.contains(tokenType)) { final PsiBuilder.Marker literal = builder.mark(); builder.advanceLexer(); literal.done(JavaElementType.LITERAL_EXPRESSION); return literal; } if (tokenType == JavaTokenType.LBRACE) { return parseArrayInitializer(builder); } if (tokenType == JavaTokenType.NEW_KEYWORD) { return parseNew(builder, null); } if (tokenType == JavaTokenType.LPARENTH) { final PsiBuilder.Marker lambda = parseLambdaAfterParenth(builder, null); if (lambda != null) { return lambda; } final PsiBuilder.Marker parenth = builder.mark(); builder.advanceLexer(); final PsiBuilder.Marker inner = parse(builder); if (inner == null) { error(builder, JavaErrorMessages.message("expected.expression")); } if (!expect(builder, JavaTokenType.RPARENTH)) { if (inner != null) { error(builder, JavaErrorMessages.message("expected.rparen")); } } parenth.done(JavaElementType.PARENTH_EXPRESSION); return parenth; } if (TYPE_START.contains(tokenType)) { final PsiBuilder.Marker mark = builder.mark(); final ReferenceParser.TypeInfo typeInfo = myParser.getReferenceParser().parseTypeInfo(builder, 0); if (typeInfo != null) { boolean optionalClassKeyword = typeInfo.isPrimitive || typeInfo.isArray; if (optionalClassKeyword || !typeInfo.hasErrors && typeInfo.isParameterized) { final PsiBuilder.Marker result = continueClassAccessOrMethodReference(builder, mark, optionalClassKeyword); if (result != null) { return result; } } } mark.rollbackTo(); } PsiBuilder.Marker annotation = null; if (tokenType == JavaTokenType.AT) { annotation = myParser.getDeclarationParser().parseAnnotations(builder); tokenType = builder.getTokenType(); } if (tokenType == JavaTokenType.IDENTIFIER) { if (builder.lookAhead(1) == JavaTokenType.ARROW) { return parseLambdaExpression(builder, false, null); } final PsiBuilder.Marker refExpr; if (annotation != null) { final PsiBuilder.Marker refParam = annotation.precede(); refParam.doneBefore(JavaElementType.REFERENCE_PARAMETER_LIST, annotation); refExpr = refParam.precede(); } else { refExpr = builder.mark(); builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); } builder.advanceLexer(); refExpr.done(JavaElementType.REFERENCE_EXPRESSION); return refExpr; } if (annotation != null) { annotation.rollbackTo(); tokenType = builder.getTokenType(); } PsiBuilder.Marker expr = null; if (tokenType == JavaTokenType.LT) { expr = builder.mark(); if (!myParser.getReferenceParser().parseReferenceParameterList(builder, false, false)) { expr.rollbackTo(); return null; } tokenType = builder.getTokenType(); if (!THIS_OR_SUPER.contains(tokenType)) { expr.rollbackTo(); return null; } } if (THIS_OR_SUPER.contains(tokenType)) { if (expr == null) { expr = builder.mark(); builder.mark().done(JavaElementType.REFERENCE_PARAMETER_LIST); } builder.advanceLexer(); expr.done( builder.getTokenType() == JavaTokenType.LPARENTH ? JavaElementType.REFERENCE_EXPRESSION : tokenType == JavaTokenType.THIS_KEYWORD ? JavaElementType.THIS_EXPRESSION : JavaElementType.SUPER_EXPRESSION); return expr; } return null; }
// todo[r.sh] make 'this', 'super' and 'class' reference expressions @Nullable private PsiBuilder.Marker parsePrimary( final PsiBuilder builder, @Nullable final BreakPoint breakPoint, final int breakOffset) { PsiBuilder.Marker startMarker = builder.mark(); PsiBuilder.Marker expr = parsePrimaryExpressionStart(builder); if (expr == null) { startMarker.drop(); return null; } while (true) { final IElementType tokenType = builder.getTokenType(); if (tokenType == JavaTokenType.DOT) { final PsiBuilder.Marker dotPos = builder.mark(); final int dotOffset = builder.getCurrentOffset(); builder.advanceLexer(); IElementType dotTokenType = builder.getTokenType(); if (dotTokenType == JavaTokenType.AT) { myParser.getDeclarationParser().parseAnnotations(builder); dotTokenType = builder.getTokenType(); } if (dotTokenType == JavaTokenType.CLASS_KEYWORD && exprType(expr) == JavaElementType.REFERENCE_EXPRESSION) { if (breakPoint == BreakPoint.P1 && builder.getCurrentOffset() == breakOffset) { error(builder, JavaErrorMessages.message("expected.identifier")); PsiBuilderUtil.drop(startMarker, dotPos); return expr; } final PsiBuilder.Marker copy = startMarker.precede(); final int offset = builder.getCurrentOffset(); startMarker.rollbackTo(); final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder); if (classObjAccess == null || builder.getCurrentOffset() < offset) { copy.rollbackTo(); return parsePrimary(builder, BreakPoint.P1, offset); } startMarker = copy; expr = classObjAccess; } else if (dotTokenType == JavaTokenType.NEW_KEYWORD) { dotPos.drop(); expr = parseNew(builder, expr); } else if (THIS_OR_SUPER.contains(dotTokenType) && exprType(expr) == JavaElementType.REFERENCE_EXPRESSION) { if (breakPoint == BreakPoint.P2 && builder.getCurrentOffset() == breakOffset) { dotPos.rollbackTo(); startMarker.drop(); return expr; } final PsiBuilder.Marker copy = startMarker.precede(); final int offset = builder.getCurrentOffset(); startMarker.rollbackTo(); final PsiBuilder.Marker ref = myParser .getReferenceParser() .parseJavaCodeReference(builder, false, true, false, false); if (ref == null || builder.getTokenType() != JavaTokenType.DOT || builder.getCurrentOffset() != dotOffset) { copy.rollbackTo(); return parsePrimary(builder, BreakPoint.P2, offset); } builder.advanceLexer(); if (builder.getTokenType() != dotTokenType) { copy.rollbackTo(); return parsePrimary(builder, BreakPoint.P2, offset); } builder.advanceLexer(); startMarker = copy; expr = ref.precede(); expr.done( dotTokenType == JavaTokenType.THIS_KEYWORD ? JavaElementType.THIS_EXPRESSION : JavaElementType.SUPER_EXPRESSION); } else if (dotTokenType == JavaTokenType.SUPER_KEYWORD) { dotPos.drop(); final PsiBuilder.Marker refExpr = expr.precede(); builder.advanceLexer(); refExpr.done(JavaElementType.REFERENCE_EXPRESSION); expr = refExpr; } else { dotPos.drop(); final PsiBuilder.Marker refExpr = expr.precede(); myParser.getReferenceParser().parseReferenceParameterList(builder, false, false); if (!expectOrError(builder, ID_OR_SUPER, "expected.identifier")) { refExpr.done(JavaElementType.REFERENCE_EXPRESSION); startMarker.drop(); return refExpr; } refExpr.done(JavaElementType.REFERENCE_EXPRESSION); expr = refExpr; } } else if (tokenType == JavaTokenType.LPARENTH) { if (exprType(expr) != JavaElementType.REFERENCE_EXPRESSION) { if (exprType(expr) == JavaElementType.SUPER_EXPRESSION) { if (breakPoint == BreakPoint.P3) { startMarker.drop(); return expr; } final PsiBuilder.Marker copy = startMarker.precede(); startMarker.rollbackTo(); final PsiBuilder.Marker qualifier = parsePrimaryExpressionStart(builder); if (qualifier != null) { final PsiBuilder.Marker refExpr = qualifier.precede(); if (builder.getTokenType() == JavaTokenType.DOT) { builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.SUPER_KEYWORD) { builder.advanceLexer(); refExpr.done(JavaElementType.REFERENCE_EXPRESSION); expr = refExpr; startMarker = copy; continue; } } } copy.rollbackTo(); return parsePrimary(builder, BreakPoint.P3, -1); } else { startMarker.drop(); return expr; } } final PsiBuilder.Marker callExpr = expr.precede(); parseArgumentList(builder); callExpr.done(JavaElementType.METHOD_CALL_EXPRESSION); expr = callExpr; } else if (tokenType == JavaTokenType.LBRACKET) { if (breakPoint == BreakPoint.P4) { startMarker.drop(); return expr; } builder.advanceLexer(); if (builder.getTokenType() == JavaTokenType.RBRACKET && exprType(expr) == JavaElementType.REFERENCE_EXPRESSION) { final int pos = builder.getCurrentOffset(); final PsiBuilder.Marker copy = startMarker.precede(); startMarker.rollbackTo(); final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder); if (classObjAccess == null || builder.getCurrentOffset() <= pos) { copy.rollbackTo(); return parsePrimary(builder, BreakPoint.P4, -1); } startMarker = copy; expr = classObjAccess; } else { final PsiBuilder.Marker arrayAccess = expr.precede(); final PsiBuilder.Marker index = parse(builder); if (index == null) { error(builder, JavaErrorMessages.message("expected.expression")); arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION); startMarker.drop(); return arrayAccess; } if (builder.getTokenType() != JavaTokenType.RBRACKET) { error(builder, JavaErrorMessages.message("expected.rbracket")); arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION); startMarker.drop(); return arrayAccess; } builder.advanceLexer(); arrayAccess.done(JavaElementType.ARRAY_ACCESS_EXPRESSION); expr = arrayAccess; } } else if (tokenType == JavaTokenType.DOUBLE_COLON) { return parseMethodReference(builder, startMarker); } else { startMarker.drop(); return expr; } } }