| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:collection' show HashSet, HashMap; | 7 import 'dart:collection' show HashSet, HashMap; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 final HashSet<FieldElement> _fieldsNeedingStorage; | 61 final HashSet<FieldElement> _fieldsNeedingStorage; |
| 62 | 62 |
| 63 /// The variable for the target of the current `..` cascade expression. | 63 /// The variable for the target of the current `..` cascade expression. |
| 64 SimpleIdentifier _cascadeTarget; | 64 SimpleIdentifier _cascadeTarget; |
| 65 | 65 |
| 66 /// The variable for the current catch clause | 66 /// The variable for the current catch clause |
| 67 SimpleIdentifier _catchParameter; | 67 SimpleIdentifier _catchParameter; |
| 68 | 68 |
| 69 ConstantEvaluator _constEvaluator; | 69 ConstantEvaluator _constEvaluator; |
| 70 | 70 |
| 71 /// Imported libraries, and the temporaries used to refer to them. |
| 72 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
| 71 final _exports = new Set<String>(); | 73 final _exports = new Set<String>(); |
| 72 final _lazyFields = <VariableDeclaration>[]; | 74 final _lazyFields = <VariableDeclaration>[]; |
| 73 final _properties = <FunctionDeclaration>[]; | 75 final _properties = <FunctionDeclaration>[]; |
| 74 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 76 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
| 75 final _extensionMethodNames = new HashSet<String>(); | 77 final _extensionMethodNames = new HashSet<String>(); |
| 76 final _pendingStatements = <JS.Statement>[]; | 78 final _pendingStatements = <JS.Statement>[]; |
| 77 final _temps = new HashMap<Element, JS.TemporaryId>(); | 79 final _temps = new HashMap<Element, JS.TemporaryId>(); |
| 78 | 80 |
| 79 /// The name for the library's exports inside itself. | 81 /// The name for the library's exports inside itself. |
| 80 /// This much be a constant because we interpolate it into template strings, | |
| 81 /// and otherwise it would break caching for them. | |
| 82 /// `exports` was chosen as the most similar to ES module patterns. | 82 /// `exports` was chosen as the most similar to ES module patterns. |
| 83 final _exportsVar = new JS.TemporaryId('exports'); | 83 final _exportsVar = new JS.TemporaryId('exports'); |
| 84 final _namedArgTemp = new JS.TemporaryId('opts'); | 84 final _namedArgTemp = new JS.TemporaryId('opts'); |
| 85 | 85 |
| 86 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or | 86 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or |
| 87 /// [ClassTypeAlias]. | 87 /// [ClassTypeAlias]. |
| 88 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); | 88 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); |
| 89 | 89 |
| 90 /// Memoized results of [_lazyClass]. | 90 /// Memoized results of [_lazyClass]. |
| 91 final _lazyClassMemo = new HashMap<Element, bool>(); | 91 final _lazyClassMemo = new HashMap<Element, bool>(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 134 |
| 135 assert(_pendingClasses.isEmpty); | 135 assert(_pendingClasses.isEmpty); |
| 136 | 136 |
| 137 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); | 137 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); |
| 138 | 138 |
| 139 // TODO(jmesserly): make these immutable in JS? | 139 // TODO(jmesserly): make these immutable in JS? |
| 140 for (var name in _exports) { | 140 for (var name in _exports) { |
| 141 body.add(js.statement('#.# = #;', [_exportsVar, name, name])); | 141 body.add(js.statement('#.# = #;', [_exportsVar, name, name])); |
| 142 } | 142 } |
| 143 | 143 |
| 144 var name = jsLibraryName(libraryInfo.library); | 144 var name = new JS.Identifier(jsLibraryName(currentLibrary)); |
| 145 | 145 |
| 146 var defaultValue = js.call(jsDefaultValue); | 146 // TODO(jmesserly): it would be great to run the renamer on the body, |
| 147 return new JS.Program([ | 147 // then figure out if we really need each of these parameters. |
| 148 js.statement('var #;', name), | 148 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 |
| 149 js.statement("(function(#) { 'use strict'; #; })(# || (# = #));", [ | 149 var program = [ |
| 150 _exportsVar, | 150 js.statement('var # = dart.defineLibrary(#, #);', [ |
| 151 body, | |
| 152 name, | 151 name, |
| 153 name, | 152 name, |
| 154 defaultValue | 153 js.call(jsDefaultValue) |
| 155 ]) | 154 ]) |
| 156 ]); | 155 ]; |
| 156 |
| 157 var params = [_exportsVar]; |
| 158 var args = [name]; |
| 159 _imports.forEach((library, temp) { |
| 160 var name = new JS.Identifier(temp.name); |
| 161 params.add(temp); |
| 162 args.add(name); |
| 163 var helper = _libraryMightNotBeLoaded(library) ? 'lazyImport' : 'import'; |
| 164 program.add(js.statement('var # = dart.#(#);', [name, helper, name])); |
| 165 }); |
| 166 |
| 167 program.add(js.statement( |
| 168 "(function(#) { 'use strict'; #; })(#);", [params, body, args])); |
| 169 |
| 170 return new JS.Program(program); |
| 157 } | 171 } |
| 158 | 172 |
| 159 JS.Identifier _initSymbol(JS.Identifier id) { | 173 JS.Identifier _initSymbol(JS.Identifier id) { |
| 160 var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); | 174 var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); |
| 161 _pendingStatements.add(s); | 175 _pendingStatements.add(s); |
| 162 return id; | 176 return id; |
| 163 } | 177 } |
| 164 | 178 |
| 165 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, | 179 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, |
| 166 // until we have better name tracking. | 180 // until we have better name tracking. |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 /// on this library via some transitive import path. | 484 /// on this library via some transitive import path. |
| 471 /// | 485 /// |
| 472 /// If we could control the global import ordering, we could eliminate some | 486 /// If we could control the global import ordering, we could eliminate some |
| 473 /// of these cases, by ordering the imports of the cyclic libraries in an | 487 /// of these cases, by ordering the imports of the cyclic libraries in an |
| 474 /// optimal way. For example, we could order the libraries in a cycle to | 488 /// optimal way. For example, we could order the libraries in a cycle to |
| 475 /// minimize laziness. However, we currently assume we cannot control the | 489 /// minimize laziness. However, we currently assume we cannot control the |
| 476 /// order that the cycle of libraries will be loaded in. | 490 /// order that the cycle of libraries will be loaded in. |
| 477 bool _typeMightNotBeLoaded(DartType type) { | 491 bool _typeMightNotBeLoaded(DartType type) { |
| 478 var library = type.element.library; | 492 var library = type.element.library; |
| 479 if (library == currentLibrary) return _lazyClass(type); | 493 if (library == currentLibrary) return _lazyClass(type); |
| 494 return _libraryMightNotBeLoaded(library); |
| 495 } |
| 480 | 496 |
| 497 bool _libraryMightNotBeLoaded(LibraryElement library) { |
| 481 // The SDK is a special case: we optimize the order to prevent laziness. | 498 // The SDK is a special case: we optimize the order to prevent laziness. |
| 482 if (library.isInSdk) { | 499 if (library.isInSdk) { |
| 483 // SDK is loaded before non-SDK libraies | 500 // SDK is loaded before non-SDK libraies |
| 484 if (!currentLibrary.isInSdk) return false; | 501 if (!currentLibrary.isInSdk) return false; |
| 485 | 502 |
| 486 // Compute the order of both SDK libraries. If unknown, assume it's after. | 503 // Compute the order of both SDK libraries. If unknown, assume it's after. |
| 487 var classOrder = corelibOrder.indexOf(library.name); | 504 var classOrder = corelibOrder.indexOf(library.name); |
| 488 if (classOrder == -1) classOrder = corelibOrder.length; | 505 if (classOrder == -1) classOrder = corelibOrder.length; |
| 489 | 506 |
| 490 var currentOrder = corelibOrder.indexOf(currentLibrary.name); | 507 var currentOrder = corelibOrder.indexOf(currentLibrary.name); |
| (...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 } | 1111 } |
| 1095 | 1112 |
| 1096 // Get the original declaring element. If we had a property accessor, this | 1113 // Get the original declaring element. If we had a property accessor, this |
| 1097 // indirects back to a (possibly synthetic) field. | 1114 // indirects back to a (possibly synthetic) field. |
| 1098 var element = accessor; | 1115 var element = accessor; |
| 1099 if (element is PropertyAccessorElement) element = accessor.variable; | 1116 if (element is PropertyAccessorElement) element = accessor.variable; |
| 1100 var name = element.name; | 1117 var name = element.name; |
| 1101 | 1118 |
| 1102 // library member | 1119 // library member |
| 1103 if (element.enclosingElement is CompilationUnitElement && | 1120 if (element.enclosingElement is CompilationUnitElement && |
| 1104 (element.library != libraryInfo.library || | 1121 (element.library != currentLibrary || |
| 1105 element is TopLevelVariableElement && !element.isConst)) { | 1122 element is TopLevelVariableElement && !element.isConst)) { |
| 1106 var memberName = _emitMemberName(name, isStatic: true); | 1123 var memberName = _emitMemberName(name, isStatic: true); |
| 1107 return js.call('#.#', [_libraryName(element.library), memberName]); | 1124 return js.call('#.#', [_libraryName(element.library), memberName]); |
| 1108 } | 1125 } |
| 1109 | 1126 |
| 1110 // Unqualified class member. This could mean implicit-this, or implicit | 1127 // Unqualified class member. This could mean implicit-this, or implicit |
| 1111 // call to a static from the same class. | 1128 // call to a static from the same class. |
| 1112 if (element is ClassMemberElement && element is! ConstructorElement) { | 1129 if (element is ClassMemberElement && element is! ConstructorElement) { |
| 1113 bool isStatic = element.isStatic; | 1130 bool isStatic = element.isStatic; |
| 1114 var type = element.enclosingElement.type; | 1131 var type = element.enclosingElement.type; |
| (...skipping 1121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2236 | 2253 |
| 2237 @override | 2254 @override |
| 2238 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 2255 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
| 2239 | 2256 |
| 2240 @override | 2257 @override |
| 2241 visitSymbolLiteral(SymbolLiteral node) { | 2258 visitSymbolLiteral(SymbolLiteral node) { |
| 2242 // TODO(vsm): When we canonicalize, we need to treat private symbols | 2259 // TODO(vsm): When we canonicalize, we need to treat private symbols |
| 2243 // correctly. | 2260 // correctly. |
| 2244 var name = js.string(node.components.join('.'), "'"); | 2261 var name = js.string(node.components.join('.'), "'"); |
| 2245 var nameHint = 'symbol_' + node.components.join('_'); | 2262 var nameHint = 'symbol_' + node.components.join('_'); |
| 2246 return _const(node, js.call('new core.Symbol(#)', name), nameHint); | 2263 return _const( |
| 2264 node, new JS.New(_emitTypeName(types.symbolType), [name]), nameHint); |
| 2247 } | 2265 } |
| 2248 | 2266 |
| 2249 @override | 2267 @override |
| 2250 visitListLiteral(ListLiteral node) { | 2268 visitListLiteral(ListLiteral node) { |
| 2251 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); | 2269 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); |
| 2252 | 2270 |
| 2253 ParameterizedType type = node.staticType; | 2271 ParameterizedType type = node.staticType; |
| 2254 if (type.typeArguments.any((a) => a != types.dynamicType)) { | 2272 if (type.typeArguments.any((a) => a != types.dynamicType)) { |
| 2255 list = js.call('dart.setType(#, #)', [list, _emitTypeName(type)]); | 2273 list = js.call('dart.setType(#, #)', [list, _emitTypeName(type)]); |
| 2256 } | 2274 } |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2485 bool _externalOrNative(node) => | 2503 bool _externalOrNative(node) => |
| 2486 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 2504 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 2487 | 2505 |
| 2488 FunctionBody _functionBody(node) => | 2506 FunctionBody _functionBody(node) => |
| 2489 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 2507 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 2490 | 2508 |
| 2491 /// Choose a canonical name from the library element. | 2509 /// Choose a canonical name from the library element. |
| 2492 /// This never uses the library's name (the identifier in the `library` | 2510 /// This never uses the library's name (the identifier in the `library` |
| 2493 /// declaration) as it doesn't have any meaningful rules enforced. | 2511 /// declaration) as it doesn't have any meaningful rules enforced. |
| 2494 JS.Identifier _libraryName(LibraryElement library) { | 2512 JS.Identifier _libraryName(LibraryElement library) { |
| 2495 if (library == libraryInfo.library) return _exportsVar; | 2513 if (library == currentLibrary) return _exportsVar; |
| 2496 return new JS.Identifier(jsLibraryName(library)); | 2514 return _imports.putIfAbsent( |
| 2515 library, () => new JS.TemporaryId(jsLibraryName(library))); |
| 2497 } | 2516 } |
| 2498 | 2517 |
| 2499 DartType getStaticType(Expression e) => rules.getStaticType(e); | 2518 DartType getStaticType(Expression e) => rules.getStaticType(e); |
| 2500 } | 2519 } |
| 2501 | 2520 |
| 2502 class JSGenerator extends CodeGenerator { | 2521 class JSGenerator extends CodeGenerator { |
| 2503 final CompilerOptions options; | 2522 final CompilerOptions options; |
| 2504 | 2523 |
| 2505 /// For fast lookup of extension methods, we first check the name, then do a | 2524 /// For fast lookup of extension methods, we first check the name, then do a |
| 2506 /// (possibly expensive) subtype test to see if it matches one of the types | 2525 /// (possibly expensive) subtype test to see if it matches one of the types |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2570 // TODO(jmesserly): validate the library. See issue #135. | 2589 // TODO(jmesserly): validate the library. See issue #135. |
| 2571 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2590 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; |
| 2572 | 2591 |
| 2573 bool _isJsPeerInterface(DartObjectImpl value) => | 2592 bool _isJsPeerInterface(DartObjectImpl value) => |
| 2574 value.type.name == 'JsPeerInterface'; | 2593 value.type.name == 'JsPeerInterface'; |
| 2575 | 2594 |
| 2576 // TODO(jacobr): we would like to do something like the following | 2595 // TODO(jacobr): we would like to do something like the following |
| 2577 // but we don't have summary support yet. | 2596 // but we don't have summary support yet. |
| 2578 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2597 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
| 2579 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2598 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
| OLD | NEW |