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(); |