| 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;
|
|
|