1 | static bool structure_showTiming, structure_checkTokenCount; |
2 | |
3 | static String structure(Object o) { |
4 | new structure_Data d; |
5 | structure_1(o, d); |
6 | while (nempty(d.stack)) |
7 | popLast(d.stack).run(); |
8 | S s = str(d.out); |
9 | if (structure_checkTokenCount) { |
10 | print("token count=" + d.n); |
11 | assertEquals("token count", l(javaTokC(s)), d.n); |
12 | } |
13 | ret s; |
14 | } |
15 | |
16 | // leave to false, unless unstructure() breaks |
17 | static boolean structure_allowShortening = false; |
18 | |
19 | static int structure_shareStringsLongerThan = 20; |
20 | |
21 | static class structure_Data { |
22 | new StringBuilder out; |
23 | int stringSizeLimit; |
24 | new IdentityHashMap<O, Integer> seen; |
25 | new BitSet refd; |
26 | new HashMap<S, Int> strings; |
27 | new HashSet<S> concepts; |
28 | HashMap<Class, L<Field>> fieldsByClass = new HashMap; |
29 | Class conceptClass = findClass("Concept"); |
30 | int n; // token count |
31 | new L<Runnable> stack; |
32 | |
33 | // append single token |
34 | structure_Data append(S token) { out.append(token); ++n; ret this; } |
35 | structure_Data append(int i) { out.append(i); ++n; ret this; } |
36 | |
37 | // append multiple tokens |
38 | structure_Data append(S token, int tokCount) { out.append(token); n += tokCount; ret this; } |
39 | |
40 | // extend last token |
41 | structure_Data app(S token) { out.append(token); ret this; } |
42 | structure_Data app(int i) { out.append(i); ret this; } |
43 | } |
44 | |
45 | static void structure_1(Object o, final structure_Data d) { |
46 | final StringBuilder out = d.out; |
47 | |
48 | if (o == null) { d.append("null"); ret; } |
49 | |
50 | Class c = o.getClass(); |
51 | S name = c.getName(); |
52 | S dynName = shortDynamicClassName(o); |
53 | bool concept = d.conceptClass != null && d.conceptClass.isInstance(o); |
54 | L<Field> lFields = d.fieldsByClass.get(c); |
55 | |
56 | if (lFields == null) { |
57 | // these are never back-referenced (for readability) |
58 | |
59 | if (o instanceof Number) { |
60 | if (o instanceof Integer) { out.append(((Int) o).intValue()); d.n++; ret; } |
61 | if (o instanceof Long) { out.append(((Long) o).longValue()).append("L"); d.n++; ret; } |
62 | if (o instanceof Float) { d.append("fl ", 2); quote_impl(str(o), out); ret; } |
63 | if (o instanceof Double) { d.append("d(", 3); quote_impl(str(o), out); d.append(")"); ret; } |
64 | if (o instanceof BigInteger) { out.append("bigint(").append(o).append(")"); d.n += 4; ret; } |
65 | } |
66 | |
67 | if (o instanceof Boolean) { |
68 | d.append(((Boolean) o).booleanValue() ? "t" : "f"); ret; |
69 | } |
70 | |
71 | if (o instanceof Character) { |
72 | d.append(quoteCharacter((Character) o)); ret; |
73 | } |
74 | |
75 | if (o instanceof File) { |
76 | d.append("File ").append(quote(((File) o).getPath())); ret; |
77 | } |
78 | |
79 | // referencable objects follow |
80 | |
81 | Integer ref = d.seen.get(o); |
82 | if (o instanceof S && ref == null) |
83 | ref = d.strings.get((S) o); |
84 | |
85 | if (ref != null) { |
86 | d.refd.set(ref); |
87 | d.append("t").app(ref); ret; |
88 | } |
89 | |
90 | ref = d.n; //d.seen.size()+1; |
91 | d.seen.put(o, ref); |
92 | //d.append("m").app(ref).app(" "); // marker |
93 | |
94 | if (o instanceof S) { |
95 | S s = d.stringSizeLimit != 0 ? shorten((S) o, d.stringSizeLimit) : (S) o; |
96 | if (l(s) >= structure_shareStringsLongerThan) |
97 | d.strings.put(s, ref); |
98 | quote_impl(s, out); d.n++; ret; |
99 | } |
100 | |
101 | if (o instanceof HashSet) { |
102 | d.append("hashset "); |
103 | structure_1(new ArrayList((Set) o), d); |
104 | ret; |
105 | } |
106 | |
107 | if (o instanceof TreeSet) { |
108 | d.append("treeset "); |
109 | structure_1(new ArrayList((Set) o), d); |
110 | ret; |
111 | } |
112 | |
113 | if (o instanceof Collection && neq(name, "main$Concept$RefL")) { |
114 | d.append("["); |
115 | final int l = out.length(); |
116 | final Iterator it = ((Collection) o).iterator(); |
117 | d.stack.add(r { |
118 | if (!it.hasNext()) |
119 | d.append("]"); |
120 | else { |
121 | d.stack.add(this); |
122 | if (out.length() != l) d.append(", "); |
123 | structure_1(it.next(), d); |
124 | } |
125 | }); |
126 | ret; |
127 | } |
128 | |
129 | if (o instanceof Map) { |
130 | if (o instanceof HashMap) d.append("hm"); |
131 | d.append("{"); |
132 | final int l = out.length(); |
133 | final Iterator it = ((Map) o).entrySet().iterator(); |
134 | |
135 | d.stack.add(new Runnable() { |
136 | bool v; |
137 | Map.Entry e; |
138 | |
139 | public void run() { |
140 | if (v) { |
141 | d.append("="); |
142 | v = false; |
143 | d.stack.add(this); |
144 | structure_1(e.getValue(), d); |
145 | } else { |
146 | if (!it.hasNext()) |
147 | d.append("}"); |
148 | else { |
149 | e = (Map.Entry) it.next(); |
150 | v = true; |
151 | d.stack.add(this); |
152 | if (out.length() != l) d.append(", "); |
153 | structure_1(e.getKey(), d); |
154 | } |
155 | } |
156 | } |
157 | }); |
158 | ret; |
159 | } |
160 | |
161 | if (c.isArray()) { |
162 | if (o instanceof byte[]) { |
163 | d.append("ba ").append(quote(bytesToHex((byte[]) o))); ret; |
164 | } |
165 | |
166 | int n = Array.getLength(o); |
167 | |
168 | if (o instanceof bool[]) { |
169 | S hex = boolArrayToHex((bool[]) o); |
170 | int i = l(hex); |
171 | while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; |
172 | d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); ret; |
173 | } |
174 | |
175 | S atype = "array", sep = ", "; |
176 | |
177 | if (o instanceof int[]) { |
178 | //ret "intarray " + quote(intArrayToHex((int[]) o)); |
179 | atype = "intarray"; |
180 | sep = " "; |
181 | } |
182 | |
183 | d.append(atype).append("{"); |
184 | for (int i = 0; i < n; i++) { |
185 | if (i != 0) d.append(sep); |
186 | structure_1(Array.get(o, i), d); |
187 | } |
188 | d.append("}"); ret; |
189 | } |
190 | |
191 | if (o instanceof Class) { |
192 | d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); ret; |
193 | } |
194 | |
195 | if (o instanceof Throwable) { |
196 | d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); ret; |
197 | } |
198 | |
199 | if (o instanceof BitSet) { |
200 | BitSet bs = (BitSet) o; |
201 | d.append("bitset{", 2); |
202 | int l = out.length(); |
203 | for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { |
204 | if (out.length() != l) d.append(", "); |
205 | d.append(i); |
206 | } |
207 | d.append("}"); ret; |
208 | } |
209 | |
210 | // Need more cases? This should cover all library classes... |
211 | if (name.startsWith("java.") || name.startsWith("javax.")) { |
212 | d.append("j ").append(quote(str(o))); ret; // Hm. this is not unstructure-able |
213 | } |
214 | |
215 | /*if (name.equals("main$Lisp")) { |
216 | fail("lisp not supported right now"); |
217 | }*/ |
218 | |
219 | if (concept && !d.concepts.contains(dynName)) { |
220 | d.concepts.add(dynName); |
221 | d.append("c "); |
222 | } |
223 | |
224 | // serialize an object with fields. |
225 | // first, collect all fields and values in fv. |
226 | |
227 | TreeSet<Field> fields = new TreeSet<Field>(new Comparator<Field>() { |
228 | public int compare(Field a, Field b) { |
229 | ret stdcompare(a.getName(), b.getName()); |
230 | } |
231 | }); |
232 | |
233 | while (c != Object.class) { |
234 | for (Field field : getDeclaredFields_cached(c)) { |
235 | if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) |
236 | continue; |
237 | S fieldName = field.getName(); |
238 | |
239 | fields.add(field); |
240 | |
241 | // put special cases here... |
242 | } |
243 | |
244 | c = c.getSuperclass(); |
245 | } |
246 | |
247 | lFields = asList(fields); |
248 | |
249 | // Render this$1 first because unstructure needs it for constructor call. |
250 | |
251 | for (int i = 0; i < l(lFields); i++) { |
252 | Field f = lFields.get(i); |
253 | if (f.getName().equals("this$1")) { |
254 | lFields.remove(i); |
255 | lFields.add(0, f); |
256 | break; |
257 | } |
258 | } |
259 | |
260 | d.fieldsByClass.put(c, lFields); |
261 | } |
262 | |
263 | new LinkedHashMap<S, O> fv; |
264 | for (Field f : lFields) { |
265 | Object value; |
266 | try { |
267 | value = f.get(o); |
268 | } catch (Exception e) { |
269 | value = "?"; |
270 | } |
271 | |
272 | if (value != null) |
273 | fv.put(f.getName(), value); |
274 | } |
275 | |
276 | String shortName = dropPrefix("main$", name); |
277 | |
278 | // Now we have fields & values. Process fieldValues if it's a DynamicObject. |
279 | |
280 | // omit field "className" if equal to class's name |
281 | if (concept && eq(fv.get("className"), shortName)) |
282 | fv.remove("className"); |
283 | |
284 | if (o instanceof DynamicObject) { |
285 | fv.putAll((Map) fv.get("fieldValues")); |
286 | fv.remove("fieldValues"); |
287 | shortName = dynName; |
288 | fv.remove("className"); |
289 | } |
290 | |
291 | S singleField = fv.size() == 1 ? first(fv.keySet()) : null; |
292 | |
293 | d.append(shortName); |
294 | |
295 | final int l = out.length(); |
296 | final Iterator it = fv.entrySet().iterator(); |
297 | |
298 | d.stack.add(r { |
299 | if (!it.hasNext()) { |
300 | if (out.length() != l) |
301 | d.append(")"); |
302 | } else { |
303 | Map.Entry e = (Map.Entry) it.next(); |
304 | d.append(out.length() == l ? "(" : ", "); |
305 | d.append((S) e.getKey()).append("="); |
306 | d.stack.add(this); |
307 | structure_1(e.getValue(), d); |
308 | } |
309 | }); |
310 | } |
Began life as a copy of #1005603
download show line numbers debug dex old transpilations
Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1005656 |
Snippet name: | structure function (v11, virtual stack) |
Eternal ID of this version: | #1005656/1 |
Text MD5: | b4257bbd790e4e9634dbc85245740929 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-12-13 15:29:13 |
Source code size: | 8982 bytes / 310 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 545 / 562 |
Referenced in: | [show references] |