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

Side by Side Diff: src/parser.cc

Issue 1033823002: [es6] emit error when for-in loop declarations are initialized in strict mode (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Update error message, add fixes for let decls Created 5 years, 9 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
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | src/preparser.cc » ('J')
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 2200 matching lines...) Expand 10 before | Expand all | Expand 10 after
2211 } 2211 }
2212 2212
2213 2213
2214 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, 2214 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
2215 ZoneList<const AstRawString*>* names, 2215 ZoneList<const AstRawString*>* names,
2216 bool* ok) { 2216 bool* ok) {
2217 // VariableStatement :: 2217 // VariableStatement ::
2218 // VariableDeclarations ';' 2218 // VariableDeclarations ';'
2219 2219
2220 const AstRawString* ignore; 2220 const AstRawString* ignore;
2221 Block* result = 2221 Block* result = ParseVariableDeclarations(var_context, nullptr, names,
2222 ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK); 2222 &ignore, nullptr, CHECK_OK);
2223 ExpectSemicolon(CHECK_OK); 2223 ExpectSemicolon(CHECK_OK);
2224 return result; 2224 return result;
2225 } 2225 }
2226 2226
2227 2227
2228 // If the variable declaration declares exactly one non-const 2228 // If the variable declaration declares exactly one non-const
2229 // variable, then *out is set to that variable. In all other cases, 2229 // variable, then *out is set to that variable. In all other cases,
2230 // *out is untouched; in particular, it is the caller's responsibility 2230 // *out is untouched; in particular, it is the caller's responsibility
2231 // to initialize it properly. This mechanism is used for the parsing 2231 // to initialize it properly. This mechanism is used for the parsing
2232 // of 'for-in' loops. 2232 // of 'for-in' loops.
2233 Block* Parser::ParseVariableDeclarations( 2233 Block* Parser::ParseVariableDeclarations(
2234 VariableDeclarationContext var_context, 2234 VariableDeclarationContext var_context,
2235 VariableDeclarationProperties* decl_props, 2235 VariableDeclarationProperties* decl_props,
2236 ZoneList<const AstRawString*>* names, 2236 ZoneList<const AstRawString*>* names, const AstRawString** out,
2237 const AstRawString** out, 2237 Scanner::Location* first_initializer_loc, bool* ok) {
2238 bool* ok) {
2239 // VariableDeclarations :: 2238 // VariableDeclarations ::
2240 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] 2239 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
2241 // 2240 //
2242 // The ES6 Draft Rev3 specifies the following grammar for const declarations 2241 // The ES6 Draft Rev3 specifies the following grammar for const declarations
2243 // 2242 //
2244 // ConstDeclaration :: 2243 // ConstDeclaration ::
2245 // const ConstBinding (',' ConstBinding)* ';' 2244 // const ConstBinding (',' ConstBinding)* ';'
2246 // ConstBinding :: 2245 // ConstBinding ::
2247 // Identifier '=' AssignmentExpression 2246 // Identifier '=' AssignmentExpression
2248 // 2247 //
2249 // TODO(ES6): 2248 // TODO(ES6):
2250 // ConstBinding :: 2249 // ConstBinding ::
2251 // BindingPattern '=' AssignmentExpression 2250 // BindingPattern '=' AssignmentExpression
2252
2253 int pos = peek_position(); 2251 int pos = peek_position();
2254 VariableMode mode = VAR; 2252 VariableMode mode = VAR;
2255 // True if the binding needs initialization. 'let' and 'const' declared 2253 // True if the binding needs initialization. 'let' and 'const' declared
2256 // bindings are created uninitialized by their declaration nodes and 2254 // bindings are created uninitialized by their declaration nodes and
2257 // need initialization. 'var' declared bindings are always initialized 2255 // need initialization. 'var' declared bindings are always initialized
2258 // immediately by their declaration nodes. 2256 // immediately by their declaration nodes.
2259 bool needs_init = false; 2257 bool needs_init = false;
2260 bool is_const = false; 2258 bool is_const = false;
2261 Token::Value init_op = Token::INIT_VAR; 2259 Token::Value init_op = Token::INIT_VAR;
2262 if (peek() == Token::VAR) { 2260 if (peek() == Token::VAR) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2307 Block* block = factory()->NewBlock(NULL, 1, true, pos); 2305 Block* block = factory()->NewBlock(NULL, 1, true, pos);
2308 int nvars = 0; // the number of variables declared 2306 int nvars = 0; // the number of variables declared
2309 const AstRawString* name = NULL; 2307 const AstRawString* name = NULL;
2310 bool is_for_iteration_variable; 2308 bool is_for_iteration_variable;
2311 do { 2309 do {
2312 if (fni_ != NULL) fni_->Enter(); 2310 if (fni_ != NULL) fni_->Enter();
2313 2311
2314 // Parse variable name. 2312 // Parse variable name.
2315 if (nvars > 0) Consume(Token::COMMA); 2313 if (nvars > 0) Consume(Token::COMMA);
2316 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); 2314 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
2315 Scanner::Location variable_loc = scanner()->location();
2317 if (fni_ != NULL) fni_->PushVariableName(name); 2316 if (fni_ != NULL) fni_->PushVariableName(name);
2318 2317
2319 // Declare variable. 2318 // Declare variable.
2320 // Note that we *always* must treat the initial value via a separate init 2319 // Note that we *always* must treat the initial value via a separate init
2321 // assignment for variables and constants because the value must be assigned 2320 // assignment for variables and constants because the value must be assigned
2322 // when the variable is encountered in the source. But the variable/constant 2321 // when the variable is encountered in the source. But the variable/constant
2323 // is declared (and set to 'undefined') upon entering the function within 2322 // is declared (and set to 'undefined') upon entering the function within
2324 // which the variable or constant is declared. Only function variables have 2323 // which the variable or constant is declared. Only function variables have
2325 // an initial value in the declaration (because they are initialized upon 2324 // an initial value in the declaration (because they are initialized upon
2326 // entering the function). 2325 // entering the function).
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
2381 2380
2382 Scope* initialization_scope = is_const ? declaration_scope : scope_; 2381 Scope* initialization_scope = is_const ? declaration_scope : scope_;
2383 Expression* value = NULL; 2382 Expression* value = NULL;
2384 int pos = -1; 2383 int pos = -1;
2385 // Harmony consts have non-optional initializers. 2384 // Harmony consts have non-optional initializers.
2386 if (peek() == Token::ASSIGN || 2385 if (peek() == Token::ASSIGN ||
2387 (mode == CONST && !is_for_iteration_variable)) { 2386 (mode == CONST && !is_for_iteration_variable)) {
2388 Expect(Token::ASSIGN, CHECK_OK); 2387 Expect(Token::ASSIGN, CHECK_OK);
2389 pos = position(); 2388 pos = position();
2390 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); 2389 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
2390 variable_loc.end_pos = scanner()->location().end_pos;
2391
2392 if (first_initializer_loc && !first_initializer_loc->IsValid()) {
2393 *first_initializer_loc = variable_loc;
2394 }
2395
2391 // Don't infer if it is "a = function(){...}();"-like expression. 2396 // Don't infer if it is "a = function(){...}();"-like expression.
2392 if (fni_ != NULL && 2397 if (fni_ != NULL &&
2393 value->AsCall() == NULL && 2398 value->AsCall() == NULL &&
2394 value->AsCallNew() == NULL) { 2399 value->AsCallNew() == NULL) {
2395 fni_->Infer(); 2400 fni_->Infer();
2396 } else { 2401 } else {
2397 fni_->RemoveLastFunction(); 2402 fni_->RemoveLastFunction();
2398 } 2403 }
2399 if (decl_props != NULL) *decl_props = kHasInitializers; 2404 if (decl_props != NULL) *decl_props = kHasInitializers;
2400 // End position of the initializer is after the assignment expression. 2405 // End position of the initializer is after the assignment expression.
(...skipping 956 matching lines...) Expand 10 before | Expand all | Expand 10 after
3357 3362
3358 Expect(Token::FOR, CHECK_OK); 3363 Expect(Token::FOR, CHECK_OK);
3359 Expect(Token::LPAREN, CHECK_OK); 3364 Expect(Token::LPAREN, CHECK_OK);
3360 for_scope->set_start_position(scanner()->location().beg_pos); 3365 for_scope->set_start_position(scanner()->location().beg_pos);
3361 bool is_let_identifier_expression = false; 3366 bool is_let_identifier_expression = false;
3362 if (peek() != Token::SEMICOLON) { 3367 if (peek() != Token::SEMICOLON) {
3363 if (peek() == Token::VAR || 3368 if (peek() == Token::VAR ||
3364 (peek() == Token::CONST && is_sloppy(language_mode()))) { 3369 (peek() == Token::CONST && is_sloppy(language_mode()))) {
3365 const AstRawString* name = NULL; 3370 const AstRawString* name = NULL;
3366 VariableDeclarationProperties decl_props = kHasNoInitializers; 3371 VariableDeclarationProperties decl_props = kHasNoInitializers;
3372 Scanner::Location first_initializer_loc = Scanner::Location::invalid();
3367 Block* variable_statement = 3373 Block* variable_statement =
3368 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, 3374 ParseVariableDeclarations(kForStatement, &decl_props, nullptr, &name,
3369 CHECK_OK); 3375 &first_initializer_loc, CHECK_OK);
3370 bool accept_OF = decl_props == kHasNoInitializers; 3376 bool accept_OF = true;
3371 ForEachStatement::VisitMode mode; 3377 ForEachStatement::VisitMode mode;
3372 int each_beg_pos = scanner()->location().beg_pos; 3378 int each_beg_pos = scanner()->location().beg_pos;
3373 int each_end_pos = scanner()->location().end_pos; 3379 int each_end_pos = scanner()->location().end_pos;
3374 3380
3375 if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) { 3381 if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
3376 if (!*ok) return nullptr; 3382 if (!*ok) return nullptr;
3383 if (first_initializer_loc.IsValid() &&
3384 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) {
arv (Not doing code reviews) 2015/03/31 14:39:15 Add a TODO that this should be an error in sloppy
3385 if (mode == ForEachStatement::ITERATE) {
3386 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer");
3387 } else {
3388 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer");
3389 }
3390 *ok = false;
3391 return nullptr;
3392 }
3377 ForEachStatement* loop = 3393 ForEachStatement* loop =
3378 factory()->NewForEachStatement(mode, labels, stmt_pos); 3394 factory()->NewForEachStatement(mode, labels, stmt_pos);
3379 Target target(&this->target_stack_, loop); 3395 Target target(&this->target_stack_, loop);
3380 3396
3381 Expression* enumerable = ParseExpression(true, CHECK_OK); 3397 Expression* enumerable = ParseExpression(true, CHECK_OK);
3382 Expect(Token::RPAREN, CHECK_OK); 3398 Expect(Token::RPAREN, CHECK_OK);
3383 3399
3384 VariableProxy* each = 3400 VariableProxy* each =
3385 scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos); 3401 scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos);
3386 Statement* body = ParseSubStatement(NULL, CHECK_OK); 3402 Statement* body = ParseSubStatement(NULL, CHECK_OK);
3387 InitializeForEachStatement(loop, each, enumerable, body); 3403 InitializeForEachStatement(loop, each, enumerable, body);
3388 Block* result = 3404 Block* result =
3389 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); 3405 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
3390 result->AddStatement(variable_statement, zone()); 3406 result->AddStatement(variable_statement, zone());
3391 result->AddStatement(loop, zone()); 3407 result->AddStatement(loop, zone());
3392 scope_ = saved_scope; 3408 scope_ = saved_scope;
3393 for_scope->set_end_position(scanner()->location().end_pos); 3409 for_scope->set_end_position(scanner()->location().end_pos);
3394 for_scope = for_scope->FinalizeBlockScope(); 3410 for_scope = for_scope->FinalizeBlockScope();
3395 DCHECK(for_scope == NULL); 3411 DCHECK(for_scope == NULL);
3396 // Parsed for-in loop w/ variable/const declaration. 3412 // Parsed for-in loop w/ variable/const declaration.
3397 return result; 3413 return result;
3398 } else { 3414 } else {
3399 init = variable_statement; 3415 init = variable_statement;
3400 } 3416 }
3401 } else if ((peek() == Token::LET || peek() == Token::CONST) && 3417 } else if ((peek() == Token::LET || peek() == Token::CONST) &&
3402 is_strict(language_mode())) { 3418 is_strict(language_mode())) {
3403 is_const = peek() == Token::CONST; 3419 is_const = peek() == Token::CONST;
3404 const AstRawString* name = NULL; 3420 const AstRawString* name = NULL;
3405 VariableDeclarationProperties decl_props = kHasNoInitializers; 3421 VariableDeclarationProperties decl_props = kHasNoInitializers;
3406 Block* variable_statement = 3422 Scanner::Location first_initializer_loc = Scanner::Location::invalid();
3407 ParseVariableDeclarations(kForStatement, &decl_props, 3423 Block* variable_statement = ParseVariableDeclarations(
3408 &lexical_bindings, &name, CHECK_OK); 3424 kForStatement, &decl_props, &lexical_bindings, &name,
3409 bool accept_IN = name != NULL && decl_props != kHasInitializers; 3425 &first_initializer_loc, CHECK_OK);
3410 bool accept_OF = decl_props == kHasNoInitializers; 3426 bool accept_IN = name != NULL;
3427 bool accept_OF = true;
3411 ForEachStatement::VisitMode mode; 3428 ForEachStatement::VisitMode mode;
3412 int each_beg_pos = scanner()->location().beg_pos; 3429 int each_beg_pos = scanner()->location().beg_pos;
3413 int each_end_pos = scanner()->location().end_pos; 3430 int each_end_pos = scanner()->location().end_pos;
3414 3431
3415 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { 3432 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
3416 if (!*ok) return nullptr; 3433 if (!*ok) return nullptr;
3417 3434 if (first_initializer_loc.IsValid() &&
3435 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) {
3436 if (mode == ForEachStatement::ITERATE) {
3437 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer");
3438 } else {
3439 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer");
3440 }
3441 *ok = false;
3442 return nullptr;
3443 }
3418 // Rewrite a for-in statement of the form 3444 // Rewrite a for-in statement of the form
3419 // 3445 //
3420 // for (let/const x in e) b 3446 // for (let/const x in e) b
3421 // 3447 //
3422 // into 3448 // into
3423 // 3449 //
3424 // <let x' be a temporary variable> 3450 // <let x' be a temporary variable>
3425 // for (x' in e) { 3451 // for (x' in e) {
3426 // let/const x; 3452 // let/const x;
3427 // x = x'; 3453 // x = x';
(...skipping 2131 matching lines...) Expand 10 before | Expand all | Expand 10 after
5559 } else { 5585 } else {
5560 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); 5586 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data());
5561 running_hash = StringHasher::ComputeRunningHash(running_hash, data, 5587 running_hash = StringHasher::ComputeRunningHash(running_hash, data,
5562 raw_string->length()); 5588 raw_string->length());
5563 } 5589 }
5564 } 5590 }
5565 5591
5566 return running_hash; 5592 return running_hash;
5567 } 5593 }
5568 } } // namespace v8::internal 5594 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | src/preparser.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698