Commit c5032419 authored by Andreas Rossberg's avatar Andreas Rossberg

[strong] deprecate empty sub-statements

R=marja@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#26701}
parent 01538bff
...@@ -164,6 +164,8 @@ var kMessages = { ...@@ -164,6 +164,8 @@ 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_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"],
malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"], malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],
generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."], generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."],
cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"], cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
...@@ -179,7 +181,6 @@ var kMessages = { ...@@ -179,7 +181,6 @@ var kMessages = {
extends_value_not_a_function: ["Class extends value ", "%0", " is not a function or null"], extends_value_not_a_function: ["Class extends value ", "%0", " is not a function or null"],
prototype_parent_not_an_object: ["Class extends value does not have valid prototype property ", "%0"], prototype_parent_not_an_object: ["Class extends value does not have valid prototype property ", "%0"],
duplicate_constructor: ["A class may only have one constructor"], duplicate_constructor: ["A class may only have one constructor"],
sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
super_constructor_call: ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."], super_constructor_call: ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."],
duplicate_proto: ["Duplicate __proto__ fields are not allowed in object literals"], duplicate_proto: ["Duplicate __proto__ fields are not allowed in object literals"],
param_after_rest: ["Rest parameter must be last formal parameter"], param_after_rest: ["Rest parameter must be last formal parameter"],
......
...@@ -1642,6 +1642,20 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { ...@@ -1642,6 +1642,20 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
bool* ok) { bool* ok) {
// Statement :: // Statement ::
// EmptyStatement
// ...
if (peek() == Token::SEMICOLON) {
Next();
return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
}
return ParseSubStatement(labels, ok);
}
Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// Statement ::
// Block // Block
// VariableStatement // VariableStatement
// EmptyStatement // EmptyStatement
...@@ -1669,6 +1683,11 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, ...@@ -1669,6 +1683,11 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseBlock(labels, ok); return ParseBlock(labels, ok);
case Token::SEMICOLON: case Token::SEMICOLON:
if (is_strong(language_mode())) {
ReportMessageAt(scanner()->peek_location(), "strong_empty");
*ok = false;
return NULL;
}
Next(); Next();
return factory()->NewEmptyStatement(RelocInfo::kNoPosition); return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
...@@ -2535,11 +2554,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels, ...@@ -2535,11 +2554,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
Expression* condition = ParseExpression(true, CHECK_OK); Expression* condition = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* then_statement = ParseStatement(labels, CHECK_OK); Statement* then_statement = ParseSubStatement(labels, CHECK_OK);
Statement* else_statement = NULL; Statement* else_statement = NULL;
if (peek() == Token::ELSE) { if (peek() == Token::ELSE) {
Next(); Next();
else_statement = ParseStatement(labels, CHECK_OK); else_statement = ParseSubStatement(labels, CHECK_OK);
} else { } else {
else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition); else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
} }
...@@ -2684,7 +2703,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, ...@@ -2684,7 +2703,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Statement* stmt; Statement* stmt;
{ BlockState block_state(&scope_, with_scope); { BlockState block_state(&scope_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos); with_scope->set_start_position(scanner()->peek_location().beg_pos);
stmt = ParseStatement(labels, CHECK_OK); stmt = ParseSubStatement(labels, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos); with_scope->set_end_position(scanner()->location().end_pos);
} }
return factory()->NewWithStatement(with_scope, expr, stmt, pos); return factory()->NewWithStatement(with_scope, expr, stmt, pos);
...@@ -2869,7 +2888,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement( ...@@ -2869,7 +2888,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK); Expect(Token::DO, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
Expect(Token::WHILE, CHECK_OK); Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
...@@ -2899,7 +2918,7 @@ WhileStatement* Parser::ParseWhileStatement( ...@@ -2899,7 +2918,7 @@ WhileStatement* Parser::ParseWhileStatement(
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
Expression* cond = ParseExpression(true, CHECK_OK); Expression* cond = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
if (loop != NULL) loop->Initialize(cond, body); if (loop != NULL) loop->Initialize(cond, body);
return loop; return loop;
...@@ -3262,7 +3281,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3262,7 +3281,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
VariableProxy* each = VariableProxy* each =
scope_->NewUnresolved(factory(), name, interface, each_pos); scope_->NewUnresolved(factory(), name, interface, each_pos);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, each, enumerable, body); InitializeForEachStatement(loop, each, enumerable, body);
Block* result = Block* result =
factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
...@@ -3321,7 +3340,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3321,7 +3340,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
VariableProxy* each = scope_->NewUnresolved( VariableProxy* each = scope_->NewUnresolved(
factory(), name, Interface::NewValue(), each_pos); factory(), name, Interface::NewValue(), each_pos);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
Block* body_block = Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN; Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN;
...@@ -3364,7 +3383,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3364,7 +3383,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* enumerable = ParseExpression(true, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, expression, enumerable, body); InitializeForEachStatement(loop, expression, enumerable, body);
scope_ = saved_scope; scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos); for_scope->set_end_position(scanner()->location().end_pos);
...@@ -3416,7 +3435,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3416,7 +3435,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseSubStatement(NULL, CHECK_OK);
Statement* result = NULL; Statement* result = NULL;
if (let_bindings.length() > 0) { if (let_bindings.length() > 0) {
......
...@@ -715,6 +715,7 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -715,6 +715,7 @@ class Parser : public ParserBase<ParserTraits> {
Scanner::Location* reserved_loc, bool* ok); Scanner::Location* reserved_loc, bool* ok);
void* ParseNamedImports(ZoneList<const AstRawString*>* names, bool* ok); void* ParseNamedImports(ZoneList<const AstRawString*>* names, bool* ok);
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok); Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names, Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool* ok); bool* ok);
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names, Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
......
...@@ -227,6 +227,14 @@ void PreParser::ParseStatementList(int end_token, bool* ok) { ...@@ -227,6 +227,14 @@ void PreParser::ParseStatementList(int end_token, bool* ok) {
PreParser::Statement PreParser::ParseStatement(bool* ok) { PreParser::Statement PreParser::ParseStatement(bool* ok) {
// Statement ::
// EmptyStatement
// ...
return ParseSubStatement(ok);
}
PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
// Statement :: // Statement ::
// Block // Block
// VariableStatement // VariableStatement
...@@ -257,6 +265,12 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) { ...@@ -257,6 +265,12 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
return ParseBlock(ok); return ParseBlock(ok);
case Token::SEMICOLON: case Token::SEMICOLON:
if (is_strong(language_mode())) {
PreParserTraits::ReportMessageAt(scanner()->peek_location(),
"strong_empty");
*ok = false;
return Statement::Default();
}
Next(); Next();
return Statement::Default(); return Statement::Default();
...@@ -550,10 +564,10 @@ PreParser::Statement PreParser::ParseIfStatement(bool* ok) { ...@@ -550,10 +564,10 @@ PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
if (peek() == Token::ELSE) { if (peek() == Token::ELSE) {
Next(); Next();
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
} }
return Statement::Default(); return Statement::Default();
} }
...@@ -636,7 +650,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) { ...@@ -636,7 +650,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
Scope* with_scope = NewScope(scope_, WITH_SCOPE); Scope* with_scope = NewScope(scope_, WITH_SCOPE);
BlockState block_state(&scope_, with_scope); BlockState block_state(&scope_, with_scope);
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
return Statement::Default(); return Statement::Default();
} }
...@@ -678,7 +692,7 @@ PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) { ...@@ -678,7 +692,7 @@ PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
// 'do' Statement 'while' '(' Expression ')' ';' // 'do' Statement 'while' '(' Expression ')' ';'
Expect(Token::DO, CHECK_OK); Expect(Token::DO, CHECK_OK);
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
Expect(Token::WHILE, CHECK_OK); Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
...@@ -696,7 +710,7 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { ...@@ -696,7 +710,7 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseStatement(ok); ParseSubStatement(ok);
return Statement::Default(); return Statement::Default();
} }
...@@ -733,7 +747,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -733,7 +747,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
return Statement::Default(); return Statement::Default();
} }
} else { } else {
...@@ -744,7 +758,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -744,7 +758,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK); ParseSubStatement(CHECK_OK);
return Statement::Default(); return Statement::Default();
} }
} }
...@@ -770,7 +784,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -770,7 +784,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseStatement(ok); ParseSubStatement(ok);
return Statement::Default(); return Statement::Default();
} }
......
...@@ -1566,6 +1566,7 @@ class PreParser : public ParserBase<PreParserTraits> { ...@@ -1566,6 +1566,7 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseStatementListItem(bool* ok); Statement ParseStatementListItem(bool* ok);
void ParseStatementList(int end_token, bool* ok); void ParseStatementList(int end_token, bool* ok);
Statement ParseStatement(bool* ok); Statement ParseStatement(bool* ok);
Statement ParseSubStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok); Statement ParseFunctionDeclaration(bool* ok);
Statement ParseClassDeclaration(bool* ok); Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok); Statement ParseBlock(bool* ok);
......
...@@ -5517,3 +5517,33 @@ TEST(VarForbiddenInStrongMode) { ...@@ -5517,3 +5517,33 @@ TEST(VarForbiddenInStrongMode) {
RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0, RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0,
always_flags, arraysize(always_flags)); always_flags, arraysize(always_flags));
} }
TEST(StrongEmptySubStatements) {
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[] = {
"if (1);",
"if (1) {} else;",
"while (1);",
"do; while (1);",
"for (;;);",
"for (x in []);",
"for (x of []);",
"for (const x = 0;;);",
"for (const x in []);",
"for (const x of []);",
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));
}
// Copyright 2014 the V8 project authors. All rights reserved. // Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
......
// 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 NoEmptySubStatement() {
assertThrows("'use strong'; if (1);", SyntaxError);
assertThrows("'use strong'; if (1) {} else;", SyntaxError);
assertThrows("'use strong'; while (1);", SyntaxError);
assertThrows("'use strong'; do; while (1);", SyntaxError);
assertThrows("'use strong'; for (;;);", SyntaxError);
assertThrows("'use strong'; for (x in []);", SyntaxError);
assertThrows("'use strong'; for (x of []);", SyntaxError);
assertThrows("'use strong'; for (let x;;);", SyntaxError);
assertThrows("'use strong'; for (let x in []);", SyntaxError);
assertThrows("'use strong'; for (let x of []);", SyntaxError);
assertThrows("'use strong'; with ({});", SyntaxError);
})();
// Copyright 2014 the V8 project authors. All rights reserved. // Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
......
// Copyright 2014 the V8 project authors. All rights reserved. // Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
......
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