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

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

Powered by Google App Engine
This is Rietveld 408576698