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