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

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

Issue 1481613002: Create ast/ and parsing/ subdirectories and move appropriate files (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 5 years 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/parsing/token.cc ('k') | src/ppc/codegen-ppc.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/ast.h"
6 #include "src/messages.h"
7 #include "src/parameter-initializer-rewriter.h"
8 #include "src/parser.h"
9
10 namespace v8 {
11
12 namespace internal {
13
14
15 void Parser::PatternRewriter::DeclareAndInitializeVariables(
16 Block* block, const DeclarationDescriptor* declaration_descriptor,
17 const DeclarationParsingResult::Declaration* declaration,
18 ZoneList<const AstRawString*>* names, bool* ok) {
19 PatternRewriter rewriter;
20
21 rewriter.pattern_ = declaration->pattern;
22 rewriter.initializer_position_ = declaration->initializer_position;
23 rewriter.block_ = block;
24 rewriter.descriptor_ = declaration_descriptor;
25 rewriter.names_ = names;
26 rewriter.ok_ = ok;
27
28 rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
29 }
30
31
32 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
33 Expression* value = current_value_;
34 descriptor_->scope->RemoveUnresolved(pattern);
35
36 // Declare variable.
37 // Note that we *always* must treat the initial value via a separate init
38 // assignment for variables and constants because the value must be assigned
39 // when the variable is encountered in the source. But the variable/constant
40 // is declared (and set to 'undefined') upon entering the function within
41 // which the variable or constant is declared. Only function variables have
42 // an initial value in the declaration (because they are initialized upon
43 // entering the function).
44 //
45 // If we have a legacy const declaration, in an inner scope, the proxy
46 // is always bound to the declared variable (independent of possibly
47 // surrounding 'with' statements).
48 // For let/const declarations in harmony mode, we can also immediately
49 // pre-resolve the proxy because it resides in the same scope as the
50 // declaration.
51 Parser* parser = descriptor_->parser;
52 const AstRawString* name = pattern->raw_name();
53 VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
54 Declaration* declaration = factory()->NewVariableDeclaration(
55 proxy, descriptor_->mode, descriptor_->scope,
56 descriptor_->declaration_pos);
57 Variable* var = parser->Declare(declaration, descriptor_->declaration_kind,
58 descriptor_->mode != VAR, ok_,
59 descriptor_->hoist_scope);
60 if (!*ok_) return;
61 DCHECK_NOT_NULL(var);
62 DCHECK(!proxy->is_resolved() || proxy->var() == var);
63 var->set_initializer_position(initializer_position_);
64
65 DCHECK(initializer_position_ != RelocInfo::kNoPosition);
66
67 if (descriptor_->declaration_scope->num_var_or_const() >
68 kMaxNumFunctionLocals) {
69 parser->ReportMessage(MessageTemplate::kTooManyVariables);
70 *ok_ = false;
71 return;
72 }
73 if (names_) {
74 names_->Add(name, zone());
75 }
76
77 // Initialize variables if needed. A
78 // declaration of the form:
79 //
80 // var v = x;
81 //
82 // is syntactic sugar for:
83 //
84 // var v; v = x;
85 //
86 // In particular, we need to re-lookup 'v' (in scope_, not
87 // declaration_scope) as it may be a different 'v' than the 'v' in the
88 // declaration (e.g., if we are inside a 'with' statement or 'catch'
89 // block).
90 //
91 // However, note that const declarations are different! A const
92 // declaration of the form:
93 //
94 // const c = x;
95 //
96 // is *not* syntactic sugar for:
97 //
98 // const c; c = x;
99 //
100 // The "variable" c initialized to x is the same as the declared
101 // one - there is no re-lookup (see the last parameter of the
102 // Declare() call above).
103 Scope* initialization_scope = descriptor_->is_const
104 ? descriptor_->declaration_scope
105 : descriptor_->scope;
106
107
108 // Global variable declarations must be compiled in a specific
109 // way. When the script containing the global variable declaration
110 // is entered, the global variable must be declared, so that if it
111 // doesn't exist (on the global object itself, see ES5 errata) it
112 // gets created with an initial undefined value. This is handled
113 // by the declarations part of the function representing the
114 // top-level global code; see Runtime::DeclareGlobalVariable. If
115 // it already exists (in the object or in a prototype), it is
116 // *not* touched until the variable declaration statement is
117 // executed.
118 //
119 // Executing the variable declaration statement will always
120 // guarantee to give the global object an own property.
121 // This way, global variable declarations can shadow
122 // properties in the prototype chain, but only after the variable
123 // declaration statement has been executed. This is important in
124 // browsers where the global object (window) has lots of
125 // properties defined in prototype objects.
126 if (initialization_scope->is_script_scope() &&
127 !IsLexicalVariableMode(descriptor_->mode)) {
128 // Compute the arguments for the runtime
129 // call.test-parsing/InitializedDeclarationsInStrictForOfError
130 ZoneList<Expression*>* arguments =
131 new (zone()) ZoneList<Expression*>(3, zone());
132 // We have at least 1 parameter.
133 arguments->Add(
134 factory()->NewStringLiteral(name, descriptor_->declaration_pos),
135 zone());
136 CallRuntime* initialize;
137
138 if (descriptor_->is_const) {
139 arguments->Add(value, zone());
140 value = NULL; // zap the value to avoid the unnecessary assignment
141
142 // Construct the call to Runtime_InitializeConstGlobal
143 // and add it to the initialization statement block.
144 // Note that the function does different things depending on
145 // the number of arguments (1 or 2).
146 initialize =
147 factory()->NewCallRuntime(Runtime::kInitializeConstGlobal, arguments,
148 descriptor_->initialization_pos);
149 } else {
150 // Add language mode.
151 // We may want to pass singleton to avoid Literal allocations.
152 LanguageMode language_mode = initialization_scope->language_mode();
153 arguments->Add(factory()->NewNumberLiteral(language_mode,
154 descriptor_->declaration_pos),
155 zone());
156
157 // Be careful not to assign a value to the global variable if
158 // we're in a with. The initialization value should not
159 // necessarily be stored in the global object in that case,
160 // which is why we need to generate a separate assignment node.
161 if (value != NULL && !descriptor_->scope->inside_with()) {
162 arguments->Add(value, zone());
163 value = NULL; // zap the value to avoid the unnecessary assignment
164 // Construct the call to Runtime_InitializeVarGlobal
165 // and add it to the initialization statement block.
166 initialize =
167 factory()->NewCallRuntime(Runtime::kInitializeVarGlobal, arguments,
168 descriptor_->declaration_pos);
169 } else {
170 initialize = NULL;
171 }
172 }
173
174 if (initialize != NULL) {
175 block_->statements()->Add(
176 factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
177 zone());
178 }
179 } else if (value != nullptr && (descriptor_->mode == CONST_LEGACY ||
180 IsLexicalVariableMode(descriptor_->mode))) {
181 // Constant initializations always assign to the declared constant which
182 // is always at the function scope level. This is only relevant for
183 // dynamically looked-up variables and constants (the
184 // start context for constant lookups is always the function context,
185 // while it is the top context for var declared variables). Sigh...
186 // For 'let' and 'const' declared variables in harmony mode the
187 // initialization also always assigns to the declared variable.
188 DCHECK_NOT_NULL(proxy);
189 DCHECK_NOT_NULL(proxy->var());
190 DCHECK_NOT_NULL(value);
191 Assignment* assignment = factory()->NewAssignment(
192 Token::INIT, proxy, value, descriptor_->initialization_pos);
193 block_->statements()->Add(
194 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
195 zone());
196 value = NULL;
197 }
198
199 // Add an assignment node to the initialization statement block if we still
200 // have a pending initialization value.
201 if (value != NULL) {
202 DCHECK(descriptor_->mode == VAR);
203 // 'var' initializations are simply assignments (with all the consequences
204 // if they are inside a 'with' statement - they may change a 'with' object
205 // property).
206 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
207 Assignment* assignment = factory()->NewAssignment(
208 Token::INIT, proxy, value, descriptor_->initialization_pos);
209 block_->statements()->Add(
210 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
211 zone());
212 }
213 }
214
215
216 Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
217 auto temp = descriptor_->parser->scope_->NewTemporary(
218 ast_value_factory()->empty_string());
219 if (value != nullptr) {
220 auto assignment = factory()->NewAssignment(
221 Token::ASSIGN, factory()->NewVariableProxy(temp), value,
222 RelocInfo::kNoPosition);
223
224 block_->statements()->Add(
225 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
226 zone());
227 }
228 return temp;
229 }
230
231
232 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
233 auto temp = CreateTempVar(current_value_);
234
235 block_->statements()->Add(descriptor_->parser->BuildAssertIsCoercible(temp),
236 zone());
237
238 for (ObjectLiteralProperty* property : *pattern->properties()) {
239 RecurseIntoSubpattern(
240 property->value(),
241 factory()->NewProperty(factory()->NewVariableProxy(temp),
242 property->key(), RelocInfo::kNoPosition));
243 }
244 }
245
246
247 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
248 auto temp = CreateTempVar(current_value_);
249
250 block_->statements()->Add(descriptor_->parser->BuildAssertIsCoercible(temp),
251 zone());
252
253 auto iterator = CreateTempVar(descriptor_->parser->GetIterator(
254 factory()->NewVariableProxy(temp), factory()));
255 auto done = CreateTempVar(
256 factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
257 auto result = CreateTempVar();
258 auto v = CreateTempVar();
259
260 Spread* spread = nullptr;
261 for (Expression* value : *node->values()) {
262 if (value->IsSpread()) {
263 spread = value->AsSpread();
264 break;
265 }
266
267 // if (!done) {
268 // result = IteratorNext(iterator);
269 // v = (done = result.done) ? undefined : result.value;
270 // }
271 auto next_block =
272 factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
273 next_block->statements()->Add(
274 factory()->NewExpressionStatement(
275 descriptor_->parser->BuildIteratorNextResult(
276 factory()->NewVariableProxy(iterator), result,
277 RelocInfo::kNoPosition),
278 RelocInfo::kNoPosition),
279 zone());
280
281 auto assign_to_done = factory()->NewAssignment(
282 Token::ASSIGN, factory()->NewVariableProxy(done),
283 factory()->NewProperty(
284 factory()->NewVariableProxy(result),
285 factory()->NewStringLiteral(ast_value_factory()->done_string(),
286 RelocInfo::kNoPosition),
287 RelocInfo::kNoPosition),
288 RelocInfo::kNoPosition);
289 auto next_value = factory()->NewConditional(
290 assign_to_done, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
291 factory()->NewProperty(
292 factory()->NewVariableProxy(result),
293 factory()->NewStringLiteral(ast_value_factory()->value_string(),
294 RelocInfo::kNoPosition),
295 RelocInfo::kNoPosition),
296 RelocInfo::kNoPosition);
297 next_block->statements()->Add(
298 factory()->NewExpressionStatement(
299 factory()->NewAssignment(Token::ASSIGN,
300 factory()->NewVariableProxy(v), next_value,
301 RelocInfo::kNoPosition),
302 RelocInfo::kNoPosition),
303 zone());
304
305 auto if_statement = factory()->NewIfStatement(
306 factory()->NewUnaryOperation(Token::NOT,
307 factory()->NewVariableProxy(done),
308 RelocInfo::kNoPosition),
309 next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
310 RelocInfo::kNoPosition);
311 block_->statements()->Add(if_statement, zone());
312
313 if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
314 RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
315 }
316 }
317
318 if (spread != nullptr) {
319 // array = [];
320 // if (!done) %concat_iterable_to_array(array, iterator);
321 auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
322 auto array = CreateTempVar(factory()->NewArrayLiteral(
323 empty_exprs,
324 // Reuse pattern's literal index - it is unused since there is no
325 // actual literal allocated.
326 node->literal_index(), is_strong(descriptor_->parser->language_mode()),
327 RelocInfo::kNoPosition));
328
329 auto arguments = new (zone()) ZoneList<Expression*>(2, zone());
330 arguments->Add(factory()->NewVariableProxy(array), zone());
331 arguments->Add(factory()->NewVariableProxy(iterator), zone());
332 auto spread_into_array_call =
333 factory()->NewCallRuntime(Context::CONCAT_ITERABLE_TO_ARRAY_INDEX,
334 arguments, RelocInfo::kNoPosition);
335
336 auto if_statement = factory()->NewIfStatement(
337 factory()->NewUnaryOperation(Token::NOT,
338 factory()->NewVariableProxy(done),
339 RelocInfo::kNoPosition),
340 factory()->NewExpressionStatement(spread_into_array_call,
341 RelocInfo::kNoPosition),
342 factory()->NewEmptyStatement(RelocInfo::kNoPosition),
343 RelocInfo::kNoPosition);
344 block_->statements()->Add(if_statement, zone());
345
346 RecurseIntoSubpattern(spread->expression(),
347 factory()->NewVariableProxy(array));
348 }
349 }
350
351
352 void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
353 // let {<pattern> = <init>} = <value>
354 // becomes
355 // temp = <value>;
356 // <pattern> = temp === undefined ? <init> : temp;
357 DCHECK(node->op() == Token::ASSIGN);
358 auto temp = CreateTempVar(current_value_);
359 Expression* is_undefined = factory()->NewCompareOperation(
360 Token::EQ_STRICT, factory()->NewVariableProxy(temp),
361 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
362 RelocInfo::kNoPosition);
363 Expression* initializer = node->value();
364 if (descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
365 descriptor_->scope->is_arrow_scope()) {
366 // TODO(adamk): Only call this if necessary.
367 RewriteParameterInitializerScope(
368 descriptor_->parser->stack_limit(), initializer,
369 descriptor_->scope->outer_scope(), descriptor_->scope);
370 }
371 Expression* value = factory()->NewConditional(
372 is_undefined, initializer, factory()->NewVariableProxy(temp),
373 RelocInfo::kNoPosition);
374 RecurseIntoSubpattern(node->target(), value);
375 }
376
377
378 // =============== UNREACHABLE =============================
379
380 void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
381
382 #define NOT_A_PATTERN(Node) \
383 void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
384 UNREACHABLE(); \
385 }
386
387 NOT_A_PATTERN(BinaryOperation)
388 NOT_A_PATTERN(Block)
389 NOT_A_PATTERN(BreakStatement)
390 NOT_A_PATTERN(Call)
391 NOT_A_PATTERN(CallNew)
392 NOT_A_PATTERN(CallRuntime)
393 NOT_A_PATTERN(CaseClause)
394 NOT_A_PATTERN(ClassLiteral)
395 NOT_A_PATTERN(CompareOperation)
396 NOT_A_PATTERN(Conditional)
397 NOT_A_PATTERN(ContinueStatement)
398 NOT_A_PATTERN(CountOperation)
399 NOT_A_PATTERN(DebuggerStatement)
400 NOT_A_PATTERN(DoExpression)
401 NOT_A_PATTERN(DoWhileStatement)
402 NOT_A_PATTERN(EmptyStatement)
403 NOT_A_PATTERN(EmptyParentheses)
404 NOT_A_PATTERN(ExportDeclaration)
405 NOT_A_PATTERN(ExpressionStatement)
406 NOT_A_PATTERN(ForInStatement)
407 NOT_A_PATTERN(ForOfStatement)
408 NOT_A_PATTERN(ForStatement)
409 NOT_A_PATTERN(FunctionDeclaration)
410 NOT_A_PATTERN(FunctionLiteral)
411 NOT_A_PATTERN(IfStatement)
412 NOT_A_PATTERN(ImportDeclaration)
413 NOT_A_PATTERN(Literal)
414 NOT_A_PATTERN(NativeFunctionLiteral)
415 NOT_A_PATTERN(Property)
416 NOT_A_PATTERN(RegExpLiteral)
417 NOT_A_PATTERN(ReturnStatement)
418 NOT_A_PATTERN(SloppyBlockFunctionStatement)
419 NOT_A_PATTERN(Spread)
420 NOT_A_PATTERN(SuperPropertyReference)
421 NOT_A_PATTERN(SuperCallReference)
422 NOT_A_PATTERN(SwitchStatement)
423 NOT_A_PATTERN(ThisFunction)
424 NOT_A_PATTERN(Throw)
425 NOT_A_PATTERN(TryCatchStatement)
426 NOT_A_PATTERN(TryFinallyStatement)
427 NOT_A_PATTERN(UnaryOperation)
428 NOT_A_PATTERN(VariableDeclaration)
429 NOT_A_PATTERN(WhileStatement)
430 NOT_A_PATTERN(WithStatement)
431 NOT_A_PATTERN(Yield)
432
433 #undef NOT_A_PATTERN
434 } // namespace internal
435 } // namespace v8
OLDNEW
« no previous file with comments | « src/parsing/token.cc ('k') | src/ppc/codegen-ppc.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698