Commit 7f6ae230 authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Adapting PatternRewriter to work in C-style for-statements.

BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1128043006

Cr-Commit-Position: refs/heads/master@{#28417}
parent bc9e5340
...@@ -959,7 +959,6 @@ source_set("v8_base") { ...@@ -959,7 +959,6 @@ source_set("v8_base") {
"src/ostreams.cc", "src/ostreams.cc",
"src/ostreams.h", "src/ostreams.h",
"src/pattern-rewriter.cc", "src/pattern-rewriter.cc",
"src/pattern-rewriter.h",
"src/parser.cc", "src/parser.cc",
"src/parser.h", "src/parser.h",
"src/pending-compilation-error-handler.cc", "src/pending-compilation-error-handler.cc",
......
...@@ -3352,6 +3352,7 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3352,6 +3352,7 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable::Kind variable_kind, Variable::Kind variable_kind,
int start_position = RelocInfo::kNoPosition, int start_position = RelocInfo::kNoPosition,
int end_position = RelocInfo::kNoPosition) { int end_position = RelocInfo::kNoPosition) {
DCHECK_NOT_NULL(name);
return new (zone_) return new (zone_)
VariableProxy(zone_, name, variable_kind, start_position, end_position); VariableProxy(zone_, name, variable_kind, start_position, end_position);
} }
......
This diff is collapsed.
...@@ -871,7 +871,6 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -871,7 +871,6 @@ class Parser : public ParserBase<ParserTraits> {
private: private:
friend class ParserTraits; friend class ParserTraits;
class PatternRewriter;
// Limit the allowed number of local variables in a function. The hard limit // Limit the allowed number of local variables in a function. The hard limit
// is that offsets computed by FullCodeGenerator::StackOperand and similar // is that offsets computed by FullCodeGenerator::StackOperand and similar
...@@ -940,12 +939,91 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -940,12 +939,91 @@ class Parser : public ParserBase<ParserTraits> {
Block* ParseVariableStatement(VariableDeclarationContext var_context, Block* ParseVariableStatement(VariableDeclarationContext var_context,
ZoneList<const AstRawString*>* names, ZoneList<const AstRawString*>* names,
bool* ok); bool* ok);
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
int* num_decl, struct DeclarationDescriptor {
ZoneList<const AstRawString*>* names, Parser* parser;
const AstRawString** out, Scope* declaration_scope;
Scanner::Location* first_initializer_loc, Scope* scope;
Scanner::Location* bindings_loc, bool* ok); VariableMode mode;
bool is_const;
bool needs_init;
int pos;
Token::Value init_op;
};
struct DeclarationParsingResult {
struct Declaration {
Declaration(Expression* pattern, int initializer_position,
Expression* initializer)
: pattern(pattern),
initializer_position(initializer_position),
initializer(initializer) {}
Expression* pattern;
int initializer_position;
Expression* initializer;
};
DeclarationParsingResult()
: declarations(4),
first_initializer_loc(Scanner::Location::invalid()),
bindings_loc(Scanner::Location::invalid()) {}
Block* BuildInitializationBlock(ZoneList<const AstRawString*>* names,
bool* ok);
const AstRawString* SingleName() const;
DeclarationDescriptor descriptor;
List<Declaration> declarations;
Scanner::Location first_initializer_loc;
Scanner::Location bindings_loc;
};
class PatternRewriter : private AstVisitor {
public:
static void DeclareAndInitializeVariables(
Block* block, const DeclarationDescriptor* declaration_descriptor,
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok);
void set_initializer_position(int pos) { initializer_position_ = pos; }
private:
PatternRewriter() {}
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node) override;
// Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void Visit(AstNode* node) override;
void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
Expression* old_value = current_value_;
current_value_ = value;
pattern->Accept(this);
current_value_ = old_value;
}
AstNodeFactory* factory() const { return descriptor_->parser->factory(); }
AstValueFactory* ast_value_factory() const {
return descriptor_->parser->ast_value_factory();
}
bool inside_with() const { return descriptor_->parser->inside_with(); }
Zone* zone() const { return descriptor_->parser->zone(); }
Expression* pattern_;
int initializer_position_;
Block* block_;
const DeclarationDescriptor* descriptor_;
ZoneList<const AstRawString*>* names_;
Expression* current_value_;
bool* ok_;
};
void ParseVariableDeclarations(VariableDeclarationContext var_context,
DeclarationParsingResult* parsing_result,
bool* ok);
Statement* ParseExpressionOrLabelledStatement( Statement* ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels, bool* ok); ZoneList<const AstRawString*>* labels, bool* ok);
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels, IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
......
...@@ -4,38 +4,32 @@ ...@@ -4,38 +4,32 @@
#include "src/ast.h" #include "src/ast.h"
#include "src/parser.h" #include "src/parser.h"
#include "src/pattern-rewriter.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
bool Parser::PatternRewriter::IsSingleVariableBinding() const { void Parser::PatternRewriter::DeclareAndInitializeVariables(
return pattern_->IsVariableProxy(); Block* block, const DeclarationDescriptor* declaration_descriptor,
} const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok) {
PatternRewriter rewriter;
const AstRawString* Parser::PatternRewriter::SingleName() const {
DCHECK(IsSingleVariableBinding());
return pattern_->AsVariableProxy()->raw_name();
}
rewriter.pattern_ = declaration->pattern;
rewriter.initializer_position_ = declaration->initializer_position;
rewriter.block_ = block;
rewriter.descriptor_ = declaration_descriptor;
rewriter.names_ = names;
rewriter.ok_ = ok;
void Parser::PatternRewriter::DeclareAndInitializeVariables(Expression* value, rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
int* nvars,
bool* ok) {
ok_ = ok;
nvars_ = nvars;
RecurseIntoSubpattern(pattern_, value);
ok_ = nullptr;
nvars_ = nullptr;
} }
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
Expression* value = current_value_; Expression* value = current_value_;
decl_->scope->RemoveUnresolved(pattern->AsVariableProxy()); descriptor_->scope->RemoveUnresolved(pattern->AsVariableProxy());
// Declare variable. // Declare variable.
// Note that we *always* must treat the initial value via a separate init // Note that we *always* must treat the initial value via a separate init
...@@ -52,24 +46,27 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -52,24 +46,27 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// For let/const declarations in harmony mode, we can also immediately // For let/const declarations in harmony mode, we can also immediately
// pre-resolve the proxy because it resides in the same scope as the // pre-resolve the proxy because it resides in the same scope as the
// declaration. // declaration.
Parser* parser = decl_->parser; Parser* parser = descriptor_->parser;
const AstRawString* name = pattern->raw_name(); const AstRawString* name = pattern->raw_name();
VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode); VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
Declaration* declaration = factory()->NewVariableDeclaration( Declaration* declaration = factory()->NewVariableDeclaration(
proxy, decl_->mode, decl_->scope, decl_->pos); proxy, descriptor_->mode, descriptor_->scope, descriptor_->pos);
Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_); Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
if (!*ok_) return; if (!*ok_) return;
DCHECK_NOT_NULL(var); DCHECK_NOT_NULL(var);
DCHECK(!proxy->is_resolved() || proxy->var() == var); DCHECK(!proxy->is_resolved() || proxy->var() == var);
var->set_initializer_position(decl_->initializer_position); var->set_initializer_position(initializer_position_);
(*nvars_)++;
if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { DCHECK(initializer_position_ != RelocInfo::kNoPosition);
if (descriptor_->declaration_scope->num_var_or_const() >
kMaxNumFunctionLocals) {
parser->ReportMessage("too_many_variables"); parser->ReportMessage("too_many_variables");
*ok_ = false; *ok_ = false;
return; return;
} }
if (decl_->names) { if (names_) {
decl_->names->Add(name, zone()); names_->Add(name, zone());
} }
// Initialize variables if needed. A // Initialize variables if needed. A
...@@ -98,8 +95,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -98,8 +95,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// The "variable" c initialized to x is the same as the declared // The "variable" c initialized to x is the same as the declared
// one - there is no re-lookup (see the last parameter of the // one - there is no re-lookup (see the last parameter of the
// Declare() call above). // Declare() call above).
Scope* initialization_scope = Scope* initialization_scope = descriptor_->is_const
decl_->is_const ? decl_->declaration_scope : decl_->scope; ? descriptor_->declaration_scope
: descriptor_->scope;
// Global variable declarations must be compiled in a specific // Global variable declarations must be compiled in a specific
...@@ -121,16 +119,16 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -121,16 +119,16 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// browsers where the global object (window) has lots of // browsers where the global object (window) has lots of
// properties defined in prototype objects. // properties defined in prototype objects.
if (initialization_scope->is_script_scope() && if (initialization_scope->is_script_scope() &&
!IsLexicalVariableMode(decl_->mode)) { !IsLexicalVariableMode(descriptor_->mode)) {
// Compute the arguments for the runtime // Compute the arguments for the runtime
// call.test-parsing/InitializedDeclarationsInStrictForOfError // call.test-parsing/InitializedDeclarationsInStrictForOfError
ZoneList<Expression*>* arguments = ZoneList<Expression*>* arguments =
new (zone()) ZoneList<Expression*>(3, zone()); new (zone()) ZoneList<Expression*>(3, zone());
// We have at least 1 parameter. // We have at least 1 parameter.
arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone()); arguments->Add(factory()->NewStringLiteral(name, descriptor_->pos), zone());
CallRuntime* initialize; CallRuntime* initialize;
if (decl_->is_const) { if (descriptor_->is_const) {
arguments->Add(value, zone()); arguments->Add(value, zone());
value = NULL; // zap the value to avoid the unnecessary assignment value = NULL; // zap the value to avoid the unnecessary assignment
...@@ -141,13 +139,13 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -141,13 +139,13 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime( initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_const_global_string(), ast_value_factory()->initialize_const_global_string(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
decl_->pos); descriptor_->pos);
} else { } else {
// Add language mode. // Add language mode.
// We may want to pass singleton to avoid Literal allocations. // We may want to pass singleton to avoid Literal allocations.
LanguageMode language_mode = initialization_scope->language_mode(); LanguageMode language_mode = initialization_scope->language_mode();
arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos), arguments->Add(
zone()); factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone());
// Be careful not to assign a value to the global variable if // Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not // we're in a with. The initialization value should not
...@@ -161,18 +159,19 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -161,18 +159,19 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime( initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_var_global_string(), ast_value_factory()->initialize_var_global_string(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments, Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
decl_->pos); descriptor_->pos);
} else { } else {
initialize = NULL; initialize = NULL;
} }
} }
if (initialize != NULL) { if (initialize != NULL) {
decl_->block->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition), factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
zone()); zone());
} }
} else if (decl_->needs_init) { } else if (value != nullptr && (descriptor_->needs_init ||
IsLexicalVariableMode(descriptor_->mode))) {
// Constant initializations always assign to the declared constant which // Constant initializations always assign to the declared constant which
// is always at the function scope level. This is only relevant for // is always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the // dynamically looked-up variables and constants (the
...@@ -183,9 +182,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -183,9 +182,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
DCHECK_NOT_NULL(proxy); DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var()); DCHECK_NOT_NULL(proxy->var());
DCHECK_NOT_NULL(value); DCHECK_NOT_NULL(value);
Assignment* assignment = Assignment* assignment = factory()->NewAssignment(
factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); descriptor_->init_op, proxy, value, descriptor_->pos);
decl_->block->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
value = NULL; value = NULL;
...@@ -194,14 +193,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -194,14 +193,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// Add an assignment node to the initialization statement block if we still // Add an assignment node to the initialization statement block if we still
// have a pending initialization value. // have a pending initialization value.
if (value != NULL) { if (value != NULL) {
DCHECK(decl_->mode == VAR); DCHECK(descriptor_->mode == VAR);
// 'var' initializations are simply assignments (with all the consequences // 'var' initializations are simply assignments (with all the consequences
// if they are inside a 'with' statement - they may change a 'with' object // if they are inside a 'with' statement - they may change a 'with' object
// property). // property).
VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
Assignment* assignment = Assignment* assignment = factory()->NewAssignment(
factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); descriptor_->init_op, proxy, value, descriptor_->pos);
decl_->block->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
} }
...@@ -209,12 +208,12 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -209,12 +208,12 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
auto temp = decl_->declaration_scope->NewTemporary( auto temp = descriptor_->declaration_scope->NewTemporary(
ast_value_factory()->empty_string()); ast_value_factory()->empty_string());
auto assignment = auto assignment =
factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
current_value_, RelocInfo::kNoPosition); current_value_, RelocInfo::kNoPosition);
decl_->block->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
for (ObjectLiteralProperty* property : *pattern->properties()) { for (ObjectLiteralProperty* property : *pattern->properties()) {
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_PATTERN_MATCHER_H_
#define V8_PATTERN_MATCHER_H_
#include "src/ast.h"
#include "src/parser.h"
namespace v8 {
namespace internal {
class Parser::PatternRewriter : private AstVisitor {
public:
struct DeclarationDescriptor {
Parser* parser;
Scope* declaration_scope;
Scope* scope;
int initializer_position;
VariableMode mode;
ZoneList<const AstRawString*>* names;
bool is_const;
Block* block;
bool needs_init;
int pos;
Token::Value init_op;
};
explicit PatternRewriter(const DeclarationDescriptor* decl,
Expression* pattern)
: decl_(decl),
pattern_(pattern),
current_value_(nullptr),
ok_(nullptr),
nvars_(nullptr) {}
PatternRewriter()
: decl_(nullptr),
pattern_(nullptr),
current_value_(nullptr),
ok_(nullptr),
nvars_(nullptr) {}
bool IsSingleVariableBinding() const;
const AstRawString* SingleName() const;
void DeclareAndInitializeVariables(Expression* value, int* nvars, bool* ok);
private:
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node) override;
// Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void Visit(AstNode* node) override;
void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
Expression* old_value = current_value_;
current_value_ = value;
pattern->Accept(this);
current_value_ = old_value;
}
AstNodeFactory* factory() const { return decl_->parser->factory(); }
AstValueFactory* ast_value_factory() const {
return decl_->parser->ast_value_factory();
}
bool inside_with() const { return decl_->parser->inside_with(); }
Zone* zone() const { return decl_->parser->zone(); }
const DeclarationDescriptor* decl_;
Expression* pattern_;
Expression* current_value_;
bool* ok_;
int* nvars_;
};
}
} // namespace v8::internal
#endif // V8_PATTERN_MATCHER_H_
...@@ -11,4 +11,46 @@ ...@@ -11,4 +11,46 @@
var {z} = { z : 3 }; var {z} = { z : 3 };
assertEquals(3, z); assertEquals(3, z);
var sum = 0;
for(var {z} = { z : 3 }; z != 0; z--) {
sum += z;
}
assertEquals(6, sum);
}());
(function TestObjectLiteralPatternLexical() {
'use strict';
let { x : x, y : y } = { x : 1, y : 2 };
assertEquals(1, x);
assertEquals(2, y);
let {z} = { z : 3 };
assertEquals(3, z);
let sum = 0;
for(let {x, z} = { x : 0, z : 3 }; z != 0; z--) {
assertEquals(0, x);
sum += z;
}
assertEquals(6, sum);
}());
(function TestObjectLiteralPatternLexicalConst() {
'use strict';
const { x : x, y : y } = { x : 1, y : 2 };
assertEquals(1, x);
assertEquals(2, y);
const {z} = { z : 3 };
assertEquals(3, z);
for(const {x, z} = { x : 0, z : 3 }; z != 3 || x != 0;) {
assertTrue(false);
}
}()); }());
...@@ -799,7 +799,6 @@ ...@@ -799,7 +799,6 @@
'../../src/ostreams.cc', '../../src/ostreams.cc',
'../../src/ostreams.h', '../../src/ostreams.h',
'../../src/pattern-rewriter.cc', '../../src/pattern-rewriter.cc',
'../../src/pattern-rewriter.h',
'../../src/parser.cc', '../../src/parser.cc',
'../../src/parser.h', '../../src/parser.h',
'../../src/pending-compilation-error-handler.cc', '../../src/pending-compilation-error-handler.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment