Commit f7263b6a authored by mike's avatar mike Committed by Commit bot

[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}
parent e7fdf5ea
...@@ -3676,7 +3676,15 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3676,7 +3676,15 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
factory()->NewForEachStatement(mode, labels, stmt_pos); factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop); 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); Expect(Token::RPAREN, CHECK_OK);
...@@ -3791,7 +3799,16 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3791,7 +3799,16 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
factory()->NewForEachStatement(mode, labels, stmt_pos); factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop); 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); Expect(Token::RPAREN, CHECK_OK);
// Make a block around the statement in case a lexical binding // Make a block around the statement in case a lexical binding
......
...@@ -950,7 +950,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -950,7 +950,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
*ok = false; *ok = false;
return Statement::Default(); return Statement::Default();
} }
if (mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier;
Expression enumerable =
ParseAssignmentExpression(true, &classifier, CHECK_OK);
PreParserTraits::RewriteNonPattern(enumerable, &classifier, CHECK_OK);
} else {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseSubStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
return Statement::Default(); return Statement::Default();
...@@ -980,7 +989,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -980,7 +989,16 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
kSyntaxError, CHECK_OK); kSyntaxError, 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); ParseExpression(true, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseSubStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
return Statement::Default(); return Statement::Default();
......
...@@ -4925,6 +4925,23 @@ TEST(ConstParsingInForIn) { ...@@ -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) { TEST(ConstParsingInForInError) {
const char* context_data[][2] = {{"'use strict';", ""}, const char* context_data[][2] = {{"'use strict';", ""},
{"function foo(){ 'use strict';", "}"}, {"function foo(){ 'use strict';", "}"},
...@@ -5098,6 +5115,76 @@ TEST(ForOfNoDeclarationsError) { ...@@ -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) { TEST(InvalidUnicodeEscapes) {
const char* context_data[][2] = {{"", ""}, const char* context_data[][2] = {{"", ""},
{"'use strict';", ""}, {"'use strict';", ""},
......
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