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

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

Powered by Google App Engine
This is Rietveld 408576698