Commit 1fb2f4b3 authored by wingo@igalia.com's avatar wingo@igalia.com

For-of statements do not permit initializers.

R=rossberg@chromium.org
BUG=v8:2720

Review URL: https://codereview.chromium.org/16739008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15082 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8f15c921
...@@ -2624,11 +2624,13 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { ...@@ -2624,11 +2624,13 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
} }
bool Parser::CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { bool Parser::CheckInOrOf(bool accept_OF,
ForEachStatement::VisitMode* visit_mode) {
if (Check(Token::IN)) { if (Check(Token::IN)) {
*visit_mode = ForEachStatement::ENUMERATE; *visit_mode = ForEachStatement::ENUMERATE;
return true; return true;
} else if (allow_for_of() && CheckContextualKeyword(CStrVector("of"))) { } else if (allow_for_of() && accept_OF &&
CheckContextualKeyword(CStrVector("of"))) {
*visit_mode = ForEachStatement::ITERATE; *visit_mode = ForEachStatement::ITERATE;
return true; return true;
} }
...@@ -2726,11 +2728,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2726,11 +2728,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
if (peek() == Token::VAR || peek() == Token::CONST) { if (peek() == Token::VAR || peek() == Token::CONST) {
bool is_const = peek() == Token::CONST; bool is_const = peek() == Token::CONST;
Handle<String> name; Handle<String> name;
VariableDeclarationProperties decl_props = kHasNoInitializers;
Block* variable_statement = Block* variable_statement =
ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK); ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
CHECK_OK);
bool accept_OF = decl_props == kHasNoInitializers;
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
if (!name.is_null() && CheckInOrOf(&mode)) { if (!name.is_null() && CheckInOrOf(accept_OF, &mode)) {
Interface* interface = Interface* interface =
is_const ? Interface::NewConst() : Interface::NewValue(); is_const ? Interface::NewConst() : Interface::NewValue();
ForEachStatement* loop = factory()->NewForEachStatement(mode, labels); ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
...@@ -2762,9 +2767,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2762,9 +2767,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
CHECK_OK); CHECK_OK);
bool accept_IN = !name.is_null() && decl_props != kHasInitializers; bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
bool accept_OF = decl_props == kHasNoInitializers;
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
if (accept_IN && CheckInOrOf(&mode)) { if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
// Rewrite a for-in statement of the form // Rewrite a for-in statement of the form
// //
// for (let x in e) b // for (let x in e) b
...@@ -2820,8 +2826,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2820,8 +2826,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
} else { } else {
Expression* expression = ParseExpression(false, CHECK_OK); Expression* expression = ParseExpression(false, CHECK_OK);
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
bool accept_OF = expression->AsVariableProxy();
if (CheckInOrOf(&mode)) { if (CheckInOrOf(accept_OF, &mode)) {
// Signal a reference error if the expression is an invalid // Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax // left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report // error here but for compatibility with JSC we choose to report
......
...@@ -729,7 +729,7 @@ class Parser BASE_EMBEDDED { ...@@ -729,7 +729,7 @@ class Parser BASE_EMBEDDED {
bool is_generator() const { return current_function_state_->is_generator(); } bool is_generator() const { return current_function_state_->is_generator(); }
bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode); bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
bool peek_any_identifier(); bool peek_any_identifier();
......
...@@ -659,10 +659,9 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { ...@@ -659,10 +659,9 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
} }
bool PreParser::CheckInOrOf() { bool PreParser::CheckInOrOf(bool accept_OF) {
if (peek() == i::Token::IN || if (peek() == i::Token::IN ||
(allow_for_of() && (allow_for_of() && accept_OF && peek() == i::Token::IDENTIFIER &&
peek() == i::Token::IDENTIFIER &&
scanner_->is_next_contextual_keyword(v8::internal::CStrVector("of")))) { scanner_->is_next_contextual_keyword(v8::internal::CStrVector("of")))) {
Next(); Next();
return true; return true;
...@@ -685,9 +684,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -685,9 +684,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
VariableDeclarationProperties decl_props = kHasNoInitializers; VariableDeclarationProperties decl_props = kHasNoInitializers;
ParseVariableDeclarations( ParseVariableDeclarations(
kForStatement, &decl_props, &decl_count, CHECK_OK); kForStatement, &decl_props, &decl_count, CHECK_OK);
bool accept_IN = decl_count == 1 && bool has_initializers = decl_props == kHasInitializers;
!(is_let && decl_props == kHasInitializers); bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
if (accept_IN && CheckInOrOf()) { bool accept_OF = !has_initializers;
if (accept_IN && CheckInOrOf(accept_OF)) {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK);
...@@ -695,8 +695,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -695,8 +695,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
return Statement::Default(); return Statement::Default();
} }
} else { } else {
ParseExpression(false, CHECK_OK); Expression lhs = ParseExpression(false, CHECK_OK);
if (CheckInOrOf()) { if (CheckInOrOf(lhs.IsIdentifier())) {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK);
......
...@@ -658,7 +658,7 @@ class PreParser { ...@@ -658,7 +658,7 @@ class PreParser {
} }
void ExpectSemicolon(bool* ok); void ExpectSemicolon(bool* ok);
bool CheckInOrOf(); bool CheckInOrOf(bool accept_OF);
static int Precedence(i::Token::Value tok, bool accept_IN); static int Precedence(i::Token::Value tok, bool accept_IN);
......
...@@ -54,6 +54,11 @@ assertThrows("function f() { for (var of of) { } }", SyntaxError); ...@@ -54,6 +54,11 @@ assertThrows("function f() { for (var of of) { } }", SyntaxError);
assertThrows("function f() { for (let of y) { } }", SyntaxError); assertThrows("function f() { for (let of y) { } }", SyntaxError);
assertThrows("function f() { for (let of of) { } }", SyntaxError); assertThrows("function f() { for (let of of) { } }", SyntaxError);
assertThrows("function f() { for (x = 3 of y) { } }", SyntaxError);
assertThrows("function f() { for (var x = 3 of y) { } }", SyntaxError);
assertThrows("function f() { for (let x = 3 of y) { } }", SyntaxError);
// Alack, this appears to be valid. // Alack, this appears to be valid.
function f() { for (of of y) { } } function f() { for (of of y) { } }
function f() { for (let of of y) { } } function f() { for (let of of y) { } }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment