Commit ca8eaef6 authored by dslomov's avatar dslomov Committed by Commit bot

harmony-scoping: better error messages for let declarations in sloppy mode.

R=rossberg@chromium.org
BUG=v8:2198
LOG=N

Review URL: https://codereview.chromium.org/713413003

Cr-Commit-Position: refs/heads/master@{#25406}
parent 55999dcb
......@@ -251,6 +251,7 @@ class AstValue : public ZoneObject {
F(get_template_callsite, "GetTemplateCallSite") \
F(initialize_const_global, "initializeConstGlobal") \
F(initialize_var_global, "initializeVarGlobal") \
F(let, "let") \
F(make_reference_error, "MakeReferenceErrorEmbedded") \
F(make_syntax_error, "MakeSyntaxErrorEmbedded") \
F(make_type_error, "MakeTypeErrorEmbedded") \
......
......@@ -180,7 +180,8 @@ var kMessages = {
unexpected_super: ["'super' keyword unexpected here"],
extends_value_not_a_function: ["Class extends value ", "%0", " is not a function or null"],
prototype_parent_not_an_object: ["Class extends value does not have valid prototype property ", "%0"],
duplicate_constructor: ["A class may only have one constructor"]
duplicate_constructor: ["A class may only have one constructor"],
lexical_strict_mode: ["Lexical declarations are currently only allowed in strict mode"],
};
......
......@@ -2479,12 +2479,20 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
// Parsed expression statement, or the context-sensitive 'module' keyword.
// Only expect semicolon in the former case.
// Also detect attempts at 'let' declarations in sloppy mode.
if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER ||
scanner()->HasAnyLineTerminatorBeforeNext() ||
expr->AsVariableProxy() == NULL ||
expr->AsVariableProxy()->raw_name() !=
ast_value_factory()->module_string() ||
scanner()->literal_contains_escapes()) {
if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
expr->AsVariableProxy()->raw_name() ==
ast_value_factory()->let_string()) {
ReportMessage("lexical_strict_mode", NULL);
*ok = false;
return NULL;
}
ExpectSemicolon(CHECK_OK);
}
return factory()->NewExpressionStatement(expr, pos);
......@@ -3214,6 +3222,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
for_scope->set_start_position(scanner()->location().beg_pos);
bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR ||
(peek() == Token::CONST && strict_mode() == SLOPPY)) {
......@@ -3325,6 +3334,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* expression = ParseExpression(false, CHECK_OK);
ForEachStatement::VisitMode mode;
bool accept_OF = expression->IsVariableProxy();
is_let_identifier_expression =
expression->IsVariableProxy() &&
expression->AsVariableProxy()->raw_name() ==
ast_value_factory()->let_string();
if (CheckInOrOf(accept_OF, &mode)) {
expression = this->CheckAndRewriteReferenceExpression(
......@@ -3357,6 +3370,13 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Target target(&this->target_stack_, loop);
// Parsed initializer at this point.
// Detect attempts at 'let' declarations in sloppy mode.
if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
is_let_identifier_expression) {
ReportMessage("lexical_strict_mode", NULL);
*ok = false;
return NULL;
}
Expect(Token::SEMICOLON, CHECK_OK);
// If there are let bindings, then condition and the next statement of the
......
......@@ -509,6 +509,13 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
// accept "native function" in the preparser.
}
// Parsed expression statement.
// Detect attempts at 'let' declarations in sloppy mode.
if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
expr.IsIdentifier() && expr.AsIdentifier().IsLet()) {
ReportMessage("lexical_strict_mode", NULL);
*ok = false;
return Statement::Default();
}
ExpectSemicolon(CHECK_OK);
return Statement::ExpressionStatement(expr);
}
......@@ -688,6 +695,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && strict_mode() == STRICT)) {
......@@ -709,6 +717,8 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
}
} else {
Expression lhs = ParseExpression(false, CHECK_OK);
is_let_identifier_expression =
lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
if (CheckInOrOf(lhs.IsIdentifier())) {
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
......@@ -720,6 +730,13 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
}
// Parsed initializer at this point.
// Detect attempts at 'let' declarations in sloppy mode.
if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
is_let_identifier_expression) {
ReportMessage("lexical_strict_mode", NULL);
*ok = false;
return Statement::Default();
}
Expect(Token::SEMICOLON, CHECK_OK);
if (peek() != Token::SEMICOLON) {
......
......@@ -4432,3 +4432,28 @@ TEST(ScanUnterminatedTemplateLiterals) {
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(LexicalScopingSloppyMode) {
const char* context_data[][2] = {
{"", ""},
{"function f() {", "}"},
{"{", "}"},
{NULL, NULL}};
const char* bad_data[] = {
"let x = 1;",
"for(let x = 1;;){}",
"for(let x of []){}",
"for(let x in []){}",
NULL};
static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
RunParserSyncTest(context_data, bad_data, kError, NULL, 0, always_flags,
arraysize(always_flags));
const char* good_data[] = {
"let = 1;",
"for(let = 1;;){}",
NULL};
RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-scoping
function CheckError(source) {
var exception = null;
try {
eval(source);
} catch (e) {
exception = e;
}
assertNotNull(exception);
assertEquals(
"Lexical declarations are currently only allowed in strict mode",
exception.message);
}
function CheckOk(source) {
eval(source);
}
CheckError("let x = 1;");
CheckError("{ let x = 1; }");
CheckError("function f() { let x = 1; }");
CheckError("for (let x = 1; x < 1; x++) {}");
CheckError("for (let x of []) {}");
CheckError("for (let x in []) {}");
CheckOk("let = 1;");
CheckOk("{ let = 1; }");
CheckOk("function f() { let = 1; }");
CheckOk("for (let = 1; let < 1; let++) {}");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment