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.