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

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

Issue 1130623004: [destructuring] Implement basic binding destructuring infrastructure (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Patch for landing 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
(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/parser.h"
7 #include "src/pattern-rewriter.h"
8
9 namespace v8 {
10
11 namespace internal {
12
13
14 bool Parser::PatternRewriter::IsSingleVariableBinding() const {
15 return pattern_->IsVariableProxy();
16 }
17
18
19 const AstRawString* Parser::PatternRewriter::SingleName() const {
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 }
34
35
36 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
37 Expression* value = current_value_;
38 decl_->scope->RemoveUnresolved(pattern->AsVariableProxy());
39
40 // Declare variable.
41 // 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
43 // when the variable is encountered in the source. But the variable/constant
44 // is declared (and set to 'undefined') upon entering the function within
45 // which the variable or constant is declared. Only function variables have
46 // an initial value in the declaration (because they are initialized upon
47 // entering the function).
48 //
49 // If we have a legacy const declaration, in an inner scope, the proxy
50 // is always bound to the declared variable (independent of possibly
51 // surrounding 'with' statements).
52 // 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
54 // declaration.
55 Parser* parser = decl_->parser;
56 const AstRawString* name = pattern->raw_name();
57 VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode);
58 Declaration* declaration = factory()->NewVariableDeclaration(
59 proxy, decl_->mode, decl_->scope, decl_->pos);
60 Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_);
61 if (!*ok_) return;
62 DCHECK_NOT_NULL(var);
63 DCHECK(!proxy->is_resolved() || proxy->var() == var);
64 var->set_initializer_position(decl_->initializer_position);
65 (*nvars_)++;
66 if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
67 parser->ReportMessage("too_many_variables");
68 *ok_ = false;
69 return;
70 }
71 if (decl_->names) {
72 decl_->names->Add(name, zone());
73 }
74
75 // Initialize variables if needed. A
76 // declaration of the form:
77 //
78 // var v = x;
79 //
80 // is syntactic sugar for:
81 //
82 // var v; v = x;
83 //
84 // 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
86 // declaration (e.g., if we are inside a 'with' statement or 'catch'
87 // block).
88 //
89 // However, note that const declarations are different! A const
90 // declaration of the form:
91 //
92 // const c = x;
93 //
94 // is *not* syntactic sugar for:
95 //
96 // const c; c = x;
97 //
98 // 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
100 // Declare() call above).
101 Scope* initialization_scope =
102 decl_->is_const ? decl_->declaration_scope : decl_->scope;
103
104
105 // Global variable declarations must be compiled in a specific
106 // way. When the script containing the global variable declaration
107 // 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
109 // gets created with an initial undefined value. This is handled
110 // by the declarations part of the function representing the
111 // top-level global code; see Runtime::DeclareGlobalVariable. If
112 // it already exists (in the object or in a prototype), it is
113 // *not* touched until the variable declaration statement is
114 // executed.
115 //
116 // Executing the variable declaration statement will always
117 // guarantee to give the global object an own property.
118 // This way, global variable declarations can shadow
119 // properties in the prototype chain, but only after the variable
120 // declaration statement has been executed. This is important in
121 // browsers where the global object (window) has lots of
122 // properties defined in prototype objects.
123 if (initialization_scope->is_script_scope() &&
124 !IsLexicalVariableMode(decl_->mode)) {
125 // Compute the arguments for the runtime
126 // call.test-parsing/InitializedDeclarationsInStrictForOfError
127 ZoneList<Expression*>* arguments =
128 new (zone()) ZoneList<Expression*>(3, zone());
129 // We have at least 1 parameter.
130 arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone());
131 CallRuntime* initialize;
132
133 if (decl_->is_const) {
134 arguments->Add(value, zone());
135 value = NULL; // zap the value to avoid the unnecessary assignment
136
137 // Construct the call to Runtime_InitializeConstGlobal
138 // and add it to the initialization statement block.
139 // Note that the function does different things depending on
140 // the number of arguments (1 or 2).
141 initialize = factory()->NewCallRuntime(
142 ast_value_factory()->initialize_const_global_string(),
143 Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
144 decl_->pos);
145 } else {
146 // Add language mode.
147 // We may want to pass singleton to avoid Literal allocations.
148 LanguageMode language_mode = initialization_scope->language_mode();
149 arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos),
150 zone());
151
152 // Be careful not to assign a value to the global variable if
153 // we're in a with. The initialization value should not
154 // necessarily be stored in the global object in that case,
155 // which is why we need to generate a separate assignment node.
156 if (value != NULL && !inside_with()) {
157 arguments->Add(value, zone());
158 value = NULL; // zap the value to avoid the unnecessary assignment
159 // Construct the call to Runtime_InitializeVarGlobal
160 // and add it to the initialization statement block.
161 initialize = factory()->NewCallRuntime(
162 ast_value_factory()->initialize_var_global_string(),
163 Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
164 decl_->pos);
165 } else {
166 initialize = NULL;
167 }
168 }
169
170 if (initialize != NULL) {
171 decl_->block->AddStatement(
172 factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
173 zone());
174 }
175 } else if (decl_->needs_init) {
176 // Constant initializations always assign to the declared constant which
177 // is always at the function scope level. This is only relevant for
178 // dynamically looked-up variables and constants (the
179 // start context for constant lookups is always the function context,
180 // while it is the top context for var declared variables). Sigh...
181 // For 'let' and 'const' declared variables in harmony mode the
182 // initialization also always assigns to the declared variable.
183 DCHECK_NOT_NULL(proxy);
184 DCHECK_NOT_NULL(proxy->var());
185 DCHECK_NOT_NULL(value);
186 Assignment* assignment =
187 factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
188 decl_->block->AddStatement(
189 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
190 zone());
191 value = NULL;
192 }
193
194 // Add an assignment node to the initialization statement block if we still
195 // have a pending initialization value.
196 if (value != NULL) {
197 DCHECK(decl_->mode == VAR);
198 // 'var' initializations are simply assignments (with all the consequences
199 // if they are inside a 'with' statement - they may change a 'with' object
200 // property).
201 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
202 Assignment* assignment =
203 factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
204 decl_->block->AddStatement(
205 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
206 zone());
207 }
208 }
209
210
211 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
212 auto temp = decl_->declaration_scope->NewTemporary(
213 ast_value_factory()->empty_string());
214 auto assignment =
215 factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
216 current_value_, RelocInfo::kNoPosition);
217 decl_->block->AddStatement(
218 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
219 zone());
220 for (ObjectLiteralProperty* property : *pattern->properties()) {
221 // TODO(dslomov): computed property names.
222 RecurseIntoSubpattern(
223 property->value(),
224 factory()->NewProperty(factory()->NewVariableProxy(temp),
225 property->key(), RelocInfo::kNoPosition));
226 }
227 }
228
229
230 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
231 // TODO(dslomov): implement.
232 }
233
234
235 void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
236 // TODO(dslomov): implement.
237 }
238
239
240 void Parser::PatternRewriter::VisitSpread(Spread* node) {
241 // TODO(dslomov): implement.
242 }
243
244
245 // =============== UNREACHABLE =============================
246
247 void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
248
249 #define NOT_A_PATTERN(Node) \
250 void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
251 UNREACHABLE(); \
252 }
253
254 NOT_A_PATTERN(BinaryOperation)
255 NOT_A_PATTERN(Block)
256 NOT_A_PATTERN(BreakStatement)
257 NOT_A_PATTERN(Call)
258 NOT_A_PATTERN(CallNew)
259 NOT_A_PATTERN(CallRuntime)
260 NOT_A_PATTERN(CaseClause)
261 NOT_A_PATTERN(ClassLiteral)
262 NOT_A_PATTERN(CompareOperation)
263 NOT_A_PATTERN(Conditional)
264 NOT_A_PATTERN(ContinueStatement)
265 NOT_A_PATTERN(CountOperation)
266 NOT_A_PATTERN(DebuggerStatement)
267 NOT_A_PATTERN(DoWhileStatement)
268 NOT_A_PATTERN(EmptyStatement)
269 NOT_A_PATTERN(ExportDeclaration)
270 NOT_A_PATTERN(ExpressionStatement)
271 NOT_A_PATTERN(ForInStatement)
272 NOT_A_PATTERN(ForOfStatement)
273 NOT_A_PATTERN(ForStatement)
274 NOT_A_PATTERN(FunctionDeclaration)
275 NOT_A_PATTERN(FunctionLiteral)
276 NOT_A_PATTERN(IfStatement)
277 NOT_A_PATTERN(ImportDeclaration)
278 NOT_A_PATTERN(Literal)
279 NOT_A_PATTERN(NativeFunctionLiteral)
280 NOT_A_PATTERN(Property)
281 NOT_A_PATTERN(RegExpLiteral)
282 NOT_A_PATTERN(ReturnStatement)
283 NOT_A_PATTERN(SuperReference)
284 NOT_A_PATTERN(SwitchStatement)
285 NOT_A_PATTERN(ThisFunction)
286 NOT_A_PATTERN(Throw)
287 NOT_A_PATTERN(TryCatchStatement)
288 NOT_A_PATTERN(TryFinallyStatement)
289 NOT_A_PATTERN(UnaryOperation)
290 NOT_A_PATTERN(VariableDeclaration)
291 NOT_A_PATTERN(WhileStatement)
292 NOT_A_PATTERN(WithStatement)
293 NOT_A_PATTERN(Yield)
294
295 #undef NOT_A_PATTERN
296 }
297 } // 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