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). R=marja@chromium.org, ulan@chromium.org BUG=v8:2198 LOG=Y Review URL: https://codereview.chromium.org/378303003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22323 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a087f30500
commit
e274edc8b8
@ -127,7 +127,6 @@ var kMessages = {
|
||||
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"],
|
||||
|
@ -1091,13 +1091,18 @@ Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
|
||||
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 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
||||
//
|
||||
// TODO(ES6): implement structuring ExportSpecifiers
|
||||
|
||||
ASSERT(strict_mode() == STRICT);
|
||||
|
||||
Expect(Token::EXPORT, CHECK_OK);
|
||||
|
||||
Statement* result = NULL;
|
||||
@ -1478,9 +1485,14 @@ Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
|
||||
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 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
|
||||
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 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
|
||||
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 @@ Block* Parser::ParseVariableDeclarations(
|
||||
}
|
||||
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 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
} 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 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
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 */,
|
||||
|
@ -61,6 +61,8 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
||||
} 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 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
|
||||
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 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
|
||||
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 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
|
||||
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 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
||||
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 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
||||
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;
|
||||
|
@ -308,6 +308,7 @@ class ParserBase : public Traits {
|
||||
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 @@ class PreParserIdentifier {
|
||||
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 @@ class PreParserIdentifier {
|
||||
kUnknownIdentifier,
|
||||
kFutureReservedIdentifier,
|
||||
kFutureStrictReservedIdentifier,
|
||||
kLetIdentifier,
|
||||
kYieldIdentifier,
|
||||
kEvalIdentifier,
|
||||
kArgumentsIdentifier
|
||||
@ -1504,6 +1510,7 @@ void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
|
||||
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 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
|
||||
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 @@ typename ParserBase<Traits>::IdentifierT ParserBase<
|
||||
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 @@ typename ParserBase<Traits>::IdentifierT
|
||||
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 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
|
||||
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 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
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 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
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)) {
|
||||
|
@ -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 @@ function Check(str) {
|
||||
}
|
||||
|
||||
// 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;");
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user