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

Side by Side Diff: runtime/vm/ast_transformer.cc

Issue 447003003: Introduce await (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: addressed comments Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/ast_transformer.h"
6
7 #include "vm/parser.h"
8
9 namespace dart {
10
11 // Quick access to the locally defined isolate() method.
12 #define I (isolate())
13
14 // Nodes that are unreachable from already parsed expressions.
15 #define FOR_EACH_UNREACHABLE_NODE(V) \
16 V(Case) \
17 V(CatchClause) \
18 V(CloneContext) \
19 V(ClosureCall) \
20 V(DoWhile) \
21 V(If) \
22 V(InlinedFinally) \
23 V(For) \
24 V(Jump) \
25 V(LoadInstanceField) \
26 V(NativeBody) \
27 V(Primary) \
28 V(Return) \
29 V(Sequence) \
30 V(StoreInstanceField) \
31 V(Switch) \
32 V(TryCatch) \
33 V(While)
34
35 #define DEFINE_UNREACHABLE(BaseName) \
36 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \
37 UNREACHABLE(); \
38 }
39
40 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE)
41 #undef DEFINE_UNREACHABLE
42
43
44 void AwaitTransformer::Transform(AstNode* expr) {
hausner 2014/08/15 18:09:31 Why not return the result_ field as a function res
Michael Lippautz (Google) 2014/08/18 18:39:30 Done. I also adjusted the parser to take this ret
45 expr->Visit(this);
46 }
47
48
49 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
50 const char* await_temp_prefix = ":await_temp_var_";
51 const String& cnt_str = String::ZoneHandle(I,
52 String::NewFormatted(
53 "%s%" Pd "", await_temp_prefix, temp_cnt_));
54 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str));
55 ASSERT(!symbol.IsNull());
56 LocalVariable* await_tmp =
57 parsed_function_->await_temps_scope()->LookupVariable(symbol, false);
58 if (await_tmp == NULL) {
59 await_tmp = new(I) LocalVariable(
60 Scanner::kNoSourcePos,
61 symbol,
62 Type::ZoneHandle(I, Type::DynamicType()));
63 parsed_function_->await_temps_scope()->AddVariable(await_tmp);
64 }
65 return await_tmp;
66 }
67
68
69 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
70 LocalVariable* tmp_var = EnsureCurrentTempVar();
71 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
72 NextTempVar();
73 return tmp_var;
74 }
75
76
77 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
78 result_ = node;
79 }
80
81
82 void AwaitTransformer::VisitTypeNode(TypeNode* node) {
83 result_ = new(I) TypeNode(node->token_pos(), node->type());
84 }
85
86
87
88 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
89 // Await transformation:
90 //
91 // :await_temp_var_X = <expr>;
92 // :result_param = :await_temp_var_X;
93 // if (:result_param is Future) {
94 // // :result_param.then(:async_op);
95 // }
96 // :await_temp_var_(X+1) = :result_param;
97
98 LocalVariable* async_op = preamble_->scope()->LookupVariable(
99 Symbols::AsyncOperation(), false);
100 ASSERT(async_op != NULL);
101 LocalVariable* result_param = preamble_->scope()->LookupVariable(
102 Symbols::AsyncOperationParam(), false);
103 ASSERT(result_param != NULL);
104
105 node->expr()->Visit(this);
106 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos,
107 result_param,
108 result_));
109 LoadLocalNode* load_result_param = new(I) LoadLocalNode(
110 Scanner::kNoSourcePos, result_param);
111 SequenceNode* is_future_branch = new(I) SequenceNode(
112 Scanner::kNoSourcePos, preamble_->scope());
113 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos);
114 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op));
115 // TODO(mlippautz): Once continuations are supported, just call .then().
116 // is_future_branch->Add(new(I) InstanceCallNode(
117 // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args));
118 //
119 // For now, throw an exception.
120 const String& exception = String::ZoneHandle(
121 I, String::New("awaitable futures not yet supported", Heap::kOld));
122 is_future_branch->Add(new(I) ThrowNode(
123 Scanner::kNoSourcePos,
124 new(I) LiteralNode(
125 Scanner::kNoSourcePos,
126 String::ZoneHandle(I, Symbols::New(exception))),
127 NULL));
128 const Class& cls = Class::ZoneHandle(
129 I, library_.LookupClass(Symbols::Future()));
130 const AbstractType& future_type = AbstractType::ZoneHandle(I,
131 cls.RareType());
132 ASSERT(!future_type.IsNull());
133 TypeNode* future_type_node = new(I) TypeNode(
134 Scanner::kNoSourcePos, future_type);
135 IfNode* is_future_if = new(I) IfNode(
136 Scanner::kNoSourcePos,
137 new(I) ComparisonNode(Scanner::kNoSourcePos,
138 Token::kIS,
139 load_result_param,
140 future_type_node),
141 is_future_branch,
142 NULL);
143 preamble_->Add(is_future_if);
144
145 // TODO(mlippautz): Join for await needs to happen here.
146
147 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode(
148 Scanner::kNoSourcePos, result_param));
149 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
150 }
151
152
153 // Transforms boolean expressions into a sequence of evaluatons that only lazily
154 // evaluate subexpressions.
155 //
156 // Example:
157 //
158 // (a || b) only evaluates b if a is true
hausner 2014/08/15 18:09:31 only evaluates b if a is *false*
Michael Lippautz (Google) 2014/08/18 18:39:30 Done.
159 //
160 // Transformation (roughly):
161 //
162 // t_1 = a;
163 // if (t_1) {
hausner 2014/08/15 18:09:31 !t_1
Michael Lippautz (Google) 2014/08/18 18:39:30 Done.
164 // t_2 = b;
165 // }
166 // t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place
167 // on this level.
168 AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
169 AstNode* new_left,
170 AstNode* right) {
171 ASSERT(logical_op == Token::kAND || logical_op == Token::kOR);
172 AstNode* result = NULL;
173 const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
174 Token::kEQ : Token::kNE;
175 SequenceNode* eval = new(I) SequenceNode(
176 Scanner::kNoSourcePos, preamble_->scope());
177 SequenceNode* saved_preamble = preamble_;
178 preamble_ = eval;
179 right->Visit(this);
180 result = result_;
181 preamble_ = saved_preamble;
182 IfNode* right_body = new(I) IfNode(
183 Scanner::kNoSourcePos,
184 new(I) ComparisonNode(
185 Scanner::kNoSourcePos,
186 compare_logical_op,
187 new_left,
188 new(I) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
189 eval,
190 NULL);
191 preamble_->Add(right_body);
192 return result;
193 }
194
195
196 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
197 node->left()->Visit(this);
198 AstNode* new_left = result_;
199 AstNode* new_right = NULL;
200 // Preserve lazy evaluaton.
201 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
202 new_right = LazyTransform(node->kind(), new_left, node->right());
203 } else {
204 node->right()->Visit(this);
205 new_right = result_;
hausner 2014/08/15 18:09:31 Would it not make sense to group these two stateme
Michael Lippautz (Google) 2014/08/18 18:39:30 Done.
206 }
207 LocalVariable* result = AddToPreambleNewTempVar(
208 new(I) BinaryOpNode(node->token_pos(),
209 node->kind(),
210 new_left,
211 new_right));
212 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
213 }
214
215
216 void AwaitTransformer::VisitBinaryOpWithMask32Node(
217 BinaryOpWithMask32Node* node) {
218 node->left()->Visit(this);
219 AstNode* new_left = result_;
220 AstNode* new_right = NULL;
221 // Preserve lazy evaluaton.
222 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
223 new_right = LazyTransform(node->kind(), new_left, node->right());
224 } else {
225 node->right()->Visit(this);
226 new_right = result_;
227 }
228 LocalVariable* result = AddToPreambleNewTempVar(
229 new(I) BinaryOpWithMask32Node(node->token_pos(),
230 node->kind(),
231 new_left,
232 new_right,
233 node->mask32()));
234 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
235 }
236
237
238 void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
239 node->left()->Visit(this);
240 AstNode* new_left = result_;
241 node->right()->Visit(this);
242 AstNode* new_right = result_;
243 LocalVariable* result = AddToPreambleNewTempVar(
244 new(I) ComparisonNode(node->token_pos(),
245 node->kind(),
246 new_left,
247 new_right));
248 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
249 }
250
251
252 void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
253 node->operand()->Visit(this);
254 AstNode* new_operand = result_;
255
256 LocalVariable* result = AddToPreambleNewTempVar(
257 new(I) UnaryOpNode(node->token_pos(),
258 node->kind(),
259 new_operand));
260 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
261 }
262
263
264 // ::= (<condition>) ? <true-branch> : <false-branch>
265 //
266 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
267 node->condition()->Visit(this);
268 AstNode* new_condition = result_;
269 SequenceNode* new_true = new(I) SequenceNode(
270 Scanner::kNoSourcePos, preamble_->scope());
271 SequenceNode* saved_preamble = preamble_;
272 preamble_ = new_true;
273 node->true_expr()->Visit(this);
274 AstNode* new_true_result = result_;
275 SequenceNode* new_false = new(I) SequenceNode(
276 Scanner::kNoSourcePos, preamble_->scope());
277 preamble_ = new_false;
278 node->false_expr()->Visit(this);
279 AstNode* new_false_result = result_;
280 preamble_ = saved_preamble;
281 IfNode* new_if = new(I) IfNode(Scanner::kNoSourcePos,
282 new_condition,
283 new_true,
284 new_false);
285 preamble_->Add(new_if);
286 LocalVariable* result = AddToPreambleNewTempVar(
287 new(I) ConditionalExprNode(Scanner::kNoSourcePos,
288 new_condition,
289 new_true_result,
290 new_false_result));
291 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
292 }
293
294
295 void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) {
296 ArgumentListNode* new_args = new(I) ArgumentListNode(node->token_pos());
297 for (intptr_t i = 0; i < node->length(); i++) {
298 node->NodeAt(i)->Visit(this);
299 new_args->Add(result_);
300 }
301 result_ = new_args;
302 }
303
304
305 void AwaitTransformer::VisitArrayNode(ArrayNode* node) {
306 GrowableArray<AstNode*> new_elements;
307 for (intptr_t i = 0; i < node->length(); i++) {
308 node->ElementAt(i)->Visit(this);
309 new_elements.Add(result_);
310 }
311 result_ = new(I) ArrayNode(node->token_pos(), node->type(), new_elements);
312 }
313
314
315 void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) {
316 node->value()->Visit(this);
317 ArrayNode* new_value = result_->AsArrayNode();
318 LocalVariable* result = AddToPreambleNewTempVar(
319 new(I) StringInterpolateNode(node->token_pos(),
320 new_value));
321 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
322 }
323
324
325 void AwaitTransformer::VisitClosureNode(ClosureNode* node) {
326 AstNode* new_receiver = node->receiver();
327 if (new_receiver != NULL) {
328 new_receiver->Visit(this);
329 new_receiver = result_;
330 }
331 LocalVariable* result = AddToPreambleNewTempVar(
332 new(I) ClosureNode(node->token_pos(),
333 node->function(),
334 new_receiver,
335 node->scope()));
336 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
337 }
338
339
340 void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
341 node->receiver()->Visit(this);
342 AstNode* new_receiver = result_;
343 node->arguments()->Visit(this);
344 ArgumentListNode* new_args = result_->AsArgumentListNode();
345
346 LocalVariable* result = AddToPreambleNewTempVar(
347 new(I) InstanceCallNode(node->token_pos(),
348 new_receiver,
349 node->function_name(),
350 new_args));
351 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
352 }
353
354
355 void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
356 node->arguments()->Visit(this);
357 ArgumentListNode* new_args = result_->AsArgumentListNode();
358
359 LocalVariable* result = AddToPreambleNewTempVar(
360 new(I) StaticCallNode(node->token_pos(),
361 node->function(),
362 new_args));
363 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
364 }
365
366
367 void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
368 node->arguments()->Visit(this);
369 ArgumentListNode* new_args = result_->AsArgumentListNode();
370
371 LocalVariable* result = AddToPreambleNewTempVar(
372 new(I) ConstructorCallNode(node->token_pos(),
373 node->type_arguments(),
374 node->constructor(),
375 new_args));
376 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
377 }
378
379
380 void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) {
381 node->receiver()->Visit(this);
382 AstNode* new_receiver = result_;
383
384 LocalVariable* result = AddToPreambleNewTempVar(
385 new(I) InstanceGetterNode(node->token_pos(),
386 new_receiver,
387 node->field_name()));
388 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
389 }
390
391
392 void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) {
393 AstNode* new_receiver = node->receiver();
394 if (new_receiver != NULL) {
395 new_receiver->Visit(this);
396 new_receiver = result_;
397 }
398
399 node->value()->Visit(this);
400 AstNode* new_value = result_;
401
402 LocalVariable* result = AddToPreambleNewTempVar(
403 new(I) InstanceSetterNode(node->token_pos(),
404 new_receiver,
405 node->field_name(),
406 new_value));
407 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
408 }
409
410
411 void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
412 AstNode* new_receiver = node->receiver();
413 if (new_receiver != NULL) {
414 new_receiver->Visit(this);
415 new_receiver = result_;
416 }
417
418 LocalVariable* result = AddToPreambleNewTempVar(
419 new(I) StaticGetterNode(node->token_pos(),
420 new_receiver,
421 node->is_super_getter(),
422 node->cls(),
423 node->field_name()));
424 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
425 }
426
427
428 void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
429 AstNode* new_receiver = node->receiver();
430 if (new_receiver != NULL) {
431 new_receiver->Visit(this);
432 new_receiver = result_;
433 }
434 node->value()->Visit(this);
435 AstNode* new_value = result_;
436
437 LocalVariable* result = AddToPreambleNewTempVar(
438 new(I) StaticSetterNode(node->token_pos(),
439 new_receiver,
440 node->cls(),
441 node->field_name(),
442 new_value));
443 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
444 }
445
446
447 void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) {
448 LocalVariable* result = AddToPreambleNewTempVar(
449 new(I) LoadLocalNode(node->token_pos(), &node->local()));
450 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
451 }
452
453
454 void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) {
455 node->value()->Visit(this);
456 AstNode* new_value = result_;
457 LocalVariable* result = AddToPreambleNewTempVar(
458 new(I) StoreLocalNode(node->token_pos(),
459 &node->local(),
460 new_value));
461 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
462 }
463
464
465 void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
466 LocalVariable* result = AddToPreambleNewTempVar(
467 new(I) LoadStaticFieldNode(node->token_pos(),
468 node->field()));
469 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
470 }
471
472
473 void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
474 node->value()->Visit(this);
475 AstNode* new_value = result_;
476 LocalVariable* result = AddToPreambleNewTempVar(
477 new(I) StoreStaticFieldNode(node->token_pos(),
478 node->field(),
479 new_value));
480 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
481 }
482
483
484 void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) {
485 node->array()->Visit(this);
486 AstNode* new_array = result_;
487 node->index_expr()->Visit(this);
488 AstNode* new_index = result_;
489 LocalVariable* result = AddToPreambleNewTempVar(
490 new(I) LoadIndexedNode(node->token_pos(),
491 new_array,
492 new_index,
493 node->super_class()));
494 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
495 }
496
497
498 void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) {
499 node->array()->Visit(this);
500 AstNode* new_array = result_;
501 node->index_expr()->Visit(this);
502 AstNode* new_index = result_;
503 node->value()->Visit(this);
504 AstNode* new_value = result_;
505 LocalVariable* result = AddToPreambleNewTempVar(
506 new(I) StoreIndexedNode(node->token_pos(),
507 new_array,
508 new_index,
509 new_value,
510 node->super_class()));
511 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
512 }
513
514
515 void AwaitTransformer::VisitAssignableNode(AssignableNode* node) {
516 node->expr()->Visit(this);
517 AstNode* new_expr = result_;
518 LocalVariable* result = AddToPreambleNewTempVar(
519 new(I) AssignableNode(node->token_pos(),
520 new_expr,
521 node->type(),
522 node->dst_name()));
523 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
524 }
525
526
527 void AwaitTransformer::VisitLetNode(LetNode* node) {
528 // TODO(mlippautz): Check initializers and their temps.
529 LetNode* result = new(I) LetNode(node->token_pos());
530 for (intptr_t i = 0; i < node->nodes().length(); i++) {
531 node->nodes()[i]->Visit(this);
532 result->AddNode(result_);
533 }
534 result_ = result;
535 }
536
537
538 void AwaitTransformer::VisitThrowNode(ThrowNode* node) {
539 // TODO(mlippautz): Check if relevant.
540 node->exception()->Visit(this);
541 AstNode* new_exception = result_;
542 node->stacktrace()->Visit(this);
543 AstNode* new_stacktrace = result_;
544 result_ = new(I) ThrowNode(node->token_pos(),
545 new_exception,
546 new_stacktrace);
547 }
548
549 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698