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

Side by Side Diff: src/parser.cc

Issue 1062263002: [parser] report better errors for multiple ForBindings in ForIn/Of loops (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: add tests for zero declarations Created 5 years, 8 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') | 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 2199 matching lines...) Expand 10 before | Expand all | Expand 10 after
2210 } 2210 }
2211 2211
2212 2212
2213 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, 2213 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
2214 ZoneList<const AstRawString*>* names, 2214 ZoneList<const AstRawString*>* names,
2215 bool* ok) { 2215 bool* ok) {
2216 // VariableStatement :: 2216 // VariableStatement ::
2217 // VariableDeclarations ';' 2217 // VariableDeclarations ';'
2218 2218
2219 const AstRawString* ignore; 2219 const AstRawString* ignore;
2220 Block* result = 2220 Block* result = ParseVariableDeclarations(
2221 ParseVariableDeclarations(var_context, names, &ignore, nullptr, CHECK_OK); 2221 var_context, nullptr, names, &ignore, nullptr, nullptr, CHECK_OK);
2222 ExpectSemicolon(CHECK_OK); 2222 ExpectSemicolon(CHECK_OK);
2223 return result; 2223 return result;
2224 } 2224 }
2225 2225
2226 2226
2227 // If the variable declaration declares exactly one non-const 2227 // If the variable declaration declares exactly one non-const
2228 // variable, then *out is set to that variable. In all other cases, 2228 // variable, then *out is set to that variable. In all other cases,
2229 // *out is untouched; in particular, it is the caller's responsibility 2229 // *out is untouched; in particular, it is the caller's responsibility
2230 // to initialize it properly. This mechanism is used for the parsing 2230 // to initialize it properly. This mechanism is used for the parsing
2231 // of 'for-in' loops. 2231 // of 'for-in' loops.
2232 Block* Parser::ParseVariableDeclarations( 2232 Block* Parser::ParseVariableDeclarations(
2233 VariableDeclarationContext var_context, 2233 VariableDeclarationContext var_context, int* num_decl,
2234 ZoneList<const AstRawString*>* names, const AstRawString** out, 2234 ZoneList<const AstRawString*>* names, const AstRawString** out,
2235 Scanner::Location* first_initializer_loc, bool* ok) { 2235 Scanner::Location* first_initializer_loc, Scanner::Location* bindings_loc,
2236 bool* ok) {
2236 // VariableDeclarations :: 2237 // VariableDeclarations ::
2237 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] 2238 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
2238 // 2239 //
2239 // The ES6 Draft Rev3 specifies the following grammar for const declarations 2240 // The ES6 Draft Rev3 specifies the following grammar for const declarations
2240 // 2241 //
2241 // ConstDeclaration :: 2242 // ConstDeclaration ::
2242 // const ConstBinding (',' ConstBinding)* ';' 2243 // const ConstBinding (',' ConstBinding)* ';'
2243 // ConstBinding :: 2244 // ConstBinding ::
2244 // Identifier '=' AssignmentExpression 2245 // Identifier '=' AssignmentExpression
2245 // 2246 //
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
2297 // 2298 //
2298 // We mark the block as initializer block because we don't want the 2299 // We mark the block as initializer block because we don't want the
2299 // rewriter to add a '.result' assignment to such a block (to get compliant 2300 // rewriter to add a '.result' assignment to such a block (to get compliant
2300 // behavior for code such as print(eval('var x = 7')), and for cosmetic 2301 // behavior for code such as print(eval('var x = 7')), and for cosmetic
2301 // reasons when pretty-printing. Also, unless an assignment (initialization) 2302 // reasons when pretty-printing. Also, unless an assignment (initialization)
2302 // is inside an initializer block, it is ignored. 2303 // is inside an initializer block, it is ignored.
2303 // 2304 //
2304 // Create new block with one expected declaration. 2305 // Create new block with one expected declaration.
2305 Block* block = factory()->NewBlock(NULL, 1, true, pos); 2306 Block* block = factory()->NewBlock(NULL, 1, true, pos);
2306 int nvars = 0; // the number of variables declared 2307 int nvars = 0; // the number of variables declared
2308 int bindings_start = peek_position();
2307 const AstRawString* name = NULL; 2309 const AstRawString* name = NULL;
2310 const AstRawString* first_name = NULL;
2308 bool is_for_iteration_variable; 2311 bool is_for_iteration_variable;
2309 do { 2312 do {
2310 if (fni_ != NULL) fni_->Enter(); 2313 if (fni_ != NULL) fni_->Enter();
2311 2314
2312 // Parse variable name. 2315 // Parse variable name.
2313 if (nvars > 0) Consume(Token::COMMA); 2316 if (nvars > 0) Consume(Token::COMMA);
2314 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); 2317 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
2318 if (!first_name) first_name = name;
2315 Scanner::Location variable_loc = scanner()->location(); 2319 Scanner::Location variable_loc = scanner()->location();
2316 if (fni_ != NULL) fni_->PushVariableName(name); 2320 if (fni_ != NULL) fni_->PushVariableName(name);
2317 2321
2318 // Declare variable. 2322 // Declare variable.
2319 // Note that we *always* must treat the initial value via a separate init 2323 // Note that we *always* must treat the initial value via a separate init
2320 // assignment for variables and constants because the value must be assigned 2324 // assignment for variables and constants because the value must be assigned
2321 // when the variable is encountered in the source. But the variable/constant 2325 // when the variable is encountered in the source. But the variable/constant
2322 // is declared (and set to 'undefined') upon entering the function within 2326 // is declared (and set to 'undefined') upon entering the function within
2323 // which the variable or constant is declared. Only function variables have 2327 // which the variable or constant is declared. Only function variables have
2324 // an initial value in the declaration (because they are initialized upon 2328 // an initial value in the declaration (because they are initialized upon
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
2512 Assignment* assignment = 2516 Assignment* assignment =
2513 factory()->NewAssignment(init_op, proxy, value, pos); 2517 factory()->NewAssignment(init_op, proxy, value, pos);
2514 block->AddStatement( 2518 block->AddStatement(
2515 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), 2519 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
2516 zone()); 2520 zone());
2517 } 2521 }
2518 2522
2519 if (fni_ != NULL) fni_->Leave(); 2523 if (fni_ != NULL) fni_->Leave();
2520 } while (peek() == Token::COMMA); 2524 } while (peek() == Token::COMMA);
2521 2525
2522 // If there was a single non-const declaration, return it in the output 2526 if (bindings_loc) {
2523 // parameter for possible use by for/in. 2527 *bindings_loc =
2524 if (nvars == 1 && (!is_const || is_for_iteration_variable)) { 2528 Scanner::Location(bindings_start, scanner()->location().end_pos);
2525 *out = name;
2526 } 2529 }
2527 2530
2531 if (num_decl) *num_decl = nvars;
2532 *out = first_name;
2533
2528 return block; 2534 return block;
2529 } 2535 }
2530 2536
2531 2537
2532 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, 2538 static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
2533 const AstRawString* label) { 2539 const AstRawString* label) {
2534 DCHECK(label != NULL); 2540 DCHECK(label != NULL);
2535 if (labels != NULL) { 2541 if (labels != NULL) {
2536 for (int i = labels->length(); i-- > 0; ) { 2542 for (int i = labels->length(); i-- > 0; ) {
2537 if (labels->at(i) == label) { 2543 if (labels->at(i) == label) {
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after
3361 3367
3362 Expect(Token::FOR, CHECK_OK); 3368 Expect(Token::FOR, CHECK_OK);
3363 Expect(Token::LPAREN, CHECK_OK); 3369 Expect(Token::LPAREN, CHECK_OK);
3364 for_scope->set_start_position(scanner()->location().beg_pos); 3370 for_scope->set_start_position(scanner()->location().beg_pos);
3365 bool is_let_identifier_expression = false; 3371 bool is_let_identifier_expression = false;
3366 if (peek() != Token::SEMICOLON) { 3372 if (peek() != Token::SEMICOLON) {
3367 if (peek() == Token::VAR || 3373 if (peek() == Token::VAR ||
3368 (peek() == Token::CONST && is_sloppy(language_mode()))) { 3374 (peek() == Token::CONST && is_sloppy(language_mode()))) {
3369 const AstRawString* name = NULL; 3375 const AstRawString* name = NULL;
3370 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); 3376 Scanner::Location first_initializer_loc = Scanner::Location::invalid();
3377 Scanner::Location bindings_loc = Scanner::Location::invalid();
3378 int num_decl;
3371 Block* variable_statement = ParseVariableDeclarations( 3379 Block* variable_statement = ParseVariableDeclarations(
3372 kForStatement, nullptr, &name, &first_initializer_loc, CHECK_OK); 3380 kForStatement, &num_decl, nullptr, &name, &first_initializer_loc,
3381 &bindings_loc, CHECK_OK);
3382 bool accept_IN = num_decl >= 1;
marja 2015/04/08 15:11:05 I was reading this code for a while and it's sligh
3373 bool accept_OF = true; 3383 bool accept_OF = true;
3374 ForEachStatement::VisitMode mode; 3384 ForEachStatement::VisitMode mode;
3375 int each_beg_pos = scanner()->location().beg_pos; 3385 int each_beg_pos = scanner()->location().beg_pos;
3376 int each_end_pos = scanner()->location().end_pos; 3386 int each_end_pos = scanner()->location().end_pos;
3377 3387
3378 if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) { 3388 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
3379 if (!*ok) return nullptr; 3389 if (!*ok) return nullptr;
3390 if (num_decl != 1) {
3391 const char* loop_type =
3392 mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
3393 ParserTraits::ReportMessageAt(
3394 bindings_loc, "for_inof_loop_multi_bindings", loop_type);
3395 *ok = false;
3396 return nullptr;
3397 }
3380 if (first_initializer_loc.IsValid() && 3398 if (first_initializer_loc.IsValid() &&
3381 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { 3399 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) {
3382 if (mode == ForEachStatement::ITERATE) { 3400 if (mode == ForEachStatement::ITERATE) {
3383 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); 3401 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer");
3384 } else { 3402 } else {
3385 // TODO(caitp): This should be an error in sloppy mode too. 3403 // TODO(caitp): This should be an error in sloppy mode too.
3386 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); 3404 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer");
3387 } 3405 }
3388 *ok = false; 3406 *ok = false;
3389 return nullptr; 3407 return nullptr;
(...skipping 20 matching lines...) Expand all
3410 // Parsed for-in loop w/ variable/const declaration. 3428 // Parsed for-in loop w/ variable/const declaration.
3411 return result; 3429 return result;
3412 } else { 3430 } else {
3413 init = variable_statement; 3431 init = variable_statement;
3414 } 3432 }
3415 } else if ((peek() == Token::LET || peek() == Token::CONST) && 3433 } else if ((peek() == Token::LET || peek() == Token::CONST) &&
3416 is_strict(language_mode())) { 3434 is_strict(language_mode())) {
3417 is_const = peek() == Token::CONST; 3435 is_const = peek() == Token::CONST;
3418 const AstRawString* name = NULL; 3436 const AstRawString* name = NULL;
3419 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); 3437 Scanner::Location first_initializer_loc = Scanner::Location::invalid();
3420 Block* variable_statement = 3438 Scanner::Location bindings_loc = Scanner::Location::invalid();
3421 ParseVariableDeclarations(kForStatement, &lexical_bindings, &name, 3439 int num_decl;
3422 &first_initializer_loc, CHECK_OK); 3440 Block* variable_statement = ParseVariableDeclarations(
3423 bool accept_IN = name != NULL; 3441 kForStatement, &num_decl, &lexical_bindings, &name,
3442 &first_initializer_loc, &bindings_loc, CHECK_OK);
3443 bool accept_IN = num_decl >= 1;
3424 bool accept_OF = true; 3444 bool accept_OF = true;
3425 ForEachStatement::VisitMode mode; 3445 ForEachStatement::VisitMode mode;
3426 int each_beg_pos = scanner()->location().beg_pos; 3446 int each_beg_pos = scanner()->location().beg_pos;
3427 int each_end_pos = scanner()->location().end_pos; 3447 int each_end_pos = scanner()->location().end_pos;
3428 3448
3429 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { 3449 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
3430 if (!*ok) return nullptr; 3450 if (!*ok) return nullptr;
3451 if (num_decl != 1) {
3452 const char* loop_type =
3453 mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
3454 ParserTraits::ReportMessageAt(
3455 bindings_loc, "for_inof_loop_multi_bindings", loop_type);
3456 *ok = false;
3457 return nullptr;
3458 }
3431 if (first_initializer_loc.IsValid() && 3459 if (first_initializer_loc.IsValid() &&
3432 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { 3460 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) {
3433 if (mode == ForEachStatement::ITERATE) { 3461 if (mode == ForEachStatement::ITERATE) {
3434 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); 3462 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer");
3435 } else { 3463 } else {
3436 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); 3464 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer");
3437 } 3465 }
3438 *ok = false; 3466 *ok = false;
3439 return nullptr; 3467 return nullptr;
3440 } 3468 }
(...skipping 2139 matching lines...) Expand 10 before | Expand all | Expand 10 after
5580 } else { 5608 } else {
5581 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); 5609 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data());
5582 running_hash = StringHasher::ComputeRunningHash(running_hash, data, 5610 running_hash = StringHasher::ComputeRunningHash(running_hash, data,
5583 raw_string->length()); 5611 raw_string->length());
5584 } 5612 }
5585 } 5613 }
5586 5614
5587 return running_hash; 5615 return running_hash;
5588 } 5616 }
5589 } } // namespace v8::internal 5617 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698