[parser] Disallow Expression in for..of statements
Although the `for..in` statement allows Expressions to define the iterator, only an AssignmentExpression may occupy this position in the `for..of` statement. BUG=v8:4692 LOG=N R=adamk@chromium.org Review URL: https://codereview.chromium.org/1602823003 Cr-Commit-Position: refs/heads/master@{#33420}
This commit is contained in:
parent
e7fdf5eaed
commit
f7263b6a3f
@ -3676,7 +3676,15 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
factory()->NewForEachStatement(mode, labels, stmt_pos);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||
Expression* enumerable;
|
||||
if (mode == ForEachStatement::ITERATE) {
|
||||
ExpressionClassifier classifier;
|
||||
enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||
enumerable = ParserTraits::RewriteNonPattern(enumerable, &classifier,
|
||||
CHECK_OK);
|
||||
} else {
|
||||
enumerable = ParseExpression(true, CHECK_OK);
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
@ -3791,7 +3799,16 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
||||
factory()->NewForEachStatement(mode, labels, stmt_pos);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||
Expression* enumerable;
|
||||
if (mode == ForEachStatement::ITERATE) {
|
||||
ExpressionClassifier classifier;
|
||||
enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||
enumerable = ParserTraits::RewriteNonPattern(enumerable, &classifier,
|
||||
CHECK_OK);
|
||||
} else {
|
||||
enumerable = ParseExpression(true, CHECK_OK);
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
// Make a block around the statement in case a lexical binding
|
||||
|
@ -950,7 +950,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
}
|
||||
ParseExpression(true, CHECK_OK);
|
||||
|
||||
if (mode == ForEachStatement::ITERATE) {
|
||||
ExpressionClassifier classifier;
|
||||
Expression enumerable =
|
||||
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||
PreParserTraits::RewriteNonPattern(enumerable, &classifier, CHECK_OK);
|
||||
} else {
|
||||
ParseExpression(true, CHECK_OK);
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
ParseSubStatement(CHECK_OK);
|
||||
return Statement::Default();
|
||||
@ -980,7 +989,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
||||
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
|
||||
kSyntaxError, CHECK_OK);
|
||||
}
|
||||
ParseExpression(true, CHECK_OK);
|
||||
|
||||
if (mode == ForEachStatement::ITERATE) {
|
||||
ExpressionClassifier classifier;
|
||||
Expression enumerable =
|
||||
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||
PreParserTraits::RewriteNonPattern(enumerable, &classifier, CHECK_OK);
|
||||
} else {
|
||||
ParseExpression(true, CHECK_OK);
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
ParseSubStatement(CHECK_OK);
|
||||
return Statement::Default();
|
||||
|
@ -4925,6 +4925,23 @@ TEST(ConstParsingInForIn) {
|
||||
}
|
||||
|
||||
|
||||
TEST(StatementParsingInForIn) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"'use strict';", ""},
|
||||
{"function foo(){ 'use strict';", "}"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* data[] = {"for(x in {}, {}) {}", "for(var x in {}, {}) {}",
|
||||
"for(let x in {}, {}) {}", "for(const x in {}, {}) {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst};
|
||||
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags,
|
||||
arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(ConstParsingInForInError) {
|
||||
const char* context_data[][2] = {{"'use strict';", ""},
|
||||
{"function foo(){ 'use strict';", "}"},
|
||||
@ -5098,6 +5115,76 @@ TEST(ForOfNoDeclarationsError) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ForOfInOperator) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"'use strict';", ""},
|
||||
{"function foo(){ 'use strict';", "}"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* data[] = {
|
||||
"for(x of 'foo' in {}) {}", "for(var x of 'foo' in {}) {}",
|
||||
"for(let x of 'foo' in {}) {}", "for(const x of 'foo' in {}) {}", NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst};
|
||||
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags,
|
||||
arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(ForOfYieldIdentifier) {
|
||||
const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
|
||||
|
||||
const char* data[] = {"for(x of yield) {}", "for(var x of yield) {}",
|
||||
"for(let x of yield) {}", "for(const x of yield) {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst};
|
||||
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags,
|
||||
arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(ForOfYieldExpression) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"'use strict';", ""},
|
||||
{"function foo(){ 'use strict';", "}"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* data[] = {"function* g() { for(x of yield) {} }",
|
||||
"function* g() { for(var x of yield) {} }",
|
||||
"function* g() { for(let x of yield) {} }",
|
||||
"function* g() { for(const x of yield) {} }", NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst};
|
||||
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags,
|
||||
arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(ForOfExpressionError) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"'use strict';", ""},
|
||||
{"function foo(){ 'use strict';", "}"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* data[] = {
|
||||
"for(x of [], []) {}", "for(var x of [], []) {}",
|
||||
"for(let x of [], []) {}", "for(const x of [], []) {}",
|
||||
|
||||
// AssignmentExpression should be validated statically:
|
||||
"for(x of { y = 23 }) {}", "for(var x of { y = 23 }) {}",
|
||||
"for(let x of { y = 23 }) {}", "for(const x of { y = 23 }) {}", NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst};
|
||||
RunParserSyncTest(context_data, data, kError, nullptr, 0, always_flags,
|
||||
arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(InvalidUnicodeEscapes) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"'use strict';", ""},
|
||||
|
Loading…
Reference in New Issue
Block a user