Commit 3973642c authored by arv's avatar arv Committed by Commit bot

Add a flag for legacy const semantics

This flag is on by default but it will allow us to turn that off in
favor of harmony-sloppy in the future.

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

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

Cr-Commit-Position: refs/heads/master@{#29526}
parent 650ef15c
......@@ -182,6 +182,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony fetaures")
DEFINE_IMPLICATION(harmony, es_staging)
DEFINE_IMPLICATION(es_staging, harmony)
DEFINE_BOOL(legacy_const, true, "legacy semantics for const in sloppy mode")
// Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS(V) \
V(harmony_modules, "harmony modules") \
......
......@@ -919,6 +919,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_spread_arrays(FLAG_harmony_spread_arrays);
set_allow_harmony_new_target(FLAG_harmony_new_target);
set_allow_strong_mode(FLAG_strong_mode);
set_allow_legacy_const(FLAG_legacy_const);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
......@@ -1379,16 +1380,21 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
}
return ParseClassDeclaration(NULL, ok);
case Token::CONST:
if (allow_const()) {
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
break;
case Token::VAR:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
if (is_strict(language_mode())) {
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
// Fall through.
break;
default:
return ParseStatement(NULL, ok);
break;
}
return ParseStatement(NULL, ok);
}
......@@ -1937,7 +1943,7 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
// In ES6 CONST is not allowed as a Statement, only as a
// LexicalDeclaration, however we continue to allow it in sloppy mode for
// backwards compatibility.
if (is_sloppy(language_mode())) {
if (is_sloppy(language_mode()) && allow_legacy_const()) {
return ParseVariableStatement(kStatement, NULL, ok);
}
......@@ -2426,13 +2432,14 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
return;
}
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
} else if (peek() == Token::CONST && allow_const()) {
Consume(Token::CONST);
if (is_sloppy(language_mode())) {
if (is_sloppy(language_mode()) && allow_legacy_const()) {
parsing_result->descriptor.mode = CONST_LEGACY;
parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
++use_counts_[v8::Isolate::kLegacyConst];
} else {
DCHECK(is_strict(language_mode()));
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
parsing_result->descriptor.init_op = Token::INIT_CONST;
......@@ -3490,7 +3497,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
bool is_let_identifier_expression = false;
DeclarationParsingResult parsing_result;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST ||
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && is_strict(language_mode()))) {
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
is_const = parsing_result.descriptor.mode == CONST;
......@@ -3531,8 +3538,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Block* init_block = nullptr;
// special case for legacy for (var/const x =.... in)
if (is_sloppy(language_mode()) &&
!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
parsing_result.declarations[0].initializer != nullptr) {
VariableProxy* single_var = scope_->NewUnresolved(
factory(), parsing_result.SingleName(), Variable::NORMAL,
......@@ -3615,8 +3621,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
// Create a TDZ for any lexically-bound names.
if (is_strict(language_mode()) &&
IsLexicalVariableMode(parsing_result.descriptor.mode)) {
if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
DCHECK_NULL(init_block);
init_block =
......
......@@ -192,15 +192,19 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
case Token::CLASS:
return ParseClassDeclaration(ok);
case Token::CONST:
return ParseVariableStatement(kStatementListItem, ok);
if (allow_const()) {
return ParseVariableStatement(kStatementListItem, ok);
}
break;
case Token::LET:
if (is_strict(language_mode())) {
return ParseVariableStatement(kStatementListItem, ok);
}
// Fall through.
break;
default:
return ParseStatement(ok);
break;
}
return ParseStatement(ok);
}
......@@ -392,7 +396,7 @@ PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
// In ES6 CONST is not allowed as a Statement, only as a
// LexicalDeclaration, however we continue to allow it in sloppy mode for
// backwards compatibility.
if (is_sloppy(language_mode())) {
if (is_sloppy(language_mode()) && allow_legacy_const()) {
return ParseVariableStatement(kStatement, ok);
}
......@@ -508,7 +512,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
return Statement::Default();
}
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
} else if (peek() == Token::CONST && allow_const()) {
// TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
//
// ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
......@@ -864,7 +868,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) {
ForEachStatement::VisitMode mode;
if (peek() == Token::VAR || peek() == Token::CONST ||
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && is_strict(language_mode()))) {
int decl_count;
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
......
......@@ -99,7 +99,8 @@ class ParserBase : public Traits {
allow_harmony_destructuring_(false),
allow_harmony_spread_arrays_(false),
allow_harmony_new_target_(false),
allow_strong_mode_(false) {}
allow_strong_mode_(false),
allow_legacy_const_(true) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
......@@ -116,6 +117,7 @@ class ParserBase : public Traits {
ALLOW_ACCESSORS(harmony_spread_arrays);
ALLOW_ACCESSORS(harmony_new_target);
ALLOW_ACCESSORS(strong_mode);
ALLOW_ACCESSORS(legacy_const);
#undef ALLOW_ACCESSORS
bool allow_harmony_modules() const { return scanner()->HarmonyModules(); }
......@@ -491,6 +493,10 @@ class ParserBase : public Traits {
LanguageMode language_mode() { return scope_->language_mode(); }
bool is_generator() const { return function_state_->is_generator(); }
bool allow_const() {
return is_strict(language_mode()) || allow_legacy_const();
}
// Report syntax errors.
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
ParseErrorType error_type = kSyntaxError) {
......@@ -788,6 +794,7 @@ class ParserBase : public Traits {
bool allow_harmony_spread_arrays_;
bool allow_harmony_new_target_;
bool allow_strong_mode_;
bool allow_legacy_const_;
};
......
......@@ -1436,7 +1436,8 @@ enum ParserFlag {
kAllowHarmonyDestructuring,
kAllowHarmonySpreadArrays,
kAllowHarmonyNewTarget,
kAllowStrongMode
kAllowStrongMode,
kNoLegacyConst
};
......@@ -1468,6 +1469,7 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
flags.Contains(kAllowHarmonySpreadArrays));
parser->set_allow_harmony_new_target(flags.Contains(kAllowHarmonyNewTarget));
parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
parser->set_allow_legacy_const(!flags.Contains(kNoLegacyConst));
}
......@@ -6762,3 +6764,29 @@ TEST(NewTarget) {
RunParserSyncTest(bad_context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(LegacyConst) {
// clang-format off
const char* context_data[][2] = {
{"", ""},
{"{", "}"},
{NULL, NULL}
};
const char* data[] = {
"const x",
"const x = 1",
"for (const x = 1; x < 1; x++) {}",
"for (const x in {}) {}",
"for (const x of []) {}",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kNoLegacyConst};
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(context_data, data, kSuccess);
}
// Copyright 2015 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: --no-legacy-const
const = 42;
*%(basename)s:7: SyntaxError: Unexpected token const
const = 42;
^^^^^
SyntaxError: Unexpected token const
// Copyright 2015 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: --no-legacy-const
const
*%(basename)s:7: SyntaxError: Unexpected token const
const
^^^^^
SyntaxError: Unexpected token const
// Copyright 2015 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: --no-legacy-const
const x = 42;
*%(basename)s:7: SyntaxError: Unexpected token const
const x = 42;
^^^^^
SyntaxError: Unexpected token const
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