OLD | NEW |
---|---|
(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 | |
hausner
2014/08/07 21:48:43
It would be nice to write up a few lines of commen
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
11 #define I Isolate::Current() | |
hausner
2014/08/07 21:48:42
It might be good to cache the current isolate in t
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
12 | |
13 // Nodes that are unreachable from already parsed expressions. | |
14 #define FOR_EACH_UNREACHABLE_NODE(V) \ | |
15 V(Case) \ | |
16 V(CatchClause) \ | |
17 V(CloneContext) \ | |
18 V(ClosureCall) \ | |
19 V(DoWhile) \ | |
20 V(If) \ | |
21 V(InlinedFinally) \ | |
22 V(For) \ | |
23 V(Jump) \ | |
24 V(LoadInstanceField) \ | |
25 V(NativeBody) \ | |
26 V(Primary) \ | |
27 V(Return) \ | |
28 V(Sequence) \ | |
29 V(StoreInstanceField) \ | |
30 V(Switch) \ | |
31 V(TryCatch) \ | |
32 V(While) | |
33 | |
34 #define DEFINE_UNREACHABLE(BaseName) \ | |
35 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \ | |
36 UNREACHABLE(); \ | |
37 } | |
38 | |
39 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE) | |
40 #undef DEFINE_UNREACHABLE | |
41 | |
42 | |
43 void AwaitTransformer::Transform(AstNode* expr) { | |
44 expr->Visit(this); | |
45 } | |
46 | |
47 | |
48 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() { | |
49 const String& cnt_str = String::Handle( | |
50 String::NewFormatted( | |
51 "%s%" Pd "", Symbols::AwaitTempVarPrefix().ToCString(), temp_cnt_)); | |
hausner
2014/08/07 21:48:41
I'm not sure it makes sense to create a symbol for
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
52 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str)); | |
53 ASSERT(!symbol.IsNull()); | |
54 LocalVariable* await_tmp = | |
55 parsed_function_->await_temps_scope()->LookupVariable(symbol, false); | |
56 if (await_tmp == NULL) { | |
57 await_tmp = new (I) LocalVariable( | |
58 Scanner::kNoSourcePos, | |
59 symbol, | |
60 Type::ZoneHandle(I, Type::DynamicType())); | |
61 parsed_function_->await_temps_scope()->AddVariable(await_tmp); | |
62 } | |
63 return await_tmp; | |
64 } | |
65 | |
66 | |
67 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) { | |
68 LocalVariable* tmp_var = EnsureCurrentTempVar(); | |
69 preamble_->Add(new (I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node)); | |
70 NextTempVar(); | |
71 return tmp_var; | |
72 } | |
73 | |
74 | |
75 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { | |
76 result_ = new (I) LiteralNode(node->token_pos(), node->literal()); | |
hausner
2014/08/07 21:48:43
Could you not just return the node given as a para
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
77 } | |
78 | |
79 | |
80 void AwaitTransformer::VisitTypeNode(TypeNode* node) { | |
81 result_ = new (I) TypeNode(node->token_pos(), node->type()); | |
82 } | |
83 | |
84 | |
85 | |
86 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { | |
87 // Await transformation: | |
88 // | |
89 // :await_temp_var_X = <expr>; | |
90 // :result_param = :await_temp_var_X; | |
91 // if (:result_param is Future) { | |
92 // // :result_param.then(:async_op); | |
93 // } | |
94 // :await_temp_var_(X+1) = :result_param; | |
95 | |
96 LocalVariable* async_op = preamble_->scope()->LookupVariable( | |
hausner
2014/08/07 21:48:42
LookupVariable() will search outer scopes, which i
Michael Lippautz (Google)
2014/08/08 18:12:17
I think LookupVariable() is right here.
The scope
| |
97 Symbols::AsyncOperation(), false); | |
98 ASSERT(async_op != NULL); | |
99 LocalVariable* result_param = preamble_->scope()->LookupVariable( | |
100 Symbols::AsyncOperationParam(), false); | |
101 ASSERT(result_param != NULL); | |
102 | |
103 node->expr()->Visit(this); | |
104 preamble_->Add(new (I) StoreLocalNode(Scanner::kNoSourcePos, | |
105 result_param, | |
106 result_)); | |
107 LoadLocalNode* load_result_param = new (I) LoadLocalNode( | |
108 Scanner::kNoSourcePos, result_param); | |
109 SequenceNode* is_future_branch = new (I) SequenceNode( | |
110 Scanner::kNoSourcePos, preamble_->scope()); | |
111 ArgumentListNode* args = new (I) ArgumentListNode(Scanner::kNoSourcePos); | |
112 args->Add(new (I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); | |
113 // TODO(mlippautz): Once continuations are supported, just call .then(). | |
114 // is_future_branch->Add(new (I) InstanceCallNode( | |
115 // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); | |
116 is_future_branch->Add(new (I) ReturnNode(Scanner::kNoSourcePos)); | |
hausner
2014/08/07 21:48:42
Instead of silently return null, maybe throw an ex
Michael Lippautz (Google)
2014/08/08 18:12:17
Done. I am not sure why the literal needs to be a
| |
117 const Class& cls = Class::Handle(library_.LookupClass( | |
118 String::Handle(String::New("Future")))); | |
hausner
2014/08/07 21:48:42
We should probably have a predefined symbol for "F
Michael Lippautz (Google)
2014/08/08 18:12:17
Done. We already had a symbol.
| |
119 const AbstractType& future_type = AbstractType::ZoneHandle(I, | |
120 cls.RareType()); | |
121 ASSERT(!future_type.IsNull()); | |
122 TypeNode* future_type_node = new (I) TypeNode( | |
123 Scanner::kNoSourcePos, future_type); | |
124 IfNode* is_future_if = new (I) IfNode( | |
125 Scanner::kNoSourcePos, | |
126 new (I) ComparisonNode(Scanner::kNoSourcePos, | |
127 Token::kIS, | |
128 load_result_param, | |
129 future_type_node), | |
130 is_future_branch, | |
131 NULL); | |
132 preamble_->Add(is_future_if); | |
133 | |
134 // TODO(mlippautz): Jump target (label) should be added here. | |
135 | |
136 LocalVariable* result = AddToPreambleNewTempVar(new (I) LoadLocalNode( | |
137 Scanner::kNoSourcePos, result_param)); | |
138 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
139 } | |
140 | |
141 | |
142 AstNode* AwaitTransformer::LazyTransform(const Token::Kind kind, | |
hausner
2014/08/07 21:48:42
How about renaming this parameter to logical_op or
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
143 AstNode* new_left, | |
144 AstNode* right) { | |
145 ASSERT(kind == Token::kAND || kind == Token::kOR); | |
146 AstNode* result = NULL; | |
147 const Token::Kind compare_kind = (kind == Token::kAND) ? | |
148 Token::kEQ : Token::kNE; | |
149 SequenceNode* eval = new SequenceNode( | |
150 Scanner::kNoSourcePos, preamble_->scope()); | |
151 SequenceNode* saved_preamble = preamble_; | |
152 preamble_ = eval; | |
153 right->Visit(this); | |
154 result = result_; | |
155 preamble_ = saved_preamble; | |
156 IfNode* right_body = new (I) IfNode( | |
157 Scanner::kNoSourcePos, | |
158 new (I) ComparisonNode( | |
159 Scanner::kNoSourcePos, | |
160 compare_kind, | |
161 new_left, | |
162 new (I) LiteralNode(Scanner::kNoSourcePos, Bool::True())), | |
163 eval, | |
164 NULL); | |
165 preamble_->Add(right_body); | |
166 return result; | |
167 } | |
168 | |
169 | |
170 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) { | |
171 node->left()->Visit(this); | |
172 AstNode* new_left = result_; | |
173 AstNode* new_right = new (I) LiteralNode( | |
hausner
2014/08/07 21:48:42
Why do you allocate a node here when new_right get
Michael Lippautz (Google)
2014/08/08 18:12:17
Not needed. Done.
| |
174 Scanner::kNoSourcePos, | |
175 Object::null_instance()); | |
176 // Preserve lazy evaluaton. | |
177 if (node->kind() == Token::kAND || node->kind() == Token::kOR) { | |
178 new_right = LazyTransform(node->kind(), new_left, node->right()); | |
179 } else { | |
180 node->right()->Visit(this); | |
181 new_right = result_; | |
182 } | |
183 LocalVariable* result = AddToPreambleNewTempVar( | |
184 new (I) BinaryOpNode(node->token_pos(), | |
185 node->kind(), | |
186 new_left, | |
187 new_right)); | |
188 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
189 } | |
190 | |
191 | |
192 void AwaitTransformer::VisitBinaryOpWithMask32Node( | |
193 BinaryOpWithMask32Node* node) { | |
194 node->left()->Visit(this); | |
195 AstNode* new_left = result_; | |
196 AstNode* new_right = new (I) LiteralNode( | |
hausner
2014/08/07 21:48:42
See note above.
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
197 Scanner::kNoSourcePos, | |
198 Object::null_instance()); | |
199 // Preserve lazy evaluaton. | |
200 if (node->kind() == Token::kAND || node->kind() == Token::kOR) { | |
201 new_right = LazyTransform(node->kind(), new_left, node->right()); | |
202 } else { | |
203 node->right()->Visit(this); | |
204 new_right = result_; | |
205 } | |
206 | |
207 LocalVariable* result = AddToPreambleNewTempVar( | |
208 new (I) BinaryOpWithMask32Node(node->token_pos(), | |
209 node->kind(), | |
210 new_left, | |
211 new_right, | |
212 node->mask32())); | |
213 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
214 } | |
215 | |
216 | |
217 void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) { | |
218 node->left()->Visit(this); | |
219 AstNode* new_left = result_; | |
220 node->right()->Visit(this); | |
221 AstNode* new_right = result_; | |
222 LocalVariable* result = AddToPreambleNewTempVar( | |
223 new (I) ComparisonNode(node->token_pos(), | |
224 node->kind(), | |
225 new_left, | |
226 new_right)); | |
227 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
228 } | |
229 | |
230 | |
231 void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) { | |
232 node->operand()->Visit(this); | |
233 AstNode* new_operand = result_; | |
234 | |
235 LocalVariable* result = AddToPreambleNewTempVar( | |
236 new (I) UnaryOpNode(node->token_pos(), | |
237 node->kind(), | |
238 new_operand)); | |
239 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
240 } | |
241 | |
242 // ::= (<condition>) ? <true-branch> : <false-branch> | |
hausner
2014/08/07 21:48:42
Nit: add empty line.
Michael Lippautz (Google)
2014/08/08 18:12:17
Done.
| |
243 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) { | |
244 // TODO(mlippautz): Optimize variable assingments and branching. | |
245 node->condition()->Visit(this); | |
246 AstNode* new_condition = result_; | |
247 SequenceNode* new_true = new (I) SequenceNode( | |
248 Scanner::kNoSourcePos, preamble_->scope()); | |
249 SequenceNode* saved_preamble = preamble_; | |
250 preamble_ = new_true; | |
251 node->true_expr()->Visit(this); | |
252 AstNode* new_true_result = result_; | |
253 SequenceNode* new_false = new (I) SequenceNode( | |
254 Scanner::kNoSourcePos, preamble_->scope()); | |
255 preamble_ = new_false; | |
256 node->false_expr()->Visit(this); | |
257 AstNode* new_false_result = result_; | |
258 preamble_ = saved_preamble; | |
259 IfNode* new_if = new (I) IfNode(Scanner::kNoSourcePos, | |
260 new_condition, | |
261 new_true, | |
262 new_false); | |
263 preamble_->Add(new_if); | |
264 LocalVariable* result = AddToPreambleNewTempVar( | |
265 new (I) ConditionalExprNode(Scanner::kNoSourcePos, | |
266 new_condition, | |
267 new_true_result, | |
268 new_false_result)); | |
269 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
270 } | |
271 | |
272 | |
273 void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) { | |
274 ArgumentListNode* new_args = new (I) ArgumentListNode(node->token_pos()); | |
275 for (intptr_t i = 0; i < node->length(); i++) { | |
276 node->NodeAt(i)->Visit(this); | |
277 new_args->Add(result_); | |
278 } | |
279 result_ = new_args; | |
280 } | |
281 | |
282 | |
283 void AwaitTransformer::VisitArrayNode(ArrayNode* node) { | |
284 GrowableArray<AstNode*> new_elements; | |
285 for (intptr_t i = 0; i < node->length(); i++) { | |
286 node->ElementAt(i)->Visit(this); | |
287 new_elements.Add(result_); | |
288 } | |
289 result_ = new (I) ArrayNode(node->token_pos(), node->type(), new_elements); | |
290 } | |
291 | |
292 | |
293 void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) { | |
294 node->value()->Visit(this); | |
295 ArrayNode* new_value = result_->AsArrayNode(); | |
296 LocalVariable* result = AddToPreambleNewTempVar( | |
297 new (I) StringInterpolateNode(node->token_pos(), | |
298 new_value)); | |
299 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
300 } | |
301 | |
302 | |
303 void AwaitTransformer::VisitClosureNode(ClosureNode* node) { | |
304 AstNode* new_receiver = node->receiver(); | |
305 if (new_receiver != NULL) { | |
306 new_receiver->Visit(this); | |
307 new_receiver = result_; | |
308 } | |
309 LocalVariable* result = AddToPreambleNewTempVar( | |
310 new (I) ClosureNode(node->token_pos(), | |
311 node->function(), | |
312 new_receiver, | |
313 node->scope())); | |
314 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
315 } | |
316 | |
317 | |
318 void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) { | |
319 node->receiver()->Visit(this); | |
320 AstNode* new_receiver = result_; | |
321 node->arguments()->Visit(this); | |
322 ArgumentListNode* new_args = result_->AsArgumentListNode(); | |
323 | |
324 LocalVariable* result = AddToPreambleNewTempVar( | |
325 new (I) InstanceCallNode(node->token_pos(), | |
326 new_receiver, | |
327 node->function_name(), | |
328 new_args)); | |
329 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
330 } | |
331 | |
332 | |
333 void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) { | |
334 node->arguments()->Visit(this); | |
335 ArgumentListNode* new_args = result_->AsArgumentListNode(); | |
336 | |
337 LocalVariable* result = AddToPreambleNewTempVar( | |
338 new (I) StaticCallNode(node->token_pos(), | |
339 node->function(), | |
340 new_args)); | |
341 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
342 } | |
343 | |
344 | |
345 void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) { | |
346 node->arguments()->Visit(this); | |
347 ArgumentListNode* new_args = result_->AsArgumentListNode(); | |
348 | |
349 LocalVariable* result = AddToPreambleNewTempVar( | |
350 new (I) ConstructorCallNode(node->token_pos(), | |
351 node->type_arguments(), | |
352 node->constructor(), | |
353 new_args)); | |
354 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
355 } | |
356 | |
357 | |
358 void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) { | |
359 node->receiver()->Visit(this); | |
360 AstNode* new_receiver = result_; | |
361 | |
362 LocalVariable* result = AddToPreambleNewTempVar( | |
363 new (I) InstanceGetterNode(node->token_pos(), | |
364 new_receiver, | |
365 node->field_name())); | |
366 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
367 } | |
368 | |
369 | |
370 void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) { | |
371 AstNode* new_receiver = node->receiver(); | |
372 if (new_receiver != NULL) { | |
373 new_receiver->Visit(this); | |
374 new_receiver = result_; | |
375 } | |
376 | |
377 node->value()->Visit(this); | |
378 AstNode* new_value = result_; | |
379 | |
380 LocalVariable* result = AddToPreambleNewTempVar( | |
381 new (I) InstanceSetterNode(node->token_pos(), | |
382 new_receiver, | |
383 node->field_name(), | |
384 new_value)); | |
385 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
386 } | |
387 | |
388 | |
389 void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) { | |
390 AstNode* new_receiver = node->receiver(); | |
391 if (new_receiver != NULL) { | |
392 new_receiver->Visit(this); | |
393 new_receiver = result_; | |
394 } | |
395 | |
396 LocalVariable* result = AddToPreambleNewTempVar( | |
397 new (I) StaticGetterNode(node->token_pos(), | |
398 new_receiver, | |
399 node->is_super_getter(), | |
400 node->cls(), | |
401 node->field_name())); | |
402 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
403 } | |
404 | |
405 | |
406 void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) { | |
407 AstNode* new_receiver = node->receiver(); | |
408 if (new_receiver != NULL) { | |
409 new_receiver->Visit(this); | |
410 new_receiver = result_; | |
411 } | |
412 node->value()->Visit(this); | |
413 AstNode* new_value = result_; | |
414 | |
415 LocalVariable* result = AddToPreambleNewTempVar( | |
416 new (I) StaticSetterNode(node->token_pos(), | |
417 new_receiver, | |
418 node->cls(), | |
419 node->field_name(), | |
420 new_value)); | |
421 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
422 } | |
423 | |
424 | |
425 void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) { | |
426 LocalVariable* result = AddToPreambleNewTempVar( | |
427 new (I) LoadLocalNode(node->token_pos(), &node->local())); | |
428 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
429 } | |
430 | |
431 | |
432 void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) { | |
433 node->value()->Visit(this); | |
434 AstNode* new_value = result_; | |
435 LocalVariable* result = AddToPreambleNewTempVar( | |
436 new (I) StoreLocalNode(node->token_pos(), | |
437 &node->local(), | |
438 new_value)); | |
439 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
440 } | |
441 | |
442 | |
443 void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) { | |
444 LocalVariable* result = AddToPreambleNewTempVar( | |
445 new (I) LoadStaticFieldNode(node->token_pos(), | |
446 node->field())); | |
447 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
448 } | |
449 | |
450 | |
451 void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { | |
452 node->value()->Visit(this); | |
453 AstNode* new_value = result_; | |
454 LocalVariable* result = AddToPreambleNewTempVar( | |
455 new (I) StoreStaticFieldNode(node->token_pos(), | |
456 node->field(), | |
457 new_value)); | |
458 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
459 } | |
460 | |
461 | |
462 void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) { | |
463 node->array()->Visit(this); | |
464 AstNode* new_array = result_; | |
465 node->index_expr()->Visit(this); | |
466 AstNode* new_index = result_; | |
467 LocalVariable* result = AddToPreambleNewTempVar( | |
468 new (I) LoadIndexedNode(node->token_pos(), | |
469 new_array, | |
470 new_index, | |
471 node->super_class())); | |
472 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
473 } | |
474 | |
475 | |
476 void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) { | |
477 node->array()->Visit(this); | |
478 AstNode* new_array = result_; | |
479 node->index_expr()->Visit(this); | |
480 AstNode* new_index = result_; | |
481 node->value()->Visit(this); | |
482 AstNode* new_value = result_; | |
483 LocalVariable* result = AddToPreambleNewTempVar( | |
484 new (I) StoreIndexedNode(node->token_pos(), | |
485 new_array, | |
486 new_index, | |
487 new_value, | |
488 node->super_class())); | |
489 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
490 } | |
491 | |
492 | |
493 void AwaitTransformer::VisitAssignableNode(AssignableNode* node) { | |
494 node->expr()->Visit(this); | |
495 AstNode* new_expr = result_; | |
496 LocalVariable* result = AddToPreambleNewTempVar( | |
497 new (I) AssignableNode(node->token_pos(), | |
498 new_expr, | |
499 node->type(), | |
500 node->dst_name())); | |
501 result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result); | |
502 } | |
503 | |
504 | |
505 void AwaitTransformer::VisitLetNode(LetNode* node) { | |
506 // TODO(mlippautz): Check initializers and their temps. | |
507 LetNode* result = new (I) LetNode(node->token_pos()); | |
508 for (intptr_t i = 0; i < node->nodes().length(); i++) { | |
509 node->nodes()[i]->Visit(this); | |
510 result->AddNode(result_); | |
511 } | |
512 result_ = result; | |
513 } | |
514 | |
515 | |
516 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { | |
517 // TODO(mlippautz): Check if relevant. | |
518 node->exception()->Visit(this); | |
519 AstNode* new_exception = result_; | |
520 node->stacktrace()->Visit(this); | |
521 AstNode* new_stacktrace = result_; | |
522 result_ = new (I) ThrowNode(node->token_pos(), | |
523 new_exception, | |
524 new_stacktrace); | |
525 } | |
526 | |
527 } // namespace dart | |
OLD | NEW |