Chromium Code Reviews| OLD | NEW |
|---|---|
| 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.async; | 5 library kernel.transformations.async; |
| 6 | 6 |
| 7 import '../kernel.dart'; | 7 import '../kernel.dart'; |
| 8 import 'continuation.dart'; | 8 import 'continuation.dart'; |
| 9 | 9 |
| 10 /// A transformer that introduces temporary variables for all subexpressions | 10 /// A transformer that introduces temporary variables for all subexpressions |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 /// of statements by emitting statements into this list. This list is built | 46 /// of statements by emitting statements into this list. This list is built |
| 47 /// in reverse because children are visited right-to-left. | 47 /// in reverse because children are visited right-to-left. |
| 48 /// | 48 /// |
| 49 /// If an expression should be named it is named before visiting its children | 49 /// If an expression should be named it is named before visiting its children |
| 50 /// so the naming assignment appears in the list before all statements | 50 /// so the naming assignment appears in the list before all statements |
| 51 /// implementating the translation of the children. | 51 /// implementating the translation of the children. |
| 52 /// | 52 /// |
| 53 /// Children that are conditionally evaluated, such as some parts of logical | 53 /// Children that are conditionally evaluated, such as some parts of logical |
| 54 /// and conditional expressions, must be delimited so that they do not emit | 54 /// and conditional expressions, must be delimited so that they do not emit |
| 55 /// unguarded statements into [statements]. This is implemented by setting | 55 /// unguarded statements into [statements]. This is implemented by setting |
| 56 /// [statements] to a fresh empty list before transforming those children and | 56 /// [statements] to a fresh empty list before transforming those children. |
| 57 /// wrapping any emitted statements in a [BlockExpression]. | |
| 58 List<Statement> statements = <Statement>[]; | 57 List<Statement> statements = <Statement>[]; |
| 59 | 58 |
| 60 | 59 |
| 61 /// The number of currently live named intermediate values. | 60 /// The number of currently live named intermediate values. |
| 62 /// | 61 /// |
| 63 /// This index is used to allocate names to temporary values. Because | 62 /// This index is used to allocate names to temporary values. Because |
| 64 /// children are visited right-to-left, names are assigned in reverse order of | 63 /// children are visited right-to-left, names are assigned in reverse order of |
| 65 /// index. | 64 /// index. |
| 66 /// | 65 /// |
| 67 /// When an assignment is emitted into [statements] to name an expression | 66 /// When an assignment is emitted into [statements] to name an expression |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 79 | 78 |
| 80 final VariableDeclaration asyncResult = | 79 final VariableDeclaration asyncResult = |
| 81 new VariableDeclaration(':result'); | 80 new VariableDeclaration(':result'); |
| 82 final List<VariableDeclaration> variables = <VariableDeclaration>[]; | 81 final List<VariableDeclaration> variables = <VariableDeclaration>[]; |
| 83 | 82 |
| 84 ExpressionLifter(this.continuationRewriter); | 83 ExpressionLifter(this.continuationRewriter); |
| 85 | 84 |
| 86 Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList()); | 85 Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList()); |
| 87 | 86 |
| 88 /// Rewrite a toplevel expression (toplevel wrt. a statement). | 87 /// Rewrite a toplevel expression (toplevel wrt. a statement). |
| 89 Expression rewrite(Expression expression) { | 88 /// |
| 89 /// Rewriting an expression produces a sequence of statements and an | |
| 90 /// expression. The sequence of statements are added to the given list. Pass | |
| 91 /// an empty list if the rewritten expression should be delimited from the | |
| 92 /// surrounding context. | |
| 93 Expression rewrite(Expression expression, List<Statement> outer) { | |
| 90 assert(statements.isEmpty); | 94 assert(statements.isEmpty); |
| 91 assert(nameIndex == 0); | 95 assert(nameIndex == 0); |
| 92 seenAwait = false; | 96 seenAwait = false; |
| 93 var result = expression.accept(this); | 97 Expression result = expression.accept(this); |
| 98 outer.addAll(statements.reversed); | |
| 99 statements.clear(); | |
| 94 nameIndex = 0; | 100 nameIndex = 0; |
| 95 if (statements.isNotEmpty) { | |
| 96 result = new BlockExpression(blockOf(statements), result); | |
| 97 statements = <Statement>[]; | |
| 98 } | |
| 99 return result; | 101 return result; |
| 100 } | 102 } |
| 101 | 103 |
| 102 // Perform an action with a given list of statements so that it cannot emit | 104 // Perform an action with a given list of statements so that it cannot emit |
| 103 // statements into the 'outer' list. | 105 // statements into the 'outer' list. |
| 104 Expression delimit(Expression action(), List<Statement> inner) { | 106 Expression delimit(Expression action(), List<Statement> inner) { |
| 105 var index = nameIndex; | 107 var index = nameIndex; |
| 106 var outer = statements; | 108 var outer = statements; |
| 107 statements = inner; | 109 statements = inner; |
| 108 Expression result = action(); | 110 Expression result = action(); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 402 ++nameIndex; | 404 ++nameIndex; |
| 403 seenAwait = seenAwait || thenAwait || otherwiseAwait; | 405 seenAwait = seenAwait || thenAwait || otherwiseAwait; |
| 404 return new VariableGet(result); | 406 return new VariableGet(result); |
| 405 } | 407 } |
| 406 | 408 |
| 407 // Others. | 409 // Others. |
| 408 TreeNode visitAwaitExpression(AwaitExpression expr) { | 410 TreeNode visitAwaitExpression(AwaitExpression expr) { |
| 409 final R = continuationRewriter; | 411 final R = continuationRewriter; |
| 410 var shouldName = seenAwait; | 412 var shouldName = seenAwait; |
| 411 var result = new VariableGet(asyncResult); | 413 var result = new VariableGet(asyncResult); |
| 414 // The statements are in reverse order, so name the result first if | |
| 415 // necessary and then add the two other statements in reverse. | |
| 412 if (shouldName) result = name(result); | 416 if (shouldName) result = name(result); |
| 417 statements.add(R.createContinuationPoint()); | |
| 418 Arguments arguments = new Arguments(<Expression>[ | |
| 419 expr.operand, | |
| 420 new VariableGet(R.thenContinuationVariable), | |
| 421 new VariableGet(R.catchErrorContinuationVariable)]); | |
| 422 statements.add(new ExpressionStatement( | |
| 423 new StaticInvocation(R.helper.awaitHelper, arguments))); | |
| 424 | |
| 413 seenAwait = false; | 425 seenAwait = false; |
| 414 var index = nameIndex; | 426 var index = nameIndex; |
| 415 var operand = expr.operand.accept(this); | 427 arguments.positional[0] = expr.operand.accept(this)..parent = arguments; |
|
Kevin Millikin (Google)
2016/10/31 12:29:32
This was a bug: the translated operand should occu
| |
| 416 | |
| 417 // The statements are in reverse order, so name the result first if | |
| 418 // necessary and then add these two in reverse. | |
| 419 statements.add(R.createContinuationPoint()); | |
| 420 statements.add(new ExpressionStatement( | |
| 421 new StaticInvocation(R.helper.awaitHelper, | |
| 422 new Arguments(<Expression>[ | |
| 423 operand, | |
| 424 new VariableGet(R.thenContinuationVariable), | |
| 425 new VariableGet(R.catchErrorContinuationVariable)])))); | |
| 426 | 428 |
| 427 if (shouldName) nameIndex = index + 1; | 429 if (shouldName) nameIndex = index + 1; |
| 428 seenAwait = true; | 430 seenAwait = true; |
| 429 return result; | 431 return result; |
| 430 } | 432 } |
| 431 | 433 |
| 432 TreeNode visitFunctionExpression(FunctionExpression expr) { | 434 TreeNode visitFunctionExpression(FunctionExpression expr) { |
| 433 expr.transformChildren(this); | 435 expr.transformChildren(this); |
| 434 return expr; | 436 return expr; |
| 435 } | 437 } |
| 436 | 438 |
| 437 TreeNode visitLet(Let expr) { | 439 TreeNode visitLet(Let expr) { |
| 438 expr.body = expr.body.accept(this)..parent = expr; | 440 return transform(expr, () { |
| 439 VariableDeclaration variable = expr.variable; | 441 expr.body = expr.body.accept(this)..parent = expr; |
| 440 variable.initializer = | 442 VariableDeclaration variable = expr.variable; |
| 441 variable.initializer.accept(this)..parent = variable; | 443 variable.initializer = |
| 442 return expr; | 444 variable.initializer.accept(this)..parent = variable; |
| 443 } | 445 }); |
| 444 | |
| 445 TreeNode visitBlockExpression(BlockExpression expr) { | |
| 446 var length = statements.length; | |
| 447 expr.value.accept(this)..parent = expr; | |
| 448 if (statements.length == length) { | |
| 449 // The statements in the body do not need be translated right-to-left | |
| 450 // because all subexpressions will be treated as delimited and so | |
| 451 // prevented from emitting statements into the list of statements. | |
| 452 expr.body = expr.body.accept(continuationRewriter)..parent = expr; | |
| 453 return expr; | |
| 454 } else { | |
| 455 // Statements were emitted from the translation of the value. The | |
| 456 // statements in the body must be executed before them. Copy the body's | |
| 457 // statements to the accumulated statement list in reverse order. | |
| 458 for (var statement in expr.body.statements.reversed) { | |
| 459 statements.add(statement.accept(continuationRewriter)); | |
| 460 } | |
| 461 return expr.value; | |
| 462 } | |
| 463 } | 446 } |
| 464 | 447 |
| 465 visitFunctionNode(FunctionNode node) { | 448 visitFunctionNode(FunctionNode node) { |
| 466 var nestedRewriter = new RecursiveContinuationRewriter( | 449 var nestedRewriter = new RecursiveContinuationRewriter( |
| 467 continuationRewriter.helper); | 450 continuationRewriter.helper); |
| 468 return node.accept(nestedRewriter); | 451 return node.accept(nestedRewriter); |
| 469 } | 452 } |
| 470 } | 453 } |
| OLD | NEW |