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

Side by Side Diff: src/pattern-rewriter.cc

Issue 1128043006: [destructuring] Adapting PatternRewriter to work in for-statements. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebased Created 5 years, 7 months 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 unified diff | Download patch
« no previous file with comments | « src/pattern-rewriter.h ('k') | test/mjsunit/harmony/destructuring.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/ast.h" 5 #include "src/ast.h"
6 #include "src/parser.h" 6 #include "src/parser.h"
7 #include "src/pattern-rewriter.h"
8 7
9 namespace v8 { 8 namespace v8 {
10 9
11 namespace internal { 10 namespace internal {
12 11
13 12
14 bool Parser::PatternRewriter::IsSingleVariableBinding() const { 13 void Parser::PatternRewriter::DeclareAndInitializeVariables(
15 return pattern_->IsVariableProxy(); 14 Block* block, const DeclarationDescriptor* declaration_descriptor,
16 } 15 const DeclarationParsingResult::Declaration* declaration,
16 ZoneList<const AstRawString*>* names, bool* ok) {
17 PatternRewriter rewriter;
17 18
19 rewriter.pattern_ = declaration->pattern;
20 rewriter.initializer_position_ = declaration->initializer_position;
21 rewriter.block_ = block;
22 rewriter.descriptor_ = declaration_descriptor;
23 rewriter.names_ = names;
24 rewriter.ok_ = ok;
18 25
19 const AstRawString* Parser::PatternRewriter::SingleName() const { 26 rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
20 DCHECK(IsSingleVariableBinding());
21 return pattern_->AsVariableProxy()->raw_name();
22 }
23
24
25 void Parser::PatternRewriter::DeclareAndInitializeVariables(Expression* value,
26 int* nvars,
27 bool* ok) {
28 ok_ = ok;
29 nvars_ = nvars;
30 RecurseIntoSubpattern(pattern_, value);
31 ok_ = nullptr;
32 nvars_ = nullptr;
33 } 27 }
34 28
35 29
36 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { 30 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
37 Expression* value = current_value_; 31 Expression* value = current_value_;
38 decl_->scope->RemoveUnresolved(pattern->AsVariableProxy()); 32 descriptor_->scope->RemoveUnresolved(pattern->AsVariableProxy());
39 33
40 // Declare variable. 34 // Declare variable.
41 // Note that we *always* must treat the initial value via a separate init 35 // Note that we *always* must treat the initial value via a separate init
42 // assignment for variables and constants because the value must be assigned 36 // assignment for variables and constants because the value must be assigned
43 // when the variable is encountered in the source. But the variable/constant 37 // when the variable is encountered in the source. But the variable/constant
44 // is declared (and set to 'undefined') upon entering the function within 38 // is declared (and set to 'undefined') upon entering the function within
45 // which the variable or constant is declared. Only function variables have 39 // which the variable or constant is declared. Only function variables have
46 // an initial value in the declaration (because they are initialized upon 40 // an initial value in the declaration (because they are initialized upon
47 // entering the function). 41 // entering the function).
48 // 42 //
49 // If we have a legacy const declaration, in an inner scope, the proxy 43 // If we have a legacy const declaration, in an inner scope, the proxy
50 // is always bound to the declared variable (independent of possibly 44 // is always bound to the declared variable (independent of possibly
51 // surrounding 'with' statements). 45 // surrounding 'with' statements).
52 // For let/const declarations in harmony mode, we can also immediately 46 // For let/const declarations in harmony mode, we can also immediately
53 // pre-resolve the proxy because it resides in the same scope as the 47 // pre-resolve the proxy because it resides in the same scope as the
54 // declaration. 48 // declaration.
55 Parser* parser = decl_->parser; 49 Parser* parser = descriptor_->parser;
56 const AstRawString* name = pattern->raw_name(); 50 const AstRawString* name = pattern->raw_name();
57 VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode); 51 VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
58 Declaration* declaration = factory()->NewVariableDeclaration( 52 Declaration* declaration = factory()->NewVariableDeclaration(
59 proxy, decl_->mode, decl_->scope, decl_->pos); 53 proxy, descriptor_->mode, descriptor_->scope, descriptor_->pos);
60 Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_); 54 Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
61 if (!*ok_) return; 55 if (!*ok_) return;
62 DCHECK_NOT_NULL(var); 56 DCHECK_NOT_NULL(var);
63 DCHECK(!proxy->is_resolved() || proxy->var() == var); 57 DCHECK(!proxy->is_resolved() || proxy->var() == var);
64 var->set_initializer_position(decl_->initializer_position); 58 var->set_initializer_position(initializer_position_);
65 (*nvars_)++; 59
66 if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { 60 DCHECK(initializer_position_ != RelocInfo::kNoPosition);
61
62 if (descriptor_->declaration_scope->num_var_or_const() >
63 kMaxNumFunctionLocals) {
67 parser->ReportMessage("too_many_variables"); 64 parser->ReportMessage("too_many_variables");
68 *ok_ = false; 65 *ok_ = false;
69 return; 66 return;
70 } 67 }
71 if (decl_->names) { 68 if (names_) {
72 decl_->names->Add(name, zone()); 69 names_->Add(name, zone());
73 } 70 }
74 71
75 // Initialize variables if needed. A 72 // Initialize variables if needed. A
76 // declaration of the form: 73 // declaration of the form:
77 // 74 //
78 // var v = x; 75 // var v = x;
79 // 76 //
80 // is syntactic sugar for: 77 // is syntactic sugar for:
81 // 78 //
82 // var v; v = x; 79 // var v; v = x;
83 // 80 //
84 // In particular, we need to re-lookup 'v' (in scope_, not 81 // In particular, we need to re-lookup 'v' (in scope_, not
85 // declaration_scope) as it may be a different 'v' than the 'v' in the 82 // declaration_scope) as it may be a different 'v' than the 'v' in the
86 // declaration (e.g., if we are inside a 'with' statement or 'catch' 83 // declaration (e.g., if we are inside a 'with' statement or 'catch'
87 // block). 84 // block).
88 // 85 //
89 // However, note that const declarations are different! A const 86 // However, note that const declarations are different! A const
90 // declaration of the form: 87 // declaration of the form:
91 // 88 //
92 // const c = x; 89 // const c = x;
93 // 90 //
94 // is *not* syntactic sugar for: 91 // is *not* syntactic sugar for:
95 // 92 //
96 // const c; c = x; 93 // const c; c = x;
97 // 94 //
98 // The "variable" c initialized to x is the same as the declared 95 // The "variable" c initialized to x is the same as the declared
99 // one - there is no re-lookup (see the last parameter of the 96 // one - there is no re-lookup (see the last parameter of the
100 // Declare() call above). 97 // Declare() call above).
101 Scope* initialization_scope = 98 Scope* initialization_scope = descriptor_->is_const
102 decl_->is_const ? decl_->declaration_scope : decl_->scope; 99 ? descriptor_->declaration_scope
100 : descriptor_->scope;
103 101
104 102
105 // Global variable declarations must be compiled in a specific 103 // Global variable declarations must be compiled in a specific
106 // way. When the script containing the global variable declaration 104 // way. When the script containing the global variable declaration
107 // is entered, the global variable must be declared, so that if it 105 // is entered, the global variable must be declared, so that if it
108 // doesn't exist (on the global object itself, see ES5 errata) it 106 // doesn't exist (on the global object itself, see ES5 errata) it
109 // gets created with an initial undefined value. This is handled 107 // gets created with an initial undefined value. This is handled
110 // by the declarations part of the function representing the 108 // by the declarations part of the function representing the
111 // top-level global code; see Runtime::DeclareGlobalVariable. If 109 // top-level global code; see Runtime::DeclareGlobalVariable. If
112 // it already exists (in the object or in a prototype), it is 110 // it already exists (in the object or in a prototype), it is
113 // *not* touched until the variable declaration statement is 111 // *not* touched until the variable declaration statement is
114 // executed. 112 // executed.
115 // 113 //
116 // Executing the variable declaration statement will always 114 // Executing the variable declaration statement will always
117 // guarantee to give the global object an own property. 115 // guarantee to give the global object an own property.
118 // This way, global variable declarations can shadow 116 // This way, global variable declarations can shadow
119 // properties in the prototype chain, but only after the variable 117 // properties in the prototype chain, but only after the variable
120 // declaration statement has been executed. This is important in 118 // declaration statement has been executed. This is important in
121 // browsers where the global object (window) has lots of 119 // browsers where the global object (window) has lots of
122 // properties defined in prototype objects. 120 // properties defined in prototype objects.
123 if (initialization_scope->is_script_scope() && 121 if (initialization_scope->is_script_scope() &&
124 !IsLexicalVariableMode(decl_->mode)) { 122 !IsLexicalVariableMode(descriptor_->mode)) {
125 // Compute the arguments for the runtime 123 // Compute the arguments for the runtime
126 // call.test-parsing/InitializedDeclarationsInStrictForOfError 124 // call.test-parsing/InitializedDeclarationsInStrictForOfError
127 ZoneList<Expression*>* arguments = 125 ZoneList<Expression*>* arguments =
128 new (zone()) ZoneList<Expression*>(3, zone()); 126 new (zone()) ZoneList<Expression*>(3, zone());
129 // We have at least 1 parameter. 127 // We have at least 1 parameter.
130 arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone()); 128 arguments->Add(factory()->NewStringLiteral(name, descriptor_->pos), zone());
131 CallRuntime* initialize; 129 CallRuntime* initialize;
132 130
133 if (decl_->is_const) { 131 if (descriptor_->is_const) {
134 arguments->Add(value, zone()); 132 arguments->Add(value, zone());
135 value = NULL; // zap the value to avoid the unnecessary assignment 133 value = NULL; // zap the value to avoid the unnecessary assignment
136 134
137 // Construct the call to Runtime_InitializeConstGlobal 135 // Construct the call to Runtime_InitializeConstGlobal
138 // and add it to the initialization statement block. 136 // and add it to the initialization statement block.
139 // Note that the function does different things depending on 137 // Note that the function does different things depending on
140 // the number of arguments (1 or 2). 138 // the number of arguments (1 or 2).
141 initialize = factory()->NewCallRuntime( 139 initialize = factory()->NewCallRuntime(
142 ast_value_factory()->initialize_const_global_string(), 140 ast_value_factory()->initialize_const_global_string(),
143 Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, 141 Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
144 decl_->pos); 142 descriptor_->pos);
145 } else { 143 } else {
146 // Add language mode. 144 // Add language mode.
147 // We may want to pass singleton to avoid Literal allocations. 145 // We may want to pass singleton to avoid Literal allocations.
148 LanguageMode language_mode = initialization_scope->language_mode(); 146 LanguageMode language_mode = initialization_scope->language_mode();
149 arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos), 147 arguments->Add(
150 zone()); 148 factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone());
151 149
152 // Be careful not to assign a value to the global variable if 150 // Be careful not to assign a value to the global variable if
153 // we're in a with. The initialization value should not 151 // we're in a with. The initialization value should not
154 // necessarily be stored in the global object in that case, 152 // necessarily be stored in the global object in that case,
155 // which is why we need to generate a separate assignment node. 153 // which is why we need to generate a separate assignment node.
156 if (value != NULL && !inside_with()) { 154 if (value != NULL && !inside_with()) {
157 arguments->Add(value, zone()); 155 arguments->Add(value, zone());
158 value = NULL; // zap the value to avoid the unnecessary assignment 156 value = NULL; // zap the value to avoid the unnecessary assignment
159 // Construct the call to Runtime_InitializeVarGlobal 157 // Construct the call to Runtime_InitializeVarGlobal
160 // and add it to the initialization statement block. 158 // and add it to the initialization statement block.
161 initialize = factory()->NewCallRuntime( 159 initialize = factory()->NewCallRuntime(
162 ast_value_factory()->initialize_var_global_string(), 160 ast_value_factory()->initialize_var_global_string(),
163 Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments, 161 Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
164 decl_->pos); 162 descriptor_->pos);
165 } else { 163 } else {
166 initialize = NULL; 164 initialize = NULL;
167 } 165 }
168 } 166 }
169 167
170 if (initialize != NULL) { 168 if (initialize != NULL) {
171 decl_->block->AddStatement( 169 block_->AddStatement(
172 factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition), 170 factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
173 zone()); 171 zone());
174 } 172 }
175 } else if (decl_->needs_init) { 173 } else if (value != nullptr && (descriptor_->needs_init ||
174 IsLexicalVariableMode(descriptor_->mode))) {
176 // Constant initializations always assign to the declared constant which 175 // Constant initializations always assign to the declared constant which
177 // is always at the function scope level. This is only relevant for 176 // is always at the function scope level. This is only relevant for
178 // dynamically looked-up variables and constants (the 177 // dynamically looked-up variables and constants (the
179 // start context for constant lookups is always the function context, 178 // start context for constant lookups is always the function context,
180 // while it is the top context for var declared variables). Sigh... 179 // while it is the top context for var declared variables). Sigh...
181 // For 'let' and 'const' declared variables in harmony mode the 180 // For 'let' and 'const' declared variables in harmony mode the
182 // initialization also always assigns to the declared variable. 181 // initialization also always assigns to the declared variable.
183 DCHECK_NOT_NULL(proxy); 182 DCHECK_NOT_NULL(proxy);
184 DCHECK_NOT_NULL(proxy->var()); 183 DCHECK_NOT_NULL(proxy->var());
185 DCHECK_NOT_NULL(value); 184 DCHECK_NOT_NULL(value);
186 Assignment* assignment = 185 Assignment* assignment = factory()->NewAssignment(
187 factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); 186 descriptor_->init_op, proxy, value, descriptor_->pos);
188 decl_->block->AddStatement( 187 block_->AddStatement(
189 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), 188 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
190 zone()); 189 zone());
191 value = NULL; 190 value = NULL;
192 } 191 }
193 192
194 // Add an assignment node to the initialization statement block if we still 193 // Add an assignment node to the initialization statement block if we still
195 // have a pending initialization value. 194 // have a pending initialization value.
196 if (value != NULL) { 195 if (value != NULL) {
197 DCHECK(decl_->mode == VAR); 196 DCHECK(descriptor_->mode == VAR);
198 // 'var' initializations are simply assignments (with all the consequences 197 // 'var' initializations are simply assignments (with all the consequences
199 // if they are inside a 'with' statement - they may change a 'with' object 198 // if they are inside a 'with' statement - they may change a 'with' object
200 // property). 199 // property).
201 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); 200 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
202 Assignment* assignment = 201 Assignment* assignment = factory()->NewAssignment(
203 factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); 202 descriptor_->init_op, proxy, value, descriptor_->pos);
204 decl_->block->AddStatement( 203 block_->AddStatement(
205 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), 204 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
206 zone()); 205 zone());
207 } 206 }
208 } 207 }
209 208
210 209
211 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { 210 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
212 auto temp = decl_->declaration_scope->NewTemporary( 211 auto temp = descriptor_->declaration_scope->NewTemporary(
213 ast_value_factory()->empty_string()); 212 ast_value_factory()->empty_string());
214 auto assignment = 213 auto assignment =
215 factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), 214 factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
216 current_value_, RelocInfo::kNoPosition); 215 current_value_, RelocInfo::kNoPosition);
217 decl_->block->AddStatement( 216 block_->AddStatement(
218 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), 217 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
219 zone()); 218 zone());
220 for (ObjectLiteralProperty* property : *pattern->properties()) { 219 for (ObjectLiteralProperty* property : *pattern->properties()) {
221 // TODO(dslomov): computed property names. 220 // TODO(dslomov): computed property names.
222 RecurseIntoSubpattern( 221 RecurseIntoSubpattern(
223 property->value(), 222 property->value(),
224 factory()->NewProperty(factory()->NewVariableProxy(temp), 223 factory()->NewProperty(factory()->NewVariableProxy(temp),
225 property->key(), RelocInfo::kNoPosition)); 224 property->key(), RelocInfo::kNoPosition));
226 } 225 }
227 } 226 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 NOT_A_PATTERN(TryFinallyStatement) 287 NOT_A_PATTERN(TryFinallyStatement)
289 NOT_A_PATTERN(UnaryOperation) 288 NOT_A_PATTERN(UnaryOperation)
290 NOT_A_PATTERN(VariableDeclaration) 289 NOT_A_PATTERN(VariableDeclaration)
291 NOT_A_PATTERN(WhileStatement) 290 NOT_A_PATTERN(WhileStatement)
292 NOT_A_PATTERN(WithStatement) 291 NOT_A_PATTERN(WithStatement)
293 NOT_A_PATTERN(Yield) 292 NOT_A_PATTERN(Yield)
294 293
295 #undef NOT_A_PATTERN 294 #undef NOT_A_PATTERN
296 } 295 }
297 } // namespace v8::internal 296 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/pattern-rewriter.h ('k') | test/mjsunit/harmony/destructuring.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698