Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index 3d94f68ca2e128ef5ea6821f13b2169556b1836f..68be51424cedbfbe8a6d4f9fdef828f5fa8200a2 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -6,6 +6,7 @@ |
| #include "src/api.h" |
| #include "src/ast/ast.h" |
| +#include "src/ast/ast-expression-rewriter.h" |
| #include "src/ast/ast-expression-visitor.h" |
| #include "src/ast/ast-literal-reindexer.h" |
| #include "src/ast/scopeinfo.h" |
| @@ -5411,20 +5412,61 @@ ObjectLiteralProperty* ParserTraits::RewriteNonPatternObjectLiteralProperty( |
| } |
| +class NonPatternRewriter : public AstExpressionRewriter { |
| + public: |
| + NonPatternRewriter(uintptr_t stack_limit, Parser* parser) |
| + : AstExpressionRewriter(stack_limit), parser_(parser) {} |
| + ~NonPatternRewriter() override {} |
| + |
| + private: |
| + bool RewriteExpression(Expression* expr) override { |
| + // Rewrite only what could have been a pattern but is not. |
| + if (expr->IsArrayLiteral()) { |
| + // Spread rewriting in array literals. |
| + ArrayLiteral* lit = expr->AsArrayLiteral(); |
| + VisitExpressions(lit->values()); |
| + replacement_ = parser_->RewriteSpreads(lit); |
| + return false; |
| + } |
| + if (expr->IsObjectLiteral()) { |
| + return true; |
| + } |
| + if (expr->IsBinaryOperation() && |
| + expr->AsBinaryOperation()->op() == Token::COMMA) { |
| + return true; |
| + } |
| + // Everything else does not need rewriting. |
| + return false; |
| + } |
| + |
| + Parser* parser_; |
| +}; |
| + |
| + |
| Expression* Parser::RewriteNonPattern(Expression* expr, |
| const ExpressionClassifier* classifier, |
| bool* ok) { |
| - // For the time being, this does no rewriting at all. |
| ValidateExpression(classifier, ok); |
| - return expr; |
| + if (!*ok) return expr; |
| + NonPatternRewriter rewriter(stack_limit_, this); |
| + Expression* result = reinterpret_cast<Expression*>(rewriter.Rewrite(expr)); |
| + DCHECK_NOT_NULL(result); |
| + return result; |
|
nickie
2016/01/14 16:35:02
This is almost trivial; rewriting happens after va
|
| } |
| ZoneList<Expression*>* Parser::RewriteNonPatternArguments( |
| ZoneList<Expression*>* args, const ExpressionClassifier* classifier, |
| bool* ok) { |
| - // For the time being, this does no rewriting at all. |
| ValidateExpression(classifier, ok); |
| + if (!*ok) return args; |
| + for (int i = 0; i < args->length(); i++) { |
| + NonPatternRewriter rewriter(stack_limit_, this); |
| + Expression* result = |
| + reinterpret_cast<Expression*>(rewriter.Rewrite(args->at(i))); |
| + DCHECK_NOT_NULL(result); |
| + args->Set(i, result); |
| + } |
|
nickie
2016/01/14 16:35:02
This is the only non-trivial addition to this reba
|
| return args; |
| } |
| @@ -5462,6 +5504,125 @@ void Parser::RewriteDestructuringAssignments() { |
| } |
| +Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { |
| + // Array literals containing spreads are rewritten using do expressions, e.g. |
| + // [1, 2, 3, ...x, 4, ...y, 5] |
| + // is roughly rewritten as: |
| + // do { |
| + // $R = [1, 2, 3]; |
| + // for ($i of x) %AppendElement($R, $i); |
| + // %AppendElement($R, 4); |
| + // for ($j of y) %AppendElement($R, $j); |
| + // %AppendElement($R, 5); |
| + // $R |
| + // } |
| + // where $R, $i and $j are fresh temporary variables. |
| + ZoneList<Expression*>::iterator s = lit->FirstSpread(); |
| + if (s == lit->EndValue()) return nullptr; // no spread, no rewriting... |
| + Variable* result = |
| + scope_->NewTemporary(ast_value_factory()->dot_result_string()); |
| + // NOTE: The value assigned to R is the whole original array literal, |
| + // spreads included. This will be fixed before the rewritten AST is returned. |
| + // $R = lit |
| + Expression* init_result = |
| + factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(result), |
| + lit, RelocInfo::kNoPosition); |
| + Block* do_block = |
| + factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition); |
| + do_block->statements()->Add( |
| + factory()->NewExpressionStatement(init_result, RelocInfo::kNoPosition), |
| + zone()); |
| + // Traverse the array literal starting from the first spread. |
| + while (s != lit->EndValue()) { |
| + Expression* value = *s++; |
| + Spread* spread = value->AsSpread(); |
| + if (spread == nullptr) { |
| + // If the element is not a spread, we're adding a single: |
| + // %AppendElement($R, value) |
| + ZoneList<Expression*>* append_element_args = NewExpressionList(2, zone()); |
| + append_element_args->Add(factory()->NewVariableProxy(result), zone()); |
| + append_element_args->Add(value, zone()); |
| + do_block->statements()->Add( |
| + factory()->NewExpressionStatement( |
| + factory()->NewCallRuntime(Runtime::kAppendElement, |
| + append_element_args, |
| + RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition), |
| + zone()); |
| + } else { |
| + // If it's a spread, we're adding a for/of loop iterating through it. |
| + Variable* each = |
| + scope_->NewTemporary(ast_value_factory()->dot_for_string()); |
| + Expression* subject = spread->expression(); |
| + Variable* iterator = |
| + scope_->NewTemporary(ast_value_factory()->dot_iterator_string()); |
| + Variable* element = |
| + scope_->NewTemporary(ast_value_factory()->dot_result_string()); |
| + // iterator = subject[Symbol.iterator]() |
| + Expression* assign_iterator = factory()->NewAssignment( |
| + Token::ASSIGN, factory()->NewVariableProxy(iterator), |
| + GetIterator(subject, factory(), spread->expression_position()), |
| + subject->position()); |
| + // !%_IsJSReceiver(element = iterator.next()) && |
| + // %ThrowIteratorResultNotAnObject(element) |
| + Expression* next_element; |
| + { |
| + // element = iterator.next() |
| + Expression* iterator_proxy = factory()->NewVariableProxy(iterator); |
| + next_element = BuildIteratorNextResult(iterator_proxy, element, |
| + spread->expression_position()); |
| + } |
| + // element.done |
| + Expression* element_done; |
| + { |
| + Expression* done_literal = factory()->NewStringLiteral( |
| + ast_value_factory()->done_string(), RelocInfo::kNoPosition); |
| + Expression* element_proxy = factory()->NewVariableProxy(element); |
| + element_done = factory()->NewProperty(element_proxy, done_literal, |
| + RelocInfo::kNoPosition); |
| + } |
| + // each = element.value |
| + Expression* assign_each; |
| + { |
| + Expression* value_literal = factory()->NewStringLiteral( |
| + ast_value_factory()->value_string(), RelocInfo::kNoPosition); |
| + Expression* element_proxy = factory()->NewVariableProxy(element); |
| + Expression* element_value = factory()->NewProperty( |
| + element_proxy, value_literal, RelocInfo::kNoPosition); |
| + assign_each = factory()->NewAssignment( |
| + Token::ASSIGN, factory()->NewVariableProxy(each), element_value, |
| + RelocInfo::kNoPosition); |
| + } |
| + // %AppendElement($R, each) |
| + Statement* append_body; |
| + { |
| + ZoneList<Expression*>* append_element_args = |
| + NewExpressionList(2, zone()); |
| + append_element_args->Add(factory()->NewVariableProxy(result), zone()); |
| + append_element_args->Add(factory()->NewVariableProxy(each), zone()); |
| + append_body = factory()->NewExpressionStatement( |
| + factory()->NewCallRuntime(Runtime::kAppendElement, |
| + append_element_args, |
| + RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition); |
| + } |
| + // for (each of spread) %AppendElement($R, each) |
| + ForEachStatement* loop = factory()->NewForEachStatement( |
| + ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition); |
| + ForOfStatement* for_of = loop->AsForOfStatement(); |
| + for_of->Initialize(factory()->NewVariableProxy(each), subject, |
| + append_body, assign_iterator, next_element, |
| + element_done, assign_each); |
| + do_block->statements()->Add(for_of, zone()); |
| + } |
| + } |
| + // Now, rewind the original array literal to truncate everything from the |
| + // first spread (included) until the end. This fixes $R's initialization. |
| + lit->RewindSpreads(); |
| + return factory()->NewDoExpression(do_block, result, lit->position()); |
| +} |
| + |
| + |
| void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) { |
| DCHECK(expr->IsRewritableAssignmentExpression()); |
| parser_->function_state_->AddDestructuringAssignment( |