Reviewers: Dan Ehrenberg, rossberg,
Message:
WDYT?
The idea is to make harmony-sloppy cover let and const but that
legacy-const has
higher priority so that if both are true we will continue to use legacy
const.
Description:
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
[email protected], [email protected]
Please review this at https://codereview.chromium.org/1218803006/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+64, -18 lines):
M src/flag-definitions.h
M src/parser.cc
M src/preparser.h
M src/preparser.cc
M test/cctest/test-parsing.cc
Index: src/flag-definitions.h
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index
3943de329dff44168e69c4efc2235aecd0163943..be27fa95547400fbb9f1f058eb25d88b0251bd5d
100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -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") \
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index
d795b3ce166ae54af87e623553386faf888cc25f..55b4122d71f8cbcccc2d04e8c5d494ef01e508a1
100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -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 =
Index: src/preparser.cc
diff --git a/src/preparser.cc b/src/preparser.cc
index
cfb8a3e3d53525ac0255bbb68e4738ac75185411..08d322b7d9a2b4ceb577667ad874ef54b322d134
100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -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();
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index
92712ff0d892cb0c035148cb50dd8955a63cf7db..2831266db7a3a206e1a6d00c2fef87bdda17ad4e
100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -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_;
};
Index: test/cctest/test-parsing.cc
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index
88dadcb1bf8ba35db6d0d986065e2f52ca370350..cbb79b16da9cc757f385978cb90193f14614163d
100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -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);
+}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.