| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.lang.java.parser; |
| |
| import com.intellij.codeInsight.daemon.JavaErrorMessages; |
| import com.intellij.lang.PsiBuilder; |
| import com.intellij.lang.WhitespacesBinders; |
| import com.intellij.psi.JavaTokenType; |
| import com.intellij.psi.impl.source.tree.ElementType; |
| import com.intellij.psi.impl.source.tree.JavaElementType; |
| import com.intellij.psi.tree.IElementType; |
| import com.intellij.psi.tree.ILazyParseableElementType; |
| import com.intellij.psi.tree.TokenSet; |
| import com.intellij.util.SmartList; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.List; |
| |
| import static com.intellij.lang.PsiBuilderUtil.*; |
| import static com.intellij.lang.java.parser.JavaParserUtil.*; |
| |
| public class StatementParser { |
| private enum BraceMode { |
| TILL_FIRST, TILL_LAST |
| } |
| |
| private static final TokenSet TRY_CLOSERS_SET = TokenSet.create(JavaTokenType.CATCH_KEYWORD, JavaTokenType.FINALLY_KEYWORD); |
| |
| private final JavaParser myParser; |
| |
| public StatementParser(@NotNull final JavaParser javaParser) { |
| myParser = javaParser; |
| } |
| |
| @Nullable |
| public PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) { |
| return parseCodeBlock(builder, false); |
| } |
| |
| @Nullable |
| public PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder, final boolean isStatement) { |
| if (builder.getTokenType() != JavaTokenType.LBRACE) return null; |
| else if (isStatement && isParseStatementCodeBlocksDeep(builder)) return parseCodeBlockDeep(builder, false); |
| |
| final PsiBuilder.Marker codeBlock = builder.mark(); |
| builder.advanceLexer(); |
| |
| boolean greedyBlock = false; |
| int braceCount = 1; |
| while (true) { |
| final IElementType tokenType = builder.getTokenType(); |
| if (tokenType == null) { |
| greedyBlock = true; |
| break; |
| } |
| if (tokenType == JavaTokenType.LBRACE) { |
| braceCount++; |
| } |
| else if (tokenType == JavaTokenType.RBRACE) { |
| braceCount--; |
| } |
| builder.advanceLexer(); |
| |
| if (braceCount == 0) { |
| break; |
| } |
| else if (braceCount == 1 && (tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.RBRACE)) { |
| final PsiBuilder.Marker position = builder.mark(); |
| final List<IElementType> list = new SmartList<IElementType>(); |
| while (true) { |
| final IElementType type = builder.getTokenType(); |
| if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || ElementType.MODIFIER_BIT_SET.contains(type) || |
| (type == JavaTokenType.IDENTIFIER && list.size() > 0) || type == JavaTokenType.LT || type == JavaTokenType.GT || |
| type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == JavaTokenType.COMMA || |
| type == JavaTokenType.DOT || type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) { |
| list.add(type); |
| builder.advanceLexer(); |
| } |
| else { |
| break; |
| } |
| } |
| if (builder.getTokenType() == JavaTokenType.LPARENTH && list.size() >= 2) { |
| final IElementType last = list.get(list.size() - 1); |
| final IElementType prevLast = list.get(list.size() - 2); |
| if (last == JavaTokenType.IDENTIFIER && |
| (prevLast == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(prevLast))) { |
| position.rollbackTo(); |
| greedyBlock = true; |
| break; |
| } |
| } |
| position.drop(); |
| } |
| } |
| |
| codeBlock.collapse(JavaElementType.CODE_BLOCK); |
| if (greedyBlock) { |
| codeBlock.setCustomEdgeTokenBinders(null, WhitespacesBinders.GREEDY_RIGHT_BINDER); |
| } |
| return codeBlock; |
| } |
| |
| @Nullable |
| public PsiBuilder.Marker parseCodeBlockDeep(final PsiBuilder builder, final boolean parseUntilEof) { |
| if (builder.getTokenType() != JavaTokenType.LBRACE) return null; |
| |
| final PsiBuilder.Marker codeBlock = builder.mark(); |
| builder.advanceLexer(); |
| |
| parseStatements(builder, parseUntilEof ? BraceMode.TILL_LAST : BraceMode.TILL_FIRST); |
| |
| final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, "expected.rbrace"); |
| builder.getTokenType(); // eat spaces |
| |
| done(codeBlock, JavaElementType.CODE_BLOCK); |
| if (greedyBlock) { |
| codeBlock.setCustomEdgeTokenBinders(null, WhitespacesBinders.GREEDY_RIGHT_BINDER); |
| } |
| return codeBlock; |
| } |
| |
| public void parseStatements(final PsiBuilder builder) { |
| parseStatements(builder, null); |
| } |
| |
| private void parseStatements(final PsiBuilder builder, @Nullable final BraceMode braceMode) { |
| while (builder.getTokenType() != null) { |
| final PsiBuilder.Marker statement = parseStatement(builder); |
| if (statement != null) continue; |
| |
| final IElementType tokenType = builder.getTokenType(); |
| if (tokenType == JavaTokenType.RBRACE) { |
| if (braceMode == BraceMode.TILL_FIRST) { |
| return; |
| } |
| else if (braceMode == BraceMode.TILL_LAST) { |
| if (builder.lookAhead(1) == null) { |
| return; |
| } |
| } |
| } |
| |
| final PsiBuilder.Marker error = builder.mark(); |
| builder.advanceLexer(); |
| if (tokenType == JavaTokenType.ELSE_KEYWORD) { |
| error.error(JavaErrorMessages.message("else.without.if")); |
| } |
| else if (tokenType == JavaTokenType.CATCH_KEYWORD) { |
| error.error(JavaErrorMessages.message("catch.without.try")); |
| } |
| else if (tokenType == JavaTokenType.FINALLY_KEYWORD) { |
| error.error(JavaErrorMessages.message("finally.without.try")); |
| } |
| else { |
| error.error(JavaErrorMessages.message("unexpected.token")); |
| } |
| } |
| } |
| |
| @Nullable |
| public PsiBuilder.Marker parseStatement(final PsiBuilder builder) { |
| final IElementType tokenType = builder.getTokenType(); |
| if (tokenType == JavaTokenType.IF_KEYWORD) { |
| return parseIfStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.WHILE_KEYWORD) { |
| return parseWhileStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.FOR_KEYWORD) { |
| return parseForStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.DO_KEYWORD) { |
| return parseDoWhileStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.SWITCH_KEYWORD) { |
| return parseSwitchStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.CASE_KEYWORD || tokenType == JavaTokenType.DEFAULT_KEYWORD) { |
| return parseSwitchLabelStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.BREAK_KEYWORD) { |
| return parseBreakStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.CONTINUE_KEYWORD) { |
| return parseContinueStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.RETURN_KEYWORD) { |
| return parseReturnStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.THROW_KEYWORD) { |
| return parseThrowStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.SYNCHRONIZED_KEYWORD) { |
| return parseSynchronizedStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.TRY_KEYWORD) { |
| return parseTryStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.ASSERT_KEYWORD) { |
| return parseAssertStatement(builder); |
| } |
| else if (tokenType == JavaTokenType.LBRACE) { |
| return parseBlockStatement(builder); |
| } |
| else if (tokenType instanceof ILazyParseableElementType) { |
| builder.advanceLexer(); |
| return null; |
| } |
| else if (tokenType == JavaTokenType.SEMICOLON) { |
| final PsiBuilder.Marker empty = builder.mark(); |
| builder.advanceLexer(); |
| done(empty, JavaElementType.EMPTY_STATEMENT); |
| return empty; |
| } |
| else if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.AT) { |
| final PsiBuilder.Marker refPos = builder.mark(); |
| myParser.getDeclarationParser().parseAnnotations(builder); |
| skipQualifiedName(builder); |
| final IElementType suspectedLT = builder.getTokenType(); |
| refPos.rollbackTo(); |
| if (suspectedLT == JavaTokenType.LT) { |
| final PsiBuilder.Marker declStatement = builder.mark(); |
| final PsiBuilder.Marker decl = myParser.getDeclarationParser().parse(builder, DeclarationParser.Context.CODE_BLOCK); |
| if (decl == null) { |
| PsiBuilder.Marker marker = myParser.getReferenceParser().parseType(builder, 0); |
| error(builder, JavaErrorMessages.message("expected.identifier")); |
| if (marker == null) builder.advanceLexer(); |
| } |
| done(declStatement, JavaElementType.DECLARATION_STATEMENT); |
| return declStatement; |
| } |
| } |
| |
| final PsiBuilder.Marker pos = builder.mark(); |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| |
| if (expr != null) { |
| int count = 1; |
| final PsiBuilder.Marker list = expr.precede(); |
| final PsiBuilder.Marker statement = list.precede(); |
| while (builder.getTokenType() == JavaTokenType.COMMA) { |
| final PsiBuilder.Marker commaPos = builder.mark(); |
| builder.advanceLexer(); |
| final PsiBuilder.Marker expr1 = myParser.getExpressionParser().parse(builder); |
| if (expr1 == null) { |
| commaPos.rollbackTo(); |
| break; |
| } |
| commaPos.drop(); |
| count++; |
| } |
| if (count > 1) { |
| pos.drop(); |
| done(list, JavaElementType.EXPRESSION_LIST); |
| semicolon(builder); |
| done(statement, JavaElementType.EXPRESSION_LIST_STATEMENT); |
| return statement; |
| } |
| if (exprType(expr) != JavaElementType.REFERENCE_EXPRESSION) { |
| drop(list, pos); |
| semicolon(builder); |
| done(statement, JavaElementType.EXPRESSION_STATEMENT); |
| return statement; |
| } |
| pos.rollbackTo(); |
| } |
| else { |
| pos.drop(); |
| } |
| |
| final PsiBuilder.Marker decl = myParser.getDeclarationParser().parse(builder, DeclarationParser.Context.CODE_BLOCK); |
| if (decl != null) { |
| final PsiBuilder.Marker statement = decl.precede(); |
| done(statement, JavaElementType.DECLARATION_STATEMENT); |
| return statement; |
| } |
| |
| if (builder.getTokenType() == JavaTokenType.IDENTIFIER && builder.lookAhead(1) == JavaTokenType.COLON) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| advance(builder, 2); |
| parseStatement(builder); |
| done(statement, JavaElementType.LABELED_STATEMENT); |
| return statement; |
| } |
| |
| if (expr != null) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| myParser.getExpressionParser().parse(builder); |
| semicolon(builder); |
| done(statement, JavaElementType.EXPRESSION_STATEMENT); |
| return statement; |
| } |
| |
| return null; |
| } |
| |
| private static void skipQualifiedName(final PsiBuilder builder) { |
| if (!expect(builder, JavaTokenType.IDENTIFIER)) return; |
| while (builder.getTokenType() == JavaTokenType.DOT && builder.lookAhead(1) == JavaTokenType.IDENTIFIER) { |
| advance(builder, 2); |
| } |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseIfStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!parseExpressionInParenth(builder)) { |
| done(statement, JavaElementType.IF_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker thenStatement = parseStatement(builder); |
| if (thenStatement == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| done(statement, JavaElementType.IF_STATEMENT); |
| return statement; |
| } |
| |
| if (!expect(builder, JavaTokenType.ELSE_KEYWORD)) { |
| done(statement, JavaElementType.IF_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker elseStatement = parseStatement(builder); |
| if (elseStatement == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| } |
| |
| done(statement, JavaElementType.IF_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseWhileStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!parseExpressionInParenth(builder)) { |
| done(statement, JavaElementType.WHILE_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker bodyStatement = parseStatement(builder); |
| if (bodyStatement == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| } |
| |
| done(statement, JavaElementType.WHILE_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseForStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!expect(builder, JavaTokenType.LPARENTH)) { |
| error(builder, JavaErrorMessages.message("expected.lparen")); |
| done(statement, JavaElementType.FOR_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker afterParenth = builder.mark(); |
| final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, false); |
| if (param == null || exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) { |
| afterParenth.rollbackTo(); |
| return parseForLoopFromInitialization(builder, statement); |
| } |
| else { |
| afterParenth.drop(); |
| return parseForEachFromColon(builder, statement); |
| } |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseForLoopFromInitialization(final PsiBuilder builder, final PsiBuilder.Marker statement) { |
| final PsiBuilder.Marker init = parseStatement(builder); |
| if (init == null){ |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| if (!expect(builder, JavaTokenType.RPARENTH)) { |
| done(statement, JavaElementType.FOR_STATEMENT); |
| return statement; |
| } |
| } |
| else { |
| myParser.getExpressionParser().parse(builder); |
| if (!expect(builder, JavaTokenType.SEMICOLON)) { |
| error(builder, JavaErrorMessages.message("expected.semicolon")); |
| if (!expect(builder, JavaTokenType.RPARENTH)) { |
| done(statement, JavaElementType.FOR_STATEMENT); |
| return statement; |
| } |
| } |
| else { |
| parseExpressionOrExpressionList(builder); |
| if (!expect(builder, JavaTokenType.RPARENTH)) { |
| error(builder, JavaErrorMessages.message("expected.rparen")); |
| done(statement, JavaElementType.FOR_STATEMENT); |
| return statement; |
| } |
| } |
| } |
| |
| final PsiBuilder.Marker bodyStatement = parseStatement(builder); |
| if (bodyStatement == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| } |
| |
| done(statement, JavaElementType.FOR_STATEMENT); |
| return statement; |
| } |
| |
| private void parseExpressionOrExpressionList(final PsiBuilder builder) { |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null) return; |
| |
| final PsiBuilder.Marker expressionStatement; |
| if (builder.getTokenType() != JavaTokenType.COMMA) { |
| expressionStatement = expr.precede(); |
| done(expressionStatement, JavaElementType.EXPRESSION_STATEMENT); |
| } |
| else { |
| final PsiBuilder.Marker expressionList = expr.precede(); |
| expressionStatement = expressionList.precede(); |
| |
| do { |
| builder.advanceLexer(); |
| final PsiBuilder.Marker nextExpression = myParser.getExpressionParser().parse(builder); |
| if (nextExpression == null) { |
| error(builder, JavaErrorMessages.message("expected.expression")); |
| } |
| } |
| while (builder.getTokenType() == JavaTokenType.COMMA); |
| |
| done(expressionList, JavaElementType.EXPRESSION_LIST); |
| done(expressionStatement, JavaElementType.EXPRESSION_LIST_STATEMENT); |
| } |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseForEachFromColon(PsiBuilder builder, PsiBuilder.Marker statement) { |
| builder.advanceLexer(); |
| |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null) { |
| error(builder, JavaErrorMessages.message("expected.expression")); |
| } |
| |
| if (expect(builder, JavaTokenType.RPARENTH)) { |
| final PsiBuilder.Marker bodyStatement = parseStatement(builder); |
| if (bodyStatement == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| } |
| } |
| else { |
| error(builder, JavaErrorMessages.message("expected.rparen")); |
| } |
| |
| done(statement, JavaElementType.FOREACH_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseDoWhileStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| final PsiBuilder.Marker body = parseStatement(builder); |
| if (body == null) { |
| error(builder, JavaErrorMessages.message("expected.statement")); |
| done(statement, JavaElementType.DO_WHILE_STATEMENT); |
| return statement; |
| } |
| |
| if (!expect(builder, JavaTokenType.WHILE_KEYWORD)) { |
| error(builder, JavaErrorMessages.message("expected.while")); |
| done(statement, JavaElementType.DO_WHILE_STATEMENT); |
| return statement; |
| } |
| |
| if (parseExpressionInParenth(builder)) { |
| semicolon(builder); |
| } |
| |
| done(statement, JavaElementType.DO_WHILE_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseSwitchStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!parseExpressionInParenth(builder)) { |
| done(statement, JavaElementType.SWITCH_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker body = parseCodeBlock(builder, true); |
| if (body == null) { |
| error(builder, JavaErrorMessages.message("expected.lbrace")); |
| } |
| |
| done(statement, JavaElementType.SWITCH_STATEMENT); |
| return statement; |
| } |
| |
| @Nullable |
| private PsiBuilder.Marker parseSwitchLabelStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| final boolean isCase = builder.getTokenType() == JavaTokenType.CASE_KEYWORD; |
| builder.advanceLexer(); |
| |
| if (isCase) { |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null) { |
| statement.rollbackTo(); |
| return null; |
| } |
| } |
| |
| expectOrError(builder, JavaTokenType.COLON, "expected.colon"); |
| |
| done(statement, JavaElementType.SWITCH_LABEL_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private static PsiBuilder.Marker parseBreakStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| expect(builder, JavaTokenType.IDENTIFIER); |
| semicolon(builder); |
| done(statement, JavaElementType.BREAK_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private static PsiBuilder.Marker parseContinueStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| expect(builder, JavaTokenType.IDENTIFIER); |
| semicolon(builder); |
| done(statement, JavaElementType.CONTINUE_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseReturnStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| myParser.getExpressionParser().parse(builder); |
| |
| semicolon(builder); |
| done(statement, JavaElementType.RETURN_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseThrowStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null) { |
| error(builder, JavaErrorMessages.message("expected.expression")); |
| done(statement, JavaElementType.THROW_STATEMENT); |
| return statement; |
| } |
| |
| semicolon(builder); |
| done(statement, JavaElementType.THROW_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseSynchronizedStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!parseExpressionInParenth(builder)) { |
| done(statement, JavaElementType.SYNCHRONIZED_STATEMENT); |
| return statement; |
| } |
| |
| final PsiBuilder.Marker body = parseCodeBlock(builder, true); |
| if (body == null) { |
| error(builder, JavaErrorMessages.message("expected.lbrace")); |
| } |
| |
| done(statement, JavaElementType.SYNCHRONIZED_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseTryStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| final boolean hasResourceList = builder.getTokenType() == JavaTokenType.LPARENTH; |
| if (hasResourceList) { |
| myParser.getDeclarationParser().parseResourceList(builder); |
| } |
| |
| final PsiBuilder.Marker tryBlock = parseCodeBlock(builder, true); |
| if (tryBlock == null) { |
| error(builder, JavaErrorMessages.message("expected.lbrace")); |
| done(statement, JavaElementType.TRY_STATEMENT); |
| return statement; |
| } |
| |
| if (!hasResourceList && !TRY_CLOSERS_SET.contains(builder.getTokenType())) { |
| error(builder, JavaErrorMessages.message("expected.catch.or.finally")); |
| done(statement, JavaElementType.TRY_STATEMENT); |
| return statement; |
| } |
| |
| while (builder.getTokenType() == JavaTokenType.CATCH_KEYWORD) { |
| if (!parseCatchBlock(builder)) break; |
| } |
| |
| if (expect(builder, JavaTokenType.FINALLY_KEYWORD)) { |
| final PsiBuilder.Marker finallyBlock = parseCodeBlock(builder, true); |
| if (finallyBlock == null) { |
| error(builder, JavaErrorMessages.message("expected.lbrace")); |
| } |
| } |
| |
| done(statement, JavaElementType.TRY_STATEMENT); |
| return statement; |
| } |
| |
| public boolean parseCatchBlock(final PsiBuilder builder) { |
| assert builder.getTokenType() == JavaTokenType.CATCH_KEYWORD : builder.getTokenType(); |
| final PsiBuilder.Marker section = builder.mark(); |
| builder.advanceLexer(); |
| |
| if (!expect(builder, JavaTokenType.LPARENTH)) { |
| error(builder, JavaErrorMessages.message("expected.lparen")); |
| done(section, JavaElementType.CATCH_SECTION); |
| return false; |
| } |
| |
| final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, true); |
| if (param == null) { |
| error(builder, JavaErrorMessages.message("expected.parameter")); |
| } |
| |
| if (!expect(builder, JavaTokenType.RPARENTH)) { |
| error(builder, JavaErrorMessages.message("expected.rparen")); |
| done(section, JavaElementType.CATCH_SECTION); |
| return false; |
| } |
| |
| final PsiBuilder.Marker body = parseCodeBlock(builder, true); |
| if (body == null) { |
| error(builder, JavaErrorMessages.message("expected.lbrace")); |
| done(section, JavaElementType.CATCH_SECTION); |
| return false; |
| } |
| |
| done(section, JavaElementType.CATCH_SECTION); |
| return true; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseAssertStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| builder.advanceLexer(); |
| |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null) { |
| error(builder, JavaErrorMessages.message("expected.boolean.expression")); |
| done(statement, JavaElementType.ASSERT_STATEMENT); |
| return statement; |
| } |
| |
| if (expect(builder, JavaTokenType.COLON)) { |
| final PsiBuilder.Marker expr2 = myParser.getExpressionParser().parse(builder); |
| if (expr2 == null) { |
| error(builder, JavaErrorMessages.message("expected.expression")); |
| done(statement, JavaElementType.ASSERT_STATEMENT); |
| return statement; |
| } |
| } |
| |
| semicolon(builder); |
| done(statement, JavaElementType.ASSERT_STATEMENT); |
| return statement; |
| } |
| |
| @NotNull |
| private PsiBuilder.Marker parseBlockStatement(final PsiBuilder builder) { |
| final PsiBuilder.Marker statement = builder.mark(); |
| parseCodeBlock(builder, true); |
| done(statement, JavaElementType.BLOCK_STATEMENT); |
| return statement; |
| } |
| |
| private boolean parseExpressionInParenth(final PsiBuilder builder) { |
| if (!expect(builder, JavaTokenType.LPARENTH)) { |
| error(builder, JavaErrorMessages.message("expected.lparen")); |
| return false; |
| } |
| |
| final PsiBuilder.Marker beforeExpr = builder.mark(); |
| final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder); |
| if (expr == null || builder.getTokenType() == JavaTokenType.SEMICOLON) { |
| beforeExpr.rollbackTo(); |
| error(builder, JavaErrorMessages.message("expected.expression")); |
| if (builder.getTokenType() != JavaTokenType.RPARENTH) { |
| return false; |
| } |
| } |
| else { |
| beforeExpr.drop(); |
| if (builder.getTokenType() != JavaTokenType.RPARENTH) { |
| error(builder, JavaErrorMessages.message("expected.rparen")); |
| return false; |
| } |
| } |
| |
| builder.advanceLexer(); |
| return true; |
| } |
| } |