| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 4aaa9a134d6b0cb89585c3d23667aeb513c6429d..62bc3d5229075c8be705e30c9d807df5f060c3da 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -549,6 +549,7 @@ Parser::Parser(CompilationInfo* info)
|
| allow_natives_syntax_(false),
|
| allow_lazy_(false),
|
| allow_generators_(false),
|
| + allow_for_of_(false),
|
| stack_overflow_(false),
|
| parenthesized_function_(false),
|
| zone_(info->zone()),
|
| @@ -560,6 +561,7 @@ Parser::Parser(CompilationInfo* info)
|
| set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
|
| set_allow_lazy(false); // Must be explicitly enabled.
|
| set_allow_generators(FLAG_harmony_generators);
|
| + set_allow_for_of(FLAG_harmony_iteration);
|
| }
|
|
|
|
|
| @@ -1028,7 +1030,7 @@ Module* Parser::ParseModule(bool* ok) {
|
| }
|
|
|
| default: {
|
| - ExpectContextualKeyword("at", CHECK_OK);
|
| + ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
|
| Module* result = ParseModuleUrl(CHECK_OK);
|
| ExpectSemicolon(CHECK_OK);
|
| return result;
|
| @@ -1200,7 +1202,7 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
|
| names.Add(name, zone());
|
| }
|
|
|
| - ExpectContextualKeyword("from", CHECK_OK);
|
| + ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
|
| Module* module = ParseModuleSpecifier(CHECK_OK);
|
| ExpectSemicolon(CHECK_OK);
|
|
|
| @@ -2622,6 +2624,18 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
|
| }
|
|
|
|
|
| +bool Parser::CheckInOrOf(ForEachStatement::VisitMode* visit_mode) {
|
| + if (Check(Token::IN)) {
|
| + *visit_mode = ForEachStatement::ENUMERATE;
|
| + return true;
|
| + } else if (allow_for_of() && CheckContextualKeyword(CStrVector("of"))) {
|
| + *visit_mode = ForEachStatement::ITERATE;
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| // ForStatement ::
|
| // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
|
| @@ -2642,14 +2656,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Handle<String> name;
|
| Block* variable_statement =
|
| ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
|
| + ForEachStatement::VisitMode mode;
|
|
|
| - if (peek() == Token::IN && !name.is_null()) {
|
| + if (!name.is_null() && CheckInOrOf(&mode)) {
|
| Interface* interface =
|
| is_const ? Interface::NewConst() : Interface::NewValue();
|
| - ForInStatement* loop = factory()->NewForInStatement(labels);
|
| + ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
|
| Target target(&this->target_stack_, loop);
|
|
|
| - Expect(Token::IN, CHECK_OK);
|
| Expression* enumerable = ParseExpression(true, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| @@ -2676,7 +2690,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
|
| CHECK_OK);
|
| bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
|
| - if (peek() == Token::IN && accept_IN) {
|
| + ForEachStatement::VisitMode mode;
|
| +
|
| + if (accept_IN && CheckInOrOf(&mode)) {
|
| // Rewrite a for-in statement of the form
|
| //
|
| // for (let x in e) b
|
| @@ -2698,11 +2714,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Handle<String> tempname = heap_factory->InternalizeString(tempstr);
|
| Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
|
| VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
|
| - ForInStatement* loop = factory()->NewForInStatement(labels);
|
| + ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
|
| Target target(&this->target_stack_, loop);
|
|
|
| // The expression does not see the loop variable.
|
| - Expect(Token::IN, CHECK_OK);
|
| top_scope_ = saved_scope;
|
| Expression* enumerable = ParseExpression(true, CHECK_OK);
|
| top_scope_ = for_scope;
|
| @@ -2732,7 +2747,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| }
|
| } else {
|
| Expression* expression = ParseExpression(false, CHECK_OK);
|
| - if (peek() == Token::IN) {
|
| + ForEachStatement::VisitMode mode;
|
| +
|
| + if (CheckInOrOf(&mode)) {
|
| // Signal a reference error if the expression is an invalid
|
| // left-hand side expression. We could report this as a syntax
|
| // error here but for compatibility with JSC we choose to report
|
| @@ -2742,15 +2759,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| isolate()->factory()->invalid_lhs_in_for_in_string();
|
| expression = NewThrowReferenceError(message);
|
| }
|
| - ForInStatement* loop = factory()->NewForInStatement(labels);
|
| + ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
|
| Target target(&this->target_stack_, loop);
|
|
|
| - Expect(Token::IN, CHECK_OK);
|
| Expression* enumerable = ParseExpression(true, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| Statement* body = ParseStatement(NULL, CHECK_OK);
|
| - if (loop) loop->Initialize(expression, enumerable, body);
|
| + loop->Initialize(expression, enumerable, body);
|
| top_scope_ = saved_scope;
|
| for_scope->set_end_position(scanner().location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| @@ -2804,10 +2820,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| result->AddStatement(init, zone());
|
| result->AddStatement(loop, zone());
|
| result->set_scope(for_scope);
|
| - if (loop) loop->Initialize(NULL, cond, next, body);
|
| + loop->Initialize(NULL, cond, next, body);
|
| return result;
|
| } else {
|
| - if (loop) loop->Initialize(init, cond, next, body);
|
| + loop->Initialize(init, cond, next, body);
|
| return loop;
|
| }
|
| }
|
| @@ -4507,6 +4523,7 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
|
| reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
|
| reusable_preparser_->set_allow_lazy(true);
|
| reusable_preparser_->set_allow_generators(allow_generators());
|
| + reusable_preparser_->set_allow_for_of(allow_for_of());
|
| }
|
| preparser::PreParser::PreParseResult result =
|
| reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
|
| @@ -4604,6 +4621,16 @@ bool Parser::Check(Token::Value token) {
|
| }
|
|
|
|
|
| +bool Parser::CheckContextualKeyword(Vector<const char> keyword) {
|
| + if (peek() == Token::IDENTIFIER &&
|
| + scanner().is_next_contextual_keyword(keyword)) {
|
| + Consume(Token::IDENTIFIER);
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| void Parser::ExpectSemicolon(bool* ok) {
|
| // Check for automatic semicolon insertion according to
|
| // the rules given in ECMA-262, section 7.9, page 21.
|
| @@ -4621,12 +4648,10 @@ void Parser::ExpectSemicolon(bool* ok) {
|
| }
|
|
|
|
|
| -void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
|
| +void Parser::ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
|
| Expect(Token::IDENTIFIER, ok);
|
| if (!*ok) return;
|
| - Handle<String> symbol = GetSymbol();
|
| - if (!*ok) return;
|
| - if (!symbol->IsUtf8EqualTo(CStrVector(keyword))) {
|
| + if (!scanner().is_literal_contextual_keyword(keyword)) {
|
| *ok = false;
|
| ReportUnexpectedToken(scanner().current_token());
|
| }
|
| @@ -5764,6 +5789,7 @@ ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) {
|
| preparser::PreParser preparser(&scanner, &recorder, stack_limit);
|
| preparser.set_allow_lazy(true);
|
| preparser.set_allow_generators(FLAG_harmony_generators);
|
| + preparser.set_allow_for_of(FLAG_harmony_iteration);
|
| preparser.set_allow_harmony_scoping(FLAG_harmony_scoping);
|
| scanner.Initialize(source);
|
| preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
|
|
|