| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 part of dart_backend; | |
| 6 | |
| 7 typedef bool IsSafeToRemoveTypeDeclarations( | |
| 8 Map<ClassElement, Iterable<Element>> classMembers); | |
| 9 typedef void ElementCallback<E>(E element); | |
| 10 typedef void ElementPostProcessFunction( | |
| 11 AstElement element, | |
| 12 ElementAst elementAst, | |
| 13 ElementCallback<TypedefElement> typedefCallback, | |
| 14 ElementCallback<ClassElement> classCallback); | |
| 15 typedef ElementAst ComputeElementAstFunction(AstElement element); | |
| 16 typedef bool ElementFilter(Element element); | |
| 17 typedef List<Element> ElementSorter(Iterable<Element> elements); | |
| 18 | |
| 19 /// Output engine for dart2dart that is shared between the dart2js and the | |
| 20 /// analyzer implementations of dart2dart. | |
| 21 class DartOutputter { | |
| 22 final DiagnosticReporter reporter; | |
| 23 final CompilerOutputProvider outputProvider; | |
| 24 final bool forceStripTypes; | |
| 25 | |
| 26 // TODO(antonm): make available from command-line options. | |
| 27 final bool outputAst = false; | |
| 28 final bool enableMinification; | |
| 29 | |
| 30 /// If `true`, libraries are generated into separate files. | |
| 31 final bool multiFile; | |
| 32 | |
| 33 /// Internal structures accessible for tests and logging. | |
| 34 // TODO(johnniwinther): Clean this up. | |
| 35 PlaceholderRenamer renamer; | |
| 36 MainOutputGenerator output; | |
| 37 LibraryInfo libraryInfo; | |
| 38 ElementInfo elementInfo; | |
| 39 | |
| 40 // TODO(johnniwinther): Support recompilation. | |
| 41 DartOutputter(this.reporter, this.outputProvider, | |
| 42 {bool this.forceStripTypes: false, | |
| 43 bool this.enableMinification: false, | |
| 44 bool this.multiFile: false}); | |
| 45 | |
| 46 /// Generate Dart code for the program starting at [mainFunction]. | |
| 47 /// | |
| 48 /// [libraries] is the set of all libraries (user/package/sdk) that are | |
| 49 /// referenced in the program. | |
| 50 /// | |
| 51 /// [instantiatedClasses] is the set of classes that are potentially | |
| 52 /// instantiated in the program. | |
| 53 /// | |
| 54 /// [resolvedElements] is the set of methods, constructors, and fields that | |
| 55 /// are potentially accessed/called in the program. | |
| 56 /// | |
| 57 /// The [sortElements] function is used to sort [instantiatedClasses] and | |
| 58 /// [resolvedElements] in the generated output. | |
| 59 /// | |
| 60 /// Returns the total size of the generated code. | |
| 61 int assembleProgram( | |
| 62 {MirrorRenamer mirrorRenamer: const MirrorRenamer(), | |
| 63 Iterable<LibraryElement> libraries, | |
| 64 Iterable<Element> instantiatedClasses, | |
| 65 Iterable<Element> resolvedElements, | |
| 66 Iterable<ClassElement> usedTypeLiterals: const <ClassElement>[], | |
| 67 FunctionElement mainFunction, | |
| 68 Uri outputUri, | |
| 69 ElementPostProcessFunction postProcessElementAst, | |
| 70 ComputeElementAstFunction computeElementAst, | |
| 71 ElementFilter shouldOutput, | |
| 72 IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations, | |
| 73 ElementSorter sortElements}) { | |
| 74 assert(invariant(NO_LOCATION_SPANNABLE, libraries != null, | |
| 75 message: "'libraries' must be non-null.")); | |
| 76 assert(invariant(NO_LOCATION_SPANNABLE, instantiatedClasses != null, | |
| 77 message: "'instantiatedClasses' must be non-null.")); | |
| 78 assert(invariant(NO_LOCATION_SPANNABLE, resolvedElements != null, | |
| 79 message: "'resolvedElements' must be non-null.")); | |
| 80 assert(invariant(NO_LOCATION_SPANNABLE, mainFunction != null, | |
| 81 message: "'mainFunction' must be non-null.")); | |
| 82 assert(invariant(NO_LOCATION_SPANNABLE, computeElementAst != null, | |
| 83 message: "'computeElementAst' must be non-null.")); | |
| 84 assert(invariant(NO_LOCATION_SPANNABLE, shouldOutput != null, | |
| 85 message: "'shouldOutput' must be non-null.")); | |
| 86 assert(invariant( | |
| 87 NO_LOCATION_SPANNABLE, isSafeToRemoveTypeDeclarations != null, | |
| 88 message: "'isSafeToRemoveTypeDeclarations' must be non-null.")); | |
| 89 | |
| 90 if (sortElements == null) { | |
| 91 // Ensure deterministic output order. | |
| 92 sortElements = (Iterable<Element> elements) { | |
| 93 List<Element> list = elements.toList(); | |
| 94 list.sort((Element a, Element b) => a.name.compareTo(b.name)); | |
| 95 return list; | |
| 96 }; | |
| 97 } | |
| 98 | |
| 99 libraryInfo = | |
| 100 LibraryInfo.processLibraries(reporter, libraries, resolvedElements); | |
| 101 | |
| 102 elementInfo = ElementInfoProcessor.createElementInfo( | |
| 103 instantiatedClasses, resolvedElements, usedTypeLiterals, | |
| 104 postProcessElementAst: postProcessElementAst, | |
| 105 parseElementAst: computeElementAst, | |
| 106 shouldOutput: shouldOutput, | |
| 107 sortElements: sortElements); | |
| 108 | |
| 109 PlaceholderCollector collector = collectPlaceholders( | |
| 110 reporter, mirrorRenamer, mainFunction, libraryInfo, elementInfo); | |
| 111 | |
| 112 renamer = createRenamer(collector, libraryInfo, elementInfo, | |
| 113 enableMinification: enableMinification, | |
| 114 forceStripTypes: forceStripTypes, | |
| 115 isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations); | |
| 116 | |
| 117 if (outputAst) { | |
| 118 String code = astOutput(reporter, elementInfo); | |
| 119 outputProvider("", "dart") | |
| 120 ..add(code) | |
| 121 ..close(); | |
| 122 return code.length; | |
| 123 } else { | |
| 124 output = new MainOutputGenerator(); | |
| 125 return output.generateCode(libraryInfo, elementInfo, collector, renamer, | |
| 126 mainFunction, outputUri, outputProvider, mirrorRenamer, | |
| 127 multiFile: multiFile, | |
| 128 forceStripTypes: forceStripTypes, | |
| 129 enableMinification: enableMinification); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 static PlaceholderCollector collectPlaceholders( | |
| 134 DiagnosticReporter reporter, | |
| 135 MirrorRenamer mirrorRenamer, | |
| 136 FunctionElement mainFunction, | |
| 137 LibraryInfo libraryInfo, | |
| 138 ElementInfo elementInfo) { | |
| 139 // Create all necessary placeholders. | |
| 140 PlaceholderCollector collector = new PlaceholderCollector( | |
| 141 reporter, | |
| 142 mirrorRenamer, | |
| 143 libraryInfo.fixedDynamicNames, | |
| 144 elementInfo.elementAsts, | |
| 145 mainFunction); | |
| 146 | |
| 147 makePlaceholders(element) { | |
| 148 collector.collect(element); | |
| 149 | |
| 150 if (element.isClass && !element.isEnumClass) { | |
| 151 elementInfo.classMembers[element].forEach(makePlaceholders); | |
| 152 } | |
| 153 } | |
| 154 elementInfo.topLevelElements.forEach(makePlaceholders); | |
| 155 return collector; | |
| 156 } | |
| 157 | |
| 158 static PlaceholderRenamer createRenamer(PlaceholderCollector collector, | |
| 159 LibraryInfo libraryInfo, ElementInfo elementInfo, | |
| 160 {bool enableMinification: false, | |
| 161 bool forceStripTypes: false, | |
| 162 isSafeToRemoveTypeDeclarations}) { | |
| 163 // Create renames. | |
| 164 bool shouldCutDeclarationTypes = forceStripTypes || | |
| 165 (enableMinification && | |
| 166 isSafeToRemoveTypeDeclarations(elementInfo.classMembers)); | |
| 167 | |
| 168 PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer( | |
| 169 libraryInfo.fixedDynamicNames, | |
| 170 libraryInfo.fixedStaticNames, | |
| 171 libraryInfo.reexportingLibraries, | |
| 172 cutDeclarationTypes: shouldCutDeclarationTypes, | |
| 173 enableMinification: enableMinification); | |
| 174 | |
| 175 placeholderRenamer.computeRenames(collector); | |
| 176 return placeholderRenamer; | |
| 177 } | |
| 178 | |
| 179 static String astOutput( | |
| 180 DiagnosticReporter reporter, ElementInfo elementInfo) { | |
| 181 // TODO(antonm): Ideally XML should be a separate backend. | |
| 182 // TODO(antonm): obey renames and minification, at least as an option. | |
| 183 StringBuffer sb = new StringBuffer(); | |
| 184 outputElement(element) { | |
| 185 sb.write(element.parseNode(reporter).toDebugString()); | |
| 186 } | |
| 187 | |
| 188 // Emit XML for AST instead of the program. | |
| 189 for (Element topLevel in elementInfo.topLevelElements) { | |
| 190 if (topLevel.isClass && | |
| 191 !elementInfo.emitNoMembersFor.contains(topLevel)) { | |
| 192 // TODO(antonm): add some class info. | |
| 193 elementInfo.classMembers[topLevel].forEach(outputElement); | |
| 194 } else { | |
| 195 outputElement(topLevel); | |
| 196 } | |
| 197 } | |
| 198 return '<Program>\n$sb</Program>\n'; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 class LibraryInfo { | |
| 203 final Set<String> fixedStaticNames; | |
| 204 final Set<String> fixedDynamicNames; | |
| 205 final Map<Element, LibraryElement> reexportingLibraries; | |
| 206 final List<LibraryElement> userLibraries; | |
| 207 | |
| 208 LibraryInfo(this.fixedStaticNames, this.fixedDynamicNames, | |
| 209 this.reexportingLibraries, this.userLibraries); | |
| 210 | |
| 211 static LibraryInfo processLibraries( | |
| 212 DiagnosticReporter reporter, | |
| 213 Iterable<LibraryElement> libraries, | |
| 214 Iterable<AstElement> resolvedElements) { | |
| 215 Set<String> fixedStaticNames = new Set<String>(); | |
| 216 Set<String> fixedDynamicNames = new Set<String>(); | |
| 217 Map<Element, LibraryElement> reexportingLibraries = | |
| 218 <Element, LibraryElement>{}; | |
| 219 List<LibraryElement> userLibraries = <LibraryElement>[]; | |
| 220 // Conservatively traverse all platform libraries and collect member names. | |
| 221 // TODO(antonm): ideally we should only collect names of used members, | |
| 222 // however as of today there are problems with names of some core library | |
| 223 // interfaces, most probably for interfaces of literals. | |
| 224 | |
| 225 for (LibraryElement library in libraries) { | |
| 226 if (!library.isPlatformLibrary) { | |
| 227 userLibraries.add(library); | |
| 228 continue; | |
| 229 } | |
| 230 library.forEachLocalMember((Element element) { | |
| 231 if (element.isClass) { | |
| 232 ClassElement classElement = element; | |
| 233 assert(invariant(classElement, classElement.isResolved, | |
| 234 message: "Unresolved platform class.")); | |
| 235 classElement.forEachLocalMember((member) { | |
| 236 if (member.isInstanceMember) { | |
| 237 fixedDynamicNames.add(member.name); | |
| 238 } else { | |
| 239 fixedStaticNames.add(member.name); | |
| 240 } | |
| 241 }); | |
| 242 } | |
| 243 // Even class names are added due to a delicate problem we have: | |
| 244 // if one imports dart:core with a prefix, we cannot tell prefix.name | |
| 245 // from dynamic invocation (alas!). So we'd better err on preserving | |
| 246 // those names. | |
| 247 fixedStaticNames.add(element.name); | |
| 248 }); | |
| 249 | |
| 250 library.forEachExport((Element export) { | |
| 251 if (!library.isInternalLibrary && export.library.isInternalLibrary) { | |
| 252 // If an element of an internal library is reexported by a platform | |
| 253 // library, we have to import the reexporting library instead of the | |
| 254 // internal library, because the internal library is an | |
| 255 // implementation detail of dart2js. | |
| 256 reexportingLibraries[export] = library; | |
| 257 } | |
| 258 }); | |
| 259 } | |
| 260 | |
| 261 // Map to keep track of names of enum classes. Since these cannot be renamed | |
| 262 // we ensure that they are unique. | |
| 263 Map<String, ClassElement> enumClassMap = <String, ClassElement>{}; | |
| 264 | |
| 265 // As of now names of named optionals are not renamed. Therefore add all | |
| 266 // field names used as named optionals into [fixedMemberNames]. | |
| 267 for (final element in resolvedElements) { | |
| 268 if (!element.isConstructor) continue; | |
| 269 for (ParameterElement parameter in element.parameters) { | |
| 270 if (parameter.isInitializingFormal && parameter.isNamed) { | |
| 271 fixedDynamicNames.add(parameter.name); | |
| 272 } | |
| 273 } | |
| 274 ClassElement cls = element.enclosingClass; | |
| 275 if (cls != null && cls.isEnumClass) { | |
| 276 fixedDynamicNames.add('index'); | |
| 277 | |
| 278 ClassElement existingEnumClass = | |
| 279 enumClassMap.putIfAbsent(cls.name, () => cls); | |
| 280 if (existingEnumClass != cls) { | |
| 281 reporter.reportError( | |
| 282 reporter.createMessage(cls, MessageKind.GENERIC, { | |
| 283 'text': "Duplicate enum names are not supported " | |
| 284 "in dart2dart." | |
| 285 }), | |
| 286 <DiagnosticMessage>[ | |
| 287 reporter.createMessage(existingEnumClass, MessageKind.GENERIC, { | |
| 288 'text': "This is the other declaration of '${cls.name}'." | |
| 289 }), | |
| 290 ]); | |
| 291 } | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 fixedStaticNames.addAll(enumClassMap.keys); | |
| 296 | |
| 297 // The VM will automatically invoke the call method of objects | |
| 298 // that are invoked as functions. Make sure to not rename that. | |
| 299 fixedDynamicNames.add('call'); | |
| 300 | |
| 301 return new LibraryInfo(fixedStaticNames, fixedDynamicNames, | |
| 302 reexportingLibraries, userLibraries); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 class ElementInfo { | |
| 307 final Map<Element, ElementAst> elementAsts; | |
| 308 final Iterable<Element> topLevelElements; | |
| 309 final Map<ClassElement, Iterable<Element>> classMembers; | |
| 310 final Iterable<ClassElement> emitNoMembersFor; | |
| 311 | |
| 312 ElementInfo(this.elementAsts, this.topLevelElements, this.classMembers, | |
| 313 this.emitNoMembersFor); | |
| 314 } | |
| 315 | |
| 316 class ElementInfoProcessor implements ElementInfo { | |
| 317 final Map<Element, ElementAst> elementAsts = new Map<Element, ElementAst>(); | |
| 318 final Set<Element> topLevelElements = new Set<Element>(); | |
| 319 final Map<ClassElement, Set<Element>> classMembers = | |
| 320 new Map<ClassElement, Set<Element>>(); | |
| 321 final Set<ClassElement> emitNoMembersFor = new Set<ClassElement>(); | |
| 322 final ElementPostProcessFunction postProcessElementAst; | |
| 323 final ComputeElementAstFunction parseElementAst; | |
| 324 final ElementFilter shouldOutput; | |
| 325 | |
| 326 ElementInfoProcessor( | |
| 327 {this.postProcessElementAst, this.parseElementAst, this.shouldOutput}); | |
| 328 | |
| 329 static ElementInfo createElementInfo( | |
| 330 Iterable<ClassElement> instantiatedClasses, | |
| 331 Iterable<AstElement> resolvedElements, | |
| 332 Iterable<ClassElement> usedTypeLiterals, | |
| 333 {ElementPostProcessFunction postProcessElementAst, | |
| 334 ComputeElementAstFunction parseElementAst, | |
| 335 ElementFilter shouldOutput, | |
| 336 ElementSorter sortElements}) { | |
| 337 ElementInfoProcessor processor = new ElementInfoProcessor( | |
| 338 postProcessElementAst: postProcessElementAst, | |
| 339 parseElementAst: parseElementAst, | |
| 340 shouldOutput: shouldOutput); | |
| 341 return processor.process( | |
| 342 instantiatedClasses, resolvedElements, usedTypeLiterals, | |
| 343 sortElements: sortElements); | |
| 344 } | |
| 345 | |
| 346 ElementInfo process( | |
| 347 Iterable<ClassElement> instantiatedClasses, | |
| 348 Iterable<AstElement> resolvedElements, | |
| 349 Iterable<ClassElement> usedTypeLiterals, | |
| 350 {ElementSorter sortElements}) { | |
| 351 // Build all top level elements to emit and necessary class members. | |
| 352 instantiatedClasses.where(shouldOutput).forEach(addClass); | |
| 353 resolvedElements.where(shouldOutput).forEach(addMember); | |
| 354 usedTypeLiterals.forEach((ClassElement element) { | |
| 355 if (shouldOutput(element)) { | |
| 356 if (!topLevelElements.contains(element)) { | |
| 357 // The class is only referenced by type literals. | |
| 358 emitNoMembersFor.add(element); | |
| 359 } | |
| 360 addClass(element); | |
| 361 } | |
| 362 }); | |
| 363 | |
| 364 // Sort elements. | |
| 365 List<Element> sortedTopLevels = sortElements(topLevelElements); | |
| 366 Map<ClassElement, List<Element>> sortedClassMembers = | |
| 367 new Map<ClassElement, List<Element>>(); | |
| 368 classMembers.forEach((classElement, members) { | |
| 369 sortedClassMembers[classElement] = sortElements(members); | |
| 370 }); | |
| 371 | |
| 372 return new ElementInfo( | |
| 373 elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor); | |
| 374 } | |
| 375 | |
| 376 void processElement(Element element, ElementAst elementAst) { | |
| 377 if (postProcessElementAst != null) { | |
| 378 postProcessElementAst(element, elementAst, newTypedefElementCallback, | |
| 379 newClassElementCallback); | |
| 380 } | |
| 381 elementAsts[element] = elementAst; | |
| 382 } | |
| 383 | |
| 384 void addTopLevel(AstElement element, ElementAst elementAst) { | |
| 385 if (topLevelElements.contains(element)) return; | |
| 386 topLevelElements.add(element); | |
| 387 processElement(element, elementAst); | |
| 388 } | |
| 389 | |
| 390 void addClass(ClassElement classElement) { | |
| 391 TreeElements treeElements = new TreeElementMapping(classElement); | |
| 392 backend2frontend.TreePrinter treePrinter = | |
| 393 new backend2frontend.TreePrinter(treeElements); | |
| 394 Node node = treePrinter.makeNodeForClassElement(classElement); | |
| 395 addTopLevel(classElement, new ElementAst(node, treeElements)); | |
| 396 classMembers.putIfAbsent(classElement, () => new Set()); | |
| 397 } | |
| 398 | |
| 399 void newTypedefElementCallback(TypedefElement element) { | |
| 400 if (!shouldOutput(element)) return; | |
| 401 TreeElements treeElements = new TreeElementMapping(element); | |
| 402 backend2frontend.TreePrinter treePrinter = | |
| 403 new backend2frontend.TreePrinter(treeElements); | |
| 404 Node node = treePrinter.makeTypedef(element); | |
| 405 addTopLevel(element, new ElementAst(node, treeElements)); | |
| 406 } | |
| 407 | |
| 408 void newClassElementCallback(ClassElement classElement) { | |
| 409 if (!shouldOutput(classElement)) return; | |
| 410 addClass(classElement); | |
| 411 } | |
| 412 | |
| 413 void addMember(element) { | |
| 414 if (element.isClassMember) { | |
| 415 ClassElement enclosingClass = element.enclosingClass; | |
| 416 assert(enclosingClass.isClass); | |
| 417 assert(shouldOutput(enclosingClass)); | |
| 418 addClass(enclosingClass); | |
| 419 classMembers[enclosingClass].add(element); | |
| 420 if (enclosingClass.isEnumClass) return; | |
| 421 processElement(element, parseElementAst(element)); | |
| 422 } else { | |
| 423 if (element.isTopLevel) { | |
| 424 addTopLevel(element, parseElementAst(element)); | |
| 425 } | |
| 426 } | |
| 427 } | |
| 428 } | |
| 429 | |
| 430 /// Main output generator for [DartOutputter] that emits dart code through a | |
| 431 /// [CompilerOutputProvider]. | |
| 432 class MainOutputGenerator { | |
| 433 final Map<ClassNode, List<Node>> memberNodes = | |
| 434 new Map<ClassNode, List<Node>>(); | |
| 435 final List<Node> topLevelNodes = <Node>[]; | |
| 436 | |
| 437 /// Generates the code and returns the total size. | |
| 438 int generateCode( | |
| 439 LibraryInfo libraryInfo, | |
| 440 ElementInfo elementInfo, | |
| 441 PlaceholderCollector collector, | |
| 442 PlaceholderRenamer placeholderRenamer, | |
| 443 FunctionElement mainFunction, | |
| 444 Uri outputUri, | |
| 445 CompilerOutputProvider outputProvider, | |
| 446 MirrorRenamer mirrorRenamer, | |
| 447 {bool multiFile: false, | |
| 448 bool forceStripTypes: false, | |
| 449 bool enableMinification: false}) { | |
| 450 for (Element element in elementInfo.topLevelElements) { | |
| 451 topLevelNodes.add(elementInfo.elementAsts[element].ast); | |
| 452 if (element.isClass) { | |
| 453 ClassElement cls = element; | |
| 454 if (cls.isMixinApplication || cls.isEnumClass) { | |
| 455 continue; | |
| 456 } | |
| 457 final members = <Node>[]; | |
| 458 for (Element member in elementInfo.classMembers[cls]) { | |
| 459 members.add(elementInfo.elementAsts[member].ast); | |
| 460 } | |
| 461 memberNodes[elementInfo.elementAsts[cls].ast] = members; | |
| 462 } | |
| 463 } | |
| 464 | |
| 465 mirrorRenamer.addRenames( | |
| 466 placeholderRenamer.renames, topLevelNodes, collector); | |
| 467 | |
| 468 Map<LibraryElement, String> outputPaths = new Map<LibraryElement, String>(); | |
| 469 Map<LibraryElement, EmitterUnparser> unparsers = | |
| 470 new Map<LibraryElement, EmitterUnparser>(); | |
| 471 | |
| 472 // The single unparser used if we collect all the output in one file. | |
| 473 EmitterUnparser mainUnparser = multiFile | |
| 474 ? null | |
| 475 : new EmitterUnparser(placeholderRenamer.renames, | |
| 476 stripTypes: forceStripTypes, minify: enableMinification); | |
| 477 | |
| 478 if (multiFile) { | |
| 479 // TODO(sigurdm): Factor handling of library-paths out from emitting. | |
| 480 String mainName = outputUri.pathSegments.last; | |
| 481 String mainBaseName = mainName.endsWith(".dart") | |
| 482 ? mainName.substring(0, mainName.length - 5) | |
| 483 : mainName; | |
| 484 // Map each library to a path based on the uri of the original | |
| 485 // library and [compiler.options.outputUri]. | |
| 486 Set<String> usedLibraryPaths = new Set<String>(); | |
| 487 for (LibraryElement library in libraryInfo.userLibraries) { | |
| 488 if (library == mainFunction.library) { | |
| 489 outputPaths[library] = mainBaseName; | |
| 490 } else { | |
| 491 List<String> names = | |
| 492 library.canonicalUri.pathSegments.last.split("."); | |
| 493 if (names.last == "dart") { | |
| 494 names = names.sublist(0, names.length - 1); | |
| 495 } | |
| 496 outputPaths[library] = | |
| 497 "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}"; | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 /// Rewrites imports/exports to refer to the paths given in [outputPaths]. | |
| 502 for (LibraryElement outputLibrary in libraryInfo.userLibraries) { | |
| 503 EmitterUnparser unparser = new EmitterUnparser( | |
| 504 placeholderRenamer.renames, | |
| 505 stripTypes: forceStripTypes, | |
| 506 minify: enableMinification); | |
| 507 unparsers[outputLibrary] = unparser; | |
| 508 if (outputLibrary.hasLibraryName) { | |
| 509 unparser.unparseLibraryName(outputLibrary.libraryName); | |
| 510 } | |
| 511 for (ImportElement import in outputLibrary.imports) { | |
| 512 LibraryElement libraryElement = import.importedLibrary; | |
| 513 String uri = outputPaths.containsKey(libraryElement) | |
| 514 ? "${outputPaths[libraryElement]}.dart" | |
| 515 : libraryElement.canonicalUri.toString(); | |
| 516 unparser.unparseImportTag(uri); | |
| 517 } | |
| 518 for (ExportElement export in outputLibrary.exports) { | |
| 519 LibraryElement libraryElement = export.exportedLibrary; | |
| 520 String uri = outputPaths.containsKey(libraryElement) | |
| 521 ? "${outputPaths[libraryElement]}.dart" | |
| 522 : libraryElement.canonicalUri.toString(); | |
| 523 unparser.unparseExportTag(uri); | |
| 524 } | |
| 525 } | |
| 526 } else { | |
| 527 placeholderRenamer.platformImports | |
| 528 .forEach((LibraryElement library, String prefix) { | |
| 529 assert(library.isPlatformLibrary && !library.isInternalLibrary); | |
| 530 mainUnparser.unparseImportTag(library.canonicalUri.toString()); | |
| 531 if (prefix != null) { | |
| 532 // Adding a prefixed import because (some) top-level access need | |
| 533 // it to avoid shadowing. | |
| 534 // TODO(johnniwinther): Avoid prefix-less import if not needed. | |
| 535 mainUnparser.unparseImportTag(library.canonicalUri.toString(), | |
| 536 prefix: prefix); | |
| 537 } | |
| 538 }); | |
| 539 } | |
| 540 | |
| 541 for (int i = 0; i < elementInfo.topLevelElements.length; i++) { | |
| 542 Element element = elementInfo.topLevelElements.elementAt(i); | |
| 543 Node node = topLevelNodes[i]; | |
| 544 Unparser unparser = multiFile ? unparsers[element.library] : mainUnparser; | |
| 545 if (node is ClassNode) { | |
| 546 // TODO(smok): Filter out default constructors here. | |
| 547 unparser.unparseClassWithBody(node, memberNodes[node]); | |
| 548 } else { | |
| 549 unparser.unparse(node); | |
| 550 } | |
| 551 unparser.newline(); | |
| 552 } | |
| 553 | |
| 554 int totalSize = 0; | |
| 555 if (multiFile) { | |
| 556 for (LibraryElement outputLibrary in libraryInfo.userLibraries) { | |
| 557 // TODO(sigurdm): Make the unparser output directly into the buffer | |
| 558 // instead of caching in `.result`. | |
| 559 String code = unparsers[outputLibrary].result; | |
| 560 totalSize += code.length; | |
| 561 outputProvider(outputPaths[outputLibrary], "dart") | |
| 562 ..add(code) | |
| 563 ..close(); | |
| 564 } | |
| 565 } else { | |
| 566 String code = mainUnparser.result; | |
| 567 outputProvider("", "dart") | |
| 568 ..add(code) | |
| 569 ..close(); | |
| 570 | |
| 571 totalSize = code.length; | |
| 572 } | |
| 573 | |
| 574 return totalSize; | |
| 575 } | |
| 576 } | |
| OLD | NEW |