Index: src/parsing/pattern-rewriter.cc |
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc |
index 68eeb6abc553ba9481f67cec18bf8884ca0aaaef..a9875bdf96f60017c8664b39b8d34be0c5f7d041 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,85 @@ void Parser::PatternRewriter::DeclareAndInitializeVariables( |
} |
+void Parser::PatternRewriter::RewriteDestructuringAssignment( |
+ Parser* parser, RewritableAssignmentExpression* to_rewrite, Scope* scope, |
+ bool* ok) { |
+ PatternRewriter rewriter; |
+ |
+ DCHECK(!to_rewrite->is_rewritten()); |
+ |
+ rewriter.scope_ = scope; |
+ rewriter.parser_ = parser; |
+ rewriter.context_ = ASSIGNMENT; |
+ rewriter.pattern_ = to_rewrite; |
+ 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(); |
+ bool is_destructuring_assignment = |
+ node->IsRewritableAssignmentExpression() && |
+ !node->AsRewritableAssignmentExpression()->is_rewritten(); |
+ bool is_assignment = |
+ node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN; |
+ if (is_destructuring_assignment || is_assignment) { |
+ 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 +127,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); |
@@ -68,7 +146,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { |
? descriptor_->scope |
: descriptor_->scope->DeclarationScope(); |
if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { |
- parser->ReportMessage(MessageTemplate::kTooManyVariables); |
+ parser_->ReportMessage(MessageTemplate::kTooManyVariables); |
*ok_ = false; |
return; |
} |
@@ -216,8 +294,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, |
@@ -231,28 +308,97 @@ Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { |
} |
-void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { |
- auto temp = CreateTempVar(current_value_); |
+void Parser::PatternRewriter::VisitRewritableAssignmentExpression( |
+ RewritableAssignmentExpression* node) { |
+ if (!IsAssignmentContext()) { |
+ // Mark the assignment as rewritten to prevent redundant rewriting, and |
+ // perform BindingPattern rewriting |
+ DCHECK(!node->is_rewritten()); |
+ node->Rewrite(node->expression()); |
+ return node->expression()->Accept(this); |
+ } |
- block_->statements()->Add(descriptor_->parser->BuildAssertIsCoercible(temp), |
- zone()); |
+ if (node->is_rewritten()) return; |
+ DCHECK(IsAssignmentContext()); |
+ Assignment* assign = node->expression()->AsAssignment(); |
+ DCHECK_NOT_NULL(assign); |
+ DCHECK_EQ(Token::ASSIGN, assign->op()); |
+ |
+ auto initializer = assign->value(); |
+ auto value = initializer; |
+ |
+ if (IsInitializerContext()) { |
+ // let {<pattern> = <init>} = <value> |
+ // becomes |
+ // temp = <value>; |
+ // <pattern> = temp === undefined ? <init> : temp; |
+ auto temp_var = CreateTempVar(current_value_); |
+ Expression* is_undefined = factory()->NewCompareOperation( |
+ Token::EQ_STRICT, factory()->NewVariableProxy(temp_var), |
+ factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
+ RelocInfo::kNoPosition); |
+ value = factory()->NewConditional(is_undefined, initializer, |
+ factory()->NewVariableProxy(temp_var), |
+ RelocInfo::kNoPosition); |
+ } |
+ |
+ PatternContext old_context = SetAssignmentContextIfNeeded(initializer); |
+ int pos = assign->position(); |
+ Block* old_block = block_; |
+ block_ = factory()->NewBlock(nullptr, 8, false, pos); |
+ Variable* 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->Rewrite(expr); |
+ block_ = old_block; |
+ if (block_) { |
+ block_->statements()->Add(factory()->NewExpressionStatement(expr, pos), |
+ zone()); |
+ } |
+ return set_context(old_context); |
+} |
+ |
+ |
+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( |
+ block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone()); |
+ |
+ auto iterator = CreateTempVar(parser_->GetIterator( |
factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition)); |
auto done = CreateTempVar( |
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition)); |
@@ -266,19 +412,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), |
@@ -315,6 +461,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) { |
@@ -325,7 +472,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()); |
@@ -351,29 +498,58 @@ 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); |
+ DCHECK_EQ(Token::ASSIGN, node->op()); |
+ |
+ 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()) { |
- // TODO(adamk): Only call this if necessary. |
- RewriteParameterInitializerScope( |
- descriptor_->parser->stack_limit(), initializer, |
- descriptor_->scope->outer_scope(), descriptor_->scope); |
+ |
+ if (IsInitializerContext()) { |
+ 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); |
} |
- Expression* value = factory()->NewConditional( |
- is_undefined, initializer, factory()->NewVariableProxy(temp), |
- RelocInfo::kNoPosition); |
+ |
+ if (IsBindingContext() && |
+ descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER && |
+ scope()->is_arrow_scope()) { |
+ RewriteParameterInitializerScope(parser_->stack_limit(), initializer, |
+ scope()->outer_scope(), scope()); |
+ } |
+ |
+ PatternContext old_context = SetAssignmentContextIfNeeded(initializer); |
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()); |
} |
@@ -414,7 +590,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) |