Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(531)

Side by Side Diff: compiler/java/com/google/dart/compiler/parser/DartParser.java

Issue 10534065: In analyzer, catch use of continue and break in inappropriate places (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Refactored a bit, handle break inside function definition Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 package com.google.dart.compiler.parser; 5 package com.google.dart.compiler.parser;
6 6
7 import com.google.common.annotations.VisibleForTesting; 7 import com.google.common.annotations.VisibleForTesting;
8 import com.google.common.io.CharStreams; 8 import com.google.common.io.CharStreams;
9 import com.google.dart.compiler.DartCompilationError; 9 import com.google.dart.compiler.DartCompilationError;
10 import com.google.dart.compiler.DartCompilerListener; 10 import com.google.dart.compiler.DartCompilerListener;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 } finally { 214 } finally {
215 reader.close(); 215 reader.close();
216 } 216 }
217 } 217 }
218 218
219 /** 219 /**
220 * A flag indicating whether function expressions are allowed. See 220 * A flag indicating whether function expressions are allowed. See
221 * {@link #setAllowFunctionExpression(boolean)}. 221 * {@link #setAllowFunctionExpression(boolean)}.
222 */ 222 */
223 private boolean allowFunctionExpression = true; 223 private boolean allowFunctionExpression = true;
224
225 /**
226 * 'break' (with no labels) and 'continue' stmts are not valid
227 * just anywhere, they must be inside a loop or a case stmt.
228 *
229 * A break with a label may be valid and is allowed through and
230 * checked in the resolver.
231 */
232 private boolean inLoopOrCaseStatement = false;
224 233
225 /** 234 /**
226 * Set the {@link #allowFunctionExpression} flag indicating whether function e xpressions are 235 * Set the {@link #allowFunctionExpression} flag indicating whether function e xpressions are
227 * allowed, returning the old value. This is required to avoid ambiguity in a few places in the 236 * allowed, returning the old value. This is required to avoid ambiguity in a few places in the
228 * grammar. 237 * grammar.
229 * 238 *
230 * @param allow true if function expressions are allowed, false if not 239 * @param allow true if function expressions are allowed, false if not
231 * @return previous value of the flag, which should be restored 240 * @return previous value of the flag, which should be restored
232 */ 241 */
233 private boolean setAllowFunctionExpression(boolean allow) { 242 private boolean setAllowFunctionExpression(boolean allow) {
(...skipping 2831 matching lines...) Expand 10 before | Expand all | Expand 10 after
3065 * <pre> 3074 * <pre>
3066 * functionStatementBody 3075 * functionStatementBody
3067 * : '=>' expression ';' 3076 * : '=>' expression ';'
3068 * | block 3077 * | block
3069 * </pre> 3078 * </pre>
3070 * 3079 *
3071 * @param requireSemicolonForArrow true if a semicolon is required after an ar row expression 3080 * @param requireSemicolonForArrow true if a semicolon is required after an ar row expression
3072 * @return {@link DartBlock} instance containing function body 3081 * @return {@link DartBlock} instance containing function body
3073 */ 3082 */
3074 private DartBlock parseFunctionStatementBody(boolean requireSemicolonForArrow) { 3083 private DartBlock parseFunctionStatementBody(boolean requireSemicolonForArrow) {
3084 // A break inside a function body should have nothing to do with a loop in
3085 // the code surrounding the definition.
3086 boolean oldInLoopOrCaseStatement = inLoopOrCaseStatement;
3087 inLoopOrCaseStatement = false;
3088 DartBlock result;
3075 if (isDietParse) { 3089 if (isDietParse) {
3076 DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>()); 3090 result = dietParseFunctionStatementBody();
3077 if (optional(Token.ARROW)) {
3078 while (true) {
3079 Token token = next();
3080 if (token == Token.SEMICOLON) {
3081 break;
3082 }
3083 }
3084 } else {
3085 if (!peek(0).equals(Token.LBRACE) && looksLikeTopLevelKeyword()) {
3086 // Allow recovery back to the top level.
3087 reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
3088 return done(emptyBlock);
3089 }
3090 expect(Token.LBRACE);
3091 int nesting = 1;
3092 while (nesting > 0) {
3093 Token token = next();
3094 switch (token) {
3095 case LBRACE:
3096 ++nesting;
3097 break;
3098 case RBRACE:
3099 --nesting;
3100 break;
3101 case EOS:
3102 return emptyBlock;
3103 }
3104 }
3105 }
3106 // Return an empty block so we don't generate unparseable code.
3107 return emptyBlock;
3108 } else { 3091 } else {
3109 beginFunctionStatementBody(); 3092 beginFunctionStatementBody();
3110 if (optional(Token.ARROW)) { 3093 if (optional(Token.ARROW)) {
3111 DartExpression expr = parseExpression(); 3094 DartExpression expr = parseExpression();
3112 if (expr == null) { 3095 if (expr == null) {
3113 expr = new DartSyntheticErrorExpression(); 3096 expr = new DartSyntheticErrorExpression();
3114 } 3097 }
3115 if (requireSemicolonForArrow) { 3098 if (requireSemicolonForArrow) {
3116 expect(Token.SEMICOLON); 3099 expect(Token.SEMICOLON);
3117 } 3100 }
3118 return done(makeReturnBlock(expr)); 3101 result = done(makeReturnBlock(expr));
3119 } else { 3102 } else {
3120 return done(parseBlock()); 3103 result = done(parseBlock());
3121 } 3104 }
3122 } 3105 }
3106 inLoopOrCaseStatement = oldInLoopOrCaseStatement;
3107 return result;
3108 }
3109
3110 private DartBlock dietParseFunctionStatementBody() {
3111 DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>());
3112 if (optional(Token.ARROW)) {
3113 while (true) {
3114 Token token = next();
3115 if (token == Token.SEMICOLON) {
3116 break;
3117 }
3118 }
3119 } else {
3120 if (!peek(0).equals(Token.LBRACE) && looksLikeTopLevelKeyword()) {
3121 // Allow recovery back to the top level.
3122 reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
3123 return done(emptyBlock);
3124 }
3125 expect(Token.LBRACE);
3126 int nesting = 1;
3127 while (nesting > 0) {
3128 Token token = next();
3129 switch (token) {
3130 case LBRACE:
3131 ++nesting;
3132 break;
3133 case RBRACE:
3134 --nesting;
3135 break;
3136 case EOS:
3137 return emptyBlock;
3138 }
3139 }
3140 }
3141 // Return an empty block so we don't generate unparseable code.
3142 return emptyBlock;
3123 } 3143 }
3124 3144
3125 /** 3145 /**
3126 * Create a block containing a single return statement. 3146 * Create a block containing a single return statement.
3127 * 3147 *
3128 * @param returnVal return value expression 3148 * @param returnVal return value expression
3129 * @return block containing a single return statement 3149 * @return block containing a single return statement
3130 */ 3150 */
3131 private DartBlock makeReturnBlock(DartExpression returnVal) { 3151 private DartBlock makeReturnBlock(DartExpression returnVal) {
3132 return new DartReturnBlock(returnVal); 3152 return new DartReturnBlock(returnVal);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
3174 * | THROW expression? ';' 3194 * | THROW expression? ';'
3175 * ; 3195 * ;
3176 * </pre> 3196 * </pre>
3177 */ 3197 */
3178 private DartBreakStatement parseBreakStatement() { 3198 private DartBreakStatement parseBreakStatement() {
3179 beginBreakStatement(); 3199 beginBreakStatement();
3180 expect(Token.BREAK); 3200 expect(Token.BREAK);
3181 DartIdentifier label = null; 3201 DartIdentifier label = null;
3182 if (match(Token.IDENTIFIER)) { 3202 if (match(Token.IDENTIFIER)) {
3183 label = parseIdentifier(); 3203 label = parseIdentifier();
3204 } else if (!inLoopOrCaseStatement) {
3205 // The validation of matching of labels to break statements is done later.
3206 reportErrorWithoutAdvancing(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP);
3184 } 3207 }
3185 expectStatmentTerminator(); 3208 expectStatmentTerminator();
3186 return done(new DartBreakStatement(label)); 3209 return done(new DartBreakStatement(label));
3187 } 3210 }
3188 3211
3189 private DartContinueStatement parseContinueStatement() { 3212 private DartContinueStatement parseContinueStatement() {
3190 beginContinueStatement(); 3213 beginContinueStatement();
3191 expect(Token.CONTINUE); 3214 expect(Token.CONTINUE);
3192 DartIdentifier label = null; 3215 DartIdentifier label = null;
3216 if (!inLoopOrCaseStatement) {
3217 reportErrorWithoutAdvancing(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP);
3218 }
3193 if (peek(0) == Token.IDENTIFIER) { 3219 if (peek(0) == Token.IDENTIFIER) {
3194 label = parseIdentifier(); 3220 label = parseIdentifier();
3195 } 3221 }
3196 expectStatmentTerminator(); 3222 expectStatmentTerminator();
3197 return done(new DartContinueStatement(label)); 3223 return done(new DartContinueStatement(label));
3198 } 3224 }
3199 3225
3200 private DartReturnStatement parseReturnStatement() { 3226 private DartReturnStatement parseReturnStatement() {
3201 beginReturnStatement(); 3227 beginReturnStatement();
3202 expect(Token.RETURN); 3228 expect(Token.RETURN);
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after
3646 * | FOR '(' forLoopParts ')' statement 3672 * | FOR '(' forLoopParts ')' statement
3647 * ; 3673 * ;
3648 * </pre> 3674 * </pre>
3649 */ 3675 */
3650 private DartWhileStatement parseWhileStatement() { 3676 private DartWhileStatement parseWhileStatement() {
3651 beginWhileStatement(); 3677 beginWhileStatement();
3652 expect(Token.WHILE); 3678 expect(Token.WHILE);
3653 expect(Token.LPAREN); 3679 expect(Token.LPAREN);
3654 DartExpression condition = parseExpression(); 3680 DartExpression condition = parseExpression();
3655 expectCloseParen(); 3681 expectCloseParen();
3656 DartStatement body = parseStatement(); 3682 DartStatement body = parseLoopOrCaseStatement();
3657 return done(new DartWhileStatement(condition, body)); 3683 return done(new DartWhileStatement(condition, body));
3658 } 3684 }
3659 3685
3660 /** 3686 /**
3661 * <pre> 3687 * <pre>
3662 * iterationStatement 3688 * iterationStatement
3663 * : WHILE '(' expression ')' statement 3689 * : WHILE '(' expression ')' statement
3664 * | DO statement WHILE '(' expression ')' ';' 3690 * | DO statement WHILE '(' expression ')' ';'
3665 * | FOR '(' forLoopParts ')' statement 3691 * | FOR '(' forLoopParts ')' statement
3666 * ; 3692 * ;
3667 * </pre> 3693 * </pre>
3668 */ 3694 */
3669 private DartDoWhileStatement parseDoWhileStatement() { 3695 private DartDoWhileStatement parseDoWhileStatement() {
3670 beginDoStatement(); 3696 beginDoStatement();
3671 expect(Token.DO); 3697 expect(Token.DO);
3672 DartStatement body = parseStatement(); 3698 DartStatement body = parseLoopOrCaseStatement();
3673 expect(Token.WHILE); 3699 expect(Token.WHILE);
3674 expect(Token.LPAREN); 3700 expect(Token.LPAREN);
3675 DartExpression condition = parseExpression(); 3701 DartExpression condition = parseExpression();
3676 expectCloseParen(); 3702 expectCloseParen();
3677 expectStatmentTerminator(); 3703 expectStatmentTerminator();
3678 return done(new DartDoWhileStatement(condition, body)); 3704 return done(new DartDoWhileStatement(condition, body));
3679 } 3705 }
3680 3706
3681 /** 3707 /**
3708 * Use this wrapper to parse the body of a loop or case statement.
3709 *
3710 * Sets up flag variables to make sure continue and break are properly
3711 * marked as errors when in wrong context.
3712 */
3713 private DartStatement parseLoopOrCaseStatement() {
3714 boolean oldInBreakable = inLoopOrCaseStatement;
3715 inLoopOrCaseStatement = true;
3716 DartStatement stmt = parseStatement();
3717 inLoopOrCaseStatement = oldInBreakable;
3718 return stmt;
3719 }
3720
3721 /**
3682 * <pre> 3722 * <pre>
3683 * iterationStatement 3723 * iterationStatement
3684 * : WHILE '(' expression ')' statement 3724 * : WHILE '(' expression ')' statement
3685 * | DO statement WHILE '(' expression ')' ';' 3725 * | DO statement WHILE '(' expression ')' ';'
3686 * | FOR '(' forLoopParts ')' statement 3726 * | FOR '(' forLoopParts ')' statement
3687 * ; 3727 * ;
3688 * 3728 *
3689 * forLoopParts 3729 * forLoopParts
3690 * : forInitializerStatement expression? ';' expressionList? 3730 * : forInitializerStatement expression? ';' expressionList?
3691 * | constVarOrType? identifier IN expression 3731 * | constVarOrType? identifier IN expression
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
3738 } else { 3778 } else {
3739 DartExpression expression = ((DartExprStmt) setup).getExpression(); 3779 DartExpression expression = ((DartExprStmt) setup).getExpression();
3740 if (!(expression instanceof DartIdentifier)) { 3780 if (!(expression instanceof DartIdentifier)) {
3741 reportError(setup, ParserErrorCode.FOR_IN_WITH_COMPLEX_VARIABLE); 3781 reportError(setup, ParserErrorCode.FOR_IN_WITH_COMPLEX_VARIABLE);
3742 } 3782 }
3743 } 3783 }
3744 3784
3745 DartExpression iterable = parseExpression(); 3785 DartExpression iterable = parseExpression();
3746 expectCloseParen(); 3786 expectCloseParen();
3747 3787
3748 DartStatement body = parseStatement(); 3788 DartStatement body = parseLoopOrCaseStatement();
3749 return done(new DartForInStatement(setup, iterable, body)); 3789 return done(new DartForInStatement(setup, iterable, body));
3750 3790
3751 } else if (optional(Token.SEMICOLON)) { 3791 } else if (optional(Token.SEMICOLON)) {
3752 3792
3753 // Condition 3793 // Condition
3754 DartExpression condition = null; 3794 DartExpression condition = null;
3755 if (peek(0) != Token.SEMICOLON) { 3795 if (peek(0) != Token.SEMICOLON) {
3756 condition = parseExpression(); 3796 condition = parseExpression();
3757 } 3797 }
3758 expect(Token.SEMICOLON); 3798 expect(Token.SEMICOLON);
3759 3799
3760 // Next 3800 // Next
3761 DartExpression next = null; 3801 DartExpression next = null;
3762 if (peek(0) != Token.RPAREN) { 3802 if (peek(0) != Token.RPAREN) {
3763 next = parseExpressionList(); 3803 next = parseExpressionList();
3764 } 3804 }
3765 expectCloseParen(); 3805 expectCloseParen();
3766 3806
3767 DartStatement body = parseStatement(); 3807 DartStatement body = parseLoopOrCaseStatement();
3768 return done(new DartForStatement(setup, condition, next, body)); 3808 return done(new DartForStatement(setup, condition, next, body));
3769 } else { 3809 } else {
3770 reportUnexpectedToken(position(), null, peek(0)); 3810 reportUnexpectedToken(position(), null, peek(0));
3771 return done(parseErrorStatement()); 3811 return done(parseErrorStatement());
3772 } 3812 }
3773 } 3813 }
3774 3814
3775 /** 3815 /**
3776 * <pre> 3816 * <pre>
3777 * selectionStatement 3817 * selectionStatement
(...skipping 27 matching lines...) Expand all
3805 List<DartStatement> statements = new ArrayList<DartStatement>(); 3845 List<DartStatement> statements = new ArrayList<DartStatement>();
3806 DartStatement statement = null; 3846 DartStatement statement = null;
3807 while (true) { 3847 while (true) {
3808 switch (peek(0)) { 3848 switch (peek(0)) {
3809 case CASE: 3849 case CASE:
3810 case DEFAULT: 3850 case DEFAULT:
3811 case RBRACE: 3851 case RBRACE:
3812 case EOS: 3852 case EOS:
3813 return statements; 3853 return statements;
3814 default: 3854 default:
3815 if ((statement = parseStatement()) == null) { 3855 if ((statement = parseLoopOrCaseStatement()) == null) {
3816 return statements; 3856 return statements;
3817 } 3857 }
3818 statements.add(statement); 3858 statements.add(statement);
3819 if (statement.isAbruptCompletingStatement()) { 3859 if (statement.isAbruptCompletingStatement()) {
3820 /* 3860 /*
3821 * TODO(jat): is this correct? It seems like we would get better 3861 * TODO(jat): is this correct? It seems like we would get better
3822 * error messages if we parsed dead code as part of this case block 3862 * error messages if we parsed dead code as part of this case block
3823 * and gave an error for unreachable code 3863 * and gave an error for unreachable code
3824 */ 3864 */
3825 return statements; 3865 return statements;
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
4202 } 4242 }
4203 4243
4204 private void reportError(DartNode node, ErrorCode errorCode, Object... argumen ts) { 4244 private void reportError(DartNode node, ErrorCode errorCode, Object... argumen ts) {
4205 reportError(new DartCompilationError(node, errorCode, arguments)); 4245 reportError(new DartCompilationError(node, errorCode, arguments));
4206 } 4246 }
4207 4247
4208 private boolean currentlyParsingToplevel() { 4248 private boolean currentlyParsingToplevel() {
4209 return !(isParsingInterface || isTopLevelAbstract || isParsingClass); 4249 return !(isParsingInterface || isTopLevelAbstract || isParsingClass);
4210 } 4250 }
4211 } 4251 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698