Chromium Code Reviews| Index: src/parsing/pattern-rewriter.cc |
| diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc |
| index 037e96b86d769d85bfbc9ada048e304c6a3f5b7a..09688e9d62886e53e3d8337b2c3790141f0e76a0 100644 |
| --- a/src/parsing/pattern-rewriter.cc |
| +++ b/src/parsing/pattern-rewriter.cc |
| @@ -11,13 +11,15 @@ namespace v8 { |
| namespace internal { |
| - |
| void Parser::PatternRewriter::DeclareAndInitializeVariables( |
| Block* block, const DeclarationDescriptor* declaration_descriptor, |
| const DeclarationParsingResult::Declaration* declaration, |
| ZoneList<const AstRawString*>* names, bool* ok) { |
| PatternRewriter rewriter; |
| + rewriter.scope_ = declaration_descriptor->scope; |
| + rewriter.parser_ = declaration_descriptor->parser; |
| + rewriter.context_ = BINDING; |
| rewriter.pattern_ = declaration->pattern; |
| rewriter.initializer_position_ = declaration->initializer_position; |
| rewriter.block_ = block; |
| @@ -29,8 +31,80 @@ void Parser::PatternRewriter::DeclareAndInitializeVariables( |
| } |
| +void Parser::PatternRewriter::RewriteDestructuringAssignment( |
| + Parser* parser, RewritableExpression* rw, Scope* scope, bool* ok) { |
| + PatternRewriter rewriter; |
| + |
| + DCHECK(assignment->IsRewritableAs( |
| + RewritableExpression::kDestructuringAssignment)); |
| + |
| + rewriter.scope_ = scope; |
| + rewriter.parser_ = parser; |
| + rewriter.context_ = ASSIGNMENT; |
| + rewriter.pattern_ = rw; |
| + rewriter.block_ = nullptr; |
| + rewriter.descriptor_ = nullptr; |
| + rewriter.names_ = nullptr; |
| + rewriter.ok_ = ok; |
| + |
| + rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr); |
| +} |
| + |
| + |
| +bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const { |
| + return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER; |
| +} |
| + |
| + |
| +bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const { |
| + return c == BINDING || c == INITIALIZER; |
| +} |
| + |
| + |
| +Parser::PatternRewriter::PatternContext |
| +Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) { |
| + PatternContext old_context = context(); |
| + if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN) { |
| + set_context(ASSIGNMENT); |
| + } |
| + return old_context; |
| +} |
| + |
| + |
| +Parser::PatternRewriter::PatternContext |
| +Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) { |
| + // Set appropriate initializer context for BindingElement and |
| + // AssignmentElement nodes |
| + PatternContext old_context = context(); |
| + if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN) { |
| + switch (old_context) { |
| + case BINDING: |
| + set_context(INITIALIZER); |
| + break; |
| + case ASSIGNMENT: |
| + set_context(ASSIGNMENT_INITIALIZER); |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + return old_context; |
| +} |
| + |
| + |
| void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { |
| Expression* value = current_value_; |
| + |
| + if (IsAssignmentContext()) { |
| + // In an assignment context, simply perform the assignment |
| + Assignment* assignment = factory()->NewAssignment( |
| + Token::ASSIGN, pattern, value, pattern->position()); |
| + block_->statements()->Add( |
| + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
| + zone()); |
| + return; |
| + } |
| + |
| descriptor_->scope->RemoveUnresolved(pattern); |
| // Declare variable. |
| @@ -48,15 +122,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { |
| // For let/const declarations in harmony mode, we can also immediately |
| // pre-resolve the proxy because it resides in the same scope as the |
| // declaration. |
| - Parser* parser = descriptor_->parser; |
| const AstRawString* name = pattern->raw_name(); |
| - VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode); |
| + VariableProxy* proxy = parser_->NewUnresolved(name, descriptor_->mode); |
| Declaration* declaration = factory()->NewVariableDeclaration( |
| proxy, descriptor_->mode, descriptor_->scope, |
| descriptor_->declaration_pos); |
| - Variable* var = parser->Declare(declaration, descriptor_->declaration_kind, |
| - descriptor_->mode != VAR, ok_, |
| - descriptor_->hoist_scope); |
| + Variable* var = |
| + parser_->Declare(declaration, descriptor_->declaration_kind, |
| + descriptor_->mode != VAR, ok_, descriptor_->hoist_scope); |
| if (!*ok_) return; |
| DCHECK_NOT_NULL(var); |
| DCHECK(!proxy->is_resolved() || proxy->var() == var); |
| @@ -66,7 +139,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { |
| if (descriptor_->declaration_scope->num_var_or_const() > |
| kMaxNumFunctionLocals) { |
| - parser->ReportMessage(MessageTemplate::kTooManyVariables); |
| + parser_->ReportMessage(MessageTemplate::kTooManyVariables); |
| *ok_ = false; |
| return; |
| } |
| @@ -214,8 +287,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { |
| Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { |
| - auto temp = descriptor_->parser->scope_->NewTemporary( |
| - ast_value_factory()->empty_string()); |
| + auto temp = scope()->NewTemporary(ast_value_factory()->empty_string()); |
| if (value != nullptr) { |
| auto assignment = factory()->NewAssignment( |
| Token::ASSIGN, factory()->NewVariableProxy(temp), value, |
| @@ -229,29 +301,93 @@ Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { |
| } |
| -void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { |
| - auto temp = CreateTempVar(current_value_); |
| +void Parser::PatternRewriter::VisitRewritableExpression( |
| + RewritableExpression* node) { |
| + if (IsAssignmentContext() && |
| + node->IsRewritableAs(RewritableExpression::kDestructuringAssignment)) { |
| + Assignment* assign = node->expression()->AsAssignment(); |
| + DCHECK_NOT_NULL(assign); |
| + DCHECK_EQ(Token::ASSIGN, assign->op()); |
| + |
| + auto initializer = assign->value(); |
| + auto value = initializer; |
| + auto temp = CreateTempVar(current_value_); |
| + |
| + if (IsInitializerContext()) { |
| + // let {<pattern> = <init>} = <value> |
| + // becomes |
| + // temp = <value>; |
| + // <pattern> = temp === undefined ? <init> : temp; |
| + Expression* is_undefined = factory()->NewCompareOperation( |
| + Token::EQ_STRICT, factory()->NewVariableProxy(temp), |
| + factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition); |
| + value = factory()->NewConditional(is_undefined, initializer, |
| + factory()->NewVariableProxy(temp), |
| + RelocInfo::kNoPosition); |
| + } |
| - block_->statements()->Add(descriptor_->parser->BuildAssertIsCoercible(temp), |
| - zone()); |
| + PatternContext old_context = SetAssignmentContextIfNeeded(initializer); |
| + int pos = assign->position(); |
| + Block* old_block = block_; |
| + block_ = factory()->NewBlock(nullptr, 8, false, pos); |
| + temp = nullptr; |
| + Expression* pattern = assign->target(); |
| + Expression* old_value = current_value_; |
| + current_value_ = value; |
| + if (pattern->IsObjectLiteral()) { |
| + VisitObjectLiteral(pattern->AsObjectLiteral(), &temp); |
| + } else { |
| + DCHECK(pattern->IsArrayLiteral()); |
| + VisitArrayLiteral(pattern->AsArrayLiteral(), &temp); |
| + } |
| + DCHECK_NOT_NULL(temp); |
| + current_value_ = old_value; |
| + Expression* expr = factory()->NewDoExpression(block_, temp, pos); |
| + node->RewriteAs(expr, RewritableExpression::kDestructuringAssignment); |
| + block_ = old_block; |
| + if (block_) { |
| + block_->statements()->Add(factory()->NewExpressionStatement(expr, pos), |
| + zone()); |
| + } |
| + return set_context(old_context); |
| + } |
| + |
| + return Visit(node->expression()); |
|
adamk
2015/12/01 22:42:57
I'd move this to the top and early return, letting
|
| +} |
| + |
| + |
| +void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern, |
| + Variable** temp_var) { |
| + auto temp = *temp_var = CreateTempVar(current_value_); |
| + |
| + block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone()); |
| for (ObjectLiteralProperty* property : *pattern->properties()) { |
| + PatternContext context = SetInitializerContextIfNeeded(property->value()); |
| RecurseIntoSubpattern( |
| property->value(), |
| factory()->NewProperty(factory()->NewVariableProxy(temp), |
| property->key(), RelocInfo::kNoPosition)); |
| + set_context(context); |
| } |
| } |
| -void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| - auto temp = CreateTempVar(current_value_); |
| +void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) { |
| + Variable* temp_var = nullptr; |
| + VisitObjectLiteral(node, &temp_var); |
| +} |
| + |
| - block_->statements()->Add(descriptor_->parser->BuildAssertIsCoercible(temp), |
| - zone()); |
| +void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, |
| + Variable** temp_var) { |
| + auto temp = *temp_var = CreateTempVar(current_value_); |
| - auto iterator = CreateTempVar(descriptor_->parser->GetIterator( |
| - factory()->NewVariableProxy(temp), factory())); |
| + block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone()); |
| + |
| + auto iterator = CreateTempVar( |
| + parser_->GetIterator(factory()->NewVariableProxy(temp), factory())); |
| auto done = CreateTempVar( |
| factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition)); |
| auto result = CreateTempVar(); |
| @@ -264,19 +400,19 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| break; |
| } |
| + PatternContext context = SetInitializerContextIfNeeded(value); |
| // if (!done) { |
| // result = IteratorNext(iterator); |
| // v = (done = result.done) ? undefined : result.value; |
| // } |
| auto next_block = |
| factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition); |
| - next_block->statements()->Add( |
| - factory()->NewExpressionStatement( |
| - descriptor_->parser->BuildIteratorNextResult( |
| - factory()->NewVariableProxy(iterator), result, |
| - RelocInfo::kNoPosition), |
| - RelocInfo::kNoPosition), |
| - zone()); |
| + next_block->statements()->Add(factory()->NewExpressionStatement( |
| + parser_->BuildIteratorNextResult( |
| + factory()->NewVariableProxy(iterator), |
| + result, RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition), |
| + zone()); |
| auto assign_to_done = factory()->NewAssignment( |
| Token::ASSIGN, factory()->NewVariableProxy(done), |
| @@ -313,6 +449,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) { |
| RecurseIntoSubpattern(value, factory()->NewVariableProxy(v)); |
| } |
| + set_context(context); |
| } |
| if (spread != nullptr) { |
| @@ -323,7 +460,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| empty_exprs, |
| // Reuse pattern's literal index - it is unused since there is no |
| // actual literal allocated. |
| - node->literal_index(), is_strong(descriptor_->parser->language_mode()), |
| + node->literal_index(), is_strong(scope()->language_mode()), |
| RelocInfo::kNoPosition)); |
| auto arguments = new (zone()) ZoneList<Expression*>(2, zone()); |
| @@ -349,29 +486,57 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| } |
| +void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) { |
| + Variable* temp_var = nullptr; |
| + VisitArrayLiteral(node, &temp_var); |
| +} |
| + |
| + |
| void Parser::PatternRewriter::VisitAssignment(Assignment* node) { |
| - // let {<pattern> = <init>} = <value> |
| - // becomes |
| - // temp = <value>; |
| - // <pattern> = temp === undefined ? <init> : temp; |
| - DCHECK(node->op() == Token::ASSIGN); |
| + auto initializer = node->value(); |
| + auto value = initializer; |
| auto temp = CreateTempVar(current_value_); |
| - Expression* is_undefined = factory()->NewCompareOperation( |
| - Token::EQ_STRICT, factory()->NewVariableProxy(temp), |
| - factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
| - RelocInfo::kNoPosition); |
| - Expression* initializer = node->value(); |
| - if (descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER && |
| - descriptor_->scope->is_arrow_scope()) { |
| + |
| + if (IsInitializerContext()) { |
| + // let {<pattern> = <init>} = <value> |
| + // becomes |
| + // temp = <value>; |
| + // <pattern> = temp === undefined ? <init> : temp; |
| + Expression* is_undefined = factory()->NewCompareOperation( |
| + Token::EQ_STRICT, factory()->NewVariableProxy(temp), |
| + factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition); |
| + value = factory()->NewConditional(is_undefined, initializer, |
| + factory()->NewVariableProxy(temp), |
| + RelocInfo::kNoPosition); |
| + } |
| + |
| + PatternContext old_context = SetAssignmentContextIfNeeded(initializer); |
| + DCHECK(node->op() == Token::ASSIGN); |
| + if (IsBindingContext(old_context) && |
| + descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER && |
| + scope()->is_arrow_scope()) { |
| // TODO(adamk): Only call this if necessary. |
| - RewriteParameterInitializerScope( |
| - descriptor_->parser->stack_limit(), initializer, |
| - descriptor_->scope->outer_scope(), descriptor_->scope); |
| + RewriteParameterInitializerScope(parser_->stack_limit(), initializer, |
| + scope()->outer_scope(), scope()); |
| } |
| - Expression* value = factory()->NewConditional( |
| - is_undefined, initializer, factory()->NewVariableProxy(temp), |
| - RelocInfo::kNoPosition); |
| RecurseIntoSubpattern(node->target(), value); |
| + set_context(old_context); |
| +} |
| + |
| + |
| +// =============== AssignmentPattern only ================== |
| + |
| +void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) { |
| + DCHECK(IsAssignmentContext()); |
| + auto value = current_value_; |
| + |
| + Assignment* assignment = |
| + factory()->NewAssignment(Token::ASSIGN, node, value, node->position()); |
| + |
| + block_->statements()->Add( |
| + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
| + zone()); |
| } |
| @@ -412,7 +577,6 @@ NOT_A_PATTERN(IfStatement) |
| NOT_A_PATTERN(ImportDeclaration) |
| NOT_A_PATTERN(Literal) |
| NOT_A_PATTERN(NativeFunctionLiteral) |
| -NOT_A_PATTERN(Property) |
| NOT_A_PATTERN(RegExpLiteral) |
| NOT_A_PATTERN(ReturnStatement) |
| NOT_A_PATTERN(SloppyBlockFunctionStatement) |