| 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; |
| 11 import 'package:analyzer/src/generated/constant.dart'; | 11 import 'package:analyzer/src/generated/constant.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; | 12 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 14 import 'package:analyzer/src/generated/scanner.dart' | 14 import 'package:analyzer/src/generated/scanner.dart' |
| 15 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
| 16 import 'package:path/path.dart' as path; | 16 import 'package:path/path.dart' as path; |
| 17 | 17 |
| 18 import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder; | 18 import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder; |
| 19 import 'package:dev_compiler/src/codegen/reify_coercions.dart' | 19 import 'package:dev_compiler/src/codegen/reify_coercions.dart' |
| 20 show CoercionReifier; | 20 show CoercionReifier; |
| 21 | 21 |
| 22 // TODO(jmesserly): import from its own package | 22 // TODO(jmesserly): import from its own package |
| 23 import 'package:dev_compiler/src/js/js_ast.dart' as JS; | 23 import 'package:dev_compiler/src/js/js_ast.dart' as JS; |
| 24 import 'package:dev_compiler/src/js/js_ast.dart' show js; | 24 import 'package:dev_compiler/src/js/js_ast.dart' show js; |
| 25 | 25 |
| 26 import 'package:dev_compiler/src/checker/rules.dart'; | 26 import 'package:dev_compiler/src/checker/rules.dart'; |
| 27 import 'package:dev_compiler/src/dependency_graph.dart'; |
| 27 import 'package:dev_compiler/src/info.dart'; | 28 import 'package:dev_compiler/src/info.dart'; |
| 28 import 'package:dev_compiler/src/options.dart'; | 29 import 'package:dev_compiler/src/options.dart'; |
| 29 import 'package:dev_compiler/src/utils.dart'; | 30 import 'package:dev_compiler/src/utils.dart'; |
| 30 | 31 |
| 31 import 'code_generator.dart'; | 32 import 'code_generator.dart'; |
| 32 import 'js_field_storage.dart'; | 33 import 'js_field_storage.dart'; |
| 33 import 'js_names.dart' show JSTemporary, invalidJSStaticMethodName; | 34 import 'js_names.dart' show JSTemporary, invalidJSStaticMethodName; |
| 34 import 'js_metalet.dart'; | 35 import 'js_metalet.dart'; |
| 35 import 'js_printer.dart' show writeJsLibrary; | 36 import 'js_printer.dart' show writeJsLibrary; |
| 36 import 'side_effect_analysis.dart'; | 37 import 'side_effect_analysis.dart'; |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 | 433 |
| 433 if (type is InterfaceType) { | 434 if (type is InterfaceType) { |
| 434 result = _typeMightNotBeLoaded(type.superclass) || | 435 result = _typeMightNotBeLoaded(type.superclass) || |
| 435 type.mixins.any(_typeMightNotBeLoaded); | 436 type.mixins.any(_typeMightNotBeLoaded); |
| 436 } else if (type is FunctionType) { | 437 } else if (type is FunctionType) { |
| 437 result = _typeMightNotBeLoaded(types.functionType); | 438 result = _typeMightNotBeLoaded(types.functionType); |
| 438 } | 439 } |
| 439 return _lazyClassMemo[type.element] = result; | 440 return _lazyClassMemo[type.element] = result; |
| 440 } | 441 } |
| 441 | 442 |
| 442 /// Curated order to minimize lazy classes needed by dart:core and its | |
| 443 /// transitive SDK imports. | |
| 444 static const CORELIB_ORDER = const [ | |
| 445 'dart.core', | |
| 446 'dart.collection', | |
| 447 'dart._internal' | |
| 448 ]; | |
| 449 | |
| 450 /// Returns true if the class might not be loaded. | 443 /// Returns true if the class might not be loaded. |
| 451 /// | 444 /// |
| 452 /// If the class is from our library, this can happen because it's lazy. | 445 /// If the class is from our library, this can happen because it's lazy. |
| 453 /// | 446 /// |
| 454 /// If the class is from a different library, it could happen if we're in | 447 /// If the class is from a different library, it could happen if we're in |
| 455 /// a library cycle. In other words, if that different library depends back | 448 /// a library cycle. In other words, if that different library depends back |
| 456 /// on this library via some transitive import path. | 449 /// on this library via some transitive import path. |
| 457 /// | 450 /// |
| 458 /// If we could control the global import ordering, we could eliminate some | 451 /// If we could control the global import ordering, we could eliminate some |
| 459 /// of these cases, by ordering the imports of the cyclic libraries in an | 452 /// of these cases, by ordering the imports of the cyclic libraries in an |
| 460 /// optimal way. For example, we could order the libraries in a cycle to | 453 /// optimal way. For example, we could order the libraries in a cycle to |
| 461 /// minimize laziness. However, we currently assume we cannot control the | 454 /// minimize laziness. However, we currently assume we cannot control the |
| 462 /// order that the cycle of libraries will be loaded in. | 455 /// order that the cycle of libraries will be loaded in. |
| 463 bool _typeMightNotBeLoaded(DartType type) { | 456 bool _typeMightNotBeLoaded(DartType type) { |
| 464 var library = type.element.library; | 457 var library = type.element.library; |
| 465 if (library == currentLibrary) return _lazyClass(type); | 458 if (library == currentLibrary) return _lazyClass(type); |
| 466 | 459 |
| 467 // The SDK is a special case: we optimize the order to prevent laziness. | 460 // The SDK is a special case: we optimize the order to prevent laziness. |
| 468 if (library.isInSdk) { | 461 if (library.isInSdk) { |
| 469 // SDK is loaded before non-SDK libraies | 462 // SDK is loaded before non-SDK libraies |
| 470 if (!currentLibrary.isInSdk) return false; | 463 if (!currentLibrary.isInSdk) return false; |
| 471 | 464 |
| 472 // Compute the order of both SDK libraries. If unknown, assume it's after. | 465 // Compute the order of both SDK libraries. If unknown, assume it's after. |
| 473 var classOrder = CORELIB_ORDER.indexOf(library.name); | 466 var classOrder = corelibOrder.indexOf(library.name); |
| 474 if (classOrder == -1) classOrder = CORELIB_ORDER.length; | 467 if (classOrder == -1) classOrder = corelibOrder.length; |
| 475 | 468 |
| 476 var currentOrder = CORELIB_ORDER.indexOf(currentLibrary.name); | 469 var currentOrder = corelibOrder.indexOf(currentLibrary.name); |
| 477 if (currentOrder == -1) currentOrder = CORELIB_ORDER.length; | 470 if (currentOrder == -1) currentOrder = corelibOrder.length; |
| 478 | 471 |
| 479 // If the dart:* library we are currently compiling is loaded after the | 472 // If the dart:* library we are currently compiling is loaded after the |
| 480 // class's library, then we know the class is available. | 473 // class's library, then we know the class is available. |
| 481 if (classOrder != currentOrder) return currentOrder < classOrder; | 474 if (classOrder != currentOrder) return currentOrder < classOrder; |
| 482 | 475 |
| 483 // If we don't know the order of the class's library or the current | 476 // If we don't know the order of the class's library or the current |
| 484 // library, do the normal cycle check. (Not all SDK libs are cycles.) | 477 // library, do the normal cycle check. (Not all SDK libs are cycles.) |
| 485 } | 478 } |
| 486 | 479 |
| 487 return _inLibraryCycle(library); | 480 return _inLibraryCycle(library); |
| (...skipping 1564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 visitIntegerLiteral(IntegerLiteral node) => js.number(node.value); | 2045 visitIntegerLiteral(IntegerLiteral node) => js.number(node.value); |
| 2053 | 2046 |
| 2054 @override | 2047 @override |
| 2055 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value); | 2048 visitDoubleLiteral(DoubleLiteral node) => js.number(node.value); |
| 2056 | 2049 |
| 2057 @override | 2050 @override |
| 2058 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 2051 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
| 2059 | 2052 |
| 2060 @override | 2053 @override |
| 2061 visitListLiteral(ListLiteral node) { | 2054 visitListLiteral(ListLiteral node) { |
| 2062 // TODO(jmesserly): make this faster. We're wasting an array. | 2055 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); |
| 2063 var list = js.call('new #.from(#)', [ | 2056 |
| 2064 _emitTypeName(node.staticType), | 2057 ParameterizedType type = node.staticType; |
| 2065 new JS.ArrayInitializer(_visitList(node.elements)) | 2058 if (type.typeArguments.any((a) => a != types.dynamicType)) { |
| 2066 ]); | 2059 list = js.call('dart.setType(#, #)', [list, _emitTypeName(type)]); |
| 2060 } |
| 2067 if (node.constKeyword != null) { | 2061 if (node.constKeyword != null) { |
| 2068 list = js.commentExpression('Unimplemented const', list); | 2062 list = js.commentExpression('Unimplemented const', list); |
| 2069 } | 2063 } |
| 2070 return list; | 2064 return list; |
| 2071 } | 2065 } |
| 2072 | 2066 |
| 2073 @override | 2067 @override |
| 2074 visitMapLiteral(MapLiteral node) { | 2068 visitMapLiteral(MapLiteral node) { |
| 2069 // TODO(jmesserly): we can likely make these faster. |
| 2075 var entries = node.entries; | 2070 var entries = node.entries; |
| 2076 var mapArguments = null; | 2071 var mapArguments = null; |
| 2077 if (entries.isEmpty) return js.call('dart.map()'); | 2072 if (entries.isEmpty) { |
| 2078 | 2073 mapArguments = []; |
| 2079 // Use JS object literal notation if possible, otherwise use an array. | 2074 } else if (entries.every((e) => e.key is StringLiteral)) { |
| 2080 // We could do this any time all keys are non-nullable String type. | 2075 // Use JS object literal notation if possible, otherwise use an array. |
| 2081 // For now, support StringLiteral as the common non-nullable String case. | 2076 // We could do this any time all keys are non-nullable String type. |
| 2082 if (entries.every((e) => e.key is StringLiteral)) { | 2077 // For now, support StringLiteral as the common non-nullable String case. |
| 2083 var props = []; | 2078 var props = []; |
| 2084 for (var e in entries) { | 2079 for (var e in entries) { |
| 2085 props.add(new JS.Property(_visit(e.key), _visit(e.value))); | 2080 props.add(new JS.Property(_visit(e.key), _visit(e.value))); |
| 2086 } | 2081 } |
| 2087 mapArguments = new JS.ObjectInitializer(props); | 2082 mapArguments = new JS.ObjectInitializer(props); |
| 2088 } else { | 2083 } else { |
| 2089 var values = []; | 2084 var values = []; |
| 2090 for (var e in entries) { | 2085 for (var e in entries) { |
| 2091 values.add(_visit(e.key)); | 2086 values.add(_visit(e.key)); |
| 2092 values.add(_visit(e.value)); | 2087 values.add(_visit(e.value)); |
| 2093 } | 2088 } |
| 2094 mapArguments = new JS.ArrayInitializer(values); | 2089 mapArguments = new JS.ArrayInitializer(values); |
| 2095 } | 2090 } |
| 2096 return js.call('dart.map(#)', [mapArguments]); | 2091 // TODO(jmesserly): add generic types args. |
| 2092 var map = js.call('dart.map(#)', [mapArguments]); |
| 2093 if (node.constKeyword != null) { |
| 2094 map = js.commentExpression('Unimplemented const', map); |
| 2095 } |
| 2096 return map; |
| 2097 } | 2097 } |
| 2098 | 2098 |
| 2099 @override | 2099 @override |
| 2100 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => | 2100 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => |
| 2101 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); | 2101 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); |
| 2102 | 2102 |
| 2103 @override | 2103 @override |
| 2104 JS.Expression visitAdjacentStrings(AdjacentStrings node) => | 2104 JS.Expression visitAdjacentStrings(AdjacentStrings node) => |
| 2105 _visitListToBinary(node.strings, '+'); | 2105 _visitListToBinary(node.strings, '+'); |
| 2106 | 2106 |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2386 return filepath; | 2386 return filepath; |
| 2387 } | 2387 } |
| 2388 | 2388 |
| 2389 // TODO(jmesserly): validate the library. See issue #135. | 2389 // TODO(jmesserly): validate the library. See issue #135. |
| 2390 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2390 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; |
| 2391 | 2391 |
| 2392 // TODO(jacobr): we would like to do something like the following | 2392 // TODO(jacobr): we would like to do something like the following |
| 2393 // but we don't have summary support yet. | 2393 // but we don't have summary support yet. |
| 2394 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2394 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
| 2395 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2395 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
| OLD | NEW |