| 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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 // Collect all Element -> Node mappings, in case we need to forward declare | 227 // Collect all Element -> Node mappings, in case we need to forward declare |
| 228 // any nodes. | 228 // any nodes. |
| 229 var nodes = new HashMap<Element, AstNode>.identity(); | 229 var nodes = new HashMap<Element, AstNode>.identity(); |
| 230 var sdkBootstrappingFns = new List<FunctionElement>(); | 230 var sdkBootstrappingFns = new List<FunctionElement>(); |
| 231 for (var unit in compilationUnits) { | 231 for (var unit in compilationUnits) { |
| 232 if (_isDartRuntime(unit.element.library)) { | 232 if (_isDartRuntime(unit.element.library)) { |
| 233 sdkBootstrappingFns.addAll(unit.element.functions); | 233 sdkBootstrappingFns.addAll(unit.element.functions); |
| 234 } | 234 } |
| 235 _collectElements(unit, nodes); | 235 _collectElements(unit, nodes); |
| 236 } | 236 } |
| 237 _loader = new ElementLoader(_emitModuleItem, nodes); | 237 _loader = new ElementLoader(nodes); |
| 238 | 238 |
| 239 // Add implicit dart:core dependency so it is first. | 239 // Add implicit dart:core dependency so it is first. |
| 240 emitLibraryName(dartCoreLibrary); | 240 emitLibraryName(dartCoreLibrary); |
| 241 | 241 |
| 242 // Emit SDK bootstrapping functions first, if any. | 242 // Emit SDK bootstrapping functions first, if any. |
| 243 sdkBootstrappingFns.forEach(_loader.emitDeclaration); | 243 sdkBootstrappingFns.forEach(_emitDeclaration); |
| 244 | 244 |
| 245 // Visit each compilation unit and emit its code. | 245 // Visit each compilation unit and emit its code. |
| 246 // | 246 // |
| 247 // NOTE: declarations are not necessarily emitted in this order. | 247 // NOTE: declarations are not necessarily emitted in this order. |
| 248 // Order will be changed as needed so the resulting code can execute. | 248 // Order will be changed as needed so the resulting code can execute. |
| 249 // This is done by forward declaring items. | 249 // This is done by forward declaring items. |
| 250 compilationUnits.forEach(visitCompilationUnit); | 250 compilationUnits.forEach(visitCompilationUnit); |
| 251 | 251 |
| 252 // Declare imports | 252 // Declare imports |
| 253 _finishImports(items); | 253 _finishImports(items); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 if (declaration is TopLevelVariableDeclaration) { | 381 if (declaration is TopLevelVariableDeclaration) { |
| 382 for (var field in declaration.variables.variables) { | 382 for (var field in declaration.variables.variables) { |
| 383 map[field.element] = field; | 383 map[field.element] = field; |
| 384 } | 384 } |
| 385 } else { | 385 } else { |
| 386 map[declaration.element] = declaration; | 386 map[declaration.element] = declaration; |
| 387 } | 387 } |
| 388 } | 388 } |
| 389 } | 389 } |
| 390 | 390 |
| 391 void _emitModuleItem(AstNode node) { | 391 /// Called to emit all top-level declarations. |
| 392 // TODO(jmesserly): ideally we could do this at a smaller granularity. | 392 /// |
| 393 // We'll need to be consistent about when we're generating functions, and | 393 /// During the course of emitting one item, we may emit another. For example |
| 394 // only run this on the outermost function. | 394 /// |
| 395 inferNullableTypes(node); | 395 /// class D extends B { C m() { ... } } |
| 396 /// |
| 397 /// Because D depends on B, we'll emit B first if needed. However C is not |
| 398 /// used by top-level JavaScript code, so we can ignore that dependency. |
| 399 void _emitDeclaration(Element e) { |
| 400 var item = _loader.emitDeclaration(e, (AstNode node) { |
| 401 // TODO(jmesserly): this is not really the right place for this. |
| 402 // Ideally we do this per function body. |
| 403 // |
| 404 // We'll need to be consistent about when we're generating functions, and |
| 405 // only run this on the outermost function, and not any closures. |
| 406 inferNullableTypes(node); |
| 407 return _visit(node); |
| 408 }); |
| 396 | 409 |
| 397 var code = _visit(node); | 410 if (item != null) _moduleItems.add(item); |
| 398 if (code != null) _moduleItems.add(code); | 411 } |
| 412 |
| 413 void _declareBeforeUse(Element e) { |
| 414 _loader.declareBeforeUse(e, _emitDeclaration); |
| 399 } | 415 } |
| 400 | 416 |
| 401 @override | 417 @override |
| 402 void visitCompilationUnit(CompilationUnit unit) { | 418 void visitCompilationUnit(CompilationUnit unit) { |
| 403 _constField = new ConstFieldVisitor(types, unit.element.source); | 419 _constField = new ConstFieldVisitor(types, unit.element.source); |
| 404 | 420 |
| 405 for (var declaration in unit.declarations) { | 421 for (var declaration in unit.declarations) { |
| 406 var element = declaration.element; | 422 var element = declaration.element; |
| 407 if (element != null) { | 423 if (element != null) { |
| 408 _loader.emitDeclaration(element); | 424 _emitDeclaration(element); |
| 409 } else { | 425 } else { |
| 410 declaration.accept(this); | 426 declaration.accept(this); |
| 411 } | 427 } |
| 412 } | 428 } |
| 413 for (var directive in unit.directives) { | 429 for (var directive in unit.directives) { |
| 414 directive.accept(this); | 430 directive.accept(this); |
| 415 } | 431 } |
| 416 } | 432 } |
| 417 | 433 |
| 418 @override | 434 @override |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 | 487 |
| 472 for (var export in exportedNames.definedNames.values) { | 488 for (var export in exportedNames.definedNames.values) { |
| 473 if (export is PropertyAccessorElement) { | 489 if (export is PropertyAccessorElement) { |
| 474 export = (export as PropertyAccessorElement).variable; | 490 export = (export as PropertyAccessorElement).variable; |
| 475 } | 491 } |
| 476 | 492 |
| 477 // Don't allow redefining names from this library. | 493 // Don't allow redefining names from this library. |
| 478 if (currentNames.containsKey(export.name)) continue; | 494 if (currentNames.containsKey(export.name)) continue; |
| 479 | 495 |
| 480 if (export.isSynthetic && export is PropertyInducingElement) { | 496 if (export.isSynthetic && export is PropertyInducingElement) { |
| 481 _loader.emitDeclaration(export.getter); | 497 _emitDeclaration(export.getter); |
| 482 _loader.emitDeclaration(export.setter); | 498 _emitDeclaration(export.setter); |
| 483 } else { | 499 } else { |
| 484 _loader.emitDeclaration(export); | 500 _emitDeclaration(export); |
| 485 } | 501 } |
| 486 if (export is ClassElement && export.typeParameters.isNotEmpty) { | 502 if (export is ClassElement && export.typeParameters.isNotEmpty) { |
| 487 // Export the generic name as well. | 503 // Export the generic name as well. |
| 488 // TODO(jmesserly): revisit generic classes | 504 // TODO(jmesserly): revisit generic classes |
| 489 emitExport(export, suffix: r'$'); | 505 emitExport(export, suffix: r'$'); |
| 490 } | 506 } |
| 491 emitExport(export); | 507 emitExport(export); |
| 492 } | 508 } |
| 493 } | 509 } |
| 494 | 510 |
| (...skipping 1290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1785 typeParams: fn.typeParams, | 1801 typeParams: fn.typeParams, |
| 1786 returnType: fn.returnType)..sourceInformation = fn.sourceInformation; | 1802 returnType: fn.returnType)..sourceInformation = fn.sourceInformation; |
| 1787 } | 1803 } |
| 1788 | 1804 |
| 1789 @override | 1805 @override |
| 1790 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 1806 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 1791 assert(node.parent is CompilationUnit); | 1807 assert(node.parent is CompilationUnit); |
| 1792 | 1808 |
| 1793 if (_externalOrNative(node)) return null; | 1809 if (_externalOrNative(node)) return null; |
| 1794 | 1810 |
| 1795 if (node.isGetter || node.isSetter) { | 1811 // If we have a getter/setter pair, they need to be defined together. |
| 1796 // If we have a getter/setter pair, they need to be defined together. | 1812 if (node.isGetter) { |
| 1797 PropertyAccessorElement element = node.element; | 1813 PropertyAccessorElement element = node.element; |
| 1798 var props = <JS.Method>[]; | 1814 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1799 var getter = element.variable.getter; | 1815 var setter = element.correspondingSetter; |
| 1800 if (getter != null) { | 1816 if (setter != null) { |
| 1801 props.add(_loader.customEmitDeclaration(getter, _emitTopLevelProperty)); | 1817 props.add(_loader.emitDeclaration(setter, _emitTopLevelProperty)); |
| 1802 } | 1818 } |
| 1803 var setter = element.variable.setter; | |
| 1804 if (setter != null) { | |
| 1805 props.add(_loader.customEmitDeclaration(setter, _emitTopLevelProperty)); | |
| 1806 } | |
| 1807 | |
| 1808 return js.statement('dart.copyProperties(#, { # });', | 1819 return js.statement('dart.copyProperties(#, { # });', |
| 1809 [emitLibraryName(currentLibrary), props]); | 1820 [emitLibraryName(currentLibrary), props]); |
| 1810 } | 1821 } |
| 1822 if (node.isSetter) { |
| 1823 PropertyAccessorElement element = node.element; |
| 1824 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| 1825 var getter = element.correspondingGetter; |
| 1826 if (getter != null) { |
| 1827 props.add(_loader.emitDeclaration(getter, _emitTopLevelProperty)); |
| 1828 } |
| 1829 return js.statement('dart.copyProperties(#, { # });', |
| 1830 [emitLibraryName(currentLibrary), props]); |
| 1831 } |
| 1811 | 1832 |
| 1812 var body = <JS.Statement>[]; | 1833 var body = <JS.Statement>[]; |
| 1813 var fn = _emitFunction(node.functionExpression); | 1834 var fn = _emitFunction(node.functionExpression); |
| 1814 | 1835 |
| 1815 if (currentLibrary.source.isInSystemLibrary && | 1836 if (currentLibrary.source.isInSystemLibrary && |
| 1816 _isInlineJSFunction(node.functionExpression)) { | 1837 _isInlineJSFunction(node.functionExpression)) { |
| 1817 fn = _simplifyPassThroughArrowFunCallBody(fn); | 1838 fn = _simplifyPassThroughArrowFunCallBody(fn); |
| 1818 } | 1839 } |
| 1819 | 1840 |
| 1820 var element = node.element; | 1841 var element = node.element; |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2122 if (accessor == null) { | 2143 if (accessor == null) { |
| 2123 return js.commentExpression( | 2144 return js.commentExpression( |
| 2124 'Unimplemented unknown name', new JS.Identifier(node.name)); | 2145 'Unimplemented unknown name', new JS.Identifier(node.name)); |
| 2125 } | 2146 } |
| 2126 | 2147 |
| 2127 // Get the original declaring element. If we had a property accessor, this | 2148 // Get the original declaring element. If we had a property accessor, this |
| 2128 // indirects back to a (possibly synthetic) field. | 2149 // indirects back to a (possibly synthetic) field. |
| 2129 var element = accessor; | 2150 var element = accessor; |
| 2130 if (accessor is PropertyAccessorElement) element = accessor.variable; | 2151 if (accessor is PropertyAccessorElement) element = accessor.variable; |
| 2131 | 2152 |
| 2132 _loader.declareBeforeUse(element); | 2153 _declareBeforeUse(element); |
| 2133 | 2154 |
| 2134 // type literal | 2155 // type literal |
| 2135 if (element is TypeDefiningElement) { | 2156 if (element is TypeDefiningElement) { |
| 2136 var typeName = _emitType(fillDynamicTypeArgs(element.type)); | 2157 var typeName = _emitType(fillDynamicTypeArgs(element.type)); |
| 2137 | 2158 |
| 2138 // If the type is a type literal expression in Dart code, wrap the raw | 2159 // If the type is a type literal expression in Dart code, wrap the raw |
| 2139 // runtime type in a "Type" instance. | 2160 // runtime type in a "Type" instance. |
| 2140 if (!_isInForeignJS && _isTypeLiteral(node)) { | 2161 if (!_isInForeignJS && _isTypeLiteral(node)) { |
| 2141 typeName = js.call('dart.wrapType(#)', typeName); | 2162 typeName = js.call('dart.wrapType(#)', typeName); |
| 2142 } | 2163 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2312 JS.Expression className}) { | 2333 JS.Expression className}) { |
| 2313 // The void and dynamic types are not defined in core. | 2334 // The void and dynamic types are not defined in core. |
| 2314 if (type.isVoid) { | 2335 if (type.isVoid) { |
| 2315 return js.call('dart.void'); | 2336 return js.call('dart.void'); |
| 2316 } else if (type.isDynamic) { | 2337 } else if (type.isDynamic) { |
| 2317 return js.call('dart.dynamic'); | 2338 return js.call('dart.dynamic'); |
| 2318 } else if (type.isBottom) { | 2339 } else if (type.isBottom) { |
| 2319 return js.call('dart.bottom'); | 2340 return js.call('dart.bottom'); |
| 2320 } | 2341 } |
| 2321 | 2342 |
| 2322 _loader.declareBeforeUse(type.element); | 2343 _declareBeforeUse(type.element); |
| 2323 | 2344 |
| 2324 // TODO(jmesserly): like constants, should we hoist function types out of | 2345 // TODO(jmesserly): like constants, should we hoist function types out of |
| 2325 // methods? Similar issue with generic types. For all of these, we may want | 2346 // methods? Similar issue with generic types. For all of these, we may want |
| 2326 // to canonicalize them too, at least when inside the same library. | 2347 // to canonicalize them too, at least when inside the same library. |
| 2327 var name = type.name; | 2348 var name = type.name; |
| 2328 var element = type.element; | 2349 var element = type.element; |
| 2329 if (name == '' || name == null || lowerTypedef) { | 2350 if (name == '' || name == null || lowerTypedef) { |
| 2330 // TODO(jmesserly): should we change how typedefs work? They currently | 2351 // TODO(jmesserly): should we change how typedefs work? They currently |
| 2331 // go through use similar logic as generic classes. This makes them | 2352 // go through use similar logic as generic classes. This makes them |
| 2332 // different from universal function types. | 2353 // different from universal function types. |
| (...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2862 } | 2883 } |
| 2863 | 2884 |
| 2864 @override | 2885 @override |
| 2865 JS.Expression visitAwaitExpression(AwaitExpression node) { | 2886 JS.Expression visitAwaitExpression(AwaitExpression node) { |
| 2866 return new JS.Yield(_visit(node.expression)); | 2887 return new JS.Yield(_visit(node.expression)); |
| 2867 } | 2888 } |
| 2868 | 2889 |
| 2869 @override | 2890 @override |
| 2870 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 2891 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 2871 for (var variable in node.variables.variables) { | 2892 for (var variable in node.variables.variables) { |
| 2872 _loader.emitDeclaration(variable.element); | 2893 _emitDeclaration(variable.element); |
| 2873 } | 2894 } |
| 2874 } | 2895 } |
| 2875 | 2896 |
| 2876 /// This is not used--we emit fields as we are emitting the class, | 2897 /// This is not used--we emit fields as we are emitting the class, |
| 2877 /// see [visitClassDeclaration]. | 2898 /// see [visitClassDeclaration]. |
| 2878 @override | 2899 @override |
| 2879 visitFieldDeclaration(FieldDeclaration node) { | 2900 visitFieldDeclaration(FieldDeclaration node) { |
| 2880 assert(false); | 2901 assert(false); |
| 2881 } | 2902 } |
| 2882 | 2903 |
| (...skipping 1254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4137 JS.Expression emitList() { | 4158 JS.Expression emitList() { |
| 4138 JS.Expression list = new JS.ArrayInitializer( | 4159 JS.Expression list = new JS.ArrayInitializer( |
| 4139 _visitList(node.elements) as List<JS.Expression>); | 4160 _visitList(node.elements) as List<JS.Expression>); |
| 4140 ParameterizedType type = node.staticType; | 4161 ParameterizedType type = node.staticType; |
| 4141 var elementType = type.typeArguments.single; | 4162 var elementType = type.typeArguments.single; |
| 4142 // TODO(jmesserly): analyzer will usually infer `List<Object>` because | 4163 // TODO(jmesserly): analyzer will usually infer `List<Object>` because |
| 4143 // that is the least upper bound of the element types. So we rarely | 4164 // that is the least upper bound of the element types. So we rarely |
| 4144 // generate a plain `List<dynamic>` anymore. | 4165 // generate a plain `List<dynamic>` anymore. |
| 4145 if (!elementType.isDynamic) { | 4166 if (!elementType.isDynamic) { |
| 4146 // dart.list helper internally depends on _interceptors.JSArray. | 4167 // dart.list helper internally depends on _interceptors.JSArray. |
| 4147 _loader.declareBeforeUse(_jsArray); | 4168 _declareBeforeUse(_jsArray); |
| 4148 list = js.call('dart.list(#, #)', [list, _emitType(elementType)]); | 4169 list = js.call('dart.list(#, #)', [list, _emitType(elementType)]); |
| 4149 } | 4170 } |
| 4150 return list; | 4171 return list; |
| 4151 } | 4172 } |
| 4152 if (node.constKeyword != null) return _emitConst(emitList); | 4173 if (node.constKeyword != null) return _emitConst(emitList); |
| 4153 return emitList(); | 4174 return emitList(); |
| 4154 } | 4175 } |
| 4155 | 4176 |
| 4156 @override | 4177 @override |
| 4157 visitMapLiteral(MapLiteral node) { | 4178 visitMapLiteral(MapLiteral node) { |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4535 } | 4556 } |
| 4536 | 4557 |
| 4537 bool isLibraryPrefix(Expression node) => | 4558 bool isLibraryPrefix(Expression node) => |
| 4538 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4559 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4539 | 4560 |
| 4540 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4561 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4541 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4562 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4542 | 4563 |
| 4543 bool _isDartRuntime(LibraryElement l) => | 4564 bool _isDartRuntime(LibraryElement l) => |
| 4544 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4565 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |