1 | static Object unstructure(String text) { |
2 | ret unstructure(text, false); |
3 | } |
4 | |
5 | static Object unstructure(String text, final boolean allDynamic) { |
6 | ret unstructure(text, allDynamic, null); |
7 | } |
8 | |
9 | static int structure_internStringsLongerThan = 50; |
10 | |
11 | abstract sclass unstructure_Receiver { |
12 | abstract void set(O o); |
13 | } |
14 | |
15 | // classFinder: func(name) -> class (optional) |
16 | static Object unstructure(String text, boolean allDynamic, |
17 | O classFinder) { |
18 | if (text == null) ret null; |
19 | final L<S> tok = javaTokC(text); |
20 | ret unstructure_tok(tok, allDynamic, classFinder); |
21 | } |
22 | |
23 | // so text can be freed |
24 | static Object unstructure_tempVar(Var<S> text) { |
25 | L<S> tok = javaTokC(text.get()); |
26 | text.clear(); |
27 | ret unstructure_tok(tok, false, null); |
28 | } |
29 | |
30 | static O unstructure_tok(final L<S> tok, final boolean allDynamic, final O classFinder) { |
31 | final boolean debug = unstructure_debug; |
32 | |
33 | class X { |
34 | int i = 0; |
35 | new HashMap<Integer, O> refs; |
36 | new HashMap<Integer, O> tokrefs; |
37 | new HashSet<S> concepts; |
38 | new HashMap<S, Class> classesMap; |
39 | new L<Runnable> stack; |
40 | |
41 | void parse(final unstructure_Receiver out) { |
42 | S t = tok.get(i); |
43 | |
44 | int refID = 0; |
45 | if (structure_isMarker(t, 0, l(t))) { |
46 | refID = parseInt(t.substring(1)); |
47 | i++; |
48 | } |
49 | final int _refID = refID; |
50 | |
51 | // if (debug) print("parse: " + quote(t)); |
52 | |
53 | final int tokIndex = i; |
54 | parse_inner(refID, tokIndex, new unstructure_Receiver { |
55 | void set(O o) { |
56 | if (_refID != 0) |
57 | refs.put(_refID, o); |
58 | if (o != null) |
59 | tokrefs.put(tokIndex, o); |
60 | out.set(o); |
61 | } |
62 | }); |
63 | } |
64 | |
65 | void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) { |
66 | S t = tok.get(i); |
67 | |
68 | // if (debug) print("parse_inner: " + quote(t)); |
69 | |
70 | Class c = classesMap.get(t); |
71 | if (c == null) { |
72 | if (t.startsWith("\"")) { |
73 | S s = internIfLongerThan(unquote(tok.get(i)), structure_internStringsLongerThan); |
74 | i++; |
75 | out.set(s); ret; |
76 | } |
77 | |
78 | if (t.startsWith("'")) { |
79 | out.set(unquoteCharacter(tok.get(i++))); ret; |
80 | } |
81 | if (t.equals("bigint")) { |
82 | out.set(parseBigInt()); ret; |
83 | } |
84 | if (t.equals("d")) { |
85 | out.set(parseDouble()); ret; |
86 | } |
87 | if (t.equals("fl")) { |
88 | out.set(parseFloat()); ret; |
89 | } |
90 | if (t.equals("false") || t.equals("f")) { |
91 | i++; out.set(false); ret; |
92 | } |
93 | if (t.equals("true") || t.equals("t")) { |
94 | i++; out.set(true); ret; |
95 | } |
96 | if (t.equals("-")) { |
97 | t = tok.get(i+1); |
98 | i += 2; |
99 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
100 | } |
101 | if (isInteger(t) || isLongConstant(t)) { |
102 | i++; |
103 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); |
104 | if (isLongConstant(t)) { |
105 | out.set(parseLong(t)); ret; |
106 | } |
107 | long l = parseLong(t); |
108 | bool isInt = l == (int) l; |
109 | if (debug) |
110 | print("l=" + l + ", isInt: " + isInt); |
111 | out.set(isInt ? (O) new Integer((int) l) : (O) new Long(l)); ret; |
112 | } |
113 | |
114 | if (t.equals("File")) { |
115 | File f = new File(unquote(tok.get(i+1))); |
116 | i += 2; |
117 | out.set(f); ret; |
118 | } |
119 | |
120 | if (t.startsWith("r") && isInteger(t.substring(1))) { |
121 | i++; |
122 | int ref = Integer.parseInt(t.substring(1)); |
123 | O o = refs.get(ref); |
124 | if (o == null) |
125 | print("Warning: unsatisfied back reference " + ref); |
126 | out.set(o); ret; |
127 | } |
128 | |
129 | if (t.startsWith("t") && isInteger(t.substring(1))) { |
130 | i++; |
131 | int ref = Integer.parseInt(t.substring(1)); |
132 | O o = tokrefs.get(ref); |
133 | if (o == null) |
134 | print("Warning: unsatisfied token reference " + ref); |
135 | out.set(o); ret; |
136 | } |
137 | |
138 | if (t.equals("hashset")) { |
139 | parseHashSet(out); ret; |
140 | } |
141 | if (t.equals("treeset")) { |
142 | parseTreeSet(out); ret; |
143 | } |
144 | if (eqOneOf(t, "hashmap", "hm")) { |
145 | parseHashMap(out); ret; |
146 | } |
147 | if (t.equals("{")) { |
148 | parseMap(out); ret; |
149 | } |
150 | if (t.equals("[")) { |
151 | parseList(out); ret; |
152 | } |
153 | if (t.equals("bitset")) { |
154 | parseBitSet(out); ret; |
155 | } |
156 | if (t.equals("array") || t.equals("intarray")) { |
157 | parseArray(out); ret; |
158 | } |
159 | if (t.equals("ba")) { |
160 | S hex = unquote(tok.get(i+1)); |
161 | i += 2; |
162 | out.set(hexToBytes(hex)); ret; |
163 | } |
164 | if (t.equals("boolarray")) { |
165 | int n = parseInt(tok.get(i+1)); |
166 | S hex = unquote(tok.get(i+2)); |
167 | i += 6; |
168 | out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret; |
169 | } |
170 | if (t.equals("class")) { |
171 | out.set(parseClass()); ret; |
172 | } |
173 | if (t.equals("l")) { |
174 | parseLisp(out); ret; |
175 | } |
176 | if (t.equals("null")) { |
177 | i++; out.set(null); ret; |
178 | } |
179 | |
180 | if (eq(t, "c")) { |
181 | consume("c"); |
182 | t = tok.get(i); |
183 | assertTrue(isJavaIdentifier(t)); |
184 | concepts.add(t); |
185 | } |
186 | } |
187 | |
188 | if (c == null && !isJavaIdentifier(t)) |
189 | throw new RuntimeException("Unknown token " + (i+1) + ": " + t); |
190 | |
191 | // any other class name |
192 | if (c == null) { |
193 | // First, find class |
194 | if (allDynamic) c = null; |
195 | else if (classFinder != null) |
196 | c = (Class) callF(classFinder, t); |
197 | else |
198 | c = findClass(t); |
199 | if (c != null) |
200 | classesMap.put(t, c); |
201 | } |
202 | |
203 | // Check if it has an outer reference |
204 | i++; |
205 | bool hasOuter = eq(get(tok, i), "(") && eq(get(tok, i+1), "this$1"); |
206 | |
207 | DynamicObject dO = null; |
208 | O o = null; |
209 | if (c != null) |
210 | o = hasOuter ? nuStubInnerObject(c) : nuEmptyObject(c); |
211 | else { |
212 | if (concepts.contains(t) && (c = findClass("Concept")) != null) |
213 | o = dO = (DynamicObject) nuEmptyObject(c); |
214 | else |
215 | dO = new DynamicObject; |
216 | dO.className = t; |
217 | if (debug) print("Made dynamic object " + t + " " + shortClassName(dO)); |
218 | } |
219 | |
220 | // Save in references list early because contents of object |
221 | // might link back to main object |
222 | |
223 | if (refID != 0) |
224 | refs.put(refID, o != null ? o : dO); |
225 | tokrefs.put(tokIndex, o != null ? o : dO); |
226 | |
227 | // NOW parse the fields! |
228 | |
229 | final new HashMap<S, O> fields; |
230 | final O _o = o; |
231 | final DynamicObject _dO = dO; |
232 | if (i < tok.size() && tok.get(i).equals("(")) { |
233 | consume("("); |
234 | stack.add(r { |
235 | if (tok.get(i).equals(")")) { |
236 | consume(")"); |
237 | objRead(_o, _dO, fields); |
238 | out.set(_o != null ? _o : _dO); |
239 | } else { |
240 | final S key = unquote(tok.get(i++)); |
241 | consume("="); |
242 | stack.add(this); |
243 | parse(new unstructure_Receiver { |
244 | void set(O value) { |
245 | fields.put(key, value); |
246 | if (tok.get(i).equals(",")) i++; |
247 | } |
248 | }); |
249 | } |
250 | }); |
251 | } else |
252 | objRead(o, dO, fields); |
253 | } |
254 | |
255 | void objRead(O o, DynamicObject dO, Map<S, O> fields) { |
256 | if (o != null) |
257 | if (dO != null) { |
258 | if (debug) |
259 | printStructure("setOptAllDyn", fields); |
260 | setOptAllDyn(dO, fields); |
261 | } else |
262 | setOptAll(o, fields); |
263 | else for (S field : keys(fields)) |
264 | dO.fieldValues.put(field.intern(), fields.get(field)); |
265 | |
266 | if (o != null) |
267 | pcallOpt_noArgs(o, "_doneLoading"); |
268 | } |
269 | |
270 | void parseSet(final Set set, final unstructure_Receiver out) { |
271 | parseList(new unstructure_Receiver { |
272 | void set(O o) { |
273 | set.addAll((L) o); |
274 | out.set(set); |
275 | } |
276 | }); |
277 | } |
278 | |
279 | void parseLisp(final unstructure_Receiver out) { |
280 | consume("l"); |
281 | consume("("); |
282 | final new ArrayList list; |
283 | stack.add(r { |
284 | if (tok.get(i).equals(")")) { |
285 | consume(")"); |
286 | out.set(newObject("main$Lisp", (S) list.get(0), subList(list, 1))); |
287 | } else { |
288 | stack.add(this); |
289 | parse(new unstructure_Receiver { |
290 | void set(O o) { |
291 | list.add(o); |
292 | if (tok.get(i).equals(",")) i++; |
293 | } |
294 | }); |
295 | } |
296 | }); |
297 | } |
298 | |
299 | void parseBitSet(final unstructure_Receiver out) { |
300 | consume("bitset"); |
301 | consume("{"); |
302 | final new BitSet bs; |
303 | stack.add(r { |
304 | if (tok.get(i).equals("}")) { |
305 | consume("}"); |
306 | out.set(bs); |
307 | } else { |
308 | stack.add(this); |
309 | parse(new unstructure_Receiver { |
310 | void set(O o) { |
311 | bs.set((Integer) o); |
312 | if (tok.get(i).equals(",")) i++; |
313 | } |
314 | }); |
315 | } |
316 | }); |
317 | } |
318 | |
319 | void parseList(final unstructure_Receiver out) { |
320 | consume("["); |
321 | final new ArrayList list; |
322 | stack.add(r { |
323 | if (tok.get(i).equals("]")) { |
324 | consume("]"); |
325 | out.set(list); |
326 | } else { |
327 | stack.add(this); |
328 | parse(new unstructure_Receiver { |
329 | void set(O o) { |
330 | //if (debug) print("List element type: " + getClassName(o)); |
331 | list.add(o); |
332 | if (tok.get(i).equals(",")) i++; |
333 | } |
334 | }); |
335 | } |
336 | }); |
337 | } |
338 | |
339 | void parseArray(final unstructure_Receiver out) { |
340 | final S type = tok.get(i); |
341 | i++; |
342 | consume("{"); |
343 | final List list = new ArrayList; |
344 | |
345 | stack.add(r { |
346 | if (tok.get(i).equals("}")) { |
347 | consume("}"); |
348 | out.set(type.equals("intarray") ? toIntArray(list) : list.toArray()); |
349 | } else { |
350 | stack.add(this); |
351 | parse(new unstructure_Receiver { |
352 | void set(O o) { |
353 | list.add(o); |
354 | if (tok.get(i).equals(",")) i++; |
355 | } |
356 | }); |
357 | } |
358 | }); |
359 | } |
360 | |
361 | Object parseClass() { |
362 | consume("class"); |
363 | consume("("); |
364 | S name = tok.get(i); |
365 | i++; |
366 | consume(")"); |
367 | Class c = allDynamic ? null : findClass(name); |
368 | if (c != null) ret c; |
369 | new DynamicObject dO; |
370 | dO.className = "java.lang.Class"; |
371 | dO.fieldValues.put("name", name); |
372 | ret dO; |
373 | } |
374 | |
375 | Object parseBigInt() { |
376 | consume("bigint"); |
377 | consume("("); |
378 | S val = tok.get(i); |
379 | i++; |
380 | if (eq(val, "-")) { |
381 | val = "-" + tok.get(i); |
382 | i++; |
383 | } |
384 | consume(")"); |
385 | ret new BigInteger(val); |
386 | } |
387 | |
388 | Object parseDouble() { |
389 | consume("d"); |
390 | consume("("); |
391 | S val = unquote(tok.get(i)); |
392 | i++; |
393 | consume(")"); |
394 | ret Double.parseDouble(val); |
395 | } |
396 | |
397 | Object parseFloat() { |
398 | consume("fl"); |
399 | S val; |
400 | if (eq(tok.get(i), "(")) { |
401 | consume("("); |
402 | val = unquote(tok.get(i)); |
403 | i++; |
404 | consume(")"); |
405 | } else { |
406 | val = unquote(tok.get(i)); |
407 | i++; |
408 | } |
409 | ret Float.parseFloat(val); |
410 | } |
411 | |
412 | void parseHashMap(unstructure_Receiver out) { |
413 | i++; |
414 | parseMap(new HashMap, out); |
415 | } |
416 | |
417 | void parseHashSet(unstructure_Receiver out) { |
418 | consume("hashset"); |
419 | parseSet(new HashSet, out); |
420 | } |
421 | |
422 | void parseTreeSet(unstructure_Receiver out) { |
423 | consume("treeset"); |
424 | parseSet(new TreeSet, out); |
425 | } |
426 | |
427 | void parseMap(unstructure_Receiver out) { |
428 | parseMap(new TreeMap, out); |
429 | } |
430 | |
431 | void parseMap(final Map map, final unstructure_Receiver out) { |
432 | consume("{"); |
433 | stack.add(new Runnable { |
434 | bool v; |
435 | O key; |
436 | |
437 | public void run() { |
438 | if (v) { |
439 | v = false; |
440 | stack.add(this); |
441 | consume("="); |
442 | parse(new unstructure_Receiver { |
443 | void set(O value) { |
444 | map.put(key, value); |
445 | if (debug) |
446 | print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(tok.get(i))); |
447 | if (tok.get(i).equals(",")) i++; |
448 | } |
449 | }); |
450 | } else { |
451 | if (tok.get(i).equals("}")) { |
452 | consume("}"); |
453 | out.set(map); |
454 | } else { |
455 | v = true; |
456 | stack.add(this); |
457 | parse(new unstructure_Receiver { |
458 | void set(O o) { |
459 | key = o; |
460 | } |
461 | }); |
462 | } |
463 | } // if v else |
464 | } // run() |
465 | }); |
466 | } |
467 | |
468 | /*void parseSub(unstructure_Receiver out) { |
469 | int n = l(stack); |
470 | parse(out); |
471 | while (l(stack) > n) |
472 | stack |
473 | }*/ |
474 | |
475 | void consume(String s) { |
476 | if (!tok.get(i).equals(s)) { |
477 | S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; |
478 | S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); |
479 | fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")"); |
480 | } |
481 | i++; |
482 | } |
483 | |
484 | void parse_x(unstructure_Receiver out) { |
485 | parse(out); |
486 | while (nempty(stack)) |
487 | popLast(stack).run(); |
488 | } |
489 | } |
490 | |
491 | final new Var v; |
492 | new X().parse_x(new unstructure_Receiver { |
493 | void set(O o) { v.set(o); } |
494 | }); |
495 | ret v.get(); |
496 | } |
497 | |
498 | static boolean unstructure_debug; |
Began life as a copy of #1005658
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1005973 |
Snippet name: | unstructure (v9, working virtual stack) |
Eternal ID of this version: | #1005973/1 |
Text MD5: | 412a9ac718f792869377c92067832700 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-12-13 18:20:20 |
Source code size: | 13925 bytes / 498 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 597 / 595 |
Referenced in: | [show references] |