| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 /** | 5 /** |
| 6 * Desugarizes all await calls in a single function. This visitor assumes that | 6 * Desugarizes all await calls in a single function. This visitor assumes that |
| 7 * the tree is already normalized with [AwaitNormalizer]. For this reason it | 7 * the tree is already normalized with [AwaitNormalizer]. For this reason it |
| 8 * only needs to recurse on statements and not on expressions. Like in | 8 * only needs to recurse on statements and not on expressions. Like in |
| 9 * [AwaitChecker], nested functions have to be processed separately. | 9 * [AwaitChecker], nested functions have to be processed separately. |
| 10 */ | 10 */ |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 } | 65 } |
| 66 | 66 |
| 67 visitFunctionDefinition(FunctionDefinition node) { | 67 visitFunctionDefinition(FunctionDefinition node) { |
| 68 if (!haveAwait.contains(node)) return node; | 68 if (!haveAwait.contains(node)) return node; |
| 69 // TODO(sigmund): consider making this part of the normalizer | 69 // TODO(sigmund): consider making this part of the normalizer |
| 70 // make implicit return explicit: | 70 // make implicit return explicit: |
| 71 if (node.body is BlockStatement) { | 71 if (node.body is BlockStatement) { |
| 72 BlockStatement block = node.body; | 72 BlockStatement block = node.body; |
| 73 if (block.body.last() is! ReturnStatement) { | 73 if (block.body.last() is! ReturnStatement) { |
| 74 continuation.addFirst( | 74 continuation.addFirst( |
| 75 _callCompleter(new NullExpression(node.span), node.span)); | 75 _callCompleter(_makeNull(node.span), node.span)); |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 | 78 |
| 79 Statement newBody = node.body.visit(this); | 79 Statement newBody = node.body.visit(this); |
| 80 // TODO(sigmund): extract type arg and put it in completer | 80 // TODO(sigmund): extract type arg and put it in completer |
| 81 // We update the body in-place to make it easier to update nested functions | 81 // We update the body in-place to make it easier to update nested functions |
| 82 // without having to rewrite the containing function's AST. | 82 // without having to rewrite the containing function's AST. |
| 83 node.body = new BlockStatement([ | 83 node.body = new BlockStatement([ |
| 84 _declareCompleter(null, node.span), | 84 _declareCompleter(null, node.span), |
| 85 _wrapInTryCatch(newBody, node == _mainMethod.definition), | 85 _wrapInTryCatch(newBody, node == _mainMethod.definition), |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 [new NewExpression(false, typeRef, null, [], span)], | 454 [new NewExpression(false, typeRef, null, [], span)], |
| 455 span); | 455 span); |
| 456 return def; | 456 return def; |
| 457 } | 457 } |
| 458 | 458 |
| 459 /** | 459 /** |
| 460 * Wrap [s] in a try-catch block that propagates errors through the future | 460 * Wrap [s] in a try-catch block that propagates errors through the future |
| 461 * that is returned from the asynchronous function. If the function that we | 461 * that is returned from the asynchronous function. If the function that we |
| 462 * are generating is `main`, we add a noop listener on the resulting future. | 462 * are generating is `main`, we add a noop listener on the resulting future. |
| 463 * Without it, we would have to make it illegal to use `await` in main. This | 463 * Without it, we would have to make it illegal to use `await` in main. This |
| 464 * is because futures swallow exceptions if their values are never used. | 464 * is because futures swallow exceptions if their values are never used. |
| 465 */ | 465 */ |
| 466 Statement _wrapInTryCatch(Statement s, bool isMain) { | 466 Statement _wrapInTryCatch(Statement s, bool isMain) { |
| 467 final ex = new Identifier("ex", s.span); | 467 final ex = new Identifier("ex", s.span); |
| 468 Statement catchStatement = | 468 Statement catchStatement = |
| 469 _callCompleterException(new VarExpression(ex, ex.span), s.span); | 469 _callCompleterException(new VarExpression(ex, ex.span), s.span); |
| 470 if (isMain) { | 470 if (isMain) { |
| 471 final future = new DotExpression( | 471 final future = new DotExpression( |
| 472 new VarExpression(new Identifier(_COMPLETER_NAME, s.span), s.span), | 472 new VarExpression(new Identifier(_COMPLETER_NAME, s.span), s.span), |
| 473 new Identifier("future", s.span), s.span); | 473 new Identifier("future", s.span), s.span); |
| 474 final noopHandler = new LambdaExpression( | 474 final noopHandler = new LambdaExpression( |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 | 554 |
| 555 /** Make a statement invoking a function in scope. */ | 555 /** Make a statement invoking a function in scope. */ |
| 556 Statement _callNoArg(String mName, SourceSpan span) { | 556 Statement _callNoArg(String mName, SourceSpan span) { |
| 557 return new ExpressionStatement(new CallExpression( | 557 return new ExpressionStatement(new CallExpression( |
| 558 new VarExpression(new Identifier(mName, span), span), [], span), span); | 558 new VarExpression(new Identifier(mName, span), span), [], span), span); |
| 559 } | 559 } |
| 560 | 560 |
| 561 /** Make the statement: [: target.method(value); :]. */ | 561 /** Make the statement: [: target.method(value); :]. */ |
| 562 Statement _callTarget1Arg( | 562 Statement _callTarget1Arg( |
| 563 String target, String method, Expression value, SourceSpan span) { | 563 String target, String method, Expression value, SourceSpan span) { |
| 564 if (value == null) value = new NullExpression(span); | 564 if (value == null) value = _makeNull(span); |
| 565 return new ExpressionStatement(new CallExpression( | 565 return new ExpressionStatement(new CallExpression( |
| 566 new DotExpression( | 566 new DotExpression( |
| 567 new VarExpression(new Identifier(target, span), span), | 567 new VarExpression(new Identifier(target, span), span), |
| 568 new Identifier(method, span), span), | 568 new Identifier(method, span), span), |
| 569 [new ArgumentNode(null, value, value.span)], span), span); | 569 [new ArgumentNode(null, value, value.span)], span), span); |
| 570 } | 570 } |
| 571 | 571 |
| 572 /** Make the statement: [: f(value); :]. */ | 572 /** Make the statement: [: f(value); :]. */ |
| 573 Statement _call1Arg(String f, Expression value, SourceSpan span) { | 573 Statement _call1Arg(String f, Expression value, SourceSpan span) { |
| 574 if (value == null) value = new NullExpression(span); | 574 if (value == null) value = _makeNull(span); |
| 575 return new ExpressionStatement(new CallExpression( | 575 return new ExpressionStatement(new CallExpression( |
| 576 new VarExpression(new Identifier(f, span), span), | 576 new VarExpression(new Identifier(f, span), span), |
| 577 [new ArgumentNode(null, value, value.span)], span), span); | 577 [new ArgumentNode(null, value, value.span)], span), span); |
| 578 } | 578 } |
| 579 | 579 |
| 580 /** Make the statement: [: f(a, b); :]. */ | 580 /** Make the statement: [: f(a, b); :]. */ |
| 581 Statement _call2Args(String f, Expression a, Expression b, | 581 Statement _call2Args(String f, Expression a, Expression b, |
| 582 SourceSpan span) { | 582 SourceSpan span) { |
| 583 if (a == null) a = new NullExpression(span); | 583 if (a == null) a = _makeNull(span); |
| 584 if (b == null) b = new NullExpression(span); | 584 if (b == null) b = _makeNull(span); |
| 585 return new ExpressionStatement(new CallExpression( | 585 return new ExpressionStatement(new CallExpression( |
| 586 new VarExpression(new Identifier(f, span), span), | 586 new VarExpression(new Identifier(f, span), span), |
| 587 [new ArgumentNode(null, a, a.span), | 587 [new ArgumentNode(null, a, a.span), |
| 588 new ArgumentNode(null, b, b.span)], span), span); | 588 new ArgumentNode(null, b, b.span)], span), span); |
| 589 } | 589 } |
| 590 | 590 |
| 591 /** Make a return statement for a boolean value. */ | 591 /** Make a return statement for a boolean value. */ |
| 592 Statement _returnBoolean(SourceSpan span, value) { | 592 Statement _returnBoolean(SourceSpan span, bool value) { |
| 593 return new ReturnStatement(new LiteralExpression(value, | 593 return new ReturnStatement( |
| 594 new TypeReference(span, world.nonNullBool), "$value", span), span); | 594 new LiteralExpression(Value.fromBool(value, span), span), span); |
| 595 } |
| 596 |
| 597 Expression _makeNull(SourceSpan span) { |
| 598 return new LiteralExpression(Value.fromNull(span), span); |
| 595 } | 599 } |
| 596 } | 600 } |
| 597 | 601 |
| 598 // TODO(sigmund): create the following tests: | 602 // TODO(sigmund): create the following tests: |
| 599 // - await within the body of getter or setter properties | 603 // - await within the body of getter or setter properties |
| 600 // - await in each valid AST construct | 604 // - await in each valid AST construct |
| 601 // - exceptions - make some of these fail and propagate errors. | 605 // - exceptions - make some of these fail and propagate errors. |
| 602 // - methods with and without returns (are returns added implicitly) | 606 // - methods with and without returns (are returns added implicitly) |
| 603 // - await within assignmetns, but not declarations (see what happens with | 607 // - await within assignmetns, but not declarations (see what happens with |
| 604 // x = await t; | 608 // x = await t; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 615 // if (a) if (b) await t; 2; | 619 // if (a) if (b) await t; 2; |
| 616 // becomes: | 620 // becomes: |
| 617 // if (a) { if (b) { await t; } } 2; | 621 // if (a) { if (b) { await t; } } 2; |
| 618 // which becomes becomes: | 622 // which becomes becomes: |
| 619 // _2() { 2; } if (a) { if (b) { t.then((_) { _2(); } } } _2(); | 623 // _2() { 2; } if (a) { if (b) { t.then((_) { _2(); } } } _2(); |
| 620 // (seems that 'a' doesn't need { }) | 624 // (seems that 'a' doesn't need { }) |
| 621 // - 'if/while' with only one statement in the continuation (check the | 625 // - 'if/while' with only one statement in the continuation (check the |
| 622 // optimization that copies code rather than adding a continuation closure). | 626 // optimization that copies code rather than adding a continuation closure). |
| 623 // - await not inside a block (could break error propagation if normalization is | 627 // - await not inside a block (could break error propagation if normalization is |
| 624 // done incorrectly). | 628 // done incorrectly). |
| OLD | NEW |