| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index feed1e4b12fcef812309dfe4c4a7870fbcd41a13..f0641d4e84b40a06582c75d264df16b8944277f8 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -1134,13 +1134,18 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
| scope->set_start_position(shared_info->start_position());
|
| FormalParameterErrorLocations error_locs;
|
| bool has_rest = false;
|
| + bool has_initializers = false;
|
| + ZoneList<Expression*>* initializers =
|
| + new (zone()) ZoneList<Expression*>(0, zone());
|
| if (Check(Token::LPAREN)) {
|
| // '(' StrictFormalParameters ')'
|
| - ParseFormalParameterList(scope, &error_locs, &has_rest, &ok);
|
| + ParseFormalParameterList(scope, &error_locs, initializers,
|
| + &has_initializers, &has_rest, &ok);
|
| if (ok) ok = Check(Token::RPAREN);
|
| } else {
|
| // BindingIdentifier
|
| - ParseFormalParameter(scope, &error_locs, has_rest, &ok);
|
| + ParseFormalParameter(scope, &error_locs, nullptr, nullptr, has_rest,
|
| + &ok);
|
| }
|
|
|
| if (ok) {
|
| @@ -1925,7 +1930,8 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name,
|
| }
|
|
|
|
|
| -Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
|
| +Variable* Parser::Declare(Declaration* declaration, bool resolve,
|
| + bool allow_redeclaration, bool* ok) {
|
| VariableProxy* proxy = declaration->proxy();
|
| DCHECK(proxy->raw_name() != NULL);
|
| const AstRawString* name = proxy->raw_name();
|
| @@ -1948,7 +1954,7 @@ Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
|
| declaration_scope->is_script_scope()) {
|
| // Declare the variable in the declaration scope.
|
| var = declaration_scope->LookupLocal(name);
|
| - if (var == NULL) {
|
| + if (var == NULL || allow_redeclaration) {
|
| // Declare the name.
|
| Variable::Kind kind = Variable::NORMAL;
|
| int declaration_group_start = -1;
|
| @@ -1960,9 +1966,16 @@ Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
|
| declaration_group_start =
|
| declaration->AsVariableDeclaration()->declaration_group_start();
|
| }
|
| - var = declaration_scope->DeclareLocal(
|
| - name, mode, declaration->initialization(), kind, kNotAssigned,
|
| - declaration_group_start);
|
| + if (var) {
|
| + DCHECK(declaration_scope->IsDeclaredParameter(name));
|
| + var = declaration_scope->RedeclareLocal(
|
| + name, mode, declaration->initialization(), kind, kNotAssigned,
|
| + declaration_group_start);
|
| + } else {
|
| + var = declaration_scope->DeclareLocal(
|
| + name, mode, declaration->initialization(), kind, kNotAssigned,
|
| + declaration_group_start);
|
| + }
|
| } else if (IsLexicalVariableMode(mode) ||
|
| IsLexicalVariableMode(var->mode()) ||
|
| ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
|
| @@ -3930,9 +3943,9 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
| // VariableProxy and recorded as unresolved in the scope. Here we undo that
|
| // parse-time side-effect.
|
| parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
|
| -
|
| + int pos = expr->AsVariableProxy()->position();
|
| bool is_rest = false;
|
| - bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest);
|
| + bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest, pos);
|
|
|
| if (is_duplicate) {
|
| // Arrow function parameter lists are parsed as StrictFormalParameters,
|
| @@ -3963,6 +3976,98 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
|
| }
|
|
|
|
|
| +ZoneList<Statement*>* Parser::DesugarInitializeParameters(
|
| + Scope* scope, bool has_initializers, ZoneList<Expression*>* initializers) {
|
| + DCHECK(scope->is_function_scope());
|
| +
|
| + ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(0, zone());
|
| + if (has_initializers) {
|
| + for (int i = 0; i < initializers->length(); ++i) {
|
| + Expression* initializer = initializers->at(i);
|
| +
|
| + // Position of parameter VariableProxy, for hole-checking
|
| + int pos = scope->parameter_position(i);
|
| +
|
| + // Lexically declare the initialized variable
|
| + static const VariableMode mode = LET;
|
| + VariableProxy* proxy =
|
| + NewUnresolved(scope->parameter(i)->raw_name(), mode);
|
| + VariableDeclaration* declaration = factory()->NewVariableDeclaration(
|
| + proxy, mode, scope, RelocInfo::kNoPosition);
|
| + // BRITTLE: this illegally redeclares the variable, be careful about this
|
| + proxy =
|
| + factory()->NewVariableProxy(Declare(declaration, true, true), pos);
|
| + proxy->var()->set_maybe_assigned();
|
| +
|
| + const AstRawString* fn_name = ast_value_factory()->empty_string();
|
| + const Runtime::Function* arguments =
|
| + Runtime::FunctionForId(Runtime::kInlineArguments);
|
| + ZoneList<Expression*>* arguments_i0 =
|
| + new (zone()) ZoneList<Expression*>(0, zone());
|
| + arguments_i0->Add(factory()->NewSmiLiteral(i, RelocInfo::kNoPosition),
|
| + zone());
|
| +
|
| + // TODO(caitp): ensure proper TDZ behaviour --- need hole-check for
|
| + // all parameter bindings, including ones without initializers
|
| + if (initializer) {
|
| + // IS_UNDEFINED(%_Arguments(i)) ? <initializer> : %_Arguments(i);
|
| + ZoneList<Expression*>* arguments_i1 =
|
| + new (zone()) ZoneList<Expression*>(0, zone());
|
| + arguments_i1->Add(factory()->NewSmiLiteral(i, RelocInfo::kNoPosition),
|
| + zone());
|
| +
|
| + Expression* arg_or_default = factory()->NewConditional(
|
| + // condition:
|
| + factory()->NewCompareOperation(
|
| + Token::EQ_STRICT,
|
| + factory()->NewCallRuntime(fn_name, arguments, arguments_i0,
|
| + RelocInfo::kNoPosition),
|
| + factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
| + RelocInfo::kNoPosition),
|
| + // if true:
|
| + initializer,
|
| + // if false:
|
| + factory()->NewCallRuntime(fn_name, arguments, arguments_i1,
|
| + RelocInfo::kNoPosition),
|
| + RelocInfo::kNoPosition);
|
| +
|
| + Expression* assign = factory()->NewAssignment(
|
| + Token::INIT_LET, proxy, arg_or_default, RelocInfo::kNoPosition);
|
| +
|
| + body->Add(
|
| + factory()->NewExpressionStatement(assign, RelocInfo::kNoPosition),
|
| + zone());
|
| + proxy->var()->set_initializer_position(initializer->position());
|
| + } else {
|
| + // let <name> = %_Arguments(i)
|
| + Expression* assign = factory()->NewAssignment(
|
| + Token::INIT_LET, proxy,
|
| + factory()->NewCallRuntime(fn_name, arguments, arguments_i0,
|
| + RelocInfo::kNoPosition),
|
| + RelocInfo::kNoPosition);
|
| + body->Add(
|
| + factory()->NewExpressionStatement(assign, RelocInfo::kNoPosition),
|
| + zone());
|
| + proxy->var()->set_initializer_position(pos);
|
| + }
|
| + }
|
| + } else {
|
| + // If hasParameterExpressions is false, remove the unnecessary parameter
|
| + // block scopes. The function body scope can't be safely removed at this
|
| + // point.
|
| + ZoneList<Scope*>* scopes = scope->inner_scopes();
|
| + for (int i = 0; i < scopes->length(); ++i) {
|
| + Scope* scope = scopes->at(i);
|
| + if (!scope->is_function_body_scope()) {
|
| + DCHECK(scope->is_block_scope());
|
| + scope->FinalizeBlockScope();
|
| + }
|
| + }
|
| + }
|
| + return body;
|
| +}
|
| +
|
| +
|
| FunctionLiteral* Parser::ParseFunctionLiteral(
|
| const AstRawString* function_name, Scanner::Location function_name_location,
|
| bool name_is_strict_reserved, FunctionKind kind, int function_token_pos,
|
| @@ -4028,6 +4133,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| declaration_scope != original_declaration_scope)
|
| ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
|
| : NewScope(scope_, FUNCTION_SCOPE, kind);
|
| + Scope* function_body = NewScope(scope, FUNCTION_BODY_SCOPE);
|
| + DCHECK_EQ(scope->function_body(), function_body);
|
| ZoneList<Statement*>* body = NULL;
|
| int materialized_literal_count = -1;
|
| int expected_property_count = -1;
|
| @@ -4042,6 +4149,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| FunctionState function_state(&function_state_, &scope_, scope, kind,
|
| &function_factory);
|
| scope_->SetScopeName(function_name);
|
| + function_body->SetScopeName(function_name);
|
|
|
| if (is_generator) {
|
| // For generators, allocating variables in contexts is currently a win
|
| @@ -4061,8 +4169,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| Expect(Token::LPAREN, CHECK_OK);
|
| int start_position = scanner()->location().beg_pos;
|
| scope_->set_start_position(start_position);
|
| + function_body->set_start_position(start_position);
|
| + ZoneList<Expression*>* initializers =
|
| + new (zone()) ZoneList<Expression*>(0, zone());
|
| + bool has_initializers = false;
|
| num_parameters =
|
| - ParseFormalParameterList(scope, &error_locs, &has_rest, CHECK_OK);
|
| + ParseFormalParameterList(scope, &error_locs, initializers,
|
| + &has_initializers, &has_rest, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
| int formals_end_position = scanner()->location().end_pos;
|
|
|
| @@ -4092,6 +4205,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| VariableProxy* proxy = factory()->NewVariableProxy(fvar);
|
| VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
|
| proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
|
| + DCHECK(scope_->is_function_scope());
|
| scope_->DeclareFunctionVar(fvar_declaration);
|
| }
|
|
|
| @@ -4133,26 +4247,47 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| !parenthesized_function_);
|
| parenthesized_function_ = false; // The bit was set for this function only.
|
|
|
| - if (is_lazily_parsed) {
|
| - for (Scope* s = scope_->outer_scope();
|
| - s != nullptr && (s != s->DeclarationScope()); s = s->outer_scope()) {
|
| - s->ForceContextAllocation();
|
| + {
|
| + // Use the FUNCTION_BODY scope only if it's needed
|
| + // TODO(caitp): This is needed when ObjectBindingPatterns with
|
| + // computed property keys are used as well.
|
| + Scope* func_scope = has_initializers ? function_body : scope_;
|
| + if (func_scope != function_body) {
|
| + function_body->FinalizeBlockScope();
|
| }
|
| - SkipLazyFunctionBody(&materialized_literal_count,
|
| - &expected_property_count, CHECK_OK);
|
| - } else {
|
| - body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
|
| - kind, CHECK_OK);
|
| - materialized_literal_count = function_state.materialized_literal_count();
|
| - expected_property_count = function_state.expected_property_count();
|
| - handler_count = function_state.handler_count();
|
| -
|
| - if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
|
| - if (!function_state.super_location().IsValid()) {
|
| - ReportMessageAt(function_name_location,
|
| - "strong_super_call_missing", kReferenceError);
|
| - *ok = false;
|
| - return nullptr;
|
| +
|
| + if (is_lazily_parsed) {
|
| + for (Scope* s = scope_->outer_scope();
|
| + s != nullptr && (s != s->DeclarationScope());
|
| + s = s->outer_scope()) {
|
| + s->ForceContextAllocation();
|
| + }
|
| + {
|
| + BlockState function_body_state(&scope_, func_scope);
|
| + SkipLazyFunctionBody(&materialized_literal_count,
|
| + &expected_property_count, CHECK_OK);
|
| + }
|
| + } else {
|
| + body =
|
| + DesugarInitializeParameters(scope, has_initializers, initializers);
|
| + {
|
| + BlockState function_body_state(&scope_, func_scope);
|
| + ZoneList<Statement*>* inner_body = ParseEagerFunctionBody(
|
| + function_name, pos, fvar, fvar_init_op, kind, CHECK_OK);
|
| + body->AddAll(*inner_body, zone());
|
| + }
|
| + materialized_literal_count =
|
| + function_state.materialized_literal_count();
|
| + expected_property_count = function_state.expected_property_count();
|
| + handler_count = function_state.handler_count();
|
| +
|
| + if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
|
| + if (!function_state.super_location().IsValid()) {
|
| + ReportMessageAt(function_name_location, "strong_super_call_missing",
|
| + kReferenceError);
|
| + *ok = false;
|
| + return nullptr;
|
| + }
|
| }
|
| }
|
| }
|
| @@ -4244,6 +4379,10 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
|
| return;
|
| }
|
| scope_->set_end_position(logger.end());
|
| + if (scope_->is_function_body_scope()) {
|
| + DCHECK(scope_->outer_scope()->is_function_scope());
|
| + scope_->outer_scope()->set_end_position(scanner()->location().end_pos);
|
| + }
|
| Expect(Token::RBRACE, ok);
|
| if (!*ok) {
|
| return;
|
| @@ -4352,6 +4491,10 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
|
|
| Expect(Token::RBRACE, CHECK_OK);
|
| scope_->set_end_position(scanner()->location().end_pos);
|
| + if (scope_->is_function_body_scope()) {
|
| + DCHECK(scope_->outer_scope()->is_function_scope());
|
| + scope_->outer_scope()->set_end_position(scanner()->location().end_pos);
|
| + }
|
|
|
| return body;
|
| }
|
|
|