Index: lib/src/codegen/js_codegen.dart |
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
index 0dd62fd6d66a560036728d90a15671685a87c050..367e895ea4c2e1a4d38574f28f9130b4a82f28ab 100644 |
--- a/lib/src/codegen/js_codegen.dart |
+++ b/lib/src/codegen/js_codegen.dart |
@@ -104,6 +104,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
/// The default value of the module object. See [visitLibraryDirective]. |
String _jsModuleValue; |
+ bool _isDartUtils; |
+ |
Map<String, DartType> _objectMembers; |
JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, |
@@ -117,6 +119,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
var src = context.sourceFactory.forUri('dart:_interceptors'); |
var interceptors = context.computeLibraryElement(src); |
_jsArray = interceptors.getType('JSArray'); |
+ _isDartUtils = currentLibrary.isInSdk && |
Jennifer Messerly
2015/11/30 18:54:11
you shouldn't need the isInSdk check, it's just ch
|
+ currentLibrary.source.uri.toString() == 'dart:_utils'; |
_objectMembers = getObjectMemberMap(types); |
} |
@@ -196,7 +200,19 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
list.add(js.string(compiler.getModuleName(library.source.uri), "'")); |
}; |
- var imports = <JS.Expression>[js.string('dart/_runtime')]; |
+ var needsDartRuntime = !_isDartUtils; |
+ |
+ var imports = <JS.Expression>[]; |
+ var moduleStatements = <JS.Statement>[]; |
+ if (needsDartRuntime) { |
+ imports.add(js.string('dart/_runtime')); |
+ |
+ var dartxImport = |
+ js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); |
Jennifer Messerly
2015/11/30 18:54:11
const?
|
+ moduleStatements.add(dartxImport); |
+ } |
+ moduleStatements.addAll(_moduleItems); |
+ |
_imports.forEach((library, temp) { |
if (_loader.libraryIsLoaded(library)) { |
processImport(library, temp, imports); |
@@ -210,11 +226,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
} |
}); |
- var dartxImport = |
- js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); |
- |
- var module = js.call("function(#) { 'use strict'; #; #; }", |
- [params, dartxImport, _moduleItems]); |
+ var module = |
+ js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); |
var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ |
js.string(jsPath, "'"), |
@@ -289,7 +302,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
args.add(new JS.ArrayInitializer(shownNames)); |
args.add(new JS.ArrayInitializer(hiddenNames)); |
} |
- _moduleItems.add(js.statement('dart.export(#);', [args])); |
+ _moduleItems.add(js.statement('dart.export_(#);', [args])); |
} |
JS.Identifier _initSymbol(JS.Identifier id) { |
@@ -1284,17 +1297,64 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
var name = node.name.name; |
+ var fn = _visit(node.functionExpression); |
+ bool needsTagging = true; |
+ if (currentLibrary.isInSdk && |
Jennifer Messerly
2015/11/30 18:54:11
I try and avoid LibraryElement.isInSdk, because an
ochafik
2015/12/01 14:41:03
Done.
|
+ _isInlineJSBody(node.functionExpression.body)) { |
+ fn = _simplifyFun(fn); |
+ needsTagging = !_isDartUtils; |
+ } |
var id = new JS.Identifier(name); |
body.add(annotate( |
- new JS.FunctionDeclaration(id, _visit(node.functionExpression)), |
+ new JS.FunctionDeclaration(id, fn), |
node.element)); |
- body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) |
- .toStatement()); |
+ if (needsTagging) { |
+ body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) |
+ .toStatement()); |
+ } |
if (isPublic(name)) _addExport(name); |
return _statement(body); |
} |
+ /// Simplify `f(x) => (function() { ... })()` to `f(x) => { ... }`. |
+ /// |
+ /// This is useful for runtime utils written with JS intrinsics, e.g. |
+ /// `foo(x) => JS('', '(function() { let x = #; ... })()', x);`. |
+ JS.Fun _simplifyFun(JS.Fun fn) { |
Jennifer Messerly
2015/11/30 18:54:11
love this!
Regarding:
JS('', '(function() { l
ochafik
2015/12/01 14:41:03
I was equally bothered by `let x = x` and the sile
|
+ if (fn.body is JS.Block && fn.body.statements.length == 1) { |
+ var stat = fn.body.statements.single; |
+ if (stat is JS.Return) { |
+ if (stat.value is JS.Call) { |
+ JS.Call call = stat.value; |
+ if (call.target is JS.Fun && call.arguments.isEmpty) { |
+ JS.Fun innerFun = call.target; |
+ return new JS.Fun(fn.params, innerFun.body); |
+ } |
+ } |
+ } |
+ } |
+ return fn; |
+ } |
+ |
+ bool _isInlineJSBody(FunctionBody body) { |
Jennifer Messerly
2015/11/30 18:54:11
It might be nice to combine this with the simplifi
ochafik
2015/12/01 14:41:03
I can't find a very clean way to combine them (hav
|
+ bool isJsInvocation(Expression expr) => |
+ expr is MethodInvocation && |
+ isInlineJS(expr.methodName.staticElement); |
+ |
+ if (body is ExpressionFunctionBody) { |
+ return isJsInvocation(body.expression); |
+ } else if (body is BlockFunctionBody) { |
+ if (body.block.statements.length == 1) { |
+ var stat = body.block.statements.single; |
+ if (stat is ReturnStatement) { |
+ return isJsInvocation(stat.expression); |
+ } |
+ } |
+ } |
+ return false; |
+ } |
+ |
JS.Method _emitTopLevelProperty(FunctionDeclaration node) { |
var name = node.name.name; |
return annotate( |