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