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}
This commit is contained in:
parent
650ef15c00
commit
3973642c98
@ -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);
|
||||
}
|
||||
|
7
test/message/no-legacy-const-2.js
Normal file
7
test/message/no-legacy-const-2.js
Normal file
@ -0,0 +1,7 @@
|
||||
// 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;
|
5
test/message/no-legacy-const-2.out
Normal file
5
test/message/no-legacy-const-2.out
Normal file
@ -0,0 +1,5 @@
|
||||
*%(basename)s:7: SyntaxError: Unexpected token const
|
||||
const = 42;
|
||||
^^^^^
|
||||
|
||||
SyntaxError: Unexpected token const
|
7
test/message/no-legacy-const-3.js
Normal file
7
test/message/no-legacy-const-3.js
Normal file
@ -0,0 +1,7 @@
|
||||
// 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
|
5
test/message/no-legacy-const-3.out
Normal file
5
test/message/no-legacy-const-3.out
Normal file
@ -0,0 +1,5 @@
|
||||
*%(basename)s:7: SyntaxError: Unexpected token const
|
||||
const
|
||||
^^^^^
|
||||
|
||||
SyntaxError: Unexpected token const
|
7
test/message/no-legacy-const.js
Normal file
7
test/message/no-legacy-const.js
Normal file
@ -0,0 +1,7 @@
|
||||
// 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;
|
5
test/message/no-legacy-const.out
Normal file
5
test/message/no-legacy-const.out
Normal file
@ -0,0 +1,5 @@
|
||||
*%(basename)s:7: SyntaxError: Unexpected token const
|
||||
const x = 42;
|
||||
^^^^^
|
||||
|
||||
SyntaxError: Unexpected token const
|
Loading…
Reference in New Issue
Block a user