OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 <cmath> | 5 #include <cmath> |
6 | 6 |
7 #include "src/allocation.h" | 7 #include "src/allocation.h" |
8 #include "src/base/logging.h" | 8 #include "src/base/logging.h" |
9 #include "src/conversions-inl.h" | 9 #include "src/conversions-inl.h" |
10 #include "src/conversions.h" | 10 #include "src/conversions.h" |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 return final; | 416 return final; |
417 } | 417 } |
418 | 418 |
419 | 419 |
420 PreParser::Statement PreParser::ParseVariableStatement( | 420 PreParser::Statement PreParser::ParseVariableStatement( |
421 VariableDeclarationContext var_context, | 421 VariableDeclarationContext var_context, |
422 bool* ok) { | 422 bool* ok) { |
423 // VariableStatement :: | 423 // VariableStatement :: |
424 // VariableDeclarations ';' | 424 // VariableDeclarations ';' |
425 | 425 |
426 Statement result = ParseVariableDeclarations( | 426 Statement result = |
427 var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK); | 427 ParseVariableDeclarations(var_context, nullptr, nullptr, CHECK_OK); |
428 ExpectSemicolon(CHECK_OK); | 428 ExpectSemicolon(CHECK_OK); |
429 return result; | 429 return result; |
430 } | 430 } |
431 | 431 |
432 | |
433 // If the variable declaration declares exactly one non-const | |
434 // variable, then *var is set to that variable. In all other cases, | |
435 // *var is untouched; in particular, it is the caller's responsibility | |
436 // to initialize it properly. This mechanism is also used for the parsing | |
437 // of 'for-in' loops. | |
438 PreParser::Statement PreParser::ParseVariableDeclarations( | |
439 VariableDeclarationContext var_context, int* num_decl, bool* is_lexical, | |
440 bool* is_binding_pattern, Scanner::Location* first_initializer_loc, | |
441 Scanner::Location* bindings_loc, bool* ok) { | |
442 // VariableDeclarations :: | |
443 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | |
444 // | |
445 // The ES6 Draft Rev3 specifies the following grammar for const declarations | |
446 // | |
447 // ConstDeclaration :: | |
448 // const ConstBinding (',' ConstBinding)* ';' | |
449 // ConstBinding :: | |
450 // Identifier '=' AssignmentExpression | |
451 // | |
452 // TODO(ES6): | |
453 // ConstBinding :: | |
454 // BindingPattern '=' AssignmentExpression | |
455 bool require_initializer = false; | |
456 bool lexical = false; | |
457 bool is_pattern = false; | |
458 if (peek() == Token::VAR) { | |
459 Consume(Token::VAR); | |
460 } else if (peek() == Token::CONST) { | |
461 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads: | |
462 // | |
463 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';' | |
464 // | |
465 // * It is a Syntax Error if the code that matches this production is not | |
466 // contained in extended code. | |
467 // | |
468 // However disallowing const in sloppy mode will break compatibility with | |
469 // existing pages. Therefore we keep allowing const with the old | |
470 // non-harmony semantics in sloppy mode. | |
471 Consume(Token::CONST); | |
472 DCHECK(var_context != kStatement); | |
473 require_initializer = true; | |
474 lexical = true; | |
475 } else if (peek() == Token::LET) { | |
476 Consume(Token::LET); | |
477 DCHECK(var_context != kStatement); | |
478 lexical = true; | |
479 } else { | |
480 *ok = false; | |
481 return Statement::Default(); | |
482 } | |
483 | |
484 // The scope of a var/const declared variable anywhere inside a function | |
485 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope | |
486 // of a let declared variable is the scope of the immediately enclosing | |
487 // block. | |
488 int nvars = 0; // the number of variables declared | |
489 int bindings_start = peek_position(); | |
490 do { | |
491 // Parse binding pattern. | |
492 if (nvars > 0) Consume(Token::COMMA); | |
493 int decl_pos = peek_position(); | |
494 PreParserExpression pattern = PreParserExpression::Default(); | |
495 { | |
496 ExpressionClassifier pattern_classifier(this); | |
497 pattern = ParsePrimaryExpression(CHECK_OK); | |
498 | |
499 ValidateBindingPattern(CHECK_OK); | |
500 if (lexical) ValidateLetPattern(CHECK_OK); | |
501 } | |
502 | |
503 is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral(); | |
504 | |
505 Scanner::Location variable_loc = scanner()->location(); | |
506 nvars++; | |
507 if (Check(Token::ASSIGN)) { | |
508 ExpressionClassifier classifier(this); | |
509 ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); | |
510 ValidateExpression(CHECK_OK); | |
511 | |
512 variable_loc.end_pos = scanner()->location().end_pos; | |
513 if (first_initializer_loc && !first_initializer_loc->IsValid()) { | |
514 *first_initializer_loc = variable_loc; | |
515 } | |
516 } else if ((require_initializer || is_pattern) && | |
517 (var_context != kForStatement || !PeekInOrOf())) { | |
518 ReportMessageAt( | |
519 Scanner::Location(decl_pos, scanner()->location().end_pos), | |
520 MessageTemplate::kDeclarationMissingInitializer, | |
521 is_pattern ? "destructuring" : "const"); | |
522 *ok = false; | |
523 return Statement::Default(); | |
524 } | |
525 } while (peek() == Token::COMMA); | |
526 | |
527 if (bindings_loc) { | |
528 *bindings_loc = | |
529 Scanner::Location(bindings_start, scanner()->location().end_pos); | |
530 } | |
531 | |
532 if (num_decl != nullptr) *num_decl = nvars; | |
533 if (is_lexical != nullptr) *is_lexical = lexical; | |
534 if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern; | |
535 return Statement::Default(); | |
536 } | |
537 | |
538 PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { | 432 PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { |
539 Consume(Token::FUNCTION); | 433 Consume(Token::FUNCTION); |
540 int pos = position(); | 434 int pos = position(); |
541 ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; | 435 ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; |
542 if (Check(Token::MUL)) { | 436 if (Check(Token::MUL)) { |
543 flags |= ParseFunctionFlags::kIsGenerator; | 437 flags |= ParseFunctionFlags::kIsGenerator; |
544 if (allow_harmony_restrictive_declarations()) { | 438 if (allow_harmony_restrictive_declarations()) { |
545 ReportMessageAt(scanner()->location(), | 439 ReportMessageAt(scanner()->location(), |
546 MessageTemplate::kGeneratorInLegacyContext); | 440 MessageTemplate::kGeneratorInLegacyContext); |
547 *ok = false; | 441 *ok = false; |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 // Create an in-between scope for let-bound iteration variables. | 685 // Create an in-between scope for let-bound iteration variables. |
792 bool has_lexical = false; | 686 bool has_lexical = false; |
793 | 687 |
794 BlockState block_state(&scope_state_); | 688 BlockState block_state(&scope_state_); |
795 Expect(Token::FOR, CHECK_OK); | 689 Expect(Token::FOR, CHECK_OK); |
796 Expect(Token::LPAREN, CHECK_OK); | 690 Expect(Token::LPAREN, CHECK_OK); |
797 if (peek() != Token::SEMICOLON) { | 691 if (peek() != Token::SEMICOLON) { |
798 ForEachStatement::VisitMode mode; | 692 ForEachStatement::VisitMode mode; |
799 if (peek() == Token::VAR || peek() == Token::CONST || | 693 if (peek() == Token::VAR || peek() == Token::CONST || |
800 (peek() == Token::LET && IsNextLetKeyword())) { | 694 (peek() == Token::LET && IsNextLetKeyword())) { |
801 int decl_count; | 695 DeclarationParsingResult parsing_result; |
802 bool is_lexical; | 696 |
803 bool is_binding_pattern; | 697 ParseVariableDeclarations(kForStatement, &parsing_result, nullptr, |
804 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); | 698 CHECK_OK); |
805 Scanner::Location bindings_loc = Scanner::Location::invalid(); | 699 if (parsing_result.descriptor.mode == CONST || |
806 ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical, | 700 parsing_result.descriptor.mode == LET) { |
807 &is_binding_pattern, &first_initializer_loc, | 701 has_lexical = true; |
808 &bindings_loc, CHECK_OK); | 702 } |
809 if (is_lexical) has_lexical = true; | |
810 if (CheckInOrOf(&mode)) { | 703 if (CheckInOrOf(&mode)) { |
811 if (decl_count != 1) { | 704 if (!*ok) return Statement::Default(); |
812 ReportMessageAt(bindings_loc, | 705 if (parsing_result.declarations.length() != 1) { |
| 706 ReportMessageAt(parsing_result.bindings_loc, |
813 MessageTemplate::kForInOfLoopMultiBindings, | 707 MessageTemplate::kForInOfLoopMultiBindings, |
814 ForEachStatement::VisitModeString(mode)); | 708 ForEachStatement::VisitModeString(mode)); |
815 *ok = false; | 709 *ok = false; |
816 return Statement::Default(); | 710 return Statement::Default(); |
817 } | 711 } |
818 if (first_initializer_loc.IsValid() && | 712 bool is_binding_pattern = |
| 713 parsing_result.declarations[0].pattern.IsObjectLiteral() || |
| 714 parsing_result.declarations[0].pattern.IsArrayLiteral(); |
| 715 if (parsing_result.first_initializer_loc.IsValid() && |
819 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE || | 716 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE || |
820 is_lexical || is_binding_pattern || allow_harmony_for_in())) { | 717 has_lexical || is_binding_pattern || allow_harmony_for_in())) { |
821 // Only increment the use count if we would have let this through | 718 // Only increment the use count if we would have let this through |
822 // without the flag. | 719 // without the flag. |
823 if (use_counts_ != nullptr && allow_harmony_for_in()) { | 720 if (use_counts_ != nullptr && allow_harmony_for_in()) { |
824 ++use_counts_[v8::Isolate::kForInInitializer]; | 721 ++use_counts_[v8::Isolate::kForInInitializer]; |
825 } | 722 } |
826 ReportMessageAt(first_initializer_loc, | 723 ReportMessageAt(parsing_result.first_initializer_loc, |
827 MessageTemplate::kForInOfLoopInitializer, | 724 MessageTemplate::kForInOfLoopInitializer, |
828 ForEachStatement::VisitModeString(mode)); | 725 ForEachStatement::VisitModeString(mode)); |
829 *ok = false; | 726 *ok = false; |
830 return Statement::Default(); | 727 return Statement::Default(); |
831 } | 728 } |
832 | 729 |
833 if (mode == ForEachStatement::ITERATE) { | 730 if (mode == ForEachStatement::ITERATE) { |
834 ExpressionClassifier classifier(this); | 731 ExpressionClassifier classifier(this); |
835 ParseAssignmentExpression(true, CHECK_OK); | 732 ParseAssignmentExpression(true, CHECK_OK); |
836 RewriteNonPattern(CHECK_OK); | 733 RewriteNonPattern(CHECK_OK); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1219 | 1116 |
1220 body->Add(PreParserStatement::ExpressionStatement(return_value), zone()); | 1117 body->Add(PreParserStatement::ExpressionStatement(return_value), zone()); |
1221 } | 1118 } |
1222 | 1119 |
1223 #undef CHECK_OK | 1120 #undef CHECK_OK |
1224 #undef CHECK_OK_CUSTOM | 1121 #undef CHECK_OK_CUSTOM |
1225 | 1122 |
1226 | 1123 |
1227 } // namespace internal | 1124 } // namespace internal |
1228 } // namespace v8 | 1125 } // namespace v8 |
OLD | NEW |