For-of statements do not permit initializers.
authorwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 Jun 2013 12:37:44 +0000 (12:37 +0000)
committerwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 Jun 2013 12:37:44 +0000 (12:37 +0000)
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

src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/mjsunit/harmony/iteration-syntax.js

index fa24bf703bc6f62a039580db9731c0a6ae131c85..996d67745685131ab78e8d0b77d23028aa7e9e8e 100644 (file)
@@ -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)) {
     *visit_mode = ForEachStatement::ENUMERATE;
     return true;
-  } else if (allow_for_of() && CheckContextualKeyword(CStrVector("of"))) {
+  } else if (allow_for_of() && accept_OF &&
+             CheckContextualKeyword(CStrVector("of"))) {
     *visit_mode = ForEachStatement::ITERATE;
     return true;
   }
@@ -2726,11 +2728,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
     if (peek() == Token::VAR || peek() == Token::CONST) {
       bool is_const = peek() == Token::CONST;
       Handle<String> name;
+      VariableDeclarationProperties decl_props = kHasNoInitializers;
       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;
 
-      if (!name.is_null() && CheckInOrOf(&mode)) {
+      if (!name.is_null() && CheckInOrOf(accept_OF, &mode)) {
         Interface* interface =
             is_const ? Interface::NewConst() : Interface::NewValue();
         ForEachStatement* loop = factory()->NewForEachStatement(mode, labels);
@@ -2762,9 +2767,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
          ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
                                    CHECK_OK);
       bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
+      bool accept_OF = decl_props == kHasNoInitializers;
       ForEachStatement::VisitMode mode;
 
-      if (accept_IN && CheckInOrOf(&mode)) {
+      if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
         // Rewrite a for-in statement of the form
         //
         //   for (let x in e) b
@@ -2820,8 +2826,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
     } else {
       Expression* expression = ParseExpression(false, CHECK_OK);
       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
         // left-hand side expression.  We could report this as a syntax
         // error here but for compatibility with JSC we choose to report
index b7e0700009f6ff56cbe92ce48b9fb5788d5cd2e9..38633b0b42973e60632bae8b47455bc657162ff5 100644 (file)
@@ -729,7 +729,7 @@ class Parser BASE_EMBEDDED {
 
   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();
 
index 828177aee0a696ddf51c75b2ca7867aacc163522..3268e3c508bc2fb6887564b5d03e5675c2f46d2a 100644 (file)
@@ -659,10 +659,9 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
 }
 
 
-bool PreParser::CheckInOrOf() {
+bool PreParser::CheckInOrOf(bool accept_OF) {
   if (peek() == i::Token::IN ||
-      (allow_for_of() &&
-       peek() == i::Token::IDENTIFIER &&
+      (allow_for_of() && accept_OF && peek() == i::Token::IDENTIFIER &&
        scanner_->is_next_contextual_keyword(v8::internal::CStrVector("of")))) {
     Next();
     return true;
@@ -685,9 +684,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
       VariableDeclarationProperties decl_props = kHasNoInitializers;
       ParseVariableDeclarations(
           kForStatement, &decl_props, &decl_count, CHECK_OK);
-      bool accept_IN = decl_count == 1 &&
-          !(is_let && decl_props == kHasInitializers);
-      if (accept_IN && CheckInOrOf()) {
+      bool has_initializers = decl_props == kHasInitializers;
+      bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
+      bool accept_OF = !has_initializers;
+      if (accept_IN && CheckInOrOf(accept_OF)) {
         ParseExpression(true, CHECK_OK);
         Expect(i::Token::RPAREN, CHECK_OK);
 
@@ -695,8 +695,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
         return Statement::Default();
       }
     } else {
-      ParseExpression(false, CHECK_OK);
-      if (CheckInOrOf()) {
+      Expression lhs = ParseExpression(false, CHECK_OK);
+      if (CheckInOrOf(lhs.IsIdentifier())) {
         ParseExpression(true, CHECK_OK);
         Expect(i::Token::RPAREN, CHECK_OK);
 
index 786316ed5071465e44eb46ffee7d2210ca783a0b..41907d12eb18e24027590faebc4ecae412cabebd 100644 (file)
@@ -658,7 +658,7 @@ class PreParser {
   }
   void ExpectSemicolon(bool* ok);
 
-  bool CheckInOrOf();
+  bool CheckInOrOf(bool accept_OF);
 
   static int Precedence(i::Token::Value tok, bool accept_IN);
 
index 21149c04bc99108beb802fcfd65a253a558aae42..3bda78ed4e16d312d7f3351a9c60158659f99e1a 100644 (file)
@@ -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 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.
 function f() { for (of of y) { } }
 function f() { for (let of of y) { } }