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

Side by Side Diff: src/parser.cc

Issue 720863002: Fix desugaring of let bindings in for loops to handle continue properly (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: New desugaring comment, not yet implemented Created 6 years, 1 month 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
« no previous file with comments | « src/parser.h ('k') | test/mjsunit/harmony/regress/regress-3683.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/ast.h" 8 #include "src/ast.h"
9 #include "src/bailout-reason.h" 9 #include "src/bailout-reason.h"
10 #include "src/base/platform/platform.h" 10 #include "src/base/platform/platform.h"
(...skipping 2965 matching lines...) Expand 10 before | Expand all | Expand 10 after
2976 result_done, 2976 result_done,
2977 assign_each); 2977 assign_each);
2978 } else { 2978 } else {
2979 stmt->Initialize(each, subject, body); 2979 stmt->Initialize(each, subject, body);
2980 } 2980 }
2981 } 2981 }
2982 2982
2983 2983
2984 Statement* Parser::DesugarLetBindingsInForStatement( 2984 Statement* Parser::DesugarLetBindingsInForStatement(
2985 Scope* inner_scope, ZoneList<const AstRawString*>* names, 2985 Scope* inner_scope, ZoneList<const AstRawString*>* names,
2986 ForStatement* loop, Statement* init, Expression* cond, Statement* next, 2986 ForStatement* loop, Statement* init, Expression* cond, Expression* next,
2987 Statement* body, bool* ok) { 2987 Statement* body, bool* ok) {
2988 // ES6 13.6.3.4 specifies that on each loop iteration the let variables are 2988 // ES6 13.6.3.4 specifies that on each loop iteration the let variables are
2989 // copied into a new environment. After copying, the "next" statement of the 2989 // copied into a new environment. After copying, the "next" statement of the
2990 // loop is executed to update the loop variables. The loop condition is 2990 // loop is executed to update the loop variables. The loop condition is
2991 // checked and the loop body is executed. 2991 // checked and the loop body is executed.
2992 // 2992 //
2993 // We rewrite a for statement of the form 2993 // We rewrite a for statement of the form
2994 // 2994 //
2995 // for (let x = i; cond; next) body 2995 // labels: for (let x = i; cond; next) body
2996 // 2996 //
2997 // into 2997 // into
2998 // 2998 //
2999 // { 2999 // {
3000 // let x = i; 3000 // let x = i;
3001 // temp_x = x; 3001 // temp_x = x;
3002 // flag = 1; 3002 // first = 1;
3003 // for (;;) { 3003 // outer: for (;;) {
3004 // let x = temp_x; 3004 // let x = temp_x;
3005 // if (flag == 1) { 3005 // if (first == 1) {
3006 // flag = 0; 3006 // first = 0;
3007 // } else {
3008 // next;
3009 // }
3010 // flag = 1;
3011 // labels: for (; flag == 1; temp_x = x, flag = 0) {
3012 // if (cond) {
3013 // body
3007 // } else { 3014 // } else {
3008 // next; 3015 // break outer;
3009 // } 3016 // }
3010 // if (cond) { 3017 // }
3011 // <empty> 3018 // if (flag == 1) {
3012 // } else { 3019 // break;
3013 // break; 3020 // }
3014 // } 3021 // }
3015 // b
3016 // temp_x = x;
3017 // }
3018 // } 3022 // }
3019 3023
3020 DCHECK(names->length() > 0); 3024 DCHECK(names->length() > 0);
3021 Scope* for_scope = scope_; 3025 Scope* for_scope = scope_;
3022 ZoneList<Variable*> temps(names->length(), zone()); 3026 ZoneList<Variable*> temps(names->length(), zone());
3023 3027
3024 Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false, 3028 Block* outer_block = factory()->NewBlock(NULL, names->length() + 2, false,
3025 RelocInfo::kNoPosition); 3029 RelocInfo::kNoPosition);
3030
3026 outer_block->AddStatement(init, zone()); 3031 outer_block->AddStatement(init, zone());
3027 3032
3028 const AstRawString* temp_name = ast_value_factory()->dot_for_string(); 3033 const AstRawString* temp_name = ast_value_factory()->dot_for_string();
3029 3034
3030 // For each let variable x: 3035 // For each let variable x:
3031 // make statement: temp_x = x. 3036 // make statement: temp_x = x.
3032 for (int i = 0; i < names->length(); i++) { 3037 for (int i = 0; i < names->length(); i++) {
3033 VariableProxy* proxy = 3038 VariableProxy* proxy =
3034 NewUnresolved(names->at(i), LET, Interface::NewValue()); 3039 NewUnresolved(names->at(i), LET, Interface::NewValue());
3035 Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name); 3040 Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name);
3036 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); 3041 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
3037 Assignment* assignment = factory()->NewAssignment( 3042 Assignment* assignment = factory()->NewAssignment(
3038 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); 3043 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3039 Statement* assignment_statement = factory()->NewExpressionStatement( 3044 Statement* assignment_statement = factory()->NewExpressionStatement(
3040 assignment, RelocInfo::kNoPosition); 3045 assignment, RelocInfo::kNoPosition);
3041 outer_block->AddStatement(assignment_statement, zone()); 3046 outer_block->AddStatement(assignment_statement, zone());
3042 temps.Add(temp, zone()); 3047 temps.Add(temp, zone());
3043 } 3048 }
3044 3049
3045 Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name); 3050 // Make statement: outer: for (;;)
3046 // Make statement: flag = 1. 3051 // Note that we don't actually create the label, or set this loop up as an
3047 { 3052 // explicit break target, instead handing it directly to those nodes that
3048 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); 3053 // need to know about it. This should be safe because we don't run any code
3049 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); 3054 // in this function that looks up break targets.
3050 Assignment* assignment = factory()->NewAssignment( 3055 ForStatement* outer_loop =
3051 Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition); 3056 factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
3052 Statement* assignment_statement = factory()->NewExpressionStatement( 3057 outer_block->AddStatement(outer_loop, zone());
3053 assignment, RelocInfo::kNoPosition);
3054 outer_block->AddStatement(assignment_statement, zone());
3055 }
3056 3058
3057 outer_block->AddStatement(loop, zone());
3058 outer_block->set_scope(for_scope); 3059 outer_block->set_scope(for_scope);
3059 scope_ = inner_scope; 3060 scope_ = inner_scope;
3060 3061
3061 Block* inner_block = factory()->NewBlock(NULL, 2 * names->length() + 3, 3062 Block* inner_block = factory()->NewBlock(NULL, names->length() + 3, false,
3062 false, RelocInfo::kNoPosition); 3063 RelocInfo::kNoPosition);
3063 int pos = scanner()->location().beg_pos; 3064 int pos = scanner()->location().beg_pos;
3064 ZoneList<Variable*> inner_vars(names->length(), zone()); 3065 ZoneList<Variable*> inner_vars(names->length(), zone());
3065 3066
3066 // For each let variable x: 3067 // For each let variable x:
3067 // make statement: let x = temp_x. 3068 // make statement: let x = temp_x.
3068 for (int i = 0; i < names->length(); i++) { 3069 for (int i = 0; i < names->length(); i++) {
3069 VariableProxy* proxy = 3070 VariableProxy* proxy =
3070 NewUnresolved(names->at(i), LET, Interface::NewValue()); 3071 NewUnresolved(names->at(i), LET, Interface::NewValue());
3071 Declaration* declaration = 3072 Declaration* declaration =
3072 factory()->NewVariableDeclaration(proxy, LET, scope_, pos); 3073 factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
3073 Declare(declaration, true, CHECK_OK); 3074 Declare(declaration, true, CHECK_OK);
3074 inner_vars.Add(declaration->proxy()->var(), zone()); 3075 inner_vars.Add(declaration->proxy()->var(), zone());
3075 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); 3076 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3076 Assignment* assignment = factory()->NewAssignment( 3077 Assignment* assignment = factory()->NewAssignment(
3077 Token::INIT_LET, proxy, temp_proxy, pos); 3078 Token::INIT_LET, proxy, temp_proxy, pos);
3078 Statement* assignment_statement = factory()->NewExpressionStatement( 3079 Statement* assignment_statement = factory()->NewExpressionStatement(
3079 assignment, pos); 3080 assignment, pos);
3080 proxy->var()->set_initializer_position(pos); 3081 proxy->var()->set_initializer_position(pos);
3081 inner_block->AddStatement(assignment_statement, zone()); 3082 inner_block->AddStatement(assignment_statement, zone());
3082 } 3083 }
3083 3084
3084 // Make statement: if (flag == 1) { flag = 0; } else { next; }. 3085 Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
3085 if (next) { 3086 // Make statement: flag = 1.
3087 {
3088 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3089 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
arv (Not doing code reviews) 2014/11/13 16:15:43 Maybe we should make these default to RelocInfo::k
3090 Assignment* assignment = factory()->NewAssignment(
3091 Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
3092 Statement* assignment_statement =
3093 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
3094 inner_block->AddStatement(assignment_statement, zone());
3095 }
3096
3097 // Make cond expression for main loop: flag == 1.
3098 Expression* flag_cond = NULL;
3099 {
3100 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3101 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3102 flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
3103 RelocInfo::kNoPosition);
3104 }
3105
3106 // Create chain of expressions "next, temp_x = x, ..., flag = 0"
3107 Statement* compound_next_statement = NULL;
3108 {
3109 Expression* compound_next = next;
3110
3111 // Make the comma-separated list of temp_x = x assignments.
3112 for (int i = 0; i < names->length(); i++) {
3113 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3114 VariableProxy* proxy =
3115 factory()->NewVariableProxy(inner_vars.at(i), RelocInfo::kNoPosition);
3116 Assignment* assignment = factory()->NewAssignment(
3117 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3118 if (compound_next) {
3119 compound_next = factory()->NewBinaryOperation(
3120 Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
3121 } else {
3122 compound_next = assignment;
3123 }
3124 }
3125
3126 // Make expression: flag = 0.
3127 {
3128 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3129 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
3130 Assignment* assignment = factory()->NewAssignment(
3131 Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
3132 compound_next = factory()->NewBinaryOperation(
3133 Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
3134 }
3135
3136 compound_next_statement = factory()->NewExpressionStatement(
3137 compound_next, next ? next->position() : RelocInfo::kNoPosition);
3138 }
3139
3140 // Make statement: if (cond) { body; } else { break aux; }
3141 Statement* if_cond_body_else_stop = NULL;
3142 {
3143 Statement* stop =
3144 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
3145 if_cond_body_else_stop =
3146 factory()->NewIfStatement(cond, body, stop, cond->position());
3147 }
3148
3149 // TODO(adamk): Does the order matter?
3150 loop->Initialize(NULL, flag_cond, compound_next_statement,
3151 if_cond_body_else_stop);
3152 inner_block->AddStatement(loop, zone());
3153
3154 // Make statement: if (flag == 1) { break; }
3155 {
3156 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
3086 Expression* compare = NULL; 3157 Expression* compare = NULL;
3087 // Make compare expresion: flag == 1. 3158 // Make compare expresion: flag == 1.
3088 { 3159 {
3089 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); 3160 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
3090 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); 3161 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
3091 compare = factory()->NewCompareOperation( 3162 compare =
3092 Token::EQ, flag_proxy, const1, pos); 3163 factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
3093 } 3164 }
3094 Statement* clear_flag = NULL; 3165 Statement* stop =
3095 // Make statement: flag = 0. 3166 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
3096 { 3167 Statement* if_flag_break =
3097 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); 3168 factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
3098 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition); 3169 inner_block->AddStatement(if_flag_break, zone());
3099 Assignment* assignment = factory()->NewAssignment(
3100 Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
3101 clear_flag = factory()->NewExpressionStatement(assignment, pos);
3102 }
3103 Statement* clear_flag_or_next = factory()->NewIfStatement(
3104 compare, clear_flag, next, RelocInfo::kNoPosition);
3105 inner_block->AddStatement(clear_flag_or_next, zone());
3106 }
3107
3108
3109 // Make statement: if (cond) { } else { break; }.
3110 if (cond) {
3111 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
3112 BreakableStatement* t = LookupBreakTarget(NULL, CHECK_OK);
3113 Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition);
3114 Statement* if_not_cond_break = factory()->NewIfStatement(
3115 cond, empty, stop, cond->position());
3116 inner_block->AddStatement(if_not_cond_break, zone());
3117 }
3118
3119 inner_block->AddStatement(body, zone());
3120
3121 // For each let variable x:
3122 // make statement: temp_x = x;
3123 for (int i = 0; i < names->length(); i++) {
3124 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
3125 int pos = scanner()->location().end_pos;
3126 VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
3127 Assignment* assignment = factory()->NewAssignment(
3128 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
3129 Statement* assignment_statement = factory()->NewExpressionStatement(
3130 assignment, RelocInfo::kNoPosition);
3131 inner_block->AddStatement(assignment_statement, zone());
3132 } 3170 }
3133 3171
3134 inner_scope->set_end_position(scanner()->location().end_pos); 3172 inner_scope->set_end_position(scanner()->location().end_pos);
3135 inner_block->set_scope(inner_scope); 3173 inner_block->set_scope(inner_scope);
3136 scope_ = for_scope; 3174 scope_ = for_scope;
3137 3175
3138 loop->Initialize(NULL, NULL, NULL, inner_block); 3176 outer_loop->Initialize(NULL, NULL, NULL, inner_block);
3139 return outer_block; 3177 return outer_block;
3140 } 3178 }
3141 3179
3142 3180
3143 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, 3181 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
3144 bool* ok) { 3182 bool* ok) {
3145 // ForStatement :: 3183 // ForStatement ::
3146 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement 3184 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
3147 3185
3148 int stmt_pos = peek_position(); 3186 int stmt_pos = peek_position();
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
3310 inner_scope->set_start_position(scanner()->location().beg_pos); 3348 inner_scope->set_start_position(scanner()->location().beg_pos);
3311 scope_ = inner_scope; 3349 scope_ = inner_scope;
3312 } 3350 }
3313 3351
3314 Expression* cond = NULL; 3352 Expression* cond = NULL;
3315 if (peek() != Token::SEMICOLON) { 3353 if (peek() != Token::SEMICOLON) {
3316 cond = ParseExpression(true, CHECK_OK); 3354 cond = ParseExpression(true, CHECK_OK);
3317 } 3355 }
3318 Expect(Token::SEMICOLON, CHECK_OK); 3356 Expect(Token::SEMICOLON, CHECK_OK);
3319 3357
3320 Statement* next = NULL; 3358 Expression* next = NULL;
3321 if (peek() != Token::RPAREN) { 3359 if (peek() != Token::RPAREN) {
3322 int next_pos = position(); 3360 next = ParseExpression(true, CHECK_OK);
3323 Expression* exp = ParseExpression(true, CHECK_OK);
3324 next = factory()->NewExpressionStatement(exp, next_pos);
3325 } 3361 }
3326 Expect(Token::RPAREN, CHECK_OK); 3362 Expect(Token::RPAREN, CHECK_OK);
3327 3363
3328 Statement* body = ParseStatement(NULL, CHECK_OK); 3364 Statement* body = ParseStatement(NULL, CHECK_OK);
3329 3365
3330 Statement* result = NULL; 3366 Statement* result = NULL;
3331 if (let_bindings.length() > 0) { 3367 if (let_bindings.length() > 0) {
3332 scope_ = for_scope; 3368 scope_ = for_scope;
3333 result = DesugarLetBindingsInForStatement(inner_scope, &let_bindings, loop, 3369 result = DesugarLetBindingsInForStatement(inner_scope, &let_bindings, loop,
3334 init, cond, next, body, CHECK_OK); 3370 init, cond, next, body, CHECK_OK);
3335 scope_ = saved_scope; 3371 scope_ = saved_scope;
3336 for_scope->set_end_position(scanner()->location().end_pos); 3372 for_scope->set_end_position(scanner()->location().end_pos);
3337 } else { 3373 } else {
3374 Statement* next_stmt = NULL;
3375 if (next) {
3376 next_stmt = factory()->NewExpressionStatement(next, next->position());
3377 }
3338 scope_ = saved_scope; 3378 scope_ = saved_scope;
3339 for_scope->set_end_position(scanner()->location().end_pos); 3379 for_scope->set_end_position(scanner()->location().end_pos);
3340 for_scope = for_scope->FinalizeBlockScope(); 3380 for_scope = for_scope->FinalizeBlockScope();
3341 if (for_scope) { 3381 if (for_scope) {
3342 // Rewrite a for statement of the form 3382 // Rewrite a for statement of the form
3343 // for (const x = i; c; n) b 3383 // for (const x = i; c; n) b
3344 // 3384 //
3345 // into 3385 // into
3346 // 3386 //
3347 // { 3387 // {
3348 // const x = i; 3388 // const x = i;
3349 // for (; c; n) b 3389 // for (; c; n) b
3350 // } 3390 // }
3351 DCHECK(init != NULL); 3391 DCHECK(init != NULL);
3352 Block* block = 3392 Block* block =
3353 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); 3393 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
3354 block->AddStatement(init, zone()); 3394 block->AddStatement(init, zone());
3355 block->AddStatement(loop, zone()); 3395 block->AddStatement(loop, zone());
3356 block->set_scope(for_scope); 3396 block->set_scope(for_scope);
3357 loop->Initialize(NULL, cond, next, body); 3397 loop->Initialize(NULL, cond, next_stmt, body);
3358 result = block; 3398 result = block;
3359 } else { 3399 } else {
3360 loop->Initialize(init, cond, next, body); 3400 loop->Initialize(init, cond, next_stmt, body);
3361 result = loop; 3401 result = loop;
3362 } 3402 }
3363 } 3403 }
3364 return result; 3404 return result;
3365 } 3405 }
3366 3406
3367 3407
3368 DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { 3408 DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3369 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser 3409 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3370 // contexts this is used as a statement which invokes the debugger as i a 3410 // contexts this is used as a statement which invokes the debugger as i a
(...skipping 1648 matching lines...) Expand 10 before | Expand all | Expand 10 after
5019 5059
5020 // We cannot internalize on a background thread; a foreground task will take 5060 // We cannot internalize on a background thread; a foreground task will take
5021 // care of calling Parser::Internalize just before compilation. 5061 // care of calling Parser::Internalize just before compilation.
5022 5062
5023 if (compile_options() == ScriptCompiler::kProduceParserCache) { 5063 if (compile_options() == ScriptCompiler::kProduceParserCache) {
5024 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); 5064 if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
5025 log_ = NULL; 5065 log_ = NULL;
5026 } 5066 }
5027 } 5067 }
5028 } } // namespace v8::internal 5068 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | test/mjsunit/harmony/regress/regress-3683.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698