| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 part of dart_backend; | 5 part of dart_backend; |
| 6 | 6 |
| 7 typedef bool IsSafeToRemoveTypeDeclarations( | 7 typedef bool IsSafeToRemoveTypeDeclarations( |
| 8 Map<ClassElement, Iterable<Element>> classMembers); | 8 Map<ClassElement, Iterable<Element>> classMembers); |
| 9 typedef void ElementCallback<E>(E element); | 9 typedef void ElementCallback<E>(E element); |
| 10 typedef void ElementPostProcessFunction( | 10 typedef void ElementPostProcessFunction( |
| 11 AstElement element, ElementAst elementAst, | 11 AstElement element, ElementAst elementAst, |
| 12 ElementCallback<TypedefElement> typedefCallback, | 12 ElementCallback<TypedefElement> typedefCallback, |
| 13 ElementCallback<ClassElement> classCallback); | 13 ElementCallback<ClassElement> classCallback); |
| 14 typedef ElementAst ComputeElementAstFunction(AstElement element); | 14 typedef ElementAst ComputeElementAstFunction(AstElement element); |
| 15 typedef bool ElementFilter(Element element); | 15 typedef bool ElementFilter(Element element); |
| 16 typedef List<Element> ElementSorter(Iterable<Element> elements); |
| 16 | 17 |
| 17 /// Output engine for dart2dart that is shared between the dart2js and the | 18 /// Output engine for dart2dart that is shared between the dart2js and the |
| 18 /// analyzer implementations of dart2dart. | 19 /// analyzer implementations of dart2dart. |
| 19 class DartOutputter { | 20 class DartOutputter { |
| 20 final DiagnosticListener listener; | 21 final DiagnosticListener listener; |
| 21 final CompilerOutputProvider outputProvider; | 22 final CompilerOutputProvider outputProvider; |
| 22 final bool forceStripTypes; | 23 final bool forceStripTypes; |
| 23 | 24 |
| 24 // TODO(antonm): make available from command-line options. | 25 // TODO(antonm): make available from command-line options. |
| 25 final bool outputAst = false; | 26 final bool outputAst = false; |
| 26 final bool enableMinification; | 27 final bool enableMinification; |
| 27 | 28 |
| 28 /// If `true`, libraries are generated into separate files. | 29 /// If `true`, libraries are generated into separate files. |
| 29 final bool multiFile; | 30 final bool multiFile; |
| 30 | 31 |
| 31 /// Internal structures accessible for tests and logging. | 32 /// Internal structures accessible for tests and logging. |
| 32 // TODO(johnniwinther): Clean this up. | 33 // TODO(johnniwinther): Clean this up. |
| 33 PlaceholderRenamer renamer; | 34 PlaceholderRenamer renamer; |
| 34 MainOutputGenerator output; | 35 MainOutputGenerator output; |
| 35 LibraryInfo libraryInfo; | 36 LibraryInfo libraryInfo; |
| 36 ElementInfo elementInfo; | 37 ElementInfo elementInfo; |
| 37 | 38 |
| 38 // TODO(johnniwinther): Support recompilation. | 39 // TODO(johnniwinther): Support recompilation. |
| 39 DartOutputter(this.listener, this.outputProvider, | 40 DartOutputter(this.listener, this.outputProvider, |
| 40 {bool this.forceStripTypes: false, | 41 {bool this.forceStripTypes: false, |
| 41 bool this.enableMinification: false, | 42 bool this.enableMinification: false, |
| 42 bool this.multiFile: false}); | 43 bool this.multiFile: false}); |
| 43 | 44 |
| 44 String assembleProgram({ | 45 String assembleProgram({ |
| 45 MirrorRenamer mirrorRenamer, | 46 MirrorRenamer mirrorRenamer: const MirrorRenamer(), |
| 46 Iterable<LibraryElement> libraries, | 47 Iterable<LibraryElement> libraries, |
| 47 Iterable<Element> instantiatedClasses, | 48 Iterable<Element> instantiatedClasses, |
| 48 Iterable<Element> resolvedElements, | 49 Iterable<Element> resolvedElements, |
| 49 Iterable<ClassElement> usedTypeLiterals, | 50 Iterable<ClassElement> usedTypeLiterals: const <ClassElement>[], |
| 50 LibraryElement mainLibrary, | |
| 51 FunctionElement mainFunction, | 51 FunctionElement mainFunction, |
| 52 Uri outputUri, | 52 Uri outputUri, |
| 53 ElementPostProcessFunction postProcessElementAst, | 53 ElementPostProcessFunction postProcessElementAst, |
| 54 ComputeElementAstFunction computeElementAst, | 54 ComputeElementAstFunction computeElementAst, |
| 55 ElementFilter shouldOutput, | 55 ElementFilter shouldOutput, |
| 56 IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations}) { | 56 IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations, |
| 57 ElementSorter sortElements}) { |
| 58 |
| 59 assert(invariant(NO_LOCATION_SPANNABLE, libraries != null, |
| 60 message: "'libraries' must be non-null.")); |
| 61 assert(invariant(NO_LOCATION_SPANNABLE, instantiatedClasses != null, |
| 62 message: "'instantiatedClasses' must be non-null.")); |
| 63 assert(invariant(NO_LOCATION_SPANNABLE, resolvedElements != null, |
| 64 message: "'resolvedElements' must be non-null.")); |
| 65 assert(invariant(NO_LOCATION_SPANNABLE, mainFunction != null, |
| 66 message: "'mainFunction' must be non-null.")); |
| 67 assert(invariant(NO_LOCATION_SPANNABLE, computeElementAst != null, |
| 68 message: "'computeElementAst' must be non-null.")); |
| 69 assert(invariant(NO_LOCATION_SPANNABLE, shouldOutput != null, |
| 70 message: "'shouldOutput' must be non-null.")); |
| 71 assert(invariant(NO_LOCATION_SPANNABLE, |
| 72 isSafeToRemoveTypeDeclarations != null, |
| 73 message: "'isSafeToRemoveTypeDeclarations' must be non-null.")); |
| 74 |
| 75 if (sortElements == null) { |
| 76 // Ensure deterministic output order. |
| 77 sortElements = (Iterable<Element> elements) { |
| 78 List<Element> list = elements.toList(); |
| 79 list.sort((Element a, Element b) => a.name.compareTo(b.name)); |
| 80 return list; |
| 81 }; |
| 82 } |
| 57 | 83 |
| 58 libraryInfo = LibraryInfo.processLibraries(libraries, resolvedElements); | 84 libraryInfo = LibraryInfo.processLibraries(libraries, resolvedElements); |
| 59 | 85 |
| 60 elementInfo = ElementInfoProcessor.createElementInfo( | 86 elementInfo = ElementInfoProcessor.createElementInfo( |
| 61 instantiatedClasses, | 87 instantiatedClasses, |
| 62 resolvedElements, | 88 resolvedElements, |
| 63 usedTypeLiterals, | 89 usedTypeLiterals, |
| 64 postProcessElementAst: postProcessElementAst, | 90 postProcessElementAst: postProcessElementAst, |
| 65 parseElementAst: computeElementAst, | 91 parseElementAst: computeElementAst, |
| 66 shouldOutput: shouldOutput); | 92 shouldOutput: shouldOutput, |
| 93 sortElements: sortElements); |
| 67 | 94 |
| 68 PlaceholderCollector collector = collectPlaceholders( | 95 PlaceholderCollector collector = collectPlaceholders( |
| 69 listener, | 96 listener, |
| 70 mirrorRenamer, | 97 mirrorRenamer, |
| 71 mainFunction, | 98 mainFunction, |
| 72 libraryInfo, | 99 libraryInfo, |
| 73 elementInfo); | 100 elementInfo); |
| 74 | 101 |
| 75 renamer = createRenamer( | 102 renamer = createRenamer( |
| 76 collector, | 103 collector, |
| 77 libraryInfo, | 104 libraryInfo, |
| 78 elementInfo, | 105 elementInfo, |
| 79 enableMinification: enableMinification, | 106 enableMinification: enableMinification, |
| 80 forceStripTypes: forceStripTypes, | 107 forceStripTypes: forceStripTypes, |
| 81 isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations); | 108 isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations); |
| 82 | 109 |
| 83 String assembledCode; | 110 String assembledCode; |
| 84 if (outputAst) { | 111 if (outputAst) { |
| 85 assembledCode = astOutput(listener, elementInfo); | 112 assembledCode = astOutput(listener, elementInfo); |
| 86 } else { | 113 } else { |
| 87 output = new MainOutputGenerator(); | 114 output = new MainOutputGenerator(); |
| 88 assembledCode = output.generateCode( | 115 assembledCode = output.generateCode( |
| 89 libraryInfo, | 116 libraryInfo, |
| 90 elementInfo, | 117 elementInfo, |
| 91 collector, | 118 collector, |
| 92 renamer, | 119 renamer, |
| 93 mainLibrary, | 120 mainFunction, |
| 94 outputUri, | 121 outputUri, |
| 95 outputProvider, | 122 outputProvider, |
| 96 mirrorRenamer, | 123 mirrorRenamer, |
| 97 multiFile: multiFile, | 124 multiFile: multiFile, |
| 98 forceStripTypes: forceStripTypes, | 125 forceStripTypes: forceStripTypes, |
| 99 enableMinification: enableMinification); | 126 enableMinification: enableMinification); |
| 100 } | 127 } |
| 101 return assembledCode; | 128 return assembledCode; |
| 102 } | 129 } |
| 103 | 130 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 | 167 |
| 141 PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer( | 168 PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer( |
| 142 libraryInfo.fixedMemberNames, libraryInfo.reexportingLibraries, | 169 libraryInfo.fixedMemberNames, libraryInfo.reexportingLibraries, |
| 143 cutDeclarationTypes: shouldCutDeclarationTypes, | 170 cutDeclarationTypes: shouldCutDeclarationTypes, |
| 144 enableMinification: enableMinification); | 171 enableMinification: enableMinification); |
| 145 | 172 |
| 146 placeholderRenamer.computeRenames(collector); | 173 placeholderRenamer.computeRenames(collector); |
| 147 return placeholderRenamer; | 174 return placeholderRenamer; |
| 148 } | 175 } |
| 149 | 176 |
| 150 static String astOutput(Compiler compiler, | 177 static String astOutput(DiagnosticListener listener, |
| 151 ElementInfo elementInfo) { | 178 ElementInfo elementInfo) { |
| 152 // TODO(antonm): Ideally XML should be a separate backend. | 179 // TODO(antonm): Ideally XML should be a separate backend. |
| 153 // TODO(antonm): obey renames and minification, at least as an option. | 180 // TODO(antonm): obey renames and minification, at least as an option. |
| 154 StringBuffer sb = new StringBuffer(); | 181 StringBuffer sb = new StringBuffer(); |
| 155 outputElement(element) { | 182 outputElement(element) { |
| 156 sb.write(element.parseNode(compiler).toDebugString()); | 183 sb.write(element.parseNode(listener).toDebugString()); |
| 157 } | 184 } |
| 158 | 185 |
| 159 // Emit XML for AST instead of the program. | 186 // Emit XML for AST instead of the program. |
| 160 for (Element topLevel in elementInfo.topLevelElements) { | 187 for (Element topLevel in elementInfo.topLevelElements) { |
| 161 if (topLevel.isClass && | 188 if (topLevel.isClass && |
| 162 !elementInfo.emitNoMembersFor.contains(topLevel)) { | 189 !elementInfo.emitNoMembersFor.contains(topLevel)) { |
| 163 // TODO(antonm): add some class info. | 190 // TODO(antonm): add some class info. |
| 164 elementInfo.classMembers[topLevel].forEach(outputElement); | 191 elementInfo.classMembers[topLevel].forEach(outputElement); |
| 165 } else { | 192 } else { |
| 166 outputElement(topLevel); | 193 outputElement(topLevel); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 {this.postProcessElementAst, | 308 {this.postProcessElementAst, |
| 282 this.parseElementAst, | 309 this.parseElementAst, |
| 283 this.shouldOutput}); | 310 this.shouldOutput}); |
| 284 | 311 |
| 285 static ElementInfo createElementInfo( | 312 static ElementInfo createElementInfo( |
| 286 Iterable<ClassElement> instantiatedClasses, | 313 Iterable<ClassElement> instantiatedClasses, |
| 287 Iterable<AstElement> resolvedElements, | 314 Iterable<AstElement> resolvedElements, |
| 288 Iterable<ClassElement> usedTypeLiterals, | 315 Iterable<ClassElement> usedTypeLiterals, |
| 289 {ElementPostProcessFunction postProcessElementAst, | 316 {ElementPostProcessFunction postProcessElementAst, |
| 290 ComputeElementAstFunction parseElementAst, | 317 ComputeElementAstFunction parseElementAst, |
| 291 ElementFilter shouldOutput}) { | 318 ElementFilter shouldOutput, |
| 319 ElementSorter sortElements}) { |
| 292 ElementInfoProcessor processor = new ElementInfoProcessor( | 320 ElementInfoProcessor processor = new ElementInfoProcessor( |
| 293 postProcessElementAst: postProcessElementAst, | 321 postProcessElementAst: postProcessElementAst, |
| 294 parseElementAst: parseElementAst, | 322 parseElementAst: parseElementAst, |
| 295 shouldOutput: shouldOutput); | 323 shouldOutput: shouldOutput); |
| 296 return processor.process( | 324 return processor.process( |
| 297 instantiatedClasses, resolvedElements, usedTypeLiterals); | 325 instantiatedClasses, resolvedElements, usedTypeLiterals, |
| 326 sortElements: sortElements); |
| 298 } | 327 } |
| 299 | 328 |
| 300 ElementInfo process(Iterable<ClassElement> instantiatedClasses, | 329 ElementInfo process(Iterable<ClassElement> instantiatedClasses, |
| 301 Iterable<AstElement> resolvedElements, | 330 Iterable<AstElement> resolvedElements, |
| 302 Iterable<ClassElement> usedTypeLiterals) { | 331 Iterable<ClassElement> usedTypeLiterals, |
| 332 {ElementSorter sortElements}) { |
| 303 // Build all top level elements to emit and necessary class members. | 333 // Build all top level elements to emit and necessary class members. |
| 304 instantiatedClasses.where(shouldOutput).forEach(addClass); | 334 instantiatedClasses.where(shouldOutput).forEach(addClass); |
| 305 resolvedElements.where(shouldOutput).forEach(addMember); | 335 resolvedElements.where(shouldOutput).forEach(addMember); |
| 306 usedTypeLiterals.forEach((ClassElement element) { | 336 usedTypeLiterals.forEach((ClassElement element) { |
| 307 if (shouldOutput(element)) { | 337 if (shouldOutput(element)) { |
| 308 if (!topLevelElements.contains(element)) { | 338 if (!topLevelElements.contains(element)) { |
| 309 // The class is only referenced by type literals. | 339 // The class is only referenced by type literals. |
| 310 emitNoMembersFor.add(element); | 340 emitNoMembersFor.add(element); |
| 311 } | 341 } |
| 312 addClass(element); | 342 addClass(element); |
| 313 } | 343 } |
| 314 }); | 344 }); |
| 315 | 345 |
| 316 // Sort elements. | 346 // Sort elements. |
| 317 List<Element> sortedTopLevels = sortElements(topLevelElements); | 347 List<Element> sortedTopLevels = sortElements(topLevelElements); |
| 318 Map<ClassElement, List<Element>> sortedClassMembers = | 348 Map<ClassElement, List<Element>> sortedClassMembers = |
| 319 new Map<ClassElement, List<Element>>(); | 349 new Map<ClassElement, List<Element>>(); |
| 320 classMembers.forEach((classElement, members) { | 350 classMembers.forEach((classElement, members) { |
| 321 sortedClassMembers[classElement] = sortElements(members); | 351 sortedClassMembers[classElement] = sortElements(members); |
| 322 }); | 352 }); |
| 323 | 353 |
| 324 return new ElementInfo( | 354 return new ElementInfo( |
| 325 elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor); | 355 elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor); |
| 326 } | 356 } |
| 327 | 357 |
| 328 void processElement(Element element, ElementAst elementAst) { | 358 void processElement(Element element, ElementAst elementAst) { |
| 329 postProcessElementAst(element, elementAst, | 359 if (postProcessElementAst != null) { |
| 330 newTypedefElementCallback, | 360 postProcessElementAst(element, elementAst, |
| 331 newClassElementCallback); | 361 newTypedefElementCallback, |
| 362 newClassElementCallback); |
| 363 } |
| 332 elementAsts[element] = elementAst; | 364 elementAsts[element] = elementAst; |
| 333 } | 365 } |
| 334 | 366 |
| 335 void addTopLevel(AstElement element, ElementAst elementAst) { | 367 void addTopLevel(AstElement element, ElementAst elementAst) { |
| 336 if (topLevelElements.contains(element)) return; | 368 if (topLevelElements.contains(element)) return; |
| 337 topLevelElements.add(element); | 369 topLevelElements.add(element); |
| 338 processElement(element, elementAst); | 370 processElement(element, elementAst); |
| 339 } | 371 } |
| 340 | 372 |
| 341 void addClass(ClassElement classElement) { | 373 void addClass(ClassElement classElement) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 class MainOutputGenerator { | 408 class MainOutputGenerator { |
| 377 final Map<ClassNode, List<Node>> memberNodes = | 409 final Map<ClassNode, List<Node>> memberNodes = |
| 378 new Map<ClassNode, List<Node>>(); | 410 new Map<ClassNode, List<Node>>(); |
| 379 final List<Node> topLevelNodes = <Node>[]; | 411 final List<Node> topLevelNodes = <Node>[]; |
| 380 | 412 |
| 381 String generateCode( | 413 String generateCode( |
| 382 LibraryInfo libraryInfo, | 414 LibraryInfo libraryInfo, |
| 383 ElementInfo elementInfo, | 415 ElementInfo elementInfo, |
| 384 PlaceholderCollector collector, | 416 PlaceholderCollector collector, |
| 385 PlaceholderRenamer placeholderRenamer, | 417 PlaceholderRenamer placeholderRenamer, |
| 386 LibraryElement mainApp, | 418 FunctionElement mainFunction, |
| 387 Uri outputUri, | 419 Uri outputUri, |
| 388 CompilerOutputProvider outputProvider, | 420 CompilerOutputProvider outputProvider, |
| 389 MirrorRenamer mirrorRenamer, | 421 MirrorRenamer mirrorRenamer, |
| 390 {bool multiFile: false, | 422 {bool multiFile: false, |
| 391 bool forceStripTypes: false, | 423 bool forceStripTypes: false, |
| 392 bool enableMinification: false}) { | 424 bool enableMinification: false}) { |
| 393 for (Element element in elementInfo.topLevelElements) { | 425 for (Element element in elementInfo.topLevelElements) { |
| 394 topLevelNodes.add(elementInfo.elementAsts[element].ast); | 426 topLevelNodes.add(elementInfo.elementAsts[element].ast); |
| 395 if (element.isClass && !element.isMixinApplication) { | 427 if (element.isClass && !element.isMixinApplication) { |
| 396 final members = <Node>[]; | 428 final members = <Node>[]; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 418 if (multiFile) { | 450 if (multiFile) { |
| 419 // TODO(sigurdm): Factor handling of library-paths out from emitting. | 451 // TODO(sigurdm): Factor handling of library-paths out from emitting. |
| 420 String mainName = outputUri.pathSegments.last; | 452 String mainName = outputUri.pathSegments.last; |
| 421 String mainBaseName = mainName.endsWith(".dart") | 453 String mainBaseName = mainName.endsWith(".dart") |
| 422 ? mainName.substring(0, mainName.length - 5) | 454 ? mainName.substring(0, mainName.length - 5) |
| 423 : mainName; | 455 : mainName; |
| 424 // Map each library to a path based on the uri of the original | 456 // Map each library to a path based on the uri of the original |
| 425 // library and [compiler.outputUri]. | 457 // library and [compiler.outputUri]. |
| 426 Set<String> usedLibraryPaths = new Set<String>(); | 458 Set<String> usedLibraryPaths = new Set<String>(); |
| 427 for (LibraryElement library in libraryInfo.userLibraries) { | 459 for (LibraryElement library in libraryInfo.userLibraries) { |
| 428 if (library == mainApp) { | 460 if (library == mainFunction.library) { |
| 429 outputPaths[library] = mainBaseName; | 461 outputPaths[library] = mainBaseName; |
| 430 } else { | 462 } else { |
| 431 List<String> names = | 463 List<String> names = |
| 432 library.canonicalUri.pathSegments.last.split("."); | 464 library.canonicalUri.pathSegments.last.split("."); |
| 433 if (names.last == "dart") { | 465 if (names.last == "dart") { |
| 434 names = names.sublist(0, names.length - 1); | 466 names = names.sublist(0, names.length - 1); |
| 435 } | 467 } |
| 436 outputPaths[library] = | 468 outputPaths[library] = |
| 437 "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}"; | 469 "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}"; |
| 438 } | 470 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 for(LibraryElement outputLibrary in libraryInfo.userLibraries) { | 523 for(LibraryElement outputLibrary in libraryInfo.userLibraries) { |
| 492 // TODO(sigurdm): Make the unparser output directly into the buffer | 524 // TODO(sigurdm): Make the unparser output directly into the buffer |
| 493 // instead of caching in `.result`. | 525 // instead of caching in `.result`. |
| 494 String code = unparsers[outputLibrary].result; | 526 String code = unparsers[outputLibrary].result; |
| 495 totalSize += code.length; | 527 totalSize += code.length; |
| 496 outputProvider(outputPaths[outputLibrary], "dart") | 528 outputProvider(outputPaths[outputLibrary], "dart") |
| 497 ..add(code) | 529 ..add(code) |
| 498 ..close(); | 530 ..close(); |
| 499 } | 531 } |
| 500 // TODO(sigurdm): We should get rid of compiler.assembledCode. | 532 // TODO(sigurdm): We should get rid of compiler.assembledCode. |
| 501 assembledCode = unparsers[mainApp].result; | 533 assembledCode = unparsers[mainFunction.library].result; |
| 502 } else { | 534 } else { |
| 503 assembledCode = mainUnparser.result; | 535 assembledCode = mainUnparser.result; |
| 504 outputProvider("", "dart") | 536 outputProvider("", "dart") |
| 505 ..add(assembledCode) | 537 ..add(assembledCode) |
| 506 ..close(); | 538 ..close(); |
| 507 | 539 |
| 508 totalSize = assembledCode.length; | 540 totalSize = assembledCode.length; |
| 509 } | 541 } |
| 510 | 542 |
| 511 return assembledCode; | 543 return assembledCode; |
| 512 } | 544 } |
| 513 } | 545 } |
| OLD | NEW |