Make let/const outside of the extended mode early errors (under harmony flag).
authorkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 29 Nov 2011 06:38:04 +0000 (06:38 +0000)
committerkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 29 Nov 2011 06:38:04 +0000 (06:38 +0000)
The ES.next drafts require that source code that matches the productions for
let and const bindings outside the extended mode trigger early syntax
errors. This CL adapts the parser / preparser accordingly under the harmony
scoping flag.

Summary:
* Harmony scoping flag not set: Old semantics allowing const in classic mode
with function level scope. Const binding in strict mode and let bindings in
classic and strict mode trigger early syntax errors.
* Harmony scoping is set: Use new harmony const and let in
extended mode and old const in classic mode. This is to preserve
compatibility with current web pages that already use
non-standard implementations of const. An early syntax error is
thrown on const in strict mode and on let in classic and strict
mode.

This depends on:
http://codereview.chromium.org/8562002/

TEST=mjsunit/harmony/block-early-errors.js

Review URL: http://codereview.chromium.org/8564001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10079 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/messages.js
src/parser.cc
src/preparser.cc
test/mjsunit/harmony/block-early-errors.js [new file with mode: 0644]

index 62dca12331ff3995831df92d71cc1eab18774a6b..5a3f12ee3a262fd5f82f4d43d75874cb402d7bf5 100644 (file)
@@ -206,6 +206,7 @@ function FormatMessage(message) {
       "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"],
index b79589160190cd4019428bf5cc4b2293ff3276a6..e4d40109e6e824d3e5d21d4cb6782b278abe5f89 100644 (file)
@@ -1267,6 +1267,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
       return ParseBlock(labels, ok);
 
     case Token::CONST:  // fall through
+    case Token::LET:
     case Token::VAR:
       stmt = ParseVariableStatement(kStatement, ok);
       break;
@@ -1708,6 +1709,16 @@ Block* Parser::ParseVariableDeclarations(
   if (peek() == Token::VAR) {
     Consume(Token::VAR);
   } else if (peek() == Token::CONST) {
+    // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
+    //
+    // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
+    //
+    // * It is a Syntax Error if the code that matches this production is not
+    //   contained in extended code.
+    //
+    // However disallowing const in classic mode will break compatibility with
+    // existing pages. Therefore we keep allowing const with the old
+    // non-harmony semantics in classic mode.
     Consume(Token::CONST);
     switch (top_scope_->language_mode()) {
       case CLASSIC_MODE:
@@ -1733,7 +1744,17 @@ Block* Parser::ParseVariableDeclarations(
     is_const = true;
     needs_init = true;
   } else if (peek() == Token::LET) {
-    ASSERT(top_scope_->is_extended_mode());
+    // 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.
+    if (!is_extended_mode()) {
+      ReportMessage("illegal_let", Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    }
     Consume(Token::LET);
     if (var_context != kSourceElement &&
         var_context != kForStatement) {
index db89e7bd6bc98823f987bf88c612cf5e2b11c6fd..49cadb661801bb86c9a7c0103bd129c9623107da 100644 (file)
@@ -227,6 +227,7 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
       return ParseBlock(ok);
 
     case i::Token::CONST:
+    case i::Token::LET:
     case i::Token::VAR:
       return ParseVariableStatement(kStatement, ok);
 
@@ -377,6 +378,17 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
   if (peek() == i::Token::VAR) {
     Consume(i::Token::VAR);
   } else if (peek() == i::Token::CONST) {
+    // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
+    //
+    // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
+    //
+    // * It is a Syntax Error if the code that matches this production is not
+    //   contained in extended code.
+    //
+    // However disallowing const in classic mode will break compatibility with
+    // existing pages. Therefore we keep allowing const with the old
+    // non-harmony semantics in classic mode.
+    Consume(i::Token::CONST);
     switch (language_mode()) {
       case i::CLASSIC_MODE:
         break;
@@ -398,9 +410,21 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
         require_initializer = true;
         break;
     }
-    Consume(i::Token::CONST);
   } else if (peek() == i::Token::LET) {
-    ASSERT(is_extended_mode());
+    // 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.
+    if (!is_extended_mode()) {
+      i::Scanner::Location location = scanner_->peek_location();
+      ReportMessageAt(location.beg_pos, location.end_pos,
+                      "illegal_let", NULL);
+      *ok = false;
+      return Statement::Default();
+    }
+    Consume(i::Token::LET);
     if (var_context != kSourceElement &&
         var_context != kForStatement) {
       i::Scanner::Location location = scanner_->peek_location();
@@ -409,7 +433,6 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
       *ok = false;
       return Statement::Default();
     }
-    Consume(i::Token::LET);
   } else {
     *ok = false;
     return Statement::Default();
diff --git a/test/mjsunit/harmony/block-early-errors.js b/test/mjsunit/harmony/block-early-errors.js
new file mode 100644 (file)
index 0000000..791f001
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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-scoping
+
+function CheckException(e) {
+  var string = e.toString();
+  assertInstanceof(e, SyntaxError);
+  assertTrue(string.indexOf("Illegal let") >= 0);
+}
+
+function Check(str) {
+  try {
+    eval("(function () { " + str + " })");
+    assertUnreachable();
+  } catch (e) {
+    CheckException(e);
+  }
+  try {
+    eval("(function () { { " + str + " } })");
+    assertUnreachable();
+  } catch (e) {
+    CheckException(e);
+  }
+}
+
+// Check for early syntax errors when using let
+// declarations outside of extended mode.
+Check("let x;");
+Check("let x = 1;");
+Check("let x, y;");