Reviewers: marja,

Description:
[strong] Deprecate for-in

[email protected]
BUG=

Please review this at https://codereview.chromium.org/939063002/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+73, -21 lines):
  M src/messages.js
  M src/parser.h
  M src/parser.cc
  M src/preparser.h
  M src/preparser.cc
  M test/cctest/test-parsing.cc
  M test/mjsunit/strong/empty-statement.js
  A test/mjsunit/strong/for-in.js


Index: src/messages.js
diff --git a/src/messages.js b/src/messages.js
index 19d61041d1942c400b9fce07e56ca39a2130d38a..510147f68e2079e6628465afb16d93d001d7d48d 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -164,6 +164,7 @@ var kMessages = {
strong_equal: ["Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"], strong_delete: ["Please don't use 'delete' in strong mode, use maps or sets instead"], strong_var: ["Please don't use 'var' in strong mode, use 'let' or 'const' instead"], + strong_for_in: ["Please don't use 'for'-'in' loops in strong mode, use 'for'-'of' instead"], strong_empty: ["Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"], sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"], malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index bb8cb52b75068f0aee6941880fd7d1ecfe58bd29..fdfa87a0e06f3202a0eeb0050ec435e3b75a3a54 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -2882,9 +2882,14 @@ WhileStatement* Parser::ParseWhileStatement(


 bool Parser::CheckInOrOf(bool accept_OF,
-                         ForEachStatement::VisitMode* visit_mode) {
+ ForEachStatement::VisitMode* visit_mode, bool* ok) {
   if (Check(Token::IN)) {
-    *visit_mode = ForEachStatement::ENUMERATE;
+    if (is_strong(language_mode())) {
+      ReportMessageAt(scanner()->location(), "strong_for_in");
+      *ok = false;
+    } else {
+      *visit_mode = ForEachStatement::ENUMERATE;
+    }
     return true;
   } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
     *visit_mode = ForEachStatement::ITERATE;
@@ -3222,7 +3227,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
       ForEachStatement::VisitMode mode;
       int each_pos = position();

-      if (name != NULL && CheckInOrOf(accept_OF, &mode)) {
+      if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
         ForEachStatement* loop =
             factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
@@ -3259,7 +3265,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
       ForEachStatement::VisitMode mode;
       int each_pos = position();

-      if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
+      if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
+
         // Rewrite a for-in statement of the form
         //
         //   for (let/const x in e) b
@@ -3321,7 +3329,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         expression->AsVariableProxy()->raw_name() ==
             ast_value_factory()->let_string();

-      if (CheckInOrOf(accept_OF, &mode)) {
+      if (CheckInOrOf(accept_OF, &mode, ok)) {
+        if (!*ok) return nullptr;
         expression = this->CheckAndRewriteReferenceExpression(
             expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);

Index: src/parser.h
diff --git a/src/parser.h b/src/parser.h
index ff36fe90e0b0cd1c9a5c44f6086b7dc6ba069e33..03933d83d6f3ab41b3c4005ab3bf4ff17d82ed76 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -781,7 +781,8 @@ class Parser : public ParserBase<ParserTraits> {
   // Magical syntax support.
   Expression* ParseV8Intrinsic(bool* ok);

- bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
+  bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode,
+                   bool* ok);

   // Get odd-ball literals.
   Literal* GetLiteralUndefined(int position);
Index: src/preparser.cc
diff --git a/src/preparser.cc b/src/preparser.cc
index 00332ada0985fdb644f006195d5ffd5f9fdbd30f..94ac6b4844ebf3916bfcfa8645efcdb5a32f8857 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -715,9 +715,14 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
 }


-bool PreParser::CheckInOrOf(bool accept_OF) {
-  if (Check(Token::IN) ||
-      (accept_OF && CheckContextualKeyword(CStrVector("of")))) {
+bool PreParser::CheckInOrOf(bool accept_OF, bool* ok) {
+  if (Check(Token::IN)) {
+    if (is_strong(language_mode())) {
+      ReportMessageAt(scanner()->location(), "strong_for_in");
+      *ok = false;
+    }
+    return true;
+  } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
     return true;
   }
   return false;
@@ -743,22 +748,24 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
       bool has_initializers = decl_props == kHasInitializers;
bool accept_IN = decl_count == 1 && !(is_lexical && has_initializers);
       bool accept_OF = !has_initializers;
-      if (accept_IN && CheckInOrOf(accept_OF)) {
-        ParseExpression(true, CHECK_OK);
-        Expect(Token::RPAREN, CHECK_OK);
-
-        ParseSubStatement(CHECK_OK);
+      if (accept_IN && CheckInOrOf(accept_OF, ok)) {
+        if (*ok) {
+          ParseExpression(true, CHECK_OK);
+          Expect(Token::RPAREN, CHECK_OK);
+          ParseSubStatement(CHECK_OK);
+        }
         return Statement::Default();
       }
     } else {
       Expression lhs = ParseExpression(false, CHECK_OK);
       is_let_identifier_expression =
           lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
-      if (CheckInOrOf(lhs.IsIdentifier())) {
-        ParseExpression(true, CHECK_OK);
-        Expect(Token::RPAREN, CHECK_OK);
-
-        ParseSubStatement(CHECK_OK);
+      if (CheckInOrOf(lhs.IsIdentifier(), ok)) {
+        if (*ok) {
+          ParseExpression(true, CHECK_OK);
+          Expect(Token::RPAREN, CHECK_OK);
+          ParseSubStatement(CHECK_OK);
+        }
         return Statement::Default();
       }
     }
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index 1cd5dadf0d13557e9e978c5a0bee07f95680c89c..c6f483f72f642c06ac025d37fb8dbc59f8edcdb2 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -1614,7 +1614,7 @@ class PreParser : public ParserBase<PreParserTraits> {
bool name_is_strict_reserved, int pos,
                                         bool* ok);

-  bool CheckInOrOf(bool accept_OF);
+  bool CheckInOrOf(bool accept_OF, bool* ok);
 };


Index: test/cctest/test-parsing.cc
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index b6c427fff9e20189b1a2debbeaf007ea47fb8946..1a17475adad318894c84287b9553db1bc39e8679 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -5548,3 +5548,25 @@ TEST(StrongEmptySubStatements) {
RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
                     arraysize(always_flags));
 }
+
+
+TEST(StrongForIn) {
+  const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+  const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+  const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+  const char* data[] = {
+      "for (x in []) {}",
+      "for (const x in []) {}",
+      NULL};
+
+  static const ParserFlag always_flags[] = {
+      kAllowStrongMode, kAllowHarmonyScoping
+  };
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+ RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
Index: test/mjsunit/strong/empty-statement.js
diff --git a/test/mjsunit/strong/empty-statement.js b/test/mjsunit/strong/empty-statement.js index b63fead6a679c9093aeeb0eef21dc2f3dae8ab9f..65edf7473389e0aee50b39af8bb884e577239ea1 100644
--- a/test/mjsunit/strong/empty-statement.js
+++ b/test/mjsunit/strong/empty-statement.js
@@ -15,5 +15,4 @@
   assertThrows("'use strong'; for (let x;;);", SyntaxError);
   assertThrows("'use strong'; for (let x in []);", SyntaxError);
   assertThrows("'use strong'; for (let x of []);", SyntaxError);
-  assertThrows("'use strong'; with ({});", SyntaxError);
 })();
Index: test/mjsunit/strong/for-in.js
diff --git a/test/mjsunit/strong/for-in.js b/test/mjsunit/strong/for-in.js
new file mode 100644
index 0000000000000000000000000000000000000000..802835e5caa71018f1546836f6658098458c7ec4
--- /dev/null
+++ b/test/mjsunit/strong/for-in.js
@@ -0,0 +1,13 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --strong-mode
+
+(function NoForInStatement() {
+  assertThrows("'use strong'; for (x in []);", SyntaxError);
+  assertThrows("'use strong'; for (let x in []);", SyntaxError);
+  assertThrows("'use strong'; for (const x in []);", SyntaxError);
+  assertThrows("'use strong'; for (var x in []);", SyntaxError);
+  assertThrows("'use strong'; for (var x = 0 in []);", SyntaxError);
+})();


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to