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") {
"src/ostreams.cc",
"src/ostreams.h",
"src/pattern-rewriter.cc",
"src/pattern-rewriter.h",
"src/parser.cc",
"src/parser.h",
"src/pending-compilation-error-handler.cc",
......
......@@ -3352,6 +3352,7 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable::Kind variable_kind,
int start_position = RelocInfo::kNoPosition,
int end_position = RelocInfo::kNoPosition) {
DCHECK_NOT_NULL(name);
return new (zone_)
VariableProxy(zone_, name, variable_kind, start_position, end_position);
}
......
This diff is collapsed.
......@@ -871,7 +871,6 @@ class Parser : public ParserBase<ParserTraits> {
private:
friend class ParserTraits;
class PatternRewriter;
// Limit the allowed number of local variables in a function. The hard limit
// is that offsets computed by FullCodeGenerator::StackOperand and similar
......@@ -940,12 +939,91 @@ class Parser : public ParserBase<ParserTraits> {
Block* ParseVariableStatement(VariableDeclarationContext var_context,
ZoneList<const AstRawString*>* names,
bool* ok);
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
int* num_decl,
ZoneList<const AstRawString*>* names,
const AstRawString** out,
Scanner::Location* first_initializer_loc,
Scanner::Location* bindings_loc, bool* ok);
struct DeclarationDescriptor {
Parser* parser;
Scope* declaration_scope;
Scope* scope;
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(
ZoneList<const AstRawString*>* labels, bool* ok);
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
......
......@@ -4,38 +4,32 @@
#include "src/ast.h"
#include "src/parser.h"
#include "src/pattern-rewriter.h"
namespace v8 {
namespace internal {
bool Parser::PatternRewriter::IsSingleVariableBinding() const {
return pattern_->IsVariableProxy();
}
const AstRawString* Parser::PatternRewriter::SingleName() const {
DCHECK(IsSingleVariableBinding());
return pattern_->AsVariableProxy()->raw_name();
}
void Parser::PatternRewriter::DeclareAndInitializeVariables(
Block* block, const DeclarationDescriptor* declaration_descriptor,
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok) {
PatternRewriter rewriter;
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,
int* nvars,
bool* ok) {
ok_ = ok;
nvars_ = nvars;
RecurseIntoSubpattern(pattern_, value);
ok_ = nullptr;
nvars_ = nullptr;
rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
}
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
Expression* value = current_value_;
decl_->scope->RemoveUnresolved(pattern->AsVariableProxy());
descriptor_->scope->RemoveUnresolved(pattern->AsVariableProxy());
// Declare variable.
// Note that we *always* must treat the initial value via a separate init
......@@ -52,24 +46,27 @@ 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 = decl_->parser;
Parser* parser = descriptor_->parser;
const AstRawString* name = pattern->raw_name();
VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode);
VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
Declaration* declaration = factory()->NewVariableDeclaration(
proxy, decl_->mode, decl_->scope, decl_->pos);
Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_);
proxy, descriptor_->mode, descriptor_->scope, descriptor_->pos);
Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
if (!*ok_) return;
DCHECK_NOT_NULL(var);
DCHECK(!proxy->is_resolved() || proxy->var() == var);
var->set_initializer_position(decl_->initializer_position);
(*nvars_)++;
if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
var->set_initializer_position(initializer_position_);
DCHECK(initializer_position_ != RelocInfo::kNoPosition);
if (descriptor_->declaration_scope->num_var_or_const() >
kMaxNumFunctionLocals) {
parser->ReportMessage("too_many_variables");
*ok_ = false;
return;
}
if (decl_->names) {
decl_->names->Add(name, zone());
if (names_) {
names_->Add(name, zone());
}
// Initialize variables if needed. A
......@@ -98,8 +95,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// The "variable" c initialized to x is the same as the declared
// one - there is no re-lookup (see the last parameter of the
// Declare() call above).
Scope* initialization_scope =
decl_->is_const ? decl_->declaration_scope : decl_->scope;
Scope* initialization_scope = descriptor_->is_const
? descriptor_->declaration_scope
: descriptor_->scope;
// Global variable declarations must be compiled in a specific
......@@ -121,16 +119,16 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
if (initialization_scope->is_script_scope() &&
!IsLexicalVariableMode(decl_->mode)) {
!IsLexicalVariableMode(descriptor_->mode)) {
// Compute the arguments for the runtime
// call.test-parsing/InitializedDeclarationsInStrictForOfError
ZoneList<Expression*>* arguments =
new (zone()) ZoneList<Expression*>(3, zone());
// We have at least 1 parameter.
arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone());
arguments->Add(factory()->NewStringLiteral(name, descriptor_->pos), zone());
CallRuntime* initialize;
if (decl_->is_const) {
if (descriptor_->is_const) {
arguments->Add(value, zone());
value = NULL; // zap the value to avoid the unnecessary assignment
......@@ -141,13 +139,13 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_const_global_string(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
decl_->pos);
descriptor_->pos);
} else {
// Add language mode.
// We may want to pass singleton to avoid Literal allocations.
LanguageMode language_mode = initialization_scope->language_mode();
arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos),
zone());
arguments->Add(
factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone());
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
......@@ -161,18 +159,19 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_var_global_string(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
decl_->pos);
descriptor_->pos);
} else {
initialize = NULL;
}
}
if (initialize != NULL) {
decl_->block->AddStatement(
block_->AddStatement(
factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
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
// is always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the
......@@ -183,9 +182,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var());
DCHECK_NOT_NULL(value);
Assignment* assignment =
factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
decl_->block->AddStatement(
Assignment* assignment = factory()->NewAssignment(
descriptor_->init_op, proxy, value, descriptor_->pos);
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
value = NULL;
......@@ -194,14 +193,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// Add an assignment node to the initialization statement block if we still
// have a pending initialization value.
if (value != NULL) {
DCHECK(decl_->mode == VAR);
DCHECK(descriptor_->mode == VAR);
// 'var' initializations are simply assignments (with all the consequences
// if they are inside a 'with' statement - they may change a 'with' object
// property).
VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
Assignment* assignment =
factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
decl_->block->AddStatement(
Assignment* assignment = factory()->NewAssignment(
descriptor_->init_op, proxy, value, descriptor_->pos);
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
}
......@@ -209,12 +208,12 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
auto temp = decl_->declaration_scope->NewTemporary(
auto temp = descriptor_->declaration_scope->NewTemporary(
ast_value_factory()->empty_string());
auto assignment =
factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
current_value_, RelocInfo::kNoPosition);
decl_->block->AddStatement(
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
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 @@
var {z} = { z : 3 };
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 @@
'../../src/ostreams.cc',
'../../src/ostreams.h',
'../../src/pattern-rewriter.cc',
'../../src/pattern-rewriter.h',
'../../src/parser.cc',
'../../src/parser.h',
'../../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