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