Reviewers: Dan Ehrenberg, rossberg,

Message:
WDYT?

The idea is to make harmony-sloppy cover let and const but that legacy-const has higher priority so that if both are true we will continue to use legacy const.

Description:
Add a flag for legacy const semantics

This flag is on by default but it will allow us to turn that off in
favor of harmony-sloppy in the future.

BUG=v8:3305, v8:2198
LOG=N
[email protected], [email protected]

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

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

Affected files (+64, -18 lines):
  M src/flag-definitions.h
  M src/parser.cc
  M src/preparser.h
  M src/preparser.cc
  M test/cctest/test-parsing.cc


Index: src/flag-definitions.h
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 3943de329dff44168e69c4efc2235aecd0163943..be27fa95547400fbb9f1f058eb25d88b0251bd5d 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -182,6 +182,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony fetaures")
 DEFINE_IMPLICATION(harmony, es_staging)
 DEFINE_IMPLICATION(es_staging, harmony)

+DEFINE_BOOL(legacy_const, true, "legacy semantics for const in sloppy mode")
+
 // Features that are still work in progress (behind individual flags).
 #define HARMONY_INPROGRESS(V)                                   \
   V(harmony_modules, "harmony modules")                         \
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index d795b3ce166ae54af87e623553386faf888cc25f..55b4122d71f8cbcccc2d04e8c5d494ef01e508a1 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -919,6 +919,7 @@ Parser::Parser(ParseInfo* info)
   set_allow_harmony_spread_arrays(FLAG_harmony_spread_arrays);
   set_allow_harmony_new_target(FLAG_harmony_new_target);
   set_allow_strong_mode(FLAG_strong_mode);
+  set_allow_legacy_const(FLAG_legacy_const);
   for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
        ++feature) {
     use_counts_[feature] = 0;
@@ -1379,16 +1380,21 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
       }
       return ParseClassDeclaration(NULL, ok);
     case Token::CONST:
+      if (allow_const()) {
+        return ParseVariableStatement(kStatementListItem, NULL, ok);
+      }
+      break;
     case Token::VAR:
       return ParseVariableStatement(kStatementListItem, NULL, ok);
     case Token::LET:
       if (is_strict(language_mode())) {
         return ParseVariableStatement(kStatementListItem, NULL, ok);
       }
-      // Fall through.
+      break;
     default:
-      return ParseStatement(NULL, ok);
+      break;
   }
+  return ParseStatement(NULL, ok);
 }


@@ -1937,7 +1943,7 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
       // In ES6 CONST is not allowed as a Statement, only as a
// LexicalDeclaration, however we continue to allow it in sloppy mode for
       // backwards compatibility.
-      if (is_sloppy(language_mode())) {
+      if (is_sloppy(language_mode()) && allow_legacy_const()) {
         return ParseVariableStatement(kStatement, NULL, ok);
       }

@@ -2426,13 +2432,14 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
       return;
     }
     Consume(Token::VAR);
-  } else if (peek() == Token::CONST) {
+  } else if (peek() == Token::CONST && allow_const()) {
     Consume(Token::CONST);
-    if (is_sloppy(language_mode())) {
+    if (is_sloppy(language_mode()) && allow_legacy_const()) {
       parsing_result->descriptor.mode = CONST_LEGACY;
       parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
       ++use_counts_[v8::Isolate::kLegacyConst];
     } else {
+      DCHECK(is_strict(language_mode()));
       DCHECK(var_context != kStatement);
       parsing_result->descriptor.mode = CONST;
       parsing_result->descriptor.init_op = Token::INIT_CONST;
@@ -3490,7 +3497,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
   bool is_let_identifier_expression = false;
   DeclarationParsingResult parsing_result;
   if (peek() != Token::SEMICOLON) {
-    if (peek() == Token::VAR || peek() == Token::CONST ||
+ if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) | |
         (peek() == Token::LET && is_strict(language_mode()))) {
       ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
       is_const = parsing_result.descriptor.mode == CONST;
@@ -3531,8 +3538,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         Block* init_block = nullptr;

         // special case for legacy for (var/const x =.... in)
-        if (is_sloppy(language_mode()) &&
-            !IsLexicalVariableMode(parsing_result.descriptor.mode) &&
+        if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
             parsing_result.declarations[0].initializer != nullptr) {
           VariableProxy* single_var = scope_->NewUnresolved(
               factory(), parsing_result.SingleName(), Variable::NORMAL,
@@ -3615,8 +3621,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         }

         // Create a TDZ for any lexically-bound names.
-        if (is_strict(language_mode()) &&
-            IsLexicalVariableMode(parsing_result.descriptor.mode)) {
+        if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
           DCHECK_NULL(init_block);

           init_block =
Index: src/preparser.cc
diff --git a/src/preparser.cc b/src/preparser.cc
index cfb8a3e3d53525ac0255bbb68e4738ac75185411..08d322b7d9a2b4ceb577667ad874ef54b322d134 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -192,15 +192,19 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
     case Token::CLASS:
       return ParseClassDeclaration(ok);
     case Token::CONST:
-      return ParseVariableStatement(kStatementListItem, ok);
+      if (allow_const()) {
+        return ParseVariableStatement(kStatementListItem, ok);
+      }
+      break;
     case Token::LET:
       if (is_strict(language_mode())) {
         return ParseVariableStatement(kStatementListItem, ok);
       }
-      // Fall through.
+      break;
     default:
-      return ParseStatement(ok);
+      break;
   }
+  return ParseStatement(ok);
 }


@@ -392,7 +396,7 @@ PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
       // In ES6 CONST is not allowed as a Statement, only as a
// LexicalDeclaration, however we continue to allow it in sloppy mode for
       // backwards compatibility.
-      if (is_sloppy(language_mode())) {
+      if (is_sloppy(language_mode()) && allow_legacy_const()) {
         return ParseVariableStatement(kStatement, ok);
       }

@@ -508,7 +512,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
       return Statement::Default();
     }
     Consume(Token::VAR);
-  } else if (peek() == Token::CONST) {
+  } else if (peek() == Token::CONST && allow_const()) {
     // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
     //
     // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
@@ -864,7 +868,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
   bool is_let_identifier_expression = false;
   if (peek() != Token::SEMICOLON) {
     ForEachStatement::VisitMode mode;
-    if (peek() == Token::VAR || peek() == Token::CONST ||
+ if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) | |
         (peek() == Token::LET && is_strict(language_mode()))) {
       int decl_count;
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index 92712ff0d892cb0c035148cb50dd8955a63cf7db..2831266db7a3a206e1a6d00c2fef87bdda17ad4e 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -99,7 +99,8 @@ class ParserBase : public Traits {
         allow_harmony_destructuring_(false),
         allow_harmony_spread_arrays_(false),
         allow_harmony_new_target_(false),
-        allow_strong_mode_(false) {}
+        allow_strong_mode_(false),
+        allow_legacy_const_(true) {}

 #define ALLOW_ACCESSORS(name)                           \
   bool allow_##name() const { return allow_##name##_; } \
@@ -116,6 +117,7 @@ class ParserBase : public Traits {
   ALLOW_ACCESSORS(harmony_spread_arrays);
   ALLOW_ACCESSORS(harmony_new_target);
   ALLOW_ACCESSORS(strong_mode);
+  ALLOW_ACCESSORS(legacy_const);
 #undef ALLOW_ACCESSORS

bool allow_harmony_modules() const { return scanner()->HarmonyModules(); }
@@ -491,6 +493,10 @@ class ParserBase : public Traits {
   LanguageMode language_mode() { return scope_->language_mode(); }
   bool is_generator() const { return function_state_->is_generator(); }

+  bool allow_const() {
+    return is_strict(language_mode()) || allow_legacy_const();
+  }
+
   // Report syntax errors.
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
                      ParseErrorType error_type = kSyntaxError) {
@@ -788,6 +794,7 @@ class ParserBase : public Traits {
   bool allow_harmony_spread_arrays_;
   bool allow_harmony_new_target_;
   bool allow_strong_mode_;
+  bool allow_legacy_const_;
 };


Index: test/cctest/test-parsing.cc
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 88dadcb1bf8ba35db6d0d986065e2f52ca370350..cbb79b16da9cc757f385978cb90193f14614163d 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1436,7 +1436,8 @@ enum ParserFlag {
   kAllowHarmonyDestructuring,
   kAllowHarmonySpreadArrays,
   kAllowHarmonyNewTarget,
-  kAllowStrongMode
+  kAllowStrongMode,
+  kNoLegacyConst
 };


@@ -1468,6 +1469,7 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
       flags.Contains(kAllowHarmonySpreadArrays));
parser->set_allow_harmony_new_target(flags.Contains(kAllowHarmonyNewTarget));
   parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
+  parser->set_allow_legacy_const(!flags.Contains(kNoLegacyConst));
 }


@@ -6762,3 +6764,29 @@ TEST(NewTarget) {
   RunParserSyncTest(bad_context_data, data, kError, NULL, 0, always_flags,
                     arraysize(always_flags));
 }
+
+
+TEST(LegacyConst) {
+  // clang-format off
+  const char* context_data[][2] = {
+    {"", ""},
+    {"{", "}"},
+    {NULL, NULL}
+  };
+
+  const char* data[] = {
+    "const x",
+    "const x = 1",
+    "for (const x = 1; x < 1; x++) {}",
+    "for (const x in {}) {}",
+    "for (const x of []) {}",
+    NULL
+  };
+  // clang-format on
+
+  static const ParserFlag always_flags[] = {kNoLegacyConst};
+
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(context_data, data, kSuccess);
+}


--
--
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