[strong] Deprecate for-in

R=marja@chromium.org
BUG=

Review URL: https://codereview.chromium.org/939063002

Cr-Commit-Position: refs/heads/master@{#26751}
This commit is contained in:
rossberg 2015-02-19 05:50:33 -08:00 committed by Commit bot
parent 0c38744579
commit 7d089a5929
8 changed files with 69 additions and 34 deletions

View File

@ -164,6 +164,7 @@ var kMessages = {
strong_equal: ["Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"], strong_equal: ["Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"],
strong_delete: ["Please don't use 'delete' in strong mode, use maps or sets instead"], strong_delete: ["Please don't use 'delete' in strong mode, use maps or sets instead"],
strong_var: ["Please don't use 'var' in strong mode, use 'let' or 'const' instead"], strong_var: ["Please don't use 'var' in strong mode, use 'let' or 'const' instead"],
strong_for_in: ["Please don't use 'for'-'in' loops in strong mode, use 'for'-'of' instead"],
strong_empty: ["Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"], strong_empty: ["Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"],
sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"], sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"], malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],

View File

@ -2881,19 +2881,6 @@ WhileStatement* Parser::ParseWhileStatement(
} }
bool Parser::CheckInOrOf(bool accept_OF,
ForEachStatement::VisitMode* visit_mode) {
if (Check(Token::IN)) {
*visit_mode = ForEachStatement::ENUMERATE;
return true;
} else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
*visit_mode = ForEachStatement::ITERATE;
return true;
}
return false;
}
void Parser::InitializeForEachStatement(ForEachStatement* stmt, void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* each, Expression* each,
Expression* subject, Expression* subject,
@ -3222,7 +3209,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
int each_pos = position(); int each_pos = position();
if (name != NULL && CheckInOrOf(accept_OF, &mode)) { if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
ForEachStatement* loop = ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos); factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
@ -3259,7 +3247,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
int each_pos = position(); int each_pos = position();
if (accept_IN && CheckInOrOf(accept_OF, &mode)) { if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
// Rewrite a for-in statement of the form // Rewrite a for-in statement of the form
// //
// for (let/const x in e) b // for (let/const x in e) b
@ -3321,7 +3311,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
expression->AsVariableProxy()->raw_name() == expression->AsVariableProxy()->raw_name() ==
ast_value_factory()->let_string(); ast_value_factory()->let_string();
if (CheckInOrOf(accept_OF, &mode)) { if (CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
expression = this->CheckAndRewriteReferenceExpression( expression = this->CheckAndRewriteReferenceExpression(
expression, lhs_location, "invalid_lhs_in_for", CHECK_OK); expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);

View File

@ -781,8 +781,6 @@ class Parser : public ParserBase<ParserTraits> {
// Magical syntax support. // Magical syntax support.
Expression* ParseV8Intrinsic(bool* ok); Expression* ParseV8Intrinsic(bool* ok);
bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
// Get odd-ball literals. // Get odd-ball literals.
Literal* GetLiteralUndefined(int position); Literal* GetLiteralUndefined(int position);

View File

@ -715,15 +715,6 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
} }
bool PreParser::CheckInOrOf(bool accept_OF) {
if (Check(Token::IN) ||
(accept_OF && CheckContextualKeyword(CStrVector("of")))) {
return true;
}
return false;
}
PreParser::Statement PreParser::ParseForStatement(bool* ok) { PreParser::Statement PreParser::ParseForStatement(bool* ok) {
// ForStatement :: // ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
@ -732,6 +723,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
bool is_let_identifier_expression = false; bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
ForEachStatement::VisitMode visit_mode;
if (peek() == Token::VAR || peek() == Token::CONST || if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && is_strict(language_mode()))) { (peek() == Token::LET && is_strict(language_mode()))) {
bool is_lexical = peek() == Token::LET || bool is_lexical = peek() == Token::LET ||
@ -743,10 +735,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
bool has_initializers = decl_props == kHasInitializers; bool has_initializers = decl_props == kHasInitializers;
bool accept_IN = decl_count == 1 && !(is_lexical && has_initializers); bool accept_IN = decl_count == 1 && !(is_lexical && has_initializers);
bool accept_OF = !has_initializers; bool accept_OF = !has_initializers;
if (accept_IN && CheckInOrOf(accept_OF)) { if (accept_IN && CheckInOrOf(accept_OF, &visit_mode, ok)) {
if (!*ok) return Statement::Default();
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();
} }
@ -754,10 +746,10 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Expression lhs = ParseExpression(false, CHECK_OK); Expression lhs = ParseExpression(false, CHECK_OK);
is_let_identifier_expression = is_let_identifier_expression =
lhs.IsIdentifier() && lhs.AsIdentifier().IsLet(); lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
if (CheckInOrOf(lhs.IsIdentifier())) { if (CheckInOrOf(lhs.IsIdentifier(), &visit_mode, ok)) {
if (!*ok) return Statement::Default();
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();
} }

View File

@ -420,6 +420,23 @@ class ParserBase : public Traits {
} }
} }
bool CheckInOrOf(
bool accept_OF, ForEachStatement::VisitMode* visit_mode, bool* ok) {
if (Check(Token::IN)) {
if (is_strong(language_mode())) {
ReportMessageAt(scanner()->location(), "strong_for_in");
*ok = false;
} else {
*visit_mode = ForEachStatement::ENUMERATE;
}
return true;
} else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) {
*visit_mode = ForEachStatement::ITERATE;
return true;
}
return false;
}
// Checks whether an octal literal was last seen between beg_pos and end_pos. // Checks whether an octal literal was last seen between beg_pos and end_pos.
// If so, reports an error. Only called for strict mode and template strings. // If so, reports an error. Only called for strict mode and template strings.
void CheckOctalLiteral(int beg_pos, int end_pos, const char* error, void CheckOctalLiteral(int beg_pos, int end_pos, const char* error,
@ -1613,8 +1630,6 @@ class PreParser : public ParserBase<PreParserTraits> {
Scanner::Location class_name_location, Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos, bool name_is_strict_reserved, int pos,
bool* ok); bool* ok);
bool CheckInOrOf(bool accept_OF);
}; };

View File

@ -5548,3 +5548,25 @@ TEST(StrongEmptySubStatements) {
RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags, RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags)); arraysize(always_flags));
} }
TEST(StrongForIn) {
const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
const char* data[] = {
"for (x in []) {}",
"for (const x in []) {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowStrongMode, kAllowHarmonyScoping
};
RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}

View File

@ -15,5 +15,4 @@
assertThrows("'use strong'; for (let x;;);", SyntaxError); assertThrows("'use strong'; for (let x;;);", SyntaxError);
assertThrows("'use strong'; for (let x in []);", SyntaxError); assertThrows("'use strong'; for (let x in []);", SyntaxError);
assertThrows("'use strong'; for (let x of []);", SyntaxError); assertThrows("'use strong'; for (let x of []);", SyntaxError);
assertThrows("'use strong'; with ({});", SyntaxError);
})(); })();

View File

@ -0,0 +1,17 @@
// 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: --strong-mode
(function NoForInStatement() {
assertThrows("'use strong'; for (x in []) {}", SyntaxError);
assertThrows("'use strong'; for (let x in []) {}", SyntaxError);
assertThrows("'use strong'; for (const x in []) {}", SyntaxError);
})();
(function ForOfStatement() {
assertTrue(eval("'use strong'; for (x of []) {} true"));
assertTrue(eval("'use strong'; for (let x of []) {} true"));
assertTrue(eval("'use strong'; for (const x of []) {} true"));
})();