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"],
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"],
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
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);
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);
}
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);
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);
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;
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);
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;
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);
}
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) {
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,
PreParser::Statement PreParser::ParseStatement(bool* ok) {
// Statement ::
+ // EmptyStatement
+ // ...
+ return ParseSubStatement(ok);
+}
+
+
+PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
+ // Statement ::
// Block
// VariableStatement
// EmptyStatement
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();
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();
}
Scope* with_scope = NewScope(scope_, WITH_SCOPE);
BlockState block_state(&scope_, with_scope);
- ParseStatement(CHECK_OK);
+ ParseSubStatement(CHECK_OK);
return Statement::Default();
}
// '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);
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- ParseStatement(ok);
+ ParseSubStatement(ok);
return Statement::Default();
}
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
+ ParseSubStatement(CHECK_OK);
return Statement::Default();
}
} else {
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
+ ParseSubStatement(CHECK_OK);
return Statement::Default();
}
}
}
Expect(Token::RPAREN, CHECK_OK);
- ParseStatement(ok);
+ ParseSubStatement(ok);
return Statement::Default();
}
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);
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.
--- /dev/null
+// 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.