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

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

Powered by Google App Engine
This is Rietveld 408576698