| 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/devc.dart' show CompilerContext; |
| 26 import 'package:dev_compiler/src/checker/rules.dart'; | 27 import 'package:dev_compiler/src/checker/rules.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' as JS; | 34 import 'js_names.dart' as JS; |
| 34 import 'js_metalet.dart' as JS; | 35 import 'js_metalet.dart' as JS; |
| 35 import 'js_module_item_order.dart'; | 36 import 'js_module_item_order.dart'; |
| 36 import 'js_printer.dart' show writeJsLibrary; | 37 import 'js_printer.dart' show writeJsLibrary; |
| 37 import 'side_effect_analysis.dart'; | 38 import 'side_effect_analysis.dart'; |
| 38 | 39 |
| 39 // Various dynamic helpers we call. | 40 // Various dynamic helpers we call. |
| 40 // If renaming these, make sure to check other places like the | 41 // If renaming these, make sure to check other places like the |
| 41 // dart_runtime.js file and comments. | 42 // dart_runtime.js file and comments. |
| 42 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can | 43 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can |
| 43 // import and generate calls to, rather than dart_runtime.js | 44 // import and generate calls to, rather than dart_runtime.js |
| 44 const DPUT = 'dput'; | 45 const DPUT = 'dput'; |
| 45 const DLOAD = 'dload'; | 46 const DLOAD = 'dload'; |
| 46 const DINDEX = 'dindex'; | 47 const DINDEX = 'dindex'; |
| 47 const DSETINDEX = 'dsetindex'; | 48 const DSETINDEX = 'dsetindex'; |
| 48 const DCALL = 'dcall'; | 49 const DCALL = 'dcall'; |
| 49 const DSEND = 'dsend'; | 50 const DSEND = 'dsend'; |
| 50 | 51 |
| 51 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { | 52 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| 53 final CompilerContext compiler; |
| 52 final CompilerOptions options; | 54 final CompilerOptions options; |
| 53 final TypeRules rules; | 55 final TypeRules rules; |
| 54 final LibraryInfo libraryInfo; | 56 final LibraryInfo libraryInfo; |
| 55 | 57 |
| 56 /// The global extension method table. | 58 /// The global extension method table. |
| 57 final HashMap<String, List<InterfaceType>> _extensionMethods; | 59 final HashMap<String, List<InterfaceType>> _extensionMethods; |
| 58 | 60 |
| 59 /// Information that is precomputed for this library, indicates which fields | 61 /// Information that is precomputed for this library, indicates which fields |
| 60 /// need storage slots. | 62 /// need storage slots. |
| 61 final HashSet<FieldElement> _fieldsNeedingStorage; | 63 final HashSet<FieldElement> _fieldsNeedingStorage; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 80 | 82 |
| 81 /// The name for the library's exports inside itself. | 83 /// The name for the library's exports inside itself. |
| 82 /// `exports` was chosen as the most similar to ES module patterns. | 84 /// `exports` was chosen as the most similar to ES module patterns. |
| 83 final _exportsVar = new JS.TemporaryId('exports'); | 85 final _exportsVar = new JS.TemporaryId('exports'); |
| 84 final _namedArgTemp = new JS.TemporaryId('opts'); | 86 final _namedArgTemp = new JS.TemporaryId('opts'); |
| 85 | 87 |
| 86 ConstFieldVisitor _constField; | 88 ConstFieldVisitor _constField; |
| 87 | 89 |
| 88 ModuleItemLoadOrder _loader; | 90 ModuleItemLoadOrder _loader; |
| 89 | 91 |
| 90 JSCodegenVisitor(this.options, this.rules, this.libraryInfo, | 92 JSCodegenVisitor(CompilerContext compiler, this.libraryInfo, |
| 91 this._extensionMethods, this._fieldsNeedingStorage) { | 93 this._extensionMethods, this._fieldsNeedingStorage) |
| 94 : compiler = compiler, |
| 95 options = compiler.options, |
| 96 rules = compiler.rules { |
| 92 _loader = new ModuleItemLoadOrder(_emitModuleItem); | 97 _loader = new ModuleItemLoadOrder(_emitModuleItem); |
| 93 } | 98 } |
| 94 | 99 |
| 95 LibraryElement get currentLibrary => libraryInfo.library; | 100 LibraryElement get currentLibrary => libraryInfo.library; |
| 96 TypeProvider get types => rules.provider; | 101 TypeProvider get types => rules.provider; |
| 97 | 102 |
| 98 JS.Program emitLibrary(LibraryUnit library) { | 103 JS.Program emitLibrary(LibraryUnit library) { |
| 99 String jsDefaultValue = null; | 104 String jsDefaultValue = null; |
| 100 | 105 |
| 101 // Modify the AST to make coercions explicit. | 106 // Modify the AST to make coercions explicit. |
| 102 new CoercionReifier(library, rules, options).reify(); | 107 new CoercionReifier(library, compiler).reify(); |
| 103 | 108 |
| 104 var unit = library.library; | 109 var unit = library.library; |
| 105 if (unit.directives.isNotEmpty) { | 110 if (unit.directives.isNotEmpty) { |
| 106 var libraryDir = unit.directives.first; | 111 var libraryDir = unit.directives.first; |
| 107 if (libraryDir is LibraryDirective) { | 112 if (libraryDir is LibraryDirective) { |
| 108 var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation); | 113 var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation); |
| 109 jsDefaultValue = getConstantField(jsName, 'name', types.stringType); | 114 jsDefaultValue = getConstantField(jsName, 'name', types.stringType); |
| 110 } | 115 } |
| 111 } | 116 } |
| 112 if (jsDefaultValue == null) jsDefaultValue = '{}'; | 117 if (jsDefaultValue == null) jsDefaultValue = '{}'; |
| (...skipping 2277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 JS.Identifier _libraryName(LibraryElement library) { | 2395 JS.Identifier _libraryName(LibraryElement library) { |
| 2391 if (library == currentLibrary) return _exportsVar; | 2396 if (library == currentLibrary) return _exportsVar; |
| 2392 return _imports.putIfAbsent( | 2397 return _imports.putIfAbsent( |
| 2393 library, () => new JS.TemporaryId(jsLibraryName(library))); | 2398 library, () => new JS.TemporaryId(jsLibraryName(library))); |
| 2394 } | 2399 } |
| 2395 | 2400 |
| 2396 DartType getStaticType(Expression e) => rules.getStaticType(e); | 2401 DartType getStaticType(Expression e) => rules.getStaticType(e); |
| 2397 } | 2402 } |
| 2398 | 2403 |
| 2399 class JSGenerator extends CodeGenerator { | 2404 class JSGenerator extends CodeGenerator { |
| 2400 final CompilerOptions options; | |
| 2401 | |
| 2402 /// For fast lookup of extension methods, we first check the name, then do a | 2405 /// For fast lookup of extension methods, we first check the name, then do a |
| 2403 /// (possibly expensive) subtype test to see if it matches one of the types | 2406 /// (possibly expensive) subtype test to see if it matches one of the types |
| 2404 /// that declares that method. | 2407 /// that declares that method. |
| 2405 final _extensionMethods = new HashMap<String, List<InterfaceType>>(); | 2408 final _extensionMethods = new HashMap<String, List<InterfaceType>>(); |
| 2406 | 2409 |
| 2407 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) | 2410 JSGenerator(CompilerContext context) : super(context) { |
| 2408 : super(outDir, root, rules) { | |
| 2409 | 2411 |
| 2410 // TODO(jacobr): determine the the set of types with extension methods from | 2412 // TODO(jacobr): determine the the set of types with extension methods from |
| 2411 // the annotations rather than hard coding the list once the analyzer | 2413 // the annotations rather than hard coding the list once the analyzer |
| 2412 // supports summaries. | 2414 // supports summaries. |
| 2413 var extensionTypes = [types.listType, types.iterableType]; | 2415 var extensionTypes = [types.listType, types.iterableType]; |
| 2414 for (var type in extensionTypes) { | 2416 for (var type in extensionTypes) { |
| 2415 type = fillDynamicTypeArgs(type, rules.provider); | 2417 type = fillDynamicTypeArgs(type, rules.provider); |
| 2416 var e = type.element; | 2418 var e = type.element; |
| 2417 var names = new HashSet<String>() | 2419 var names = new HashSet<String>() |
| 2418 ..addAll(e.methods.map((m) => m.name)) | 2420 ..addAll(e.methods.map((m) => m.name)) |
| 2419 ..addAll(e.accessors.map((m) => m.name)); | 2421 ..addAll(e.accessors.map((m) => m.name)); |
| 2420 for (var name in names) { | 2422 for (var name in names) { |
| 2421 _extensionMethods.putIfAbsent(name, () => []).add(type); | 2423 _extensionMethods.putIfAbsent(name, () => []).add(type); |
| 2422 } | 2424 } |
| 2423 } | 2425 } |
| 2424 } | 2426 } |
| 2425 | 2427 |
| 2426 TypeProvider get types => rules.provider; | 2428 TypeProvider get types => rules.provider; |
| 2427 | 2429 |
| 2428 String generateLibrary(LibraryUnit unit, LibraryInfo info) { | 2430 String generateLibrary(LibraryUnit unit, LibraryInfo info) { |
| 2429 var fields = findFieldsNeedingStorage(unit); | 2431 var fields = findFieldsNeedingStorage(unit); |
| 2430 var codegen = | 2432 var codegen = |
| 2431 new JSCodegenVisitor(options, rules, info, _extensionMethods, fields); | 2433 new JSCodegenVisitor(compiler, info, _extensionMethods, fields); |
| 2432 var module = codegen.emitLibrary(unit); | 2434 var module = codegen.emitLibrary(unit); |
| 2433 var dir = path.join(outDir, jsOutputPath(info, root)); | 2435 var dir = path.join(outDir, jsOutputPath(info, root)); |
| 2434 return writeJsLibrary(module, dir, emitSourceMaps: options.emitSourceMaps); | 2436 return writeJsLibrary(module, dir, emitSourceMaps: options.emitSourceMaps); |
| 2435 } | 2437 } |
| 2436 } | 2438 } |
| 2437 | 2439 |
| 2438 /// Choose a canonical name from the library element. | 2440 /// Choose a canonical name from the library element. |
| 2439 /// This never uses the library's name (the identifier in the `library` | 2441 /// This never uses the library's name (the identifier in the `library` |
| 2440 /// declaration) as it doesn't have any meaningful rules enforced. | 2442 /// declaration) as it doesn't have any meaningful rules enforced. |
| 2441 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); | 2443 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2477 | 2479 |
| 2478 /// A special kind of element created by the compiler, signifying a temporary | 2480 /// A special kind of element created by the compiler, signifying a temporary |
| 2479 /// variable. These objects use instance equality, and should be shared | 2481 /// variable. These objects use instance equality, and should be shared |
| 2480 /// everywhere in the tree where they are treated as the same variable. | 2482 /// everywhere in the tree where they are treated as the same variable. |
| 2481 class TemporaryVariableElement extends LocalVariableElementImpl { | 2483 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 2482 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 2484 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 2483 | 2485 |
| 2484 int get hashCode => identityHashCode(this); | 2486 int get hashCode => identityHashCode(this); |
| 2485 bool operator ==(Object other) => identical(this, other); | 2487 bool operator ==(Object other) => identical(this, other); |
| 2486 } | 2488 } |
| OLD | NEW |