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") \
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"],
};
// 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);
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)) {
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(
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
// 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);
}
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)) {
}
} 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);
}
// 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) {
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));
+}
--- /dev/null
+// 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++) {}");