| 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 import 'dart:io' show Directory, File; | 8 import 'dart:io' show Directory, File; |
| 9 | 9 |
| 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 12 import 'package:analyzer/src/generated/constant.dart'; | 12 import 'package:analyzer/src/generated/constant.dart'; |
| 13 import 'package:analyzer/src/generated/element.dart'; | 13 import 'package:analyzer/src/generated/element.dart'; |
| 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:source_maps/source_maps.dart' as srcmaps show Printer; | 16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; |
| 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; | 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; |
| 18 import 'package:source_span/source_span.dart' show SourceLocation; | 18 import 'package:source_span/source_span.dart' show SourceLocation; |
| 19 import 'package:path/path.dart' as path; | 19 import 'package:path/path.dart' as path; |
| 20 | 20 |
| 21 import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder; | 21 import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder; |
| 22 | 22 |
| 23 // TODO(jmesserly): import from its own package | 23 // TODO(jmesserly): import from its own package |
| 24 import 'package:dev_compiler/src/js/js_ast.dart' as JS; | 24 import 'package:dev_compiler/src/js/js_ast.dart' as JS; |
| 25 import 'package:dev_compiler/src/js/js_ast.dart' show js; | 25 import 'package:dev_compiler/src/js/js_ast.dart' show js; |
| 26 | 26 |
| 27 import 'package:dev_compiler/src/checker/rules.dart'; | 27 import 'package:dev_compiler/src/checker/rules.dart'; |
| 28 import 'package:dev_compiler/src/info.dart'; | 28 import 'package:dev_compiler/src/info.dart'; |
| 29 import 'package:dev_compiler/src/options.dart'; | 29 import 'package:dev_compiler/src/options.dart'; |
| 30 import 'package:dev_compiler/src/report.dart'; | |
| 31 import 'package:dev_compiler/src/utils.dart'; | 30 import 'package:dev_compiler/src/utils.dart'; |
| 32 | 31 |
| 33 import 'code_generator.dart'; | 32 import 'code_generator.dart'; |
| 34 import 'js_names.dart'; | 33 import 'js_names.dart'; |
| 35 | 34 |
| 36 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; | 35 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; |
| 37 | 36 |
| 38 Annotation _getAnnotation(AnnotatedNode node, String name) => node.metadata | 37 Annotation _getAnnotation(AnnotatedNode node, String name) => node.metadata |
| 39 .firstWhere((annotation) => _isAnnotationType(annotation, name), | 38 .firstWhere((annotation) => _isAnnotationType(annotation, name), |
| 40 orElse: () => null); | 39 orElse: () => null); |
| 41 | 40 |
| 42 Annotation _getJsNameAnnotation(AnnotatedNode node) => | 41 Annotation _getJsNameAnnotation(AnnotatedNode node) => |
| 43 _getAnnotation(node, "JsName"); | 42 _getAnnotation(node, "JsName"); |
| 44 | 43 |
| 45 // TODO(jacobr): we would like to do something like the following | 44 // TODO(jacobr): we would like to do something like the following |
| 46 // but we don't have summary support yet. | 45 // but we don't have summary support yet. |
| 47 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 46 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
| 48 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 47 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
| 49 | 48 |
| 50 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { | 49 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| 51 final LibraryInfo libraryInfo; | 50 final LibraryInfo libraryInfo; |
| 52 final TypeRules rules; | 51 final TypeRules rules; |
| 53 | 52 |
| 54 // TODO(jmesserly): this is needed because RestrictedTypeRules can send | |
| 55 // messages to CheckerReporter, for things like missing types. | |
| 56 // We should probably refactor so this can't happen, as codegen would be too | |
| 57 // late to be issuing these messages. | |
| 58 final CheckerReporter _checkerReporter; | |
| 59 | |
| 60 /// The variable for the target of the current `..` cascade expression. | 53 /// The variable for the target of the current `..` cascade expression. |
| 61 SimpleIdentifier _cascadeTarget; | 54 SimpleIdentifier _cascadeTarget; |
| 62 /// The variable for the current catch clause | 55 /// The variable for the current catch clause |
| 63 SimpleIdentifier _catchParameter; | 56 SimpleIdentifier _catchParameter; |
| 64 | 57 |
| 65 ClassDeclaration currentClass; | 58 ClassDeclaration currentClass; |
| 66 ConstantEvaluator _constEvaluator; | 59 ConstantEvaluator _constEvaluator; |
| 67 | 60 |
| 68 final _exports = new Set<String>(); | 61 final _exports = new Set<String>(); |
| 69 final _lazyFields = <VariableDeclaration>[]; | 62 final _lazyFields = <VariableDeclaration>[]; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or | 102 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or |
| 110 /// [ClassTypeAlias]. | 103 /// [ClassTypeAlias]. |
| 111 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); | 104 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); |
| 112 | 105 |
| 113 /// Memoized results of [_lazyClass]. | 106 /// Memoized results of [_lazyClass]. |
| 114 final _lazyClassMemo = new HashMap<Element, bool>(); | 107 final _lazyClassMemo = new HashMap<Element, bool>(); |
| 115 | 108 |
| 116 /// Memoized results of [_inLibraryCycle]. | 109 /// Memoized results of [_inLibraryCycle]. |
| 117 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); | 110 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); |
| 118 | 111 |
| 119 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter); | 112 JSCodegenVisitor(this.libraryInfo, this.rules); |
| 120 | 113 |
| 121 LibraryElement get currentLibrary => libraryInfo.library; | 114 LibraryElement get currentLibrary => libraryInfo.library; |
| 122 | 115 |
| 123 /// The name for the library's exports inside itself. | 116 /// The name for the library's exports inside itself. |
| 124 /// This much be a constant because we interpolate it into template strings, | 117 /// This much be a constant because we interpolate it into template strings, |
| 125 /// and otherwise it would break caching for them. | 118 /// and otherwise it would break caching for them. |
| 126 /// `exports` was chosen as the most similar to ES module patterns. | 119 /// `exports` was chosen as the most similar to ES module patterns. |
| 127 final JSTemporary _exportsVar = new JSTemporary('exports'); | 120 final JSTemporary _exportsVar = new JSTemporary('exports'); |
| 128 final JSTemporary _namedArgTemp = new JSTemporary('opts'); | 121 final JSTemporary _namedArgTemp = new JSTemporary('opts'); |
| 129 | 122 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 var name = currentLibrary.name; | 187 var name = currentLibrary.name; |
| 195 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol'; | 188 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol'; |
| 196 return 'Symbol'; | 189 return 'Symbol'; |
| 197 } | 190 } |
| 198 | 191 |
| 199 @override | 192 @override |
| 200 JS.Statement visitCompilationUnit(CompilationUnit node) { | 193 JS.Statement visitCompilationUnit(CompilationUnit node) { |
| 201 var source = node.element.source; | 194 var source = node.element.source; |
| 202 | 195 |
| 203 _constEvaluator = new ConstantEvaluator(source, rules.provider); | 196 _constEvaluator = new ConstantEvaluator(source, rules.provider); |
| 204 _checkerReporter.enterSource(source); | |
| 205 | 197 |
| 206 // TODO(jmesserly): scriptTag, directives. | 198 // TODO(jmesserly): scriptTag, directives. |
| 207 var body = <JS.Statement>[]; | 199 var body = <JS.Statement>[]; |
| 208 for (var child in node.declarations) { | 200 for (var child in node.declarations) { |
| 209 // Attempt to group adjacent fields/properties. | 201 // Attempt to group adjacent fields/properties. |
| 210 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); | 202 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); |
| 211 if (child is! FunctionDeclaration) _flushLibraryProperties(body); | 203 if (child is! FunctionDeclaration) _flushLibraryProperties(body); |
| 212 | 204 |
| 213 var code = _visit(child); | 205 var code = _visit(child); |
| 214 | 206 |
| 215 if (code != null) { | 207 if (code != null) { |
| 216 if (_pendingPrivateNames.isNotEmpty) { | 208 if (_pendingPrivateNames.isNotEmpty) { |
| 217 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); | 209 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); |
| 218 _pendingPrivateNames.clear(); | 210 _pendingPrivateNames.clear(); |
| 219 } | 211 } |
| 220 if (_pendingExtensionMethodNames.isNotEmpty) { | 212 if (_pendingExtensionMethodNames.isNotEmpty) { |
| 221 body.addAll( | 213 body.addAll( |
| 222 _pendingExtensionMethodNames.map(_initExtensionMethodSymbol)); | 214 _pendingExtensionMethodNames.map(_initExtensionMethodSymbol)); |
| 223 _pendingExtensionMethodNames.clear(); | 215 _pendingExtensionMethodNames.clear(); |
| 224 } | 216 } |
| 225 body.add(code); | 217 body.add(code); |
| 226 } | 218 } |
| 227 } | 219 } |
| 228 | 220 |
| 229 // Flush any unwritten fields/properties. | 221 // Flush any unwritten fields/properties. |
| 230 _flushLazyFields(body); | 222 _flushLazyFields(body); |
| 231 _flushLibraryProperties(body); | 223 _flushLibraryProperties(body); |
| 232 | 224 |
| 233 _checkerReporter.leaveSource(); | |
| 234 | |
| 235 assert(_pendingPrivateNames.isEmpty); | 225 assert(_pendingPrivateNames.isEmpty); |
| 236 return _statement(body); | 226 return _statement(body); |
| 237 } | 227 } |
| 238 | 228 |
| 239 bool isPublic(String name) => !name.startsWith('_'); | 229 bool isPublic(String name) => !name.startsWith('_'); |
| 240 | 230 |
| 241 /// Conversions that we don't handle end up here. | 231 /// Conversions that we don't handle end up here. |
| 242 @override | 232 @override |
| 243 visitConversion(Conversion node) { | 233 visitConversion(Conversion node) { |
| 244 var from = node.baseType; | 234 var from = node.baseType; |
| (...skipping 2134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2379 } | 2369 } |
| 2380 } | 2370 } |
| 2381 } | 2371 } |
| 2382 | 2372 |
| 2383 class JSGenerator extends CodeGenerator { | 2373 class JSGenerator extends CodeGenerator { |
| 2384 final JSCodeOptions options; | 2374 final JSCodeOptions options; |
| 2385 | 2375 |
| 2386 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) | 2376 JSGenerator(String outDir, Uri root, TypeRules rules, this.options) |
| 2387 : super(outDir, root, rules); | 2377 : super(outDir, root, rules); |
| 2388 | 2378 |
| 2389 String generateLibrary( | 2379 String generateLibrary(LibraryUnit unit, LibraryInfo info) { |
| 2390 LibraryUnit unit, LibraryInfo info, CheckerReporter reporter) { | 2380 var jsTree = new JSCodegenVisitor(info, rules).emitLibrary(unit); |
| 2391 var jsTree = new JSCodegenVisitor(info, rules, reporter).emitLibrary(unit); | |
| 2392 | 2381 |
| 2393 var outputPath = path.join(outDir, jsOutputPath(info, root)); | 2382 var outputPath = path.join(outDir, jsOutputPath(info, root)); |
| 2394 new Directory(path.dirname(outputPath)).createSync(recursive: true); | 2383 new Directory(path.dirname(outputPath)).createSync(recursive: true); |
| 2395 | 2384 |
| 2396 if (options.emitSourceMaps) { | 2385 if (options.emitSourceMaps) { |
| 2397 var outFilename = path.basename(outputPath); | 2386 var outFilename = path.basename(outputPath); |
| 2398 var printer = new srcmaps.Printer(outFilename); | 2387 var printer = new srcmaps.Printer(outFilename); |
| 2399 _writeNode( | 2388 _writeNode( |
| 2400 new SourceMapPrintingContext(printer, path.dirname(outputPath)), | 2389 new SourceMapPrintingContext(printer, path.dirname(outputPath)), |
| 2401 jsTree); | 2390 jsTree); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2505 | 2494 |
| 2506 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2495 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2507 printer.mark(_location(node.end)); | 2496 printer.mark(_location(node.end)); |
| 2508 } | 2497 } |
| 2509 | 2498 |
| 2510 String _getIdentifier(AstNode node) { | 2499 String _getIdentifier(AstNode node) { |
| 2511 if (node is SimpleIdentifier) return node.name; | 2500 if (node is SimpleIdentifier) return node.name; |
| 2512 return null; | 2501 return null; |
| 2513 } | 2502 } |
| 2514 } | 2503 } |
| OLD | NEW |