| 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 | 
|---|