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