OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE.md file. | |
4 | |
5 library fletchc.fletch_system_printer; | |
6 | |
7 import '../fletch_system.dart' show | |
8 FletchClass, | |
9 FletchFunction, | |
10 FletchSystem; | |
11 | |
12 import 'package:compiler/src/util/uri_extras.dart' show | |
13 relativize; | |
14 | |
15 import 'fletch_selector.dart' show | |
16 FletchSelector, | |
17 SelectorKind; | |
18 | |
19 import 'package:compiler/src/elements/elements.dart' show | |
20 Element, | |
21 CompilationUnitElement; | |
22 | |
23 class FletchSystemPrinter { | |
24 final FletchSystem system; | |
25 final Uri base; | |
26 final StringBuffer buffer = new StringBuffer(); | |
27 final String baseIndentation = " "; | |
28 | |
29 bool beginningOfLine = true; | |
30 | |
31 int indentationLevel = 0; | |
32 | |
33 FletchSystemPrinter(this.system, this.base); | |
34 | |
35 void indent() { | |
36 for (int i = 0; i < indentationLevel; i++) { | |
37 buffer.write(baseIndentation); | |
38 } | |
39 } | |
40 | |
41 void indented(f()) { | |
42 ++indentationLevel; | |
43 try { | |
44 f(); | |
45 } finally { | |
46 --indentationLevel; | |
47 } | |
48 } | |
49 | |
50 void write(String text) { | |
51 if (beginningOfLine) { | |
52 indent(); | |
53 beginningOfLine = false; | |
54 } | |
55 buffer.write(text); | |
56 } | |
57 | |
58 void writeLine([String line = ""]) { | |
59 write("$line\n"); | |
60 beginningOfLine = true; | |
61 } | |
62 | |
63 void writeFletchFunctionAsBody(FletchFunction function) { | |
64 if (function.element != null) { | |
65 writeLine("=> ${function.element};"); | |
66 } else { | |
67 writeLine("{"); | |
68 indented(() { | |
69 for (String line in function.verboseToString().trim().split("\n")) { | |
70 writeLine("// $line"); | |
71 } | |
72 }); | |
73 writeLine("}"); | |
74 } | |
75 } | |
76 | |
77 void writeMethodTableEntry( | |
78 DecodedFletchSelector selector, int functionId) { | |
79 switch (selector.kind) { | |
80 case SelectorKind.Method: | |
81 write("${selector.symbol}#${selector.arity}()"); | |
82 break; | |
83 | |
84 case SelectorKind.Getter: | |
85 assert(selector.arity == 0); | |
86 if (selector.symbol.startsWith("?is?")) { | |
87 writeLine("type test ${selector.symbol.substring(4)}"); | |
88 return; | |
89 } | |
90 write("get ${selector.symbol}"); | |
91 break; | |
92 | |
93 case SelectorKind.Setter: | |
94 assert(selector.arity == 1); | |
95 write("set ${selector.symbol}"); | |
96 break; | |
97 } | |
98 write(" "); | |
99 FletchFunction function = system.functionsById[functionId]; | |
100 writeFletchFunctionAsBody(function); | |
101 } | |
102 | |
103 void writeFletchClass(FletchClass cls, Set<FletchFunction> unseen) { | |
104 // TODO(ahe): Important if class is builtin or not. Information lost in | |
105 // FletchNewClassBuilder.finalizeClass. | |
106 if (cls.element != null) { | |
107 writeLine("class ${cls.element.name} {"); | |
108 } else { | |
109 writeLine("$cls {"); | |
110 } | |
111 indented(() { | |
112 Map<DecodedFletchSelector, int> methodTable = | |
113 <DecodedFletchSelector, int>{}; | |
114 for (var pair in cls.methodTable) { | |
115 DecodedFletchSelector selector = | |
116 new DecodedFletchSelector.fromEncodedSelector(pair.fst, system); | |
117 methodTable[selector] = pair.snd; | |
118 } | |
119 List<DecodedFletchSelector> selectors = methodTable.keys.toList()..sort(); | |
120 for (DecodedFletchSelector selector in selectors) { | |
121 int methodId = methodTable[selector]; | |
122 unseen.remove(system.lookupFunctionById(methodId)); | |
123 writeMethodTableEntry(selector, methodId); | |
124 } | |
125 }); | |
126 writeLine("}"); | |
127 } | |
128 | |
129 String generateDebugString() { | |
130 buffer.clear(); | |
131 | |
132 Map<String, List<Element>> elementsByPath = <String, List<Element>>{}; | |
133 Set<FletchFunction> unseenFunctions = new Set<FletchFunction>(); | |
134 | |
135 for (var pair in system.functionsById) { | |
136 unseenFunctions.add(pair.snd); | |
137 } | |
138 | |
139 groupByPath(pair) { | |
140 Element element = pair.fst; | |
141 String path = | |
142 relativize(base, element.compilationUnit.script.resourceUri, false); | |
143 List<Element> elements = | |
144 elementsByPath.putIfAbsent(path, () => <Element>[]); | |
145 elements.add(element); | |
146 } | |
147 system.functionsByElement.forEach(groupByPath); | |
148 system.classesByElement.forEach(groupByPath); | |
149 List paths = elementsByPath.keys.toList(); | |
150 paths.sort(); | |
151 for (String path in paths) { | |
152 writeLine("$path"); | |
153 indented(() { | |
154 List<Element> elements = elementsByPath[path]; | |
155 elements.sort((a, b) => "$a".compareTo("$b")); | |
156 for (Element element in elements) { | |
157 if (element.isClass) { | |
158 writeFletchClass(system.classesByElement[element], unseenFunctions); | |
159 } else if (!element.isInstanceMember) { | |
160 unseenFunctions.remove(system.functionsByElement[element]); | |
161 // TODO(ahe): It would probably be better to call | |
162 // writeFletchFunctionAsBody here, but we have an element, not an | |
163 // ID. | |
164 writeLine("$element"); | |
165 } | |
166 } | |
167 }); | |
168 } | |
169 | |
170 writeLine("Classes without an element:"); | |
171 indented(() { | |
172 for (var pair in system.classesById) { | |
173 FletchClass fletchClass = pair.snd; | |
174 if (system.classesByElement[fletchClass.element] != fletchClass) { | |
175 writeFletchClass(fletchClass, unseenFunctions); | |
176 } | |
177 } | |
178 }); | |
179 | |
180 writeLine("Other functions:"); | |
181 indented(() { | |
182 for (var pair in system.functionsById) { | |
183 FletchFunction fletchFunction = pair.snd; | |
184 if (unseenFunctions.remove(fletchFunction)) { | |
185 write("$fletchFunction "); | |
186 writeFletchFunctionAsBody(fletchFunction); | |
187 } | |
188 } | |
189 }); | |
190 | |
191 return "$buffer"; | |
192 } | |
193 | |
194 int compareUnits(CompilationUnitElement a, CompilationUnitElement b) { | |
195 String aPath = relativize(base, a.script.resourceUri, false); | |
196 String bPath = relativize(base, b.script.resourceUri, false); | |
197 return aPath.compareTo(bPath); | |
198 } | |
199 } | |
200 | |
201 class DecodedFletchSelector implements Comparable<DecodedFletchSelector> { | |
202 final FletchSelector selector; | |
203 | |
204 final String symbol; | |
205 | |
206 const DecodedFletchSelector(this.selector, this.symbol); | |
207 | |
208 factory DecodedFletchSelector.fromEncodedSelector( | |
209 int encodedSelector, | |
210 FletchSystem system) { | |
211 FletchSelector selector = new FletchSelector(encodedSelector); | |
212 return new DecodedFletchSelector( | |
213 selector, system.symbolByFletchSelectorId[selector.id]); | |
214 } | |
215 | |
216 int get id => selector.id; | |
217 | |
218 SelectorKind get kind => selector.kind; | |
219 | |
220 int get arity => selector.arity; | |
221 | |
222 String toString() => "DecodedFletchSelector($id, $symbol, $kind, $arity)"; | |
223 | |
224 int compareTo(DecodedFletchSelector other) { | |
225 int result = this.symbol.compareTo(other.symbol); | |
226 if (result != 0) return result; | |
227 result = this.kind.index.compareTo(other.kind.index); | |
228 if (result != 0) return result; | |
229 return this.arity.compareTo(other.arity); | |
230 } | |
231 } | |
OLD | NEW |