1 | static String structure(Object o) { |
2 | new HashSet refd; |
3 | return structure_2(structure_1(o, new structure_Data(refd)), refd); |
4 | } |
5 | |
6 | // leave to false, unless unstructure() breaks |
7 | static boolean structure_allowShortening = false; |
8 | |
9 | static int structure_shareStringsLongerThan = 20; |
10 | |
11 | static class structure_Data { |
12 | int stringSizeLimit; |
13 | new IdentityHashMap<O, Integer> seen; |
14 | HashSet<Integer> refd; |
15 | new HashMap<S, Int> strings; |
16 | new HashSet<S> concepts; |
17 | Class conceptClass = findClass("Concept"); |
18 | |
19 | *(HashSet<Int> *refd) {} |
20 | } |
21 | |
22 | static String structure_1(Object o, structure_Data d) { |
23 | if (o == null) return "null"; |
24 | |
25 | // these are never back-referenced (for readability) |
26 | |
27 | if (o instanceof BigInteger) |
28 | return "bigint(" + o + ")"; |
29 | |
30 | if (o instanceof Double) |
31 | return "d(" + quote(str(o)) + ")"; |
32 | |
33 | if (o instanceof Float) |
34 | return "fl " + quote(str(o)); |
35 | |
36 | if (o instanceof Long) |
37 | return o + "L"; |
38 | |
39 | if (o instanceof Integer) |
40 | return str(o); |
41 | |
42 | if (o instanceof Boolean) |
43 | return ((Boolean) o).booleanValue() ? "t" : "f"; |
44 | |
45 | if (o instanceof Character) |
46 | ret quoteCharacter((Character) o); |
47 | |
48 | if (o instanceof File) |
49 | ret "File " + quote(((File) o).getPath()); |
50 | |
51 | // referencable objects follow |
52 | |
53 | Integer ref = d.seen.get(o); |
54 | if (ref != null) { |
55 | d.refd.add(ref); |
56 | return "r" + ref; |
57 | } |
58 | |
59 | if (o instanceof S && (ref = d.strings.get((S) o)) != null) { |
60 | d.refd.add(ref); |
61 | return "r" + ref; |
62 | } |
63 | |
64 | ref = d.seen.size()+1; |
65 | d.seen.put(o, ref); |
66 | S r = "m" + ref + " "; // marker |
67 | |
68 | if (o instanceof S) { |
69 | S s = d.stringSizeLimit != 0 ? shorten((S) o, d.stringSizeLimit) : (S) o; |
70 | if (l(s) >= structure_shareStringsLongerThan) |
71 | d.strings.put(s, ref); |
72 | return r + quote(s); |
73 | } |
74 | |
75 | String name = o.getClass().getName(); |
76 | |
77 | StringBuilder buf = new StringBuilder(); |
78 | |
79 | if (o instanceof HashSet) |
80 | return r + "hashset " + structure_1(new ArrayList((Set) o), d); |
81 | |
82 | if (o instanceof TreeSet) |
83 | return r + "treeset " + structure_1(new ArrayList((Set) o), d); |
84 | |
85 | if (o instanceof Collection && neq(name, "main$Concept$RefL")) { |
86 | for (Object x : (Collection) o) { |
87 | if (buf.length() != 0) buf.append(", "); |
88 | buf.append(structure_1(x, d)); |
89 | } |
90 | return r + "[" + buf + "]"; |
91 | } |
92 | |
93 | if (o instanceof Map) { |
94 | for (Object e : ((Map) o).entrySet()) { |
95 | if (buf.length() != 0) buf.append(", "); |
96 | buf.append(structure_1(((Map.Entry) e).getKey(), d)); |
97 | buf.append("="); |
98 | buf.append(structure_1(((Map.Entry) e).getValue(), d)); |
99 | } |
100 | return r + (o instanceof HashMap ? "hm" : "") + "{" + buf + "}"; |
101 | } |
102 | |
103 | if (o.getClass().isArray()) { |
104 | if (o instanceof byte[]) |
105 | ret "ba " + quote(bytesToHex((byte[]) o)); |
106 | |
107 | int n = Array.getLength(o); |
108 | |
109 | if (o instanceof bool[]) { |
110 | S hex = boolArrayToHex((bool[]) o); |
111 | int i = l(hex); |
112 | while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; |
113 | ret "boolarray " + n + " " + quote(substring(hex, 0, i)); |
114 | } |
115 | |
116 | S atype = "array", sep = ", "; |
117 | |
118 | if (o instanceof int[]) { |
119 | //ret "intarray " + quote(intArrayToHex((int[]) o)); |
120 | atype = "intarray"; |
121 | sep = " "; |
122 | } |
123 | |
124 | for (int i = 0; i < n; i++) { |
125 | if (buf.length() != 0) buf.append(sep); |
126 | buf.append(structure_1(Array.get(o, i), d)); |
127 | } |
128 | return r + atype + "{" + buf + "}"; |
129 | } |
130 | |
131 | if (o instanceof Class) |
132 | return r + "class(" + quote(((Class) o).getName()) + ")"; |
133 | |
134 | if (o instanceof Throwable) |
135 | return r + "exception(" + quote(((Throwable) o).getMessage()) + ")"; |
136 | |
137 | if (o instanceof BitSet) { |
138 | BitSet bs = (BitSet) o; |
139 | for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { |
140 | if (buf.length() != 0) buf.append(", "); |
141 | buf.append(i); |
142 | } |
143 | return "bitset{" + buf + "}"; |
144 | } |
145 | |
146 | // Need more cases? This should cover all library classes... |
147 | if (name.startsWith("java.") || name.startsWith("javax.")) |
148 | return r + String.valueOf(o); |
149 | |
150 | String shortName = o.getClass().getName().replaceAll("^main\\$", ""); |
151 | |
152 | if (shortName.equals("Lisp")) { |
153 | buf.append("l(" + structure_1(getOpt(o, "head"), d)); |
154 | L args = cast getOpt(o, "args"); |
155 | if (nempty(args)) |
156 | for (int i = 0; i < l(args); i++) { |
157 | buf.append(", "); |
158 | O arg = args.get(i); |
159 | |
160 | // sweet shortening |
161 | if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty"))) |
162 | arg = get(arg, "head"); |
163 | |
164 | buf.append(structure_1(arg, d)); |
165 | } |
166 | buf.append(")"); |
167 | ret r + str(buf); |
168 | } |
169 | |
170 | Class c = o.getClass(); |
171 | bool concept = d.conceptClass != null && d.conceptClass.isInstance(o); |
172 | if (concept && !d.concepts.contains(c.getName())) { |
173 | d.concepts.add(c.getName()); |
174 | r += "c "; |
175 | } |
176 | |
177 | // serialize an object with fields. |
178 | // first, collect all fields and values in fv. |
179 | |
180 | new TreeMap<S, O> fv; |
181 | while (c != Object.class) { |
182 | for (Field field : c.getDeclaredFields()) { |
183 | if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) |
184 | continue; |
185 | S fieldName = field.getName(); |
186 | |
187 | Object value; |
188 | try { |
189 | field.setAccessible(true); |
190 | value = field.get(o); |
191 | } catch (Exception e) { |
192 | value = "?"; |
193 | } |
194 | |
195 | // omit field "className" if equal to class's name |
196 | if (concept && eq(fieldName, "className") |
197 | && eq(value, shortName)) value = null; |
198 | |
199 | // put special cases here... |
200 | |
201 | if (value != null) |
202 | fv.put(fieldName, value); |
203 | } |
204 | c = c.getSuperclass(); |
205 | } |
206 | |
207 | // Now we have fields & values. Process fieldValues if it's a DynamicObject. |
208 | |
209 | if (o instanceof DynamicObject) { |
210 | fv.putAll((Map) fv.get("fieldValues")); |
211 | fv.remove("fieldValues"); |
212 | shortName = (S) fv.get("className"); |
213 | fv.remove("className"); |
214 | } |
215 | |
216 | S singleField = fv.size() == 1 ? first(fv.keySet()) : null; |
217 | |
218 | // Render this$1 first because unstructure needs it for constructor call. |
219 | |
220 | if (fv.containsKey("this$1")) { |
221 | buf.append("this$1=" + structure_1(fv.get("this$1"), d)); |
222 | fv.remove("this$1"); |
223 | } |
224 | |
225 | // Render the other fields. |
226 | |
227 | for (S fieldName : fv.keySet()) { |
228 | if (buf.length() != 0) buf.append(", "); |
229 | buf.append(fieldName + "=" + structure_1(fv.get(fieldName), d)); |
230 | } |
231 | |
232 | String b = buf.toString(); |
233 | |
234 | if (structure_allowShortening && singleField != null) |
235 | b = b.replaceAll("^" + singleField + "=", ""); // drop field name if only one |
236 | String s = shortName; |
237 | if (buf.length() != 0) |
238 | s += "(" + b + ")"; |
239 | return r + s; |
240 | } |
241 | |
242 | // drop unused markers |
243 | static S structure_2(S s, HashSet<Integer> refd) { |
244 | L<S> tok = javaTok(s); |
245 | new StringBuilder out; |
246 | for (int i = 1; i < l(tok); i += 2) { |
247 | S t = tok.get(i); |
248 | if (t.startsWith("m") && isInteger(t.substring(1)) |
249 | && !refd.contains(parseInt(t.substring(1)))) |
250 | continue; |
251 | out.append(t).append(tok.get(i+1)); |
252 | } |
253 | ret str(out); |
254 | } |
Began life as a copy of #1002825
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1003037 |
Snippet name: | structure function (v6, with new new backrefs) |
Eternal ID of this version: | #1003037/1 |
Text MD5: | a0acb3866ce02a679ddf5befccbaa029 |
Author: | stefan |
Category: | |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-11-14 01:35:59 |
Source code size: | 7217 bytes / 254 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 742 / 2200 |
Referenced in: | [show references] |