Chromium Code Reviews| Index: lib/src/codegen/js_codegen.dart |
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
| index 34f9534b4839ceab94b0dd3e63ae7defa0d634a6..6bcc4f18b440af3d6ac32dcf9ba48f4d402864d9 100644 |
| --- a/lib/src/codegen/js_codegen.dart |
| +++ b/lib/src/codegen/js_codegen.dart |
| @@ -1117,7 +1117,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| if (params == null) params = []; |
| return new JS.Method( |
| - _elementMemberName(node.element), new JS.Fun(params, _visit(node.body)), |
| + _elementMemberName(node.element), _emitJsFunction(params, node.body), |
| isGetter: node.isGetter, |
| isSetter: node.isSetter, |
| isStatic: node.isStatic); |
| @@ -1202,10 +1202,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| if (params == null) params = []; |
| var parent = node.parent; |
| - var inDecl = parent is FunctionDeclaration; |
| var inStmt = parent.parent is FunctionDeclarationStatement; |
| - if (inDecl && !inStmt) { |
| - return new JS.Fun(params, _visit(node.body)); |
| + if (parent is FunctionDeclaration) { |
| + return _emitJsFunction(params, node.body); |
| } else { |
| String code; |
| AstNode body; |
| @@ -1214,6 +1213,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| code = '(#) => #'; |
| body = nodeBody.expression; |
| } else { |
| + // We need to bind |
|
Jennifer Messerly
2015/06/25 18:17:45
oops, removing this.
|
| code = '(#) => { #; }'; |
| body = nodeBody; |
| } |
| @@ -1227,6 +1227,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| } |
| } |
| + JS.Fun _emitJsFunction(List<JS.Parameter> params, FunctionBody body) { |
| + // TODO(jmesserly): async/async* |
| + var syncStar = body.isSynchronous && body.star != null; |
| + return new JS.Fun(params, _visit(body), isGenerator: syncStar); |
| + } |
| + |
| @override |
| JS.Statement visitFunctionDeclarationStatement( |
| FunctionDeclarationStatement node) { |
| @@ -1235,12 +1241,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| return js.comment('Unimplemented function get/set statement: $node'); |
| } |
| - // Use an => function to bind this. |
| - // Technically we only need to do this if the function actually closes over |
| - // `this`, but it seems harmless enough to just do it always. |
| + var fn = _visit(func.functionExpression); |
| + var jsThis = new _JsThisFinder(); |
| + fn.accept(jsThis); |
| + |
| var name = new JS.Identifier(func.name.name); |
| + JS.Statement declareFn; |
| + if (jsThis.found) { |
| + declareFn = js.statement('let # = #.bind(this);', [name, fn]); |
| + } else { |
| + declareFn = new JS.FunctionDeclaration(name, fn); |
| + } |
| + |
| return new JS.Block([ |
| - js.statement('let # = #;', [name, _visit(func.functionExpression)]), |
| + declareFn, |
| _emitFunctionTagged(name, func.element.type).toStatement() |
| ]); |
| } |
| @@ -1642,7 +1656,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| JS.Statement visitReturnStatement(ReturnStatement node) { |
| var e = node.expression; |
| if (e == null) return new JS.Return(); |
| - return _visit(e).toReturn(); |
| + return (_visit(e) as JS.Expression).toReturn(); |
| + } |
| + |
| + @override |
| + JS.Statement visitYieldStatement(YieldStatement node) { |
| + JS.Expression jsExpr = _visit(node.expression); |
| + return jsExpr.toYieldStatement(star: node.star != null); |
| } |
| @override |
| @@ -2579,10 +2599,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor { |
| JS.Expression visitExpression(Expression node) => |
| _unimplementedCall('Unimplemented ${node.runtimeType}: $node'); |
| - @override |
| - JS.Statement visitYieldStatement(YieldStatement node) => |
| - _unimplementedCall('Unimplemented yield: $node').toStatement(); |
| - |
| JS.Expression _unimplementedCall(String comment) { |
| return js.call('dart.throw_(#)', [js.escapedString(comment)]); |
| } |
| @@ -2805,3 +2821,13 @@ class TemporaryVariableElement extends LocalVariableElementImpl { |
| int get hashCode => identityHashCode(this); |
| bool operator ==(Object other) => identical(this, other); |
| } |
| + |
| +class _JsThisFinder extends JS.BaseVisitor { |
| + bool found = false; |
| + visitThis(JS.This node) { |
| + found = true; |
| + } |
| + visitNode(JS.Node node) { |
| + if (!found) super.visitNode(node); |
| + } |
| +} |