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 = {
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_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"],
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"],
......@@ -179,7 +181,6 @@ var kMessages = {
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"],
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."],
duplicate_proto: ["Duplicate __proto__ fields are not allowed in object literals"],
param_after_rest: ["Rest parameter must be last formal parameter"],
......
......@@ -1642,6 +1642,20 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// 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
// VariableStatement
// EmptyStatement
......@@ -1669,6 +1683,11 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseBlock(labels, ok);
case Token::SEMICOLON:
if (is_strong(language_mode())) {
ReportMessageAt(scanner()->peek_location(), "strong_empty");
*ok = false;
return NULL;
}
Next();
return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
......@@ -2535,11 +2554,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::LPAREN, CHECK_OK);
Expression* condition = ParseExpression(true, 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;
if (peek() == Token::ELSE) {
Next();
else_statement = ParseStatement(labels, CHECK_OK);
else_statement = ParseSubStatement(labels, CHECK_OK);
} else {
else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
}
......@@ -2684,7 +2703,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Statement* stmt;
{ BlockState block_state(&scope_, with_scope);
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);
}
return factory()->NewWithStatement(with_scope, expr, stmt, pos);
......@@ -2869,7 +2888,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(
Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
......@@ -2899,7 +2918,7 @@ WhileStatement* Parser::ParseWhileStatement(
Expect(Token::LPAREN, CHECK_OK);
Expression* cond = ParseExpression(true, 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);
return loop;
......@@ -3262,7 +3281,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
VariableProxy* each =
scope_->NewUnresolved(factory(), name, interface, each_pos);
Statement* body = ParseStatement(NULL, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, each, enumerable, body);
Block* result =
factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
......@@ -3321,7 +3340,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
VariableProxy* each = scope_->NewUnresolved(
factory(), name, Interface::NewValue(), each_pos);
Statement* body = ParseStatement(NULL, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN;
......@@ -3364,7 +3383,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expression* enumerable = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
InitializeForEachStatement(loop, expression, enumerable, body);
scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos);
......@@ -3416,7 +3435,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
Statement* result = NULL;
if (let_bindings.length() > 0) {
......
......@@ -715,6 +715,7 @@ class Parser : public ParserBase<ParserTraits> {
Scanner::Location* reserved_loc, bool* ok);
void* ParseNamedImports(ZoneList<const AstRawString*>* names, bool* ok);
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
......
......@@ -227,6 +227,14 @@ void PreParser::ParseStatementList(int end_token, bool* ok) {
PreParser::Statement PreParser::ParseStatement(bool* ok) {
// Statement ::
// EmptyStatement
// ...
return ParseSubStatement(ok);
}
PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
// Statement ::
// Block
// VariableStatement
......@@ -257,6 +265,12 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
return ParseBlock(ok);
case Token::SEMICOLON:
if (is_strong(language_mode())) {
PreParserTraits::ReportMessageAt(scanner()->peek_location(),
"strong_empty");
*ok = false;
return Statement::Default();
}
Next();
return Statement::Default();
......@@ -550,10 +564,10 @@ PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
if (peek() == Token::ELSE) {
Next();
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
}
return Statement::Default();
}
......@@ -636,7 +650,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
Scope* with_scope = NewScope(scope_, WITH_SCOPE);
BlockState block_state(&scope_, with_scope);
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
return Statement::Default();
}
......@@ -678,7 +692,7 @@ PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
// 'do' Statement 'while' '(' Expression ')' ';'
Expect(Token::DO, CHECK_OK);
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
......@@ -696,7 +710,7 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ParseStatement(ok);
ParseSubStatement(ok);
return Statement::Default();
}
......@@ -733,7 +747,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
return Statement::Default();
}
} else {
......@@ -744,7 +758,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
ParseSubStatement(CHECK_OK);
return Statement::Default();
}
}
......@@ -770,7 +784,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
}
Expect(Token::RPAREN, CHECK_OK);
ParseStatement(ok);
ParseSubStatement(ok);
return Statement::Default();
}
......
......@@ -1566,6 +1566,7 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseStatementListItem(bool* ok);
void ParseStatementList(int end_token, bool* ok);
Statement ParseStatement(bool* ok);
Statement ParseSubStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
......
......@@ -5517,3 +5517,33 @@ TEST(VarForbiddenInStrongMode) {
RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0,
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
// 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
// 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
// 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