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

Side by Side Diff: lib/transformations/continuation.dart

Issue 2460373002: Remove BlockExpression from the Kernel language. (Closed)
Patch Set: Created 4 years, 1 month 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
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library kernel.transformations.continuation; 5 library kernel.transformations.continuation;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 8
9 import '../ast.dart'; 9 import '../ast.dart';
10 import '../visitor.dart'; 10 import '../visitor.dart';
(...skipping 15 matching lines...) Expand all
26 26
27 RecursiveContinuationRewriter(this.helper); 27 RecursiveContinuationRewriter(this.helper);
28 28
29 Program rewriteProgram(Program node) { 29 Program rewriteProgram(Program node) {
30 return node.accept(this); 30 return node.accept(this);
31 } 31 }
32 32
33 visitFunctionNode(FunctionNode node) { 33 visitFunctionNode(FunctionNode node) {
34 switch (node.asyncMarker) { 34 switch (node.asyncMarker) {
35 case AsyncMarker.Sync: 35 case AsyncMarker.Sync:
36 return super.visitFunctionNode(node); 36 case AsyncMarker.SyncYielding:
37 node.transformChildren(new RecursiveContinuationRewriter(helper));
Kevin Millikin (Google) 2016/10/31 12:29:32 super.visitFunctionNode(node) is node.transformChi
38 return node;
37 case AsyncMarker.SyncStar: 39 case AsyncMarker.SyncStar:
38 return new SyncStarFunctionRewriter(helper, node).rewrite(); 40 return new SyncStarFunctionRewriter(helper, node).rewrite();
39 case AsyncMarker.Async: 41 case AsyncMarker.Async:
40 return new AsyncFunctionRewriter(helper, node).rewrite(); 42 return new AsyncFunctionRewriter(helper, node).rewrite();
41 case AsyncMarker.AsyncStar: 43 case AsyncMarker.AsyncStar:
42 return new AsyncStarFunctionRewriter(helper, node).rewrite(); 44 return new AsyncStarFunctionRewriter(helper, node).rewrite();
43 case AsyncMarker.SyncYielding:
44 return super.visitFunctionNode(node);
45 } 45 }
46 } 46 }
47 } 47 }
48 48
49 abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter { 49 abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter {
50 final FunctionNode enclosingFunction; 50 final FunctionNode enclosingFunction;
51 51
52 int currentTryDepth; // Nesting depth for try-blocks. 52 int currentTryDepth; // Nesting depth for try-blocks.
53 int currentCatchDepth = 0; // Nesting depth for catch-blocks. 53 int currentCatchDepth = 0; // Nesting depth for catch-blocks.
54 int capturedTryDepth = 0; // Deepest yield point within a try-block. 54 int capturedTryDepth = 0; // Deepest yield point within a try-block.
55 int capturedCatchDepth = 0; // Deepest yield point within a catch-block. 55 int capturedCatchDepth = 0; // Deepest yield point within a catch-block.
56 56
57 ContinuationRewriterBase(HelperNodes helper, 57 ContinuationRewriterBase(HelperNodes helper,
58 this.enclosingFunction, 58 this.enclosingFunction,
59 {this.currentTryDepth: 0}) 59 {this.currentTryDepth: 0})
60 : super(helper); 60 : super(helper);
61 61
62 Statement createContinuationPoint([value]) { 62 Statement createContinuationPoint([Expression value]) {
63 if (value == null) value = new NullLiteral(); 63 if (value == null) value = new NullLiteral();
64 capturedTryDepth = math.max(capturedTryDepth, currentTryDepth); 64 capturedTryDepth = math.max(capturedTryDepth, currentTryDepth);
65 capturedCatchDepth = math.max(capturedCatchDepth, currentCatchDepth); 65 capturedCatchDepth = math.max(capturedCatchDepth, currentCatchDepth);
66 return new YieldStatement(value, isNative: true); 66 return new YieldStatement(value, isNative: true);
67 } 67 }
68 68
69 TreeNode visitTryCatch(TryCatch node) { 69 TreeNode visitTryCatch(TryCatch node) {
70 if (node.body != null) { 70 if (node.body != null) {
71 currentTryDepth++; 71 currentTryDepth++;
72 node.body = node.body.accept(this); 72 node.body = node.body.accept(this);
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 final VariableDeclaration catchErrorContinuationVariable = 182 final VariableDeclaration catchErrorContinuationVariable =
183 new VariableDeclaration(":async_op_error"); 183 new VariableDeclaration(":async_op_error");
184 184
185 ExpressionLifter expressionRewriter; 185 ExpressionLifter expressionRewriter;
186 186
187 AsyncRewriterBase(helper, enclosingFunction) 187 AsyncRewriterBase(helper, enclosingFunction)
188 // Body is wrapped in the try-catch so initial currentTryDepth is 1. 188 // Body is wrapped in the try-catch so initial currentTryDepth is 1.
189 : super(helper, enclosingFunction, currentTryDepth: 1) { 189 : super(helper, enclosingFunction, currentTryDepth: 1) {
190 } 190 }
191 191
192 setupAsyncContinuations(List<Statement> statements) { 192 void setupAsyncContinuations(List<Statement> statements) {
193 expressionRewriter = new ExpressionLifter(this); 193 expressionRewriter = new ExpressionLifter(this);
194 194
195 // var :async_op_then; 195 // var :async_op_then;
196 statements.add(thenContinuationVariable); 196 statements.add(thenContinuationVariable);
197 197
198 // var :async_op_error; 198 // var :async_op_error;
199 statements.add(catchErrorContinuationVariable); 199 statements.add(catchErrorContinuationVariable);
200 200
201 // :async_op([:result, :exception, :stack_trace]) { 201 // :async_op([:result, :exception, :stack_trace]) {
202 // modified <node.body>; 202 // modified <node.body>;
203 // } 203 // }
204 final parameters = [ 204 final parameters = <VariableDeclaration>[
205 expressionRewriter.asyncResult, 205 expressionRewriter.asyncResult,
206 new VariableDeclaration(':exception'), 206 new VariableDeclaration(':exception'),
207 new VariableDeclaration(':stack_trace'), 207 new VariableDeclaration(':stack_trace'),
208 ]; 208 ];
209 final function = new FunctionNode( 209 final function = new FunctionNode(
210 buildWrappedBody(), 210 buildWrappedBody(),
211 positionalParameters: parameters, 211 positionalParameters: parameters,
212 requiredParameterCount: 0, 212 requiredParameterCount: 0,
213 asyncMarker: AsyncMarker.SyncYielding); 213 asyncMarker: AsyncMarker.SyncYielding);
214 214
215 // The await expression lifter might have created a number of 215 // The await expression lifter might have created a number of
216 // [VariableDeclarations]. 216 // [VariableDeclarations].
217 // TODO(kustermann): If we didn't need any variables we should not emit 217 // TODO(kustermann): If we didn't need any variables we should not emit
218 // these. 218 // these.
219 statements.addAll(variableDeclarations()); 219 statements.addAll(variableDeclarations());
220 statements.addAll(expressionRewriter.variables); 220 statements.addAll(expressionRewriter.variables);
221 221
222 // Now add the closure function itself. 222 // Now add the closure function itself.
223 final closureFunction = 223 final closureFunction =
224 new FunctionDeclaration(nestedClosureVariable, function); 224 new FunctionDeclaration(nestedClosureVariable, function);
225 statements.add(closureFunction); 225 statements.add(closureFunction);
226 226
227 // :async_op_then = _asyncThenWrapperHelper(asyncBody); 227 // :async_op_then = _asyncThenWrapperHelper(asyncBody);
228 final boundThenClosure = new StaticInvocation( 228 final boundThenClosure = new StaticInvocation(
229 helper.asyncThenWrapper, 229 helper.asyncThenWrapper,
230 new Arguments([new VariableGet(nestedClosureVariable)])); 230 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]));
231 final thenClosureVariableAssign = new ExpressionStatement(new VariableSet( 231 final thenClosureVariableAssign = new ExpressionStatement(new VariableSet(
232 thenContinuationVariable, boundThenClosure)); 232 thenContinuationVariable, boundThenClosure));
233 statements.add(thenClosureVariableAssign); 233 statements.add(thenClosureVariableAssign);
234 234
235 // :async_op_error = _asyncErrorWrapperHelper(asyncBody); 235 // :async_op_error = _asyncErrorWrapperHelper(asyncBody);
236 final boundCatchErrorClosure = new StaticInvocation( 236 final boundCatchErrorClosure = new StaticInvocation(
237 helper.asyncErrorWrapper, 237 helper.asyncErrorWrapper,
238 new Arguments([new VariableGet(nestedClosureVariable)])); 238 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]));
239 final catchErrorClosureVariableAssign = 239 final catchErrorClosureVariableAssign =
240 new ExpressionStatement(new VariableSet( 240 new ExpressionStatement(new VariableSet(
241 catchErrorContinuationVariable , boundCatchErrorClosure)); 241 catchErrorContinuationVariable , boundCatchErrorClosure));
242 statements.add(catchErrorClosureVariableAssign); 242 statements.add(catchErrorClosureVariableAssign);
243 } 243 }
244 244
245 Statement buildWrappedBody() { 245 Statement buildWrappedBody() {
246 // No explicit return at the end of the body => we will add one! 246 // No explicit return at the end of the body => we will add one!
247 var body = addReturnStatementIfNecessary(enclosingFunction.body); 247 var body = addReturnStatementIfNecessary(enclosingFunction.body);
248 var userBody = buildClosureBody(body); 248 var userBody = visitDelimited(body);
249 249
250 var exceptionVariable = new VariableDeclaration(":exception"); 250 var exceptionVariable = new VariableDeclaration(":exception");
251 var stackTraceVariable = new VariableDeclaration(":stack_trace"); 251 var stackTraceVariable = new VariableDeclaration(":stack_trace");
252 252
253 var completeErrorStatement = 253 var completeErrorStatement =
254 buildCatchBody(exceptionVariable, stackTraceVariable); 254 buildCatchBody(exceptionVariable, stackTraceVariable);
255 255
256 var catchBody = new Block(<Statement>[completeErrorStatement]); 256 var catchBody = new Block(<Statement>[completeErrorStatement]);
257 var catches = [new Catch(exceptionVariable, 257 var catches = <Catch>[new Catch(exceptionVariable,
258 catchBody, 258 catchBody,
259 stackTrace: stackTraceVariable)]; 259 stackTrace: stackTraceVariable)];
260 return new TryCatch(userBody, catches); 260 return new TryCatch(userBody, catches);
261 } 261 }
262 262
263 addReturnStatementIfNecessary(Statement body) { 263 Statement addReturnStatementIfNecessary(Statement body) {
264 if (body is Block) { 264 if (body is Block) {
265 Block block = body; 265 Block block = body;
266 if (block.statements.isEmpty || 266 if (block.statements.isEmpty ||
267 block.statements.last is! ReturnStatement) { 267 block.statements.last is! ReturnStatement) {
268 var returnStatement = new ReturnStatement(); 268 var returnStatement = new ReturnStatement();
269 block.statements.add(returnStatement); 269 block.statements.add(returnStatement);
270 returnStatement.parent = block; 270 returnStatement.parent = block;
271 } 271 }
272 } else if (body is! ReturnStatement) { 272 } else if (body is! ReturnStatement) {
273 var returnStatement = new ReturnStatement(); 273 var returnStatement = new ReturnStatement();
274 body = new Block([body, returnStatement]); 274 body = new Block(<Statement>[body, returnStatement]);
275 } 275 }
276 return body; 276 return body;
277 } 277 }
278 278
279 Statement buildClosureBody(Statement node);
280
281 Statement buildCatchBody(Statement exceptionVariable, 279 Statement buildCatchBody(Statement exceptionVariable,
282 Statement stackTraceVariable); 280 Statement stackTraceVariable);
283 281
284 visitForInStatement(ForInStatement node) { 282 List<Statement> statements = <Statement>[];
285 if (node.isAsync) { 283
284 TreeNode visitInvalidStatement(InvalidStatemnt stmt) {
asgerf 2016/11/01 10:44:45 InvalidStatemnt -> InvalidStatement
Kevin Millikin (Google) 2016/11/01 13:11:31 Done.
285 statements.add(stmt);
286 return null;
Kevin Millikin (Google) 2016/10/31 12:29:32 The statement translation functions always return
287 }
288
289 TreeNode visitExpressionStatement(ExpressionStatement stmt) {
290 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements)
291 ..parent = stmt;
292 statements.add(stmt);
293 return null;
294 }
295
296 TreeNode visitBlock(Block stmt) {
297 var saved = statements;
298 statements = <Statement>[];
299 for (var statement in stmt.statements) {
300 statement.accept(this);
301 }
302 saved.add(new Block(statements));
303 statements = saved;
304 return null;
305 }
306
307 TreeNode visitEmptyStatement(EmptyStatement stmt) {
308 statements.add(stmt);
309 return null;
310 }
311
312 TreeNode visitAssertStatement(AssertStatement stmt) {
313 // TODO!
314 return null;
315 }
316
317 Statement visitDelimited(Statement stmt) {
318 var saved = statements;
319 statements = <Statement>[];
320 stmt.accept(this);
321 Statement result =
322 statements.length == 1 ? statements.first : new Block(statements);
323 statements = saved;
324 return result;
325 }
326
327 Statement visitLabeledStatement(LabeledStatement stmt) {
328 stmt.body = visitDelimited(stmt.body)..parent = stmt;
329 statements.add(stmt);
330 return null;
331 }
332
333 Statement visitBreakStatement(BreakStatement stmt) {
334 statements.add(stmt);
335 return null;
336 }
337
338 TreeNode visitWhileStatement(WhileStatement stmt) {
339 Statement body = visitDelimited(stmt.body);
340 List<Statement> effects = <Statement>[];
341 Expression cond = expressionRewriter.rewrite(stmt.condition, effects);
342 if (effects.isEmpty) {
343 stmt.condition = cond..parent = stmt;
344 stmt.body = body..parent = stmt;
345 statements.add(stmt);
346 } else {
347 // The condition rewrote to a non-empty sequence of statements S* and
348 // value V. Rewrite the loop to:
349 //
350 // L: while (true) {
351 // S*
352 // if (V) {
353 // [body]
354 // else {
355 // break L;
356 // }
357 // }
358 LabeledStatement labeled = new LabeledStatement(stmt);
359 stmt.condition = new BoolLiteral(true)..parent = stmt;
360 effects.add(new IfStatement(cond, body, new BreakStatement(labeled)));
361 stmt.body = new Block(effects)..parent = stmt;
362 statements.add(labeled);
363 }
364 return null;
365 }
366
367 TreeNode visitDoStatement(DoStatement stmt) {
368 Statement body = visitDelimited(stmt.body);
369 List<Statement> effects = <Statement>[];
370 stmt.condition = expressionRewriter.rewrite(stmt.condition, effects)
371 ..parent = stmt;
372 if (effects.isNotEmpty) {
373 // The condition rewrote to a non-empty sequence of statements S* and
374 // value V. Add the statements to the end of the loop body.
375 Block block = body is Block ? body : body = new Block(<Statement>[body]);
376 for (var effect in effects) {
377 block.statements.add(effect);
378 effect.parent = body;
379 }
380 }
381 stmt.body = body..parent = stmt;
382 statements.add(stmt);
383 return null;
384 }
385
386 TreeNode visitForStatement(ForStatement stmt) {
387 // Because of for-loop scoping and variable capture, it is tricky to deal
388 // with await in the loop's variable initializers or update expressions.
389 bool isSimple = true;
390 int length = stmt.variables.length;
391 List<List<Statement>> initEffects = new List<List<Statement>>(length);
392 for (int i = 0; i < length; ++i) {
393 VariableDeclaration decl = stmt.variables[i];
394 initEffects[i] = <Statement>[];
395 if (decl.initializer != null) {
396 decl.initializer =
397 expressionRewriter.rewrite(decl.initializer, initEffects[i])
398 ..parent = decl;
399 }
400 isSimple = isSimple && initEffects[i].isEmpty;
401 }
402
403 length = stmt.updates.length;
404 List<List<Statement>> updateEffects = new List<List<Statement>>(length);
405 for (int i = 0; i < stmt.updates.length; ++i) {
asgerf 2016/11/01 10:44:45 Did you mean to use "i < length" here? (since we h
Kevin Millikin (Google) 2016/11/01 13:11:31 Yes. Done.
406 updateEffects[i] = <Statement>[];
407 stmt.updates[i] =
408 expressionRewriter.rewrite(stmt.updates[i], updateEffects[i])
409 ..parent = stmt;
410 isSimple = isSimple && updateEffects[i].isEmpty;
411 }
412
413 Statement body = visitDelimited(stmt.body);
414 Expression cond = stmt.condition;
415 List<Statement> condEffects;
416 if (cond != null) {
417 condEffects = <Statement>[];
418 cond = expressionRewriter.rewrite(stmt.condition, condEffects);
419 }
420
421 if (isSimple) {
422 // If the condition contains await, we use a translation like the one for
423 // while loops, but leaving the variable declarations and the update
424 // expressions in place.
425 if (condEffects == null || condEffects.isEmpty) {
426 if (cond != null) stmt.condition = cond..parent = stmt;
427 stmt.body = body..parent = stmt;
428 statements.add(stmt);
429 } else {
430 LabeledStatement labeled = new LabeledStatement(stmt);
431 stmt.condition = null; // No condition in a for loop is the same as tru e.
asgerf 2016/11/01 10:44:45 Long line.
Kevin Millikin (Google) 2016/11/01 13:11:31 I just ran the whole file through the formatter.
432 condEffects.add(
433 new IfStatement(cond, body, new BreakStatement(labeled)));
434 stmt.body = new Block(condEffects)..parent = stmt;
435 statements.add(labeled);
436 }
437 return null;
438 }
439
440 // If the rewrite of the initializer or update expressions produces a
441 // non-empty sequence of statements then the loop is desugared. If the loop
442 // has the form:
443 //
444 // label: for (Type x = init; cond; update) body
445 //
446 // it is translated as if it were:
447 //
448 // {
449 // bool first = true;
450 // Type temp;
451 // label: while (true) {
452 // Type x;
453 // if (first) {
454 // first = false;
455 // x = init;
456 // } else {
457 // x = temp;
458 // update;
459 // }
460 // if (cond) {
461 // body;
462 // temp = x;
463 // } else {
464 // break;
465 // }
466 // }
467 // }
468
469 // Place the loop variable declarations at the beginning of the body
470 // statements and move their initializers to a guarded list of statements.
471 // Add assignments to the loop variables from the previous iteration's temp
472 // variables before the updates.
473 //
474 // temps.first is the flag 'first'.
475 // TODO(kmillikin) bool type for first.
476 List<VariableDeclaration> temps = <VariableDeclaration>[
477 new VariableDeclaration.forValue(new BoolLiteral(true),
478 isFinal: false)];
479 List<Statement> loopBody = <Statement>[];
480 List<Statement> initializers = <Statement>[
481 new ExpressionStatement(
482 new VariableSet(temps.first, new BoolLiteral(false)))];
483 List<Statment> updates = <Statement>[];
asgerf 2016/11/01 10:44:45 Statment -> Statement
Kevin Millikin (Google) 2016/11/01 13:11:31 Done.
484 List<Statement> newBody = <Statement>[body];
485 for (int i = 0; i < stmt.variables.length; ++i) {
486 VariableDeclaration decl = stmt.variables[i];
487 temps.add(new VariableDeclaration(null, type: decl.type));
488 loopBody.add(decl);
489 if (decl.initializer != null) {
490 initializers.addAll(initEffects[i]);
491 initializers.add(
492 new ExpressionStatement(new VariableSet(decl, decl.initializer)));
493 decl.initializer = null;
494 }
495 updates.add(new ExpressionStatement(
496 new VariableSet(decl, new VariableGet(temps.last))));
497 newBody.add(new ExpressionStatement(
498 new VariableSet(temps.last, new VariableGet(decl))));
499 }
500 // Add the updates to their guarded list of statements.
501 for (int i = 0; i < stmt.updates.length; ++i) {
502 updates.addAll(updateEffects[i]);
503 updates.add(new ExpressionStatement(stmt.updates[i]));
504 }
505 // Initializers or updates could be empty.
506 loopBody.add(new IfStatement(new VariableGet(temps.first),
507 new Block(initializers),
508 new Block(updates)));
509
510 LabeledStatement labeled = new LabeledStatement(null);
511 if (cond != null) {
512 loopBody.addAll(condEffects);
513 } else {
514 cond = new BoolLiteral(true);
515 }
516 loopBody.add(
517 new IfStatement(cond, new Block(newBody), new BreakStatement(labeled)));
518 labeled.body =
519 new WhileStatement(new BoolLiteral(true), new Block(loopBody));
520 statements.add(new Block(<Statement>[]..addAll(temps)..add(labeled)));
521 return null;
522 }
523
524 TreeNode visitForInStatement(ForInStatement stmt) {
525 if (stmt.isAsync) {
286 // Transform 526 // Transform
287 // 527 //
288 // await for (var variable in <stream-expression>) { ... } 528 // await for (var variable in <stream-expression>) { ... }
289 // 529 //
290 // To: 530 // To:
291 // 531 //
292 // { 532 // {
293 // var :for-iterator = new StreamIterator(<stream-expression>); 533 // var :for-iterator = new StreamIterator(<stream-expression>);
294 // try { 534 // try {
295 // while (await :for-iterator.moveNext()) { 535 // while (await :for-iterator.moveNext()) {
296 // var <variable> = :for-iterator.current; 536 // var <variable> = :for-iterator.current;
297 // ... 537 // ...
298 // } 538 // }
299 // } finally { 539 // } finally {
300 // :for-iterator.cancel(); 540 // :for-iterator.cancel();
301 // } 541 // }
302 // } 542 // }
303 var iteratorVariable = new VariableDeclaration( 543 var iteratorVariable = new VariableDeclaration(
304 ':for-iterator', 544 ':for-iterator',
305 initializer: new ConstructorInvocation( 545 initializer: new ConstructorInvocation(
306 helper.streamIteratorConstructor, 546 helper.streamIteratorConstructor,
307 new Arguments([expressionRewriter.rewrite(node.iterable)]))); 547 new Arguments(<Expression>[stmt.iterable])));
308 548
309 // await iterator.moveNext() 549 // await iterator.moveNext()
310 var condition = new AwaitExpression(new MethodInvocation( 550 var condition = new AwaitExpression(new MethodInvocation(
311 new VariableGet(iteratorVariable), 551 new VariableGet(iteratorVariable),
312 new Name('moveNext'), 552 new Name('moveNext'),
313 new Arguments([]))); 553 new Arguments(<Expression>[])));
314 554
315 // var <variable> = iterator.current; 555 // var <variable> = iterator.current;
316 var valueVariable = node.variable; 556 var valueVariable = stmt.variable;
317 valueVariable.initializer = new PropertyGet( 557 valueVariable.initializer = new PropertyGet(
318 new VariableGet(iteratorVariable), 558 new VariableGet(iteratorVariable),
319 new Name('current')); 559 new Name('current'));
320 valueVariable.initializer.parent = valueVariable; 560 valueVariable.initializer.parent = valueVariable;
321 561
322 var whileBody = new Block([valueVariable, node.body]); 562 var whileBody = new Block(<Statement>[valueVariable, stmt.body]);
323 var tryBody = new WhileStatement(condition, whileBody); 563 var tryBody = new WhileStatement(condition, whileBody);
324 564
325 // iterator.cancel(); 565 // iterator.cancel();
326 var tryFinalizer = new ExpressionStatement( 566 var tryFinalizer = new ExpressionStatement(
327 new MethodInvocation( 567 new MethodInvocation(
328 new VariableGet(iteratorVariable), 568 new VariableGet(iteratorVariable),
329 new Name('cancel'), 569 new Name('cancel'),
330 new Arguments([]))); 570 new Arguments(<Expression>[])));
331 571
332 var tryFinally = new TryFinally(tryBody, tryFinalizer); 572 var tryFinally = new TryFinally(tryBody, tryFinalizer);
333 573
334 var block = new Block([ 574 var block = new Block(<Statement>[iteratorVariable, tryFinally]);
335 iteratorVariable, 575 block.accept(this);
336 tryFinally,
337 ]);
338 return block.accept(this);
339 } else { 576 } else {
340 return super.visitForInStatement(node); 577 stmt.iterable =
578 expressionRewriter.rewrite(stmt.iterable, statements)..parent = stmt;
579 stmt.body = visitDelimited(stmt.body)..parent = stmt;
580 statements.add(stmt);
341 } 581 }
582 return null;
342 } 583 }
343 584
344 defaultExpression(TreeNode node) { 585 TreeNode visitSwitchStatement(SwitchStatement stmt) {
345 return expressionRewriter.rewrite(node); 586 stmt.expression =
587 expressionRewriter.rewrite(stmt.expression, statements)..parent = stmt;
588 for (var switchCase in stmt.cases) {
589 // Expressions in switch cases cannot contain await so they do not need to
590 // be translated.
591 switchCase.body = visitDelimited(switchCase.body)..parent = switchCase;
592 }
593 statements.add(stmt);
594 return null;
346 } 595 }
596
597 TreeNode visitContinueSwitchStatement(ContinueSwitchStatement stmt) {
598 statements.add(stmt);
599 return null;
600 }
601
602 TreeNode visitIfStatement(IfStatement stmt) {
603 stmt.condition =
604 expressionRewriter.rewrite(stmt.condition, statements)..parent = stmt;
605 stmt.then = visitDelimited(stmt.then)..parent = stmt;
606 if (stmt.otherwise != null) {
607 stmt.otherwise = visitDelimited(stmt.otherwise)..parent = stmt;
608 }
609 statements.add(stmt);
610 return null;
611 }
612
613 TreeNode visitReturnStatement(ReturnStatement stmt) {
614 if (stmt.expression != null) {
615 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements)
616 ..parent = stmt;
617 }
618 statements.add(stmt);
619 return null;
620 }
621
622 TreeNode visitTryCatch(TryCatch stmt) {
623 ++currentTryDepth;
624 stmt.body = visitDelimited(stmt.body)..parent = stmt;
625 --currentTryDepth;
626
627 ++currentCatchDepth;
628 for (var clause in stmt.catches) {
629 clause.body = visitDelimited(clause.body)..parent = clause;
630 }
631 --currentCatchDepth;
632 statements.add(stmt);
633 return null;
634 }
635
636 TreeNode visitTryFinally(TryFinally stmt) {
637 ++currentTryDepth;
638 stmt.body = visitDelimited(stmt.body)..parent = stmt;
639 --currentTryDepth;
640 stmt.finalizer = visitDelimited(stmt.finalizer)..parent = stmt;
641 statements.add(stmt);
642 return null;
643 }
644
645 TreeNode visitYieldStatement(YieldStatement stmt) {
646 stmt.expression =
647 expressionRewriter.rewrite(stmt.expression, statements)..parent = stmt;
648 statements.add(stmt);
649 return null;
650 }
651
652 TreeNode visitVariableDeclaration(VariableDeclaration stmt) {
653 if (stmt.initializer != null) {
654 stmt.initializer =
655 expressionRewriter.rewrite(stmt.initializer, statements)
656 ..parent = stmt;
657 }
658 statements.add(stmt);
659 return null;
660 }
661
662 TreeNode visitFunctionDeclaration(FunctionDeclaration stmt) {
663 stmt.function = stmt.function.accept(this)..parent = stmt;
664 statements.add(stmt);
665 return null;
666 }
667
668 defaultExpression(TreeNode node) => throw 'unreachable';
347 } 669 }
348 670
349 class AsyncStarFunctionRewriter extends AsyncRewriterBase { 671 class AsyncStarFunctionRewriter extends AsyncRewriterBase {
350 VariableDeclaration controllerVariable; 672 VariableDeclaration controllerVariable;
351 673
352 AsyncStarFunctionRewriter(helper, enclosingFunction) 674 AsyncStarFunctionRewriter(helper, enclosingFunction)
353 : super(helper, enclosingFunction); 675 : super(helper, enclosingFunction);
354 676
355 FunctionNode rewrite() { 677 FunctionNode rewrite() {
356 var statements = <Statement>[]; 678 var statements = <Statement>[];
357 679
358 // var :controller; 680 // var :controller;
359 controllerVariable = new VariableDeclaration(":controller"); 681 controllerVariable = new VariableDeclaration(":controller");
360 statements.add(controllerVariable); 682 statements.add(controllerVariable);
361 683
362 super.setupAsyncContinuations(statements); 684 super.setupAsyncContinuations(statements);
363 685
364 // :controller = new _AsyncController(:async_op); 686 // :controller = new _AsyncController(:async_op);
365 var arguments = new Arguments([new VariableGet(nestedClosureVariable)]); 687 var arguments =
688 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]);
366 var buildController = new ConstructorInvocation( 689 var buildController = new ConstructorInvocation(
367 helper.streamControllerConstructor, arguments); 690 helper.streamControllerConstructor, arguments);
368 var setController = new ExpressionStatement( 691 var setController = new ExpressionStatement(
369 new VariableSet(controllerVariable, buildController)); 692 new VariableSet(controllerVariable, buildController));
370 statements.add(setController); 693 statements.add(setController);
371 694
372 // return :controller.stream; 695 // return :controller.stream;
373 var completerGet = new VariableGet(controllerVariable); 696 var completerGet = new VariableGet(controllerVariable);
374 var returnStatement = new ReturnStatement( 697 var returnStatement = new ReturnStatement(
375 new PropertyGet(completerGet, new Name('stream', helper.asyncLibrary))); 698 new PropertyGet(completerGet, new Name('stream', helper.asyncLibrary)));
376 statements.add(returnStatement); 699 statements.add(returnStatement);
377 700
378 enclosingFunction.body = new Block(statements); 701 enclosingFunction.body = new Block(statements);
379 enclosingFunction.body.parent = enclosingFunction; 702 enclosingFunction.body.parent = enclosingFunction;
380 enclosingFunction.asyncMarker = AsyncMarker.Sync; 703 enclosingFunction.asyncMarker = AsyncMarker.Sync;
381 return enclosingFunction; 704 return enclosingFunction;
382 } 705 }
383 706
384 Statement buildClosureBody(Statement node) {
385 // The body will insert calls to
386 // :controller.add()
387 // :controller.addStream()
388 // :controller.addError()
389 // :controller.close()
390 return node.accept(this);
391 }
392
393 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { 707 Statement buildCatchBody(exceptionVariable, stackTraceVariable) {
394 return new ExpressionStatement( 708 return new ExpressionStatement(
395 new MethodInvocation( 709 new MethodInvocation(
396 new VariableGet(controllerVariable), 710 new VariableGet(controllerVariable),
397 new Name("completeError", helper.asyncLibrary), 711 new Name("completeError", helper.asyncLibrary),
398 new Arguments([new VariableGet(exceptionVariable), 712 new Arguments(<Expression>[new VariableGet(exceptionVariable),
399 new VariableGet(stackTraceVariable)]))); 713 new VariableGet(stackTraceVariable)])));
400 } 714 }
401 715
402 visitYieldStatement(YieldStatement node) { 716 TreeNode visitYieldStatement(YieldStatement stmt) {
403 var transformedExpression = node.expression.accept(this); 717 Expression expr = expressionRewriter.rewrite(stmt.expression, statements);
404 718
405 var addExpression = new MethodInvocation( 719 var addExpression = new MethodInvocation(
406 new VariableGet(controllerVariable), 720 new VariableGet(controllerVariable),
407 new Name(node.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), 721 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary),
408 new Arguments([transformedExpression])); 722 new Arguments(<Expression>[expr]));
409 723
410 var addAndReturnOrYield = new IfStatement( 724 statements.add(new IfStatement(
411 addExpression, 725 addExpression,
412 new ReturnStatement(new NullLiteral()), 726 new ReturnStatement(new NullLiteral()),
413 createContinuationPoint()); 727 createContinuationPoint()));
414 return new Block([addAndReturnOrYield]); 728 return null;
415 } 729 }
416 730
417 visitReturnStatement(ReturnStatement node) { 731 TreeNode visitReturnStatement(ReturnStatement node) {
418 // async* functions cannot have normal [ReturnStatement]s in them. 732 // async* functions cannot have normal [ReturnStatement]s in them.
419 assert(node.expression == null || node.expression is NullLiteral); 733 assert(node.expression == null || node.expression is NullLiteral);
420 734
421 var close = new ExpressionStatement( 735 statements.add(new ExpressionStatement(
422 new MethodInvocation( 736 new MethodInvocation(
423 new VariableGet(controllerVariable), 737 new VariableGet(controllerVariable),
424 new Name("close", helper.asyncLibrary), 738 new Name("close", helper.asyncLibrary),
425 new Arguments([]))); 739 new Arguments(<Expression>[]))));
426 var returnStatement = new ReturnStatement(); 740 statements.add(new ReturnStatement());
427 return new Block([close, returnStatement]); 741 return null;
428 } 742 }
429 } 743 }
430 744
431 class AsyncFunctionRewriter extends AsyncRewriterBase { 745 class AsyncFunctionRewriter extends AsyncRewriterBase {
432 VariableDeclaration completerVariable; 746 VariableDeclaration completerVariable;
433 747
434 AsyncFunctionRewriter(helper, enclosingFunction) 748 AsyncFunctionRewriter(helper, enclosingFunction)
435 : super(helper, enclosingFunction); 749 : super(helper, enclosingFunction);
436 750
437 FunctionNode rewrite() { 751 FunctionNode rewrite() {
(...skipping 21 matching lines...) Expand all
459 var returnStatement = new ReturnStatement( 773 var returnStatement = new ReturnStatement(
460 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary))); 774 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary)));
461 statements.add(returnStatement); 775 statements.add(returnStatement);
462 776
463 enclosingFunction.body = new Block(statements); 777 enclosingFunction.body = new Block(statements);
464 enclosingFunction.body.parent = enclosingFunction; 778 enclosingFunction.body.parent = enclosingFunction;
465 enclosingFunction.asyncMarker = AsyncMarker.Sync; 779 enclosingFunction.asyncMarker = AsyncMarker.Sync;
466 return enclosingFunction; 780 return enclosingFunction;
467 } 781 }
468 782
469 Statement buildClosureBody(Statement node) {
470 // TODO(kustermann): Can we assume the frontend will insert proper
471 // [ReturnStatement]s?
472
473 // Translating the body will insert calls to
474 // :completer.completeError()
475 // :completer.complete()
476 return node.accept(this);
477 }
478
479 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { 783 Statement buildCatchBody(exceptionVariable, stackTraceVariable) {
480 return new ExpressionStatement( 784 return new ExpressionStatement(
481 new MethodInvocation( 785 new MethodInvocation(
482 new VariableGet(completerVariable), 786 new VariableGet(completerVariable),
483 new Name("completeError", helper.asyncLibrary), 787 new Name("completeError", helper.asyncLibrary),
484 new Arguments([new VariableGet(exceptionVariable), 788 new Arguments([new VariableGet(exceptionVariable),
485 new VariableGet(stackTraceVariable)]))); 789 new VariableGet(stackTraceVariable)])));
486 } 790 }
487 791
488 visitReturnStatement(ReturnStatement node) { 792 visitReturnStatement(ReturnStatement node) {
489 var transformedExpression; 793 var expr;
490 if (node.expression == null) { 794 if (node.expression == null) {
491 transformedExpression = new NullLiteral(); 795 expr = new NullLiteral();
492 } else { 796 } else {
493 transformedExpression = expressionRewriter.rewrite(node.expression); 797 expr = expressionRewriter.rewrite(node.expression, statements);
494 } 798 }
495 799
496 // Note: transformed expression can't be used directly as part of the 800 statements.add(new ExpressionStatement(
497 // method invocation because it might contain yield points and
498 // expression stack might not be empty.
499 var resultVar = new VariableDeclaration(':async_temp',
500 initializer: transformedExpression);
501 var completeCompleter = new ExpressionStatement(
502 new MethodInvocation( 801 new MethodInvocation(
503 new VariableGet(completerVariable), 802 new VariableGet(completerVariable),
504 new Name("complete", helper.asyncLibrary), 803 new Name("complete", helper.asyncLibrary),
505 new Arguments([new VariableGet(resultVar)]))); 804 new Arguments([expr]))));
506 var returnStatement = new ReturnStatement(new NullLiteral()); 805 statements.add(new ReturnStatement(new NullLiteral()));
507 return new Block([resultVar, completeCompleter, returnStatement]); 806 return null;
508 } 807 }
509 } 808 }
510 809
511 class HelperNodes { 810 class HelperNodes {
512 final Library asyncLibrary; 811 final Library asyncLibrary;
513 final Library coreLibrary; 812 final Library coreLibrary;
514 final Procedure printProcedure; 813 final Procedure printProcedure;
515 final Procedure completerConstructor; 814 final Procedure completerConstructor;
516 final Procedure futureMicrotaskConstructor; 815 final Procedure futureMicrotaskConstructor;
517 final Constructor streamControllerConstructor; 816 final Constructor streamControllerConstructor;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 coreLibrary, 885 coreLibrary,
587 findProcedure(coreLibrary, 'print'), 886 findProcedure(coreLibrary, 'print'),
588 findFactoryConstructor(completerClass, 'sync'), 887 findFactoryConstructor(completerClass, 'sync'),
589 findConstructor(syncIterableClass, ''), 888 findConstructor(syncIterableClass, ''),
590 findConstructor(streamIteratorClass , ''), 889 findConstructor(streamIteratorClass , ''),
591 findFactoryConstructor(futureClass, 'microtask'), 890 findFactoryConstructor(futureClass, 'microtask'),
592 findConstructor(streamControllerClass, ''), 891 findConstructor(streamControllerClass, ''),
593 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), 892 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'),
594 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), 893 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'),
595 findProcedure(asyncLibrary, '_awaitHelper')); 894 findProcedure(asyncLibrary, '_awaitHelper'));
596 } 895 }
597 } 896 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698