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 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 /// Takes the metadata for the build unit, as well as resolved trees and | 184 /// Takes the metadata for the build unit, as well as resolved trees and |
185 /// errors, and computes the output module code and optionally the source map. | 185 /// errors, and computes the output module code and optionally the source map. |
186 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits, | 186 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits, |
187 List<String> errors) { | 187 List<String> errors) { |
188 _buildUnit = unit; | 188 _buildUnit = unit; |
189 _libraryRoot = _buildUnit.libraryRoot; | 189 _libraryRoot = _buildUnit.libraryRoot; |
190 if (!_libraryRoot.endsWith(separator)) { | 190 if (!_libraryRoot.endsWith(separator)) { |
191 _libraryRoot += separator; | 191 _libraryRoot += separator; |
192 } | 192 } |
193 | 193 |
194 var module = _emitModule(compilationUnits); | 194 var module = _emitModule(compilationUnits, unit.name); |
195 var dartApiSummary = _summarizeModule(compilationUnits); | 195 var dartApiSummary = _summarizeModule(compilationUnits); |
196 | 196 |
197 return new JSModuleFile(unit.name, errors, options, module, dartApiSummary); | 197 return new JSModuleFile(unit.name, errors, options, module, dartApiSummary); |
198 } | 198 } |
199 | 199 |
200 List<int> _summarizeModule(List<CompilationUnit> units) { | 200 List<int> _summarizeModule(List<CompilationUnit> units) { |
201 if (!options.summarizeApi) return null; | 201 if (!options.summarizeApi) return null; |
202 | 202 |
203 if (!units.any((u) => resolutionMap | 203 if (!units.any((u) => resolutionMap |
204 .elementDeclaredByCompilationUnit(u) | 204 .elementDeclaredByCompilationUnit(u) |
(...skipping 25 matching lines...) Expand all Loading... |
230 context.declaredVariables.get, | 230 context.declaredVariables.get, |
231 true) | 231 true) |
232 .forEach(assembler.addLinkedLibrary); | 232 .forEach(assembler.addLinkedLibrary); |
233 | 233 |
234 var bundle = assembler.assemble(); | 234 var bundle = assembler.assemble(); |
235 // Preserve only API-level information in the summary. | 235 // Preserve only API-level information in the summary. |
236 bundle.flushInformative(); | 236 bundle.flushInformative(); |
237 return bundle.toBuffer(); | 237 return bundle.toBuffer(); |
238 } | 238 } |
239 | 239 |
240 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { | 240 JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) { |
241 if (_moduleItems.isNotEmpty) { | 241 if (_moduleItems.isNotEmpty) { |
242 throw new StateError('Can only call emitModule once.'); | 242 throw new StateError('Can only call emitModule once.'); |
243 } | 243 } |
244 | 244 |
245 // Transform the AST to make coercions explicit. | 245 // Transform the AST to make coercions explicit. |
246 compilationUnits = CoercionReifier.reify(compilationUnits); | 246 compilationUnits = CoercionReifier.reify(compilationUnits); |
247 | 247 |
248 if (compilationUnits.any((u) => _isDartRuntime( | 248 if (compilationUnits.any((u) => _isDartRuntime( |
249 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { | 249 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { |
250 // Don't allow these to be renamed when we're building the SDK. | 250 // Don't allow these to be renamed when we're building the SDK. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 // This is done by forward declaring items. | 313 // This is done by forward declaring items. |
314 compilationUnits.forEach(_finishDeclarationsInUnit); | 314 compilationUnits.forEach(_finishDeclarationsInUnit); |
315 | 315 |
316 // Declare imports | 316 // Declare imports |
317 _finishImports(items); | 317 _finishImports(items); |
318 | 318 |
319 // Discharge the type table cache variables and | 319 // Discharge the type table cache variables and |
320 // hoisted definitions. | 320 // hoisted definitions. |
321 items.addAll(_typeTable.discharge()); | 321 items.addAll(_typeTable.discharge()); |
322 | 322 |
| 323 // Track the module name for each library in the module. |
| 324 // This data is only required for debugging. |
| 325 _moduleItems.add(js.statement('#.trackLibraries(#, #);', |
| 326 [_runtimeModule, js.string(name), _librariesDebuggerObject()])); |
| 327 |
323 // Add the module's code (produced by visiting compilation units, above) | 328 // Add the module's code (produced by visiting compilation units, above) |
324 _copyAndFlattenBlocks(items, _moduleItems); | 329 _copyAndFlattenBlocks(items, _moduleItems); |
325 | 330 |
326 // Build the module. | 331 // Build the module. |
327 return new JS.Program(items, name: _buildUnit.name); | 332 return new JS.Program(items, name: _buildUnit.name); |
328 } | 333 } |
329 | 334 |
| 335 JS.ObjectInitializer _librariesDebuggerObject() { |
| 336 var properties = <JS.Property>[]; |
| 337 _libraries.forEach((library, value) { |
| 338 // TODO(jacobr): we could specify a short library name instead of the |
| 339 // full library uri if we wanted to save space. |
| 340 properties.add(new JS.Property( |
| 341 js.string(jsLibraryDebuggerName(_libraryRoot, library)), value)); |
| 342 }); |
| 343 return new JS.ObjectInitializer(properties); |
| 344 } |
| 345 |
330 List<String> _getJSName(Element e) { | 346 List<String> _getJSName(Element e) { |
331 if (e.library == null || | 347 if (e.library == null || |
332 findAnnotation(e.library, isPublicJSAnnotation) == null) { | 348 findAnnotation(e.library, isPublicJSAnnotation) == null) { |
333 return null; | 349 return null; |
334 } | 350 } |
335 | 351 |
336 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 352 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
337 var libraryPrefix = <String>[]; | 353 var libraryPrefix = <String>[]; |
338 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 354 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
339 libraryPrefix.addAll(libraryJSName.split('.')); | 355 libraryPrefix.addAll(libraryJSName.split('.')); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 // | 466 // |
451 // import {foo} from 'foo'; // if no rename needed | 467 // import {foo} from 'foo'; // if no rename needed |
452 // import {foo as foo$} from 'foo'; // if rename was needed | 468 // import {foo as foo$} from 'foo'; // if rename was needed |
453 // | 469 // |
454 var imports = | 470 var imports = |
455 libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList(); | 471 libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList(); |
456 if (module == coreModuleName) { | 472 if (module == coreModuleName) { |
457 imports.add(new JS.NameSpecifier(_runtimeModule)); | 473 imports.add(new JS.NameSpecifier(_runtimeModule)); |
458 imports.add(new JS.NameSpecifier(_extensionSymbolsModule)); | 474 imports.add(new JS.NameSpecifier(_extensionSymbolsModule)); |
459 } | 475 } |
| 476 |
460 items.add(new JS.ImportDeclaration( | 477 items.add(new JS.ImportDeclaration( |
461 namedImports: imports, from: js.string(module, "'"))); | 478 namedImports: imports, from: js.string(module, "'"))); |
462 }); | 479 }); |
463 } | 480 } |
464 | 481 |
465 /// Collect toplevel elements and nodes we need to emit, and returns | 482 /// Collect toplevel elements and nodes we need to emit, and returns |
466 /// an ordered map of these. | 483 /// an ordered map of these. |
467 static void _collectElements( | 484 static void _collectElements( |
468 CompilationUnit unit, Map<Element, AstNode> map) { | 485 CompilationUnit unit, Map<Element, AstNode> map) { |
469 for (var declaration in unit.declarations) { | 486 for (var declaration in unit.declarations) { |
(...skipping 5376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5846 qualifiedPath = | 5863 qualifiedPath = |
5847 uri.path.substring(libraryRoot.length).replaceAll('/', separator); | 5864 uri.path.substring(libraryRoot.length).replaceAll('/', separator); |
5848 } else { | 5865 } else { |
5849 // We don't have a unique name. | 5866 // We don't have a unique name. |
5850 throw 'Invalid library root. $libraryRoot does not contain ${uri | 5867 throw 'Invalid library root. $libraryRoot does not contain ${uri |
5851 .toFilePath()}'; | 5868 .toFilePath()}'; |
5852 } | 5869 } |
5853 return pathToJSIdentifier(qualifiedPath); | 5870 return pathToJSIdentifier(qualifiedPath); |
5854 } | 5871 } |
5855 | 5872 |
| 5873 /// Debugger friendly name for a Dart Library. |
| 5874 String jsLibraryDebuggerName(String libraryRoot, LibraryElement library) { |
| 5875 var uri = library.source.uri; |
| 5876 // For package: and dart: uris show the entire |
| 5877 if (uri.scheme == 'dart' || uri.scheme == 'package') return uri.toString(); |
| 5878 |
| 5879 if (!uri.toFilePath().startsWith(libraryRoot)) { |
| 5880 throw 'Invalid library root. $libraryRoot does not contain ${uri |
| 5881 .toFilePath()}'; |
| 5882 } |
| 5883 // Relative path to the library. |
| 5884 return uri.path.substring(libraryRoot.length); |
| 5885 } |
| 5886 |
| 5887 String jsDebuggingLibraryName(String libraryRoot, LibraryElement library) { |
| 5888 var uri = library.source.uri; |
| 5889 if (uri.scheme == 'dart') { |
| 5890 return uri.path; |
| 5891 } |
| 5892 // TODO(vsm): This is not necessarily unique if '__' appears in a file name. |
| 5893 var separator = '__'; |
| 5894 String qualifiedPath; |
| 5895 if (uri.scheme == 'package') { |
| 5896 // Strip the package name. |
| 5897 // TODO(vsm): This is not unique if an escaped '/'appears in a filename. |
| 5898 // E.g., "foo/bar.dart" and "foo$47bar.dart" would collide. |
| 5899 qualifiedPath = uri.pathSegments.skip(1).join(separator); |
| 5900 } else if (uri.toFilePath().startsWith(libraryRoot)) { |
| 5901 qualifiedPath = |
| 5902 uri.path.substring(libraryRoot.length).replaceAll('/', separator); |
| 5903 } else { |
| 5904 // We don't have a unique name. |
| 5905 throw 'Invalid library root. $libraryRoot does not contain ${uri |
| 5906 .toFilePath()}'; |
| 5907 } |
| 5908 return pathToJSIdentifier(qualifiedPath); |
| 5909 } |
| 5910 |
5856 /// Shorthand for identifier-like property names. | 5911 /// Shorthand for identifier-like property names. |
5857 /// For now, we emit them as strings and the printer restores them to | 5912 /// For now, we emit them as strings and the printer restores them to |
5858 /// identifiers if it can. | 5913 /// identifiers if it can. |
5859 // TODO(jmesserly): avoid the round tripping through quoted form. | 5914 // TODO(jmesserly): avoid the round tripping through quoted form. |
5860 JS.LiteralString _propertyName(String name) => js.string(name, "'"); | 5915 JS.LiteralString _propertyName(String name) => js.string(name, "'"); |
5861 | 5916 |
5862 // TODO(jacobr): we would like to do something like the following | 5917 // TODO(jacobr): we would like to do something like the following |
5863 // but we don't have summary support yet. | 5918 // but we don't have summary support yet. |
5864 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 5919 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
5865 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 5920 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5901 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5956 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5902 var prefix = targetIdentifier.staticElement as PrefixElement; | 5957 var prefix = targetIdentifier.staticElement as PrefixElement; |
5903 | 5958 |
5904 // The library the prefix is referring to must come from a deferred import. | 5959 // The library the prefix is referring to must come from a deferred import. |
5905 var containingLibrary = resolutionMap | 5960 var containingLibrary = resolutionMap |
5906 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5961 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5907 .library; | 5962 .library; |
5908 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5963 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5909 return imports.length == 1 && imports[0].isDeferred; | 5964 return imports.length == 1 && imports[0].isDeferred; |
5910 } | 5965 } |
OLD | NEW |