Merge branch 'master' of git@git.labs.intellij.net:idea/community
[idea/community.git] / java / java-impl / src / com / intellij / lang / java / parser / StatementParser.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.lang.java.parser;
17
18 import com.intellij.codeInsight.daemon.JavaErrorMessages;
19 import com.intellij.lang.PsiBuilder;
20 import com.intellij.psi.JavaTokenType;
21 import com.intellij.psi.impl.source.tree.ElementType;
22 import com.intellij.psi.impl.source.tree.JavaElementType;
23 import com.intellij.psi.tree.IElementType;
24 import com.intellij.psi.tree.ILazyParseableElementType;
25 import com.intellij.psi.tree.TokenSet;
26 import com.intellij.util.SmartList;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29
30 import java.util.List;
31
32 import static com.intellij.lang.PsiBuilderUtil.*;
33 import static com.intellij.lang.java.parser.JavaParserUtil.*;
34
35
36 public class StatementParser {
37   private static final boolean DEEP_PARSE_BLOCKS_IN_STATEMENTS = false;
38
39   private enum BraceMode {
40     TILL_FIRST, TILL_LAST
41   }
42
43   private static final TokenSet TRY_CLOSERS_SET = TokenSet.create(JavaTokenType.CATCH_KEYWORD, JavaTokenType.FINALLY_KEYWORD);
44
45   private StatementParser() { }
46
47   @Nullable
48   public static PsiBuilder.Marker parseCodeBlock(final PsiBuilder builder) {
49     if (builder.getTokenType() != JavaTokenType.LBRACE) return null;
50     else if (DEEP_PARSE_BLOCKS_IN_STATEMENTS) return parseCodeBlockDeep(builder, false);
51
52     final PsiBuilder.Marker codeBlock = builder.mark();
53     builder.advanceLexer();
54
55     boolean greedyBlock = false;
56     int braceCount = 1;
57     while (true) {
58       final IElementType tokenType = builder.getTokenType();
59       if (tokenType == null) {
60         greedyBlock = true;
61         break;
62       }
63       if (tokenType == JavaTokenType.LBRACE) {
64         braceCount++;
65       }
66       else if (tokenType == JavaTokenType.RBRACE) {
67         braceCount--;
68       }
69       builder.advanceLexer();
70
71       if (braceCount == 0) {
72         break;
73       }
74       else if (braceCount == 1 && (tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.RBRACE)) {
75         final PsiBuilder.Marker position = builder.mark();
76         final List<IElementType> list = new SmartList<IElementType>();
77         while (true) {
78           final IElementType type = builder.getTokenType();
79           if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(type) || ElementType.MODIFIER_BIT_SET.contains(type) ||
80               type == JavaTokenType.IDENTIFIER || type == JavaTokenType.LT || type == JavaTokenType.GT ||
81               type == JavaTokenType.GTGT || type == JavaTokenType.GTGTGT || type == JavaTokenType.COMMA ||
82               type == JavaTokenType.DOT || type == JavaTokenType.EXTENDS_KEYWORD || type == JavaTokenType.IMPLEMENTS_KEYWORD) {
83             list.add(type);
84             builder.advanceLexer();
85           } else {
86             break;
87           }
88         }
89         if (builder.getTokenType() == JavaTokenType.LPARENTH && list.size() >= 2) {
90           final IElementType last = list.get(list.size() - 1);
91           final IElementType prevLast = list.get(list.size() - 2);
92           if (last == JavaTokenType.IDENTIFIER &&
93               (prevLast == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(prevLast))) {
94             position.rollbackTo();
95             greedyBlock = true;
96             break;
97           }
98         }
99         position.drop();
100       }
101     }
102
103     codeBlock.collapse(JavaElementType.CODE_BLOCK);
104     if (greedyBlock) {
105       codeBlock.setCustomEdgeProcessors(null, GREEDY_RIGHT_EDGE_PROCESSOR);
106     }
107     return codeBlock;
108   }
109
110   @Nullable
111   public static PsiBuilder.Marker parseCodeBlockDeep(final PsiBuilder builder, final boolean parseUntilEof) {
112     if (builder.getTokenType() != JavaTokenType.LBRACE) return null;
113
114     final PsiBuilder.Marker codeBlock = builder.mark();
115     builder.advanceLexer();
116
117     parseStatements(builder, (parseUntilEof ? BraceMode.TILL_LAST : BraceMode.TILL_FIRST));
118
119     final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
120
121     done(codeBlock, JavaElementType.CODE_BLOCK);
122     if (greedyBlock) {
123       codeBlock.setCustomEdgeProcessors(null, GREEDY_RIGHT_EDGE_PROCESSOR);
124     }
125     return codeBlock;
126   }
127
128   private static void parseStatements(final PsiBuilder builder, final BraceMode braceMode) {
129     while (builder.getTokenType() != null) {
130       final PsiBuilder.Marker statement = parseStatement(builder);
131       if (statement != null) continue;
132
133       final IElementType tokenType = builder.getTokenType();
134       if (tokenType == JavaTokenType.RBRACE) {
135         if (braceMode == BraceMode.TILL_FIRST) {
136           return;
137         }
138         else if (braceMode == BraceMode.TILL_LAST) {
139           if (nextTokenType(builder) == null) {
140             return;
141           }
142         }
143       }
144
145       final PsiBuilder.Marker error = builder.mark();
146       builder.advanceLexer();
147       if (tokenType == JavaTokenType.ELSE_KEYWORD) {
148         error.error(JavaErrorMessages.message("else.without.if"));
149       }
150       else if (tokenType == JavaTokenType.CATCH_KEYWORD) {
151         error.error(JavaErrorMessages.message("catch.without.try"));
152       }
153       else if (tokenType == JavaTokenType.FINALLY_KEYWORD) {
154         error.error(JavaErrorMessages.message("finally.without.try"));
155       }
156       else {
157         error.error(JavaErrorMessages.message("unexpected.token"));
158       }
159     }
160   }
161
162   @Nullable
163   private static PsiBuilder.Marker parseStatement(final PsiBuilder builder) {
164     final IElementType tokenType = builder.getTokenType();
165
166     // todo: custom parsers (?)
167
168     if (tokenType == JavaTokenType.IF_KEYWORD) {
169       return parseIfStatement(builder);
170     }
171     else if (tokenType == JavaTokenType.WHILE_KEYWORD) {
172       return parseWhileStatement(builder);
173     }
174     else if (tokenType == JavaTokenType.FOR_KEYWORD) {
175       return parseForStatement(builder);
176     }
177     else if (tokenType == JavaTokenType.DO_KEYWORD) {
178       return parseDoWhileStatement(builder);
179     }
180     else if (tokenType == JavaTokenType.SWITCH_KEYWORD) {
181       return parseSwitchStatement(builder);
182     }
183     else if (tokenType == JavaTokenType.CASE_KEYWORD || tokenType == JavaTokenType.DEFAULT_KEYWORD) {
184       return parseSwitchLabelStatement(builder);
185     }
186     else if (tokenType == JavaTokenType.BREAK_KEYWORD) {
187       return parseBreakStatement(builder);
188     }
189     else if (tokenType == JavaTokenType.CONTINUE_KEYWORD) {
190       return parseContinueStatement(builder);
191     }
192     else if (tokenType == JavaTokenType.RETURN_KEYWORD) {
193       return parseReturnStatement(builder);
194     }
195     else if (tokenType == JavaTokenType.THROW_KEYWORD) {
196       return parseThrowStatement(builder);
197     }
198     else if (tokenType == JavaTokenType.SYNCHRONIZED_KEYWORD) {
199       return parseSynchronizedStatement(builder);
200     }
201     else if (tokenType == JavaTokenType.TRY_KEYWORD) {
202       return parseTryStatement(builder);
203     }
204     else if (tokenType == JavaTokenType.ASSERT_KEYWORD) {
205       return parseAssertStatement(builder);
206     }
207     else if (tokenType == JavaTokenType.LBRACE) {
208       return parseBlockStatement(builder);
209     }
210     else if (tokenType instanceof ILazyParseableElementType) {
211       builder.advanceLexer();
212       return null;
213     }
214     else if (tokenType == JavaTokenType.SEMICOLON) {
215       final PsiBuilder.Marker empty = builder.mark();
216       builder.advanceLexer();
217       done(empty, JavaElementType.EMPTY_STATEMENT);
218       return empty;
219     }
220     else if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.AT) {
221       final PsiBuilder.Marker refPos = builder.mark();
222       DeclarationParser.parseAnnotations(builder);
223       skipQualifiedName(builder);
224       final IElementType suspectedLT = builder.getTokenType();
225       refPos.rollbackTo();
226       if (suspectedLT == JavaTokenType.LT) {
227         final PsiBuilder.Marker declStatement = builder.mark();
228         final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
229         if (decl == null) {
230           ReferenceParser.parseType(builder, false, false, false);
231           error(builder, JavaErrorMessages.message("expected.identifier"));
232         }
233         done(declStatement, JavaElementType.DECLARATION_STATEMENT);
234         return declStatement;
235       }
236     }
237
238     final PsiBuilder.Marker pos = builder.mark();
239     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
240
241     if (expr != null) {
242       int count = 1;
243       final PsiBuilder.Marker list = expr.precede();
244       final PsiBuilder.Marker statement = list.precede();
245       while (builder.getTokenType() == JavaTokenType.COMMA) {
246         final PsiBuilder.Marker commaPos = builder.mark();
247         builder.advanceLexer();
248         final PsiBuilder.Marker expr1 = ExpressionParser.parse(builder);
249         if (expr1 == null) {
250           commaPos.rollbackTo();
251           break;
252         }
253         commaPos.drop();
254         count++;
255       }
256       if (count > 1) {
257         pos.drop();
258         done(list, JavaElementType.EXPRESSION_LIST);
259         semicolon(builder);
260         done(statement, JavaElementType.EXPRESSION_LIST_STATEMENT);
261         return statement;
262       }
263       if (exprType(expr) != JavaElementType.REFERENCE_EXPRESSION) {
264         drop(list, pos);
265         semicolon(builder);
266         done(statement, JavaElementType.EXPRESSION_STATEMENT);
267         return statement;
268       }
269       pos.rollbackTo();
270     }
271     else {
272       pos.drop();
273     }
274
275     final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
276     if (decl != null) {
277       final PsiBuilder.Marker statement = decl.precede();
278       done(statement, JavaElementType.DECLARATION_STATEMENT);
279       return statement;
280     }
281
282     if (lookAhead(builder, JavaTokenType.IDENTIFIER, JavaTokenType.COLON)) {
283       final PsiBuilder.Marker statement = builder.mark();
284       advance(builder, 2);
285       parseStatement(builder);
286       done(statement, JavaElementType.LABELED_STATEMENT);
287       return statement;
288     }
289
290     if (expr != null) {
291       final PsiBuilder.Marker statement = builder.mark();
292       ExpressionParser.parse(builder);
293       semicolon(builder);
294       done(statement, JavaElementType.EXPRESSION_STATEMENT);
295       return statement;
296     }
297
298     return null;
299   }
300
301   private static void skipQualifiedName(final PsiBuilder builder) {
302     if (!expect(builder, JavaTokenType.IDENTIFIER)) return;
303     while (lookAhead(builder, JavaTokenType.DOT, JavaTokenType.IDENTIFIER)) {
304       advance(builder, 2);
305     }
306   }
307
308   @NotNull
309   private static PsiBuilder.Marker parseIfStatement(final PsiBuilder builder) {
310     final PsiBuilder.Marker statement = builder.mark();
311     builder.advanceLexer();
312
313     if (!parseExpressionInParenth(builder)) {
314       done(statement, JavaElementType.IF_STATEMENT);
315       return statement;
316     }
317
318     final PsiBuilder.Marker thenStatement = parseStatement(builder);
319     if (thenStatement == null) {
320       error(builder, JavaErrorMessages.message("expected.statement"));
321       done(statement, JavaElementType.IF_STATEMENT);
322       return statement;
323     }
324
325     if (!expect(builder, JavaTokenType.ELSE_KEYWORD)) {
326       done(statement, JavaElementType.IF_STATEMENT);
327       return statement;
328     }
329
330     final PsiBuilder.Marker elseStatement = parseStatement(builder);
331     if (elseStatement == null) {
332       error(builder, JavaErrorMessages.message("expected.statement"));
333     }
334
335     done(statement, JavaElementType.IF_STATEMENT);
336     return statement;
337   }
338
339   @NotNull
340   private static PsiBuilder.Marker parseWhileStatement(final PsiBuilder builder) {
341     final PsiBuilder.Marker statement = builder.mark();
342     builder.advanceLexer();
343
344     if (!parseExpressionInParenth(builder)) {
345       done(statement, JavaElementType.WHILE_STATEMENT);
346       return statement;
347     }
348
349     final PsiBuilder.Marker bodyStatement = parseStatement(builder);
350     if (bodyStatement == null) {
351       error(builder, JavaErrorMessages.message("expected.statement"));
352     }
353
354     done(statement, JavaElementType.WHILE_STATEMENT);
355     return statement;
356   }
357
358   @NotNull
359   private static PsiBuilder.Marker parseForStatement(final PsiBuilder builder) {
360     final PsiBuilder.Marker statement = builder.mark();
361     builder.advanceLexer();
362
363     if (!expect(builder, JavaTokenType.LPARENTH)) {
364       error(builder, JavaErrorMessages.message("expected.lparen"));
365       done(statement, JavaElementType.FOR_STATEMENT);
366       return statement;
367     }
368
369     final PsiBuilder.Marker afterParenth = builder.mark();
370     final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false);
371     if (param == null || builder.getTokenType() != JavaTokenType.COLON) {
372       afterParenth.rollbackTo();
373       return parseForLoopFromInitialization(builder, statement);
374     }
375     else {
376       afterParenth.drop();
377       return parseForEachFromColon(builder, statement);
378     }
379   }
380
381   @NotNull
382   private static PsiBuilder.Marker parseForLoopFromInitialization(final PsiBuilder builder, final PsiBuilder.Marker statement) {
383     final PsiBuilder.Marker init = parseStatement(builder);
384     if (init == null){
385       error(builder, JavaErrorMessages.message("expected.statement"));
386       if (!expect(builder, JavaTokenType.RPARENTH)) {
387         done(statement, JavaElementType.FOR_STATEMENT);
388         return statement;
389       }
390     }
391     else {
392       ExpressionParser.parse(builder);
393       if (!expect(builder, JavaTokenType.SEMICOLON)) {
394         error(builder, JavaErrorMessages.message("expected.semicolon"));
395         if (!expect(builder, JavaTokenType.RPARENTH)) {
396           done(statement, JavaElementType.FOR_STATEMENT);
397           return statement;
398         }
399       }
400       else {
401         parseExpressionOrExpressionList(builder);
402         if (!expect(builder, JavaTokenType.RPARENTH)) {
403           error(builder, JavaErrorMessages.message("expected.rparen"));
404           done(statement, JavaElementType.FOR_STATEMENT);
405           return statement;
406         }
407       }
408     }
409
410     final PsiBuilder.Marker bodyStatement = parseStatement(builder);
411     if (bodyStatement == null) {
412       error(builder, JavaErrorMessages.message("expected.statement"));
413     }
414
415     done(statement, JavaElementType.FOR_STATEMENT);
416     return statement;
417   }
418
419   private static void parseExpressionOrExpressionList(final PsiBuilder builder) {
420     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
421     if (expr == null) return;
422
423     final PsiBuilder.Marker expressionStatement;
424     if (builder.getTokenType() != JavaTokenType.COMMA) {
425       expressionStatement = expr.precede();
426       done(expressionStatement, JavaElementType.EXPRESSION_STATEMENT);
427     }
428     else {
429       final PsiBuilder.Marker expressionList = expr.precede();
430       expressionStatement = expressionList.precede();
431
432       do {
433         builder.advanceLexer();
434         final PsiBuilder.Marker nextExpression = ExpressionParser.parse(builder);
435         if (nextExpression == null) {
436           error(builder, JavaErrorMessages.message("expected.expression"));
437         }
438       }
439       while (builder.getTokenType() == JavaTokenType.COMMA);
440
441       done(expressionList, JavaElementType.EXPRESSION_LIST);
442       done(expressionStatement, JavaElementType.EXPRESSION_LIST_STATEMENT);
443     }
444   }
445
446   @NotNull
447   private static PsiBuilder.Marker parseForEachFromColon(PsiBuilder builder, PsiBuilder.Marker statement) {
448     builder.advanceLexer();
449
450     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
451     if (expr == null) {
452       error(builder, JavaErrorMessages.message("expected.expression"));
453     }
454
455     if (expect(builder, JavaTokenType.RPARENTH)) {
456       final PsiBuilder.Marker bodyStatement = parseStatement(builder);
457       if (bodyStatement == null) {
458         error(builder, JavaErrorMessages.message("expected.statement"));
459       }
460     }
461     else {
462       error(builder, JavaErrorMessages.message("expected.rparen"));
463     }
464
465     done(statement, JavaElementType.FOREACH_STATEMENT);
466     return statement;
467   }
468
469   @NotNull
470   private static PsiBuilder.Marker parseDoWhileStatement(final PsiBuilder builder) {
471     final PsiBuilder.Marker statement = builder.mark();
472     builder.advanceLexer();
473
474     final PsiBuilder.Marker body = parseStatement(builder);
475     if (body == null) {
476       error(builder, JavaErrorMessages.message("expected.statement"));
477       done(statement, JavaElementType.DO_WHILE_STATEMENT);
478       return statement;
479     }
480
481     if (!expect(builder, JavaTokenType.WHILE_KEYWORD)) {
482       error(builder, JavaErrorMessages.message("expected.while"));
483       done(statement, JavaElementType.DO_WHILE_STATEMENT);
484       return statement;
485     }
486
487     if (parseExpressionInParenth(builder)) {
488       semicolon(builder);
489     }
490
491     done(statement, JavaElementType.DO_WHILE_STATEMENT);
492     return statement;
493   }
494
495   @NotNull
496   private static PsiBuilder.Marker parseSwitchStatement(final PsiBuilder builder) {
497     final PsiBuilder.Marker statement = builder.mark();
498     builder.advanceLexer();
499
500     if (!parseExpressionInParenth(builder)) {
501       done(statement, JavaElementType.SWITCH_STATEMENT);
502       return statement;
503     }
504
505     final PsiBuilder.Marker body = parseCodeBlock(builder);
506     if (body == null) {
507       error(builder, JavaErrorMessages.message("expected.lbrace"));
508     }
509
510     done(statement, JavaElementType.SWITCH_STATEMENT);
511     return statement;
512   }
513
514   @Nullable
515   private static PsiBuilder.Marker parseSwitchLabelStatement(final PsiBuilder builder) {
516     final PsiBuilder.Marker statement = builder.mark();
517     final boolean isCase = builder.getTokenType() == JavaTokenType.CASE_KEYWORD;
518     builder.advanceLexer();
519
520     if (isCase) {
521       final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
522       if (expr == null) {
523         statement.rollbackTo();
524         return null;
525       }
526     }
527
528     expectOrError(builder, JavaTokenType.COLON, JavaErrorMessages.message("expected.colon"));
529
530     done(statement, JavaElementType.SWITCH_LABEL_STATEMENT);
531     return statement;
532   }
533
534   @NotNull
535   private static PsiBuilder.Marker parseBreakStatement(final PsiBuilder builder) {
536     final PsiBuilder.Marker statement = builder.mark();
537     builder.advanceLexer();
538     expect(builder, JavaTokenType.IDENTIFIER);
539     semicolon(builder);
540     done(statement, JavaElementType.BREAK_STATEMENT);
541     return statement;
542   }
543
544   @NotNull
545   private static PsiBuilder.Marker parseContinueStatement(final PsiBuilder builder) {
546     final PsiBuilder.Marker statement = builder.mark();
547     builder.advanceLexer();
548     expect(builder, JavaTokenType.IDENTIFIER);
549     semicolon(builder);
550     done(statement, JavaElementType.CONTINUE_STATEMENT);
551     return statement;
552   }
553
554   @NotNull
555   private static PsiBuilder.Marker parseReturnStatement(final PsiBuilder builder) {
556     final PsiBuilder.Marker statement = builder.mark();
557     builder.advanceLexer();
558
559     ExpressionParser.parse(builder);
560
561     semicolon(builder);
562     done(statement, JavaElementType.RETURN_STATEMENT);
563     return statement;
564   }
565
566   @NotNull
567   private static PsiBuilder.Marker parseThrowStatement(final PsiBuilder builder) {
568     final PsiBuilder.Marker statement = builder.mark();
569     builder.advanceLexer();
570
571     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
572     if (expr == null) {
573       error(builder, JavaErrorMessages.message("expected.expression"));
574       done(statement, JavaElementType.THROW_STATEMENT);
575       return statement;
576     }
577
578     semicolon(builder);
579     done(statement, JavaElementType.THROW_STATEMENT);
580     return statement;
581   }
582
583   @NotNull
584   private static PsiBuilder.Marker parseSynchronizedStatement(final PsiBuilder builder) {
585     final PsiBuilder.Marker statement = builder.mark();
586     builder.advanceLexer();
587
588     if (!parseExpressionInParenth(builder)) {
589       done(statement, JavaElementType.SYNCHRONIZED_STATEMENT);
590       return statement;
591     }
592
593     final PsiBuilder.Marker body = parseCodeBlock(builder);
594     if (body == null) {
595       error(builder, JavaErrorMessages.message("expected.lbrace"));
596     }
597
598     done(statement, JavaElementType.SYNCHRONIZED_STATEMENT);
599     return statement;
600   }
601
602   @NotNull
603   private static PsiBuilder.Marker parseTryStatement(final PsiBuilder builder) {
604     final PsiBuilder.Marker statement = builder.mark();
605     builder.advanceLexer();
606
607     final PsiBuilder.Marker tryBlock = parseCodeBlock(builder);
608     if (tryBlock == null) {
609       error(builder, JavaErrorMessages.message("expected.lbrace"));
610       done(statement, JavaElementType.TRY_STATEMENT);
611       return statement;
612     }
613
614     if (!TRY_CLOSERS_SET.contains(builder.getTokenType())) {
615       error(builder, JavaErrorMessages.message("expected.catch.or.finally"));
616       done(statement, JavaElementType.TRY_STATEMENT);
617       return statement;
618     }
619
620     while (builder.getTokenType() == JavaTokenType.CATCH_KEYWORD) {
621       if (!parseCatchBlock(builder)) break;
622     }
623
624     if (expect(builder, JavaTokenType.FINALLY_KEYWORD)) {
625       final PsiBuilder.Marker finallyBlock = parseCodeBlock(builder);
626       if (finallyBlock == null) {
627         error(builder, JavaErrorMessages.message("expected.lbrace"));
628       }
629     }
630
631     done(statement, JavaElementType.TRY_STATEMENT);
632     return statement;
633   }
634
635   private static boolean parseCatchBlock(final PsiBuilder builder) {
636     final PsiBuilder.Marker section = builder.mark();
637     builder.advanceLexer();
638
639     if (!expect(builder, JavaTokenType.LPARENTH)) {
640       error(builder, JavaErrorMessages.message("expected.lparen"));
641       done(section, JavaElementType.CATCH_SECTION);
642       return false;
643     }
644
645     final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false);
646     if (param == null) {
647       error(builder, JavaErrorMessages.message("expected.parameter"));
648     }
649
650     if (!expect(builder, JavaTokenType.RPARENTH)) {
651       error(builder, JavaErrorMessages.message("expected.rparen"));
652       done(section, JavaElementType.CATCH_SECTION);
653       return false;
654     }
655
656     final PsiBuilder.Marker body = parseCodeBlock(builder);
657     if (body == null) {
658       error(builder, JavaErrorMessages.message("expected.lbrace"));
659       done(section, JavaElementType.CATCH_SECTION);
660       return false;
661     }
662
663     done(section, JavaElementType.CATCH_SECTION);
664     return true;
665   }
666
667   @NotNull
668   private static PsiBuilder.Marker parseAssertStatement(final PsiBuilder builder) {
669     final PsiBuilder.Marker statement = builder.mark();
670     builder.advanceLexer();
671
672     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
673     if (expr == null) {
674       error(builder, JavaErrorMessages.message("expected.boolean.expression"));
675       done(statement, JavaElementType.ASSERT_STATEMENT);
676       return statement;
677     }
678
679     if (expect(builder, JavaTokenType.COLON)) {
680       final PsiBuilder.Marker expr2 = ExpressionParser.parse(builder);
681       if (expr2 == null) {
682         error(builder, JavaErrorMessages.message("expected.expression"));
683         done(statement, JavaElementType.ASSERT_STATEMENT);
684         return statement;
685       }
686     }
687
688     semicolon(builder);
689     done(statement, JavaElementType.ASSERT_STATEMENT);
690     return statement;
691   }
692
693   @NotNull
694   private static PsiBuilder.Marker parseBlockStatement(final PsiBuilder builder) {
695     final PsiBuilder.Marker statement = builder.mark();
696     parseCodeBlock(builder);
697     done(statement, JavaElementType.BLOCK_STATEMENT);
698     return statement;
699   }
700
701   private static boolean parseExpressionInParenth(final PsiBuilder builder) {
702     if (!expect(builder, JavaTokenType.LPARENTH)) {
703       error(builder, JavaErrorMessages.message("expected.lparen"));
704       return false;
705     }
706
707     final PsiBuilder.Marker beforeExpr = builder.mark();
708     final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
709     if (expr == null || builder.getTokenType() == JavaTokenType.SEMICOLON) {
710       beforeExpr.rollbackTo();
711       error(builder, JavaErrorMessages.message("expected.expression"));
712       if (builder.getTokenType() != JavaTokenType.RPARENTH) {
713         return false;
714       }
715     }
716     else {
717       beforeExpr.drop();
718       if (builder.getTokenType() != JavaTokenType.RPARENTH) {
719         error(builder, JavaErrorMessages.message("expected.rparen"));
720         return false;
721       }
722     }
723
724     builder.advanceLexer();
725     return true;
726   }
727 }