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