Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Unified Diff: src/parsing/pattern-rewriter.cc

Issue 1309813007: [es6] implement destructuring assignment (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase*** oops Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parsing/parser.cc ('k') | src/parsing/preparser.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)
« no previous file with comments | « src/parsing/parser.cc ('k') | src/parsing/preparser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698