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 |