Revision: 22323
Author:   [email protected]
Date:     Thu Jul 10 14:06:37 2014 UTC
Log:      Make `let` usable as an identifier in ES6 sloppy mode.

All of our mjsunit suite now runs through with --harmony-scoping enabled, up to expected failures (tests checking syntax errors for const/function in strict mode).

[email protected], [email protected]
BUG=v8:2198
LOG=Y

Review URL: https://codereview.chromium.org/378303003
http://code.google.com/p/v8/source/detail?r=22323

Modified:
 /branches/bleeding_edge/src/messages.js
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/preparser.cc
 /branches/bleeding_edge/src/preparser.h
 /branches/bleeding_edge/test/mjsunit/harmony/block-early-errors.js
 /branches/bleeding_edge/test/mjsunit/harmony/iteration-syntax.js

=======================================
--- /branches/bleeding_edge/src/messages.js     Thu Jul 10 12:27:07 2014 UTC
+++ /branches/bleeding_edge/src/messages.js     Thu Jul 10 14:06:37 2014 UTC
@@ -127,7 +127,6 @@
   illegal_break:                 ["Illegal break statement"],
   illegal_continue:              ["Illegal continue statement"],
   illegal_return:                ["Illegal return statement"],
- illegal_let: ["Illegal let declaration outside extended mode"],
   error_loading_debugger:        ["Error loading debugger"],
   no_input_to_regexp:            ["No input to ", "%0"],
   invalid_json:                  ["String '", "%0", "' is not valid JSON"],
=======================================
--- /branches/bleeding_edge/src/parser.cc       Thu Jul 10 12:27:07 2014 UTC
+++ /branches/bleeding_edge/src/parser.cc       Thu Jul 10 14:06:37 2014 UTC
@@ -1091,13 +1091,18 @@
   switch (peek()) {
     case Token::FUNCTION:
       return ParseFunctionDeclaration(NULL, ok);
-    case Token::LET:
-    case Token::CONST:
-      return ParseVariableStatement(kModuleElement, NULL, ok);
     case Token::IMPORT:
       return ParseImportDeclaration(ok);
     case Token::EXPORT:
       return ParseExportDeclaration(ok);
+    case Token::CONST:
+      return ParseVariableStatement(kModuleElement, NULL, ok);
+    case Token::LET:
+      ASSERT(allow_harmony_scoping());
+      if (strict_mode() == STRICT) {
+        return ParseVariableStatement(kModuleElement, NULL, ok);
+      }
+      // Fall through.
     default: {
       Statement* stmt = ParseStatement(labels, CHECK_OK);
       // Handle 'module' as a context-sensitive keyword.
@@ -1396,6 +1401,8 @@
   //
   // TODO(ES6): implement structuring ExportSpecifiers

+  ASSERT(strict_mode() == STRICT);
+
   Expect(Token::EXPORT, CHECK_OK);

   Statement* result = NULL;
@@ -1478,9 +1485,14 @@
   switch (peek()) {
     case Token::FUNCTION:
       return ParseFunctionDeclaration(NULL, ok);
-    case Token::LET:
     case Token::CONST:
       return ParseVariableStatement(kModuleElement, NULL, ok);
+    case Token::LET:
+      ASSERT(allow_harmony_scoping());
+      if (strict_mode() == STRICT) {
+        return ParseVariableStatement(kModuleElement, NULL, ok);
+      }
+      // Fall through.
     default:
       return ParseStatement(labels, ok);
   }
@@ -1516,11 +1528,6 @@
     case Token::LBRACE:
       return ParseBlock(labels, ok);

-    case Token::CONST:  // fall through
-    case Token::LET:
-    case Token::VAR:
-      return ParseVariableStatement(kStatement, NULL, ok);
-
     case Token::SEMICOLON:
       Next();
       return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
@@ -1592,6 +1599,16 @@
     case Token::DEBUGGER:
       return ParseDebuggerStatement(ok);

+    case Token::VAR:
+    case Token::CONST:
+      return ParseVariableStatement(kStatement, NULL, ok);
+
+    case Token::LET:
+      ASSERT(allow_harmony_scoping());
+      if (strict_mode() == STRICT) {
+        return ParseVariableStatement(kStatement, NULL, ok);
+      }
+      // Fall through.
     default:
       return ParseExpressionOrLabelledStatement(labels, ok);
   }
@@ -1995,20 +2012,7 @@
     }
     is_const = true;
     needs_init = true;
-  } else if (peek() == Token::LET) {
-    // ES6 Draft Rev4 section 12.2.1:
-    //
-    // LetDeclaration : let LetBindingList ;
-    //
- // * It is a Syntax Error if the code that matches this production is not
-    //   contained in extended code.
-    //
-    // TODO(rossberg): make 'let' a legal identifier in sloppy mode.
-    if (!allow_harmony_scoping() || strict_mode() == SLOPPY) {
-      ReportMessage("illegal_let");
-      *ok = false;
-      return NULL;
-    }
+  } else if (peek() == Token::LET && strict_mode() == STRICT) {
     Consume(Token::LET);
     if (var_context == kStatement) {
       // Let declarations are only allowed in source element positions.
@@ -3047,7 +3051,7 @@
       } else {
         init = variable_statement;
       }
-    } else if (peek() == Token::LET) {
+    } else if (peek() == Token::LET && strict_mode() == STRICT) {
       const AstRawString* name = NULL;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
       Block* variable_statement =
@@ -3478,8 +3482,8 @@
         fvar_init_op = Token::INIT_CONST;
       }
       VariableMode fvar_mode =
-          allow_harmony_scoping() && strict_mode() == STRICT ? CONST
- : CONST_LEGACY;
+          allow_harmony_scoping() && strict_mode() == STRICT
+              ? CONST : CONST_LEGACY;
       ASSERT(function_name != NULL);
       fvar = new(zone()) Variable(scope_,
          function_name, fvar_mode, true /* is valid LHS */,
=======================================
--- /branches/bleeding_edge/src/preparser.cc    Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/preparser.cc    Thu Jul 10 14:06:37 2014 UTC
@@ -61,6 +61,8 @@
   } else if (scanner->current_token() ==
              Token::FUTURE_STRICT_RESERVED_WORD) {
     return PreParserIdentifier::FutureStrictReserved();
+  } else if (scanner->current_token() == Token::LET) {
+    return PreParserIdentifier::Let();
   } else if (scanner->current_token() == Token::YIELD) {
     return PreParserIdentifier::Yield();
   }
@@ -167,9 +169,14 @@
   switch (peek()) {
     case Token::FUNCTION:
       return ParseFunctionDeclaration(ok);
-    case Token::LET:
     case Token::CONST:
       return ParseVariableStatement(kSourceElement, ok);
+    case Token::LET:
+      ASSERT(allow_harmony_scoping());
+      if (strict_mode() == STRICT) {
+        return ParseVariableStatement(kSourceElement, ok);
+      }
+      // Fall through.
     default:
       return ParseStatement(ok);
   }
@@ -237,11 +244,6 @@
     case Token::LBRACE:
       return ParseBlock(ok);

-    case Token::CONST:
-    case Token::LET:
-    case Token::VAR:
-      return ParseVariableStatement(kStatement, ok);
-
     case Token::SEMICOLON:
       Next();
       return Statement::Default();
@@ -297,6 +299,16 @@
     case Token::DEBUGGER:
       return ParseDebuggerStatement(ok);

+    case Token::VAR:
+    case Token::CONST:
+      return ParseVariableStatement(kStatement, ok);
+
+    case Token::LET:
+      ASSERT(allow_harmony_scoping());
+      if (strict_mode() == STRICT) {
+        return ParseVariableStatement(kStatement, ok);
+      }
+      // Fall through.
     default:
       return ParseExpressionOrLabelledStatement(ok);
   }
@@ -415,23 +427,9 @@
         return Statement::Default();
       }
     }
-  } else if (peek() == Token::LET) {
-    // ES6 Draft Rev4 section 12.2.1:
-    //
-    // LetDeclaration : let LetBindingList ;
-    //
- // * It is a Syntax Error if the code that matches this production is not
-    //   contained in extended code.
-    //
-    // TODO(rossberg): make 'let' a legal identifier in sloppy mode.
-    if (!allow_harmony_scoping() || strict_mode() == SLOPPY) {
-      ReportMessageAt(scanner()->peek_location(), "illegal_let");
-      *ok = false;
-      return Statement::Default();
-    }
+  } else if (peek() == Token::LET && strict_mode() == STRICT) {
     Consume(Token::LET);
-    if (var_context != kSourceElement &&
-        var_context != kForStatement) {
+    if (var_context != kSourceElement && var_context != kForStatement) {
       ReportMessageAt(scanner()->peek_location(), "unprotected_let");
       *ok = false;
       return Statement::Default();
@@ -669,7 +667,7 @@
   Expect(Token::LPAREN, CHECK_OK);
   if (peek() != Token::SEMICOLON) {
     if (peek() == Token::VAR || peek() == Token::CONST ||
-        peek() == Token::LET) {
+        (peek() == Token::LET && strict_mode() == STRICT)) {
       bool is_let = peek() == Token::LET;
       int decl_count;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
=======================================
--- /branches/bleeding_edge/src/preparser.h     Thu Jul 10 12:27:07 2014 UTC
+++ /branches/bleeding_edge/src/preparser.h     Thu Jul 10 14:06:37 2014 UTC
@@ -308,6 +308,7 @@
     return next == Token::IDENTIFIER ||
         next == Token::FUTURE_RESERVED_WORD ||
         next == Token::FUTURE_STRICT_RESERVED_WORD ||
+        next == Token::LET ||
         next == Token::YIELD;
   }

@@ -565,12 +566,16 @@
   static PreParserIdentifier FutureStrictReserved() {
     return PreParserIdentifier(kFutureStrictReservedIdentifier);
   }
+  static PreParserIdentifier Let() {
+    return PreParserIdentifier(kLetIdentifier);
+  }
   static PreParserIdentifier Yield() {
     return PreParserIdentifier(kYieldIdentifier);
   }
   bool IsEval() const { return type_ == kEvalIdentifier; }
   bool IsArguments() const { return type_ == kArgumentsIdentifier; }
   bool IsEvalOrArguments() const { return type_ >= kEvalIdentifier; }
+  bool IsLet() const { return type_ == kLetIdentifier; }
   bool IsYield() const { return type_ == kYieldIdentifier; }
bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
   bool IsFutureStrictReserved() const {
@@ -591,6 +596,7 @@
     kUnknownIdentifier,
     kFutureReservedIdentifier,
     kFutureStrictReservedIdentifier,
+    kLetIdentifier,
     kYieldIdentifier,
     kEvalIdentifier,
     kArgumentsIdentifier
@@ -1504,6 +1510,7 @@
return ReportMessageAt(source_location, "unexpected_token_identifier");
     case Token::FUTURE_RESERVED_WORD:
       return ReportMessageAt(source_location, "unexpected_reserved");
+    case Token::LET:
     case Token::YIELD:
     case Token::FUTURE_STRICT_RESERVED_WORD:
       return ReportMessageAt(source_location, strict_mode() == SLOPPY
@@ -1531,6 +1538,7 @@
     return name;
   } else if (strict_mode() == SLOPPY &&
              (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+             (next == Token::LET) ||
              (next == Token::YIELD && !is_generator()))) {
     return this->GetSymbol(scanner());
   } else {
@@ -1549,6 +1557,7 @@
   if (next == Token::IDENTIFIER) {
     *is_strict_reserved = false;
   } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+             next == Token::LET ||
              (next == Token::YIELD && !this->is_generator())) {
     *is_strict_reserved = true;
   } else {
@@ -1565,6 +1574,7 @@
 ParserBase<Traits>::ParseIdentifierName(bool* ok) {
   Token::Value next = Next();
   if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
+      next != Token::LET && next != Token::YIELD &&
next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
     this->ReportUnexpectedToken(next);
     *ok = false;
@@ -1660,6 +1670,7 @@
       break;

     case Token::IDENTIFIER:
+    case Token::LET:
     case Token::YIELD:
     case Token::FUTURE_STRICT_RESERVED_WORD: {
       // Using eval or arguments in this context is OK even in strict mode.
@@ -1806,6 +1817,8 @@
     switch (next) {
       case Token::FUTURE_RESERVED_WORD:
       case Token::FUTURE_STRICT_RESERVED_WORD:
+      case Token::LET:
+      case Token::YIELD:
       case Token::IDENTIFIER: {
         bool is_getter = false;
         bool is_setter = false;
@@ -1821,6 +1834,8 @@
           if (next != i::Token::IDENTIFIER &&
               next != i::Token::FUTURE_RESERVED_WORD &&
               next != i::Token::FUTURE_STRICT_RESERVED_WORD &&
+              next != i::Token::LET &&
+              next != i::Token::YIELD &&
               next != i::Token::NUMBER &&
               next != i::Token::STRING &&
               !Token::IsKeyword(next)) {
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/block-early-errors.js Tue Nov 29 06:38:04 2011 UTC +++ /branches/bleeding_edge/test/mjsunit/harmony/block-early-errors.js Thu Jul 10 14:06:37 2014 UTC
@@ -30,7 +30,6 @@
 function CheckException(e) {
   var string = e.toString();
   assertInstanceof(e, SyntaxError);
-  assertTrue(string.indexOf("Illegal let") >= 0);
 }

 function Check(str) {
@@ -49,7 +48,7 @@
 }

 // Check for early syntax errors when using let
-// declarations outside of extended mode.
+// declarations outside of strict mode.
 Check("let x;");
 Check("let x = 1;");
 Check("let x, y;");
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/iteration-syntax.js Wed Jun 12 12:37:44 2013 UTC +++ /branches/bleeding_edge/test/mjsunit/harmony/iteration-syntax.js Thu Jul 10 14:06:37 2014 UTC
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-// Flags: --harmony-iteration --harmony-scoping
+// Flags: --harmony-iteration --harmony-scoping --use-strict

 // Test for-of syntax.

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