Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 36c966110b2f432202993592a552d3c46bc3e0fb..0511569ffd184dd4f2ab45d233130bba5ef06b1b 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -774,6 +774,8 @@ Parser::Parser(ParseInfo* info) |
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); |
set_allow_harmony_function_name(FLAG_harmony_function_name); |
set_allow_harmony_function_sent(FLAG_harmony_function_sent); |
+ set_allow_harmony_restrictive_declarations( |
+ FLAG_harmony_restrictive_declarations); |
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
++feature) { |
use_counts_[feature] = 0; |
@@ -1839,26 +1841,18 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, |
case Token::SWITCH: |
return ParseSwitchStatement(labels, ok); |
- case Token::FUNCTION: { |
- // FunctionDeclaration is only allowed in the context of SourceElements |
- // (Ecma 262 5th Edition, clause 14): |
- // SourceElement: |
- // Statement |
- // FunctionDeclaration |
- // Common language extension is to allow function declaration in place |
- // of any statement. This language extension is disabled in strict mode. |
- // |
- // In Harmony mode, this case also handles the extension: |
- // Statement: |
- // GeneratorDeclaration |
- if (is_strict(language_mode())) { |
- ReportMessageAt(scanner()->peek_location(), |
- MessageTemplate::kStrictFunction); |
- *ok = false; |
- return NULL; |
- } |
- return ParseFunctionDeclaration(NULL, ok); |
- } |
+ case Token::FUNCTION: |
+ // FunctionDeclaration only allowed as a StatementListItem, not in |
+ // an arbitrary Statement position. Exceptions such as |
+ // ES#sec-functiondeclarations-in-ifstatement-statement-clauses |
+ // are handled by calling ParseScopedStatement rather than |
+ // ParseSubStatement directly. |
+ ReportMessageAt(scanner()->peek_location(), |
+ is_strict(language_mode()) |
+ ? MessageTemplate::kStrictFunction |
+ : MessageTemplate::kSloppyFunction); |
+ *ok = false; |
+ return nullptr; |
case Token::DEBUGGER: |
return ParseDebuggerStatement(ok); |
@@ -2581,6 +2575,10 @@ Statement* Parser::ParseExpressionOrLabelledStatement( |
// during the scope processing. |
scope_->RemoveUnresolved(var); |
Expect(Token::COLON, CHECK_OK); |
+ // ES#sec-labelled-function-declarations Labelled Function Declarations |
+ if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { |
+ return ParseFunctionDeclaration(labels, ok); |
+ } |
return ParseStatement(labels, ok); |
} |
@@ -2621,11 +2619,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 = ParseSubStatement(labels, CHECK_OK); |
+ Statement* then_statement = ParseScopedStatement(labels, false, CHECK_OK); |
Statement* else_statement = NULL; |
if (peek() == Token::ELSE) { |
Next(); |
- else_statement = ParseSubStatement(labels, CHECK_OK); |
+ else_statement = ParseScopedStatement(labels, false, CHECK_OK); |
} else { |
else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
} |
@@ -2824,25 +2822,10 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, |
scope_->DeclarationScope()->RecordWithStatement(); |
Scope* with_scope = NewScope(scope_, WITH_SCOPE); |
- Block* body; |
+ Statement* body; |
{ BlockState block_state(&scope_, with_scope); |
with_scope->set_start_position(scanner()->peek_location().beg_pos); |
- |
- // The body of the with statement must be enclosed in an additional |
- // lexical scope in case the body is a FunctionDeclaration. |
- body = factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition); |
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); |
- block_scope->set_start_position(scanner()->location().beg_pos); |
- { |
- BlockState block_state(&scope_, block_scope); |
- Target target(&this->target_stack_, body); |
- Statement* stmt = ParseSubStatement(labels, CHECK_OK); |
- body->statements()->Add(stmt, zone()); |
- block_scope->set_end_position(scanner()->location().end_pos); |
- block_scope = block_scope->FinalizeBlockScope(); |
- body->set_scope(block_scope); |
- } |
- |
+ body = ParseScopedStatement(labels, true, CHECK_OK); |
with_scope->set_end_position(scanner()->location().end_pos); |
} |
return factory()->NewWithStatement(with_scope, expr, body, pos); |
@@ -3183,7 +3166,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement( |
Target target(&this->target_stack_, loop); |
Expect(Token::DO, CHECK_OK); |
- Statement* body = ParseSubStatement(NULL, CHECK_OK); |
+ Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); |
Expect(Token::WHILE, CHECK_OK); |
Expect(Token::LPAREN, CHECK_OK); |
@@ -3213,7 +3196,7 @@ WhileStatement* Parser::ParseWhileStatement( |
Expect(Token::LPAREN, CHECK_OK); |
Expression* cond = ParseExpression(true, CHECK_OK); |
Expect(Token::RPAREN, CHECK_OK); |
- Statement* body = ParseSubStatement(NULL, CHECK_OK); |
+ Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); |
if (loop != NULL) loop->Initialize(cond, body); |
return loop; |
@@ -3595,6 +3578,28 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
return outer_block; |
} |
+Statement* Parser::ParseScopedStatement(ZoneList<const AstRawString*>* labels, |
+ bool legacy, bool* ok) { |
+ if (is_strict(language_mode()) || peek() != Token::FUNCTION || |
+ (legacy && allow_harmony_restrictive_declarations())) { |
+ return ParseSubStatement(labels, ok); |
+ } else { |
+ if (legacy) { |
+ ++use_counts_[v8::Isolate::kLegacyFunctionDeclaration]; |
+ } |
+ // Make a block around the statement for a lexical binding |
+ // is introduced by a FunctionDeclaration. |
+ Scope* body_scope = NewScope(scope_, BLOCK_SCOPE); |
+ BlockState block_state(&scope_, body_scope); |
+ Block* block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); |
+ Statement* body = ParseFunctionDeclaration(NULL, CHECK_OK); |
+ block->statements()->Add(body, zone()); |
+ body_scope->set_end_position(scanner()->location().end_pos); |
+ body_scope = body_scope->FinalizeBlockScope(); |
+ block->set_scope(body_scope); |
+ return block; |
+ } |
+} |
Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
bool* ok) { |
@@ -3708,7 +3713,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
{ |
BlockState block_state(&scope_, body_scope); |
- Statement* body = ParseSubStatement(NULL, CHECK_OK); |
+ Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); |
auto each_initialization_block = |
factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); |
@@ -3825,25 +3830,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
Expect(Token::RPAREN, CHECK_OK); |
- // Make a block around the statement in case a lexical binding |
- // is introduced, e.g. by a FunctionDeclaration. |
- // This block must not use for_scope as its scope because if a |
- // lexical binding is introduced which overlaps with the for-in/of, |
- // expressions in head of the loop should actually have variables |
- // resolved in the outer scope. |
- Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE); |
- { |
- BlockState block_state(&scope_, body_scope); |
- Block* block = |
- factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); |
- Statement* body = ParseSubStatement(NULL, CHECK_OK); |
- block->statements()->Add(body, zone()); |
- InitializeForEachStatement(loop, expression, enumerable, block, |
- is_destructuring); |
- body_scope->set_end_position(scanner()->location().end_pos); |
- body_scope = body_scope->FinalizeBlockScope(); |
- block->set_scope(body_scope); |
- } |
+ // For legacy compat reasons, give for loops similar treatment to |
+ // if statements in allowing a function declaration for a body |
+ Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); |
+ InitializeForEachStatement(loop, expression, enumerable, body, |
+ is_destructuring); |
Statement* final_loop = loop->IsForOfStatement() |
? FinalizeForOfStatement( |
@@ -3900,7 +3891,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
} |
Expect(Token::RPAREN, CHECK_OK); |
- body = ParseSubStatement(NULL, CHECK_OK); |
+ body = ParseScopedStatement(NULL, true, CHECK_OK); |
} |
Statement* result = NULL; |