Index: lib/src/codegen/js_metalet.dart |
diff --git a/lib/src/codegen/js_metalet.dart b/lib/src/codegen/js_metalet.dart |
index a51298e346af0684d3b583c4d59e260d6d9e9737..12f7811c390da883ffce5366c1a9c70b887fe550 100644 |
--- a/lib/src/codegen/js_metalet.dart |
+++ b/lib/src/codegen/js_metalet.dart |
@@ -64,7 +64,8 @@ class MetaLet extends Expression { |
ExpressionStatement es = s.first; |
return es.expression; |
} |
- return new Call(new ArrowFun([], block), []); |
+ |
+ return _toInvokedFunction(block); |
} |
Expression toAssignExpression(Expression left) { |
@@ -94,8 +95,7 @@ class MetaLet extends Expression { |
return _expression = es.value; |
} |
// Wrap it in an immediately called function to get in expression context. |
- // TODO(jmesserly): |
- return _expression = new Call(new ArrowFun([], block), []); |
+ return _expression = _toInvokedFunction(block); |
} |
Block toStatement() { |
@@ -129,6 +129,19 @@ class MetaLet extends Expression { |
/// This generates as either a comma expression or a call. |
int get precedenceLevel => variables.isEmpty ? EXPRESSION : CALL; |
+ Expression _toInvokedFunction(Statement block) { |
+ var finder = new _YieldFinder(); |
+ block.accept(finder); |
+ if (!finder.hasYield) { |
+ return new Call(new ArrowFun([], block), []); |
+ } |
+ // If we have a yield, it's more tricky. We'll create a `function*`, which |
+ // we `yield*` to immediately invoke. We also may need to bind this: |
+ Expression fn = new Fun([], block, isGenerator: true); |
+ if (finder.hasThis) fn = js.call('#.bind(this)', fn); |
+ return new Yield(new Call(fn, []), star: true); |
+ } |
+ |
Block _finishStatement(List<Statement> statements) { |
var params = <TemporaryId>[]; |
var values = <Expression>[]; |
@@ -230,7 +243,7 @@ class MetaLet extends Expression { |
class _VariableUseCounter extends BaseVisitor { |
final counts = <String, int>{}; |
- visitInterpolatedExpression(InterpolatedExpression node) { |
+ @override visitInterpolatedExpression(InterpolatedExpression node) { |
int n = counts[node.nameOrPosition]; |
counts[node.nameOrPosition] = n == null ? 1 : n + 1; |
} |
@@ -241,10 +254,31 @@ class _IdentFinder extends BaseVisitor { |
bool found = false; |
_IdentFinder(this.name); |
- visitIdentifier(Identifier node) { |
+ @override visitIdentifier(Identifier node) { |
if (node.name == name) found = true; |
} |
- visitNode(Node node) { |
+ @override visitNode(Node node) { |
if (!found) super.visitNode(node); |
} |
} |
+ |
+class _YieldFinder extends BaseVisitor { |
+ bool hasYield = false; |
+ bool hasThis = false; |
+ bool _nestedFunction = false; |
+ @override visitThis(This node) { |
+ hasThis = true; |
+ } |
+ @override visitFunctionExpression(FunctionExpression node) { |
+ var savedNested = _nestedFunction; |
+ _nestedFunction = true; |
+ super.visitFunctionExpression(node); |
+ _nestedFunction = savedNested; |
+ } |
+ @override visitYield(Yield node) { |
+ if (!_nestedFunction) hasYield = true; |
+ } |
+ @override visitNode(Node node) { |
+ if (!hasYield) super.visitNode(node); |
+ } |
+} |