Transpiled version (11875L) is out of date.
1 | scope unstructure |
2 | |
3 | // TODO: cyclic structures involving certain lists & sets |
4 | |
5 | ifdef UseEclipseCollections |
6 | !include once #1027304 // Eclipse Collections |
7 | endifdef |
8 | |
9 | sO unstructure(String text) { |
10 | ret unstructure(text, false); |
11 | } |
12 | |
13 | sO unstructure(S text, bool allDynamic) { |
14 | ret unstructure(text, allDynamic, null); |
15 | } |
16 | |
17 | sO unstructure(S text, IF1<S, Class> classFinder) { |
18 | ret unstructure(text, false, classFinder); |
19 | } |
20 | |
21 | static int structure_internStringsLongerThan = 50; |
22 | static int unstructure_unquoteBufSize = 100; |
23 | |
24 | static int unstructure_tokrefs; // stats |
25 | |
26 | abstract sclass unstructure_Receiver { |
27 | abstract void set(O o); |
28 | } |
29 | |
30 | // classFinder: func(name) -> class (optional) |
31 | static Object unstructure(String text, boolean allDynamic, |
32 | O classFinder) { |
33 | if (text == null) ret null; |
34 | ret unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder); |
35 | } |
36 | |
37 | static O unstructure_reader(BufferedReader reader) { |
38 | ret unstructure_tok(javaTokC_noMLS_onReader(reader), false, null); |
39 | } |
40 | |
41 | interface #Handler { |
42 | void parse(int refID, int tokIndex, unstructure_Receiver out); |
43 | } |
44 | |
45 | sclass Unstructurer { |
46 | settable Producer<S> tok; |
47 | settable bool allDynamic; |
48 | int i = -1; |
49 | O classFinder; |
50 | S mcDollar = actualMCDollar(); |
51 | |
52 | selfType classFinder(O _classFinder) { |
53 | classFinder = _classFinder != null ? _classFinder : _defaultClassFinder(); |
54 | this; |
55 | } |
56 | |
57 | // use Eclipse primitive collection if possible (smaller & hopefully faster?) |
58 | ifdef UseEclipseCollections |
59 | new IntObjectHashMap<O> refs; |
60 | new IntObjectHashMap<O> tokrefs; |
61 | endifdef |
62 | ifndef UseEclipseCollections |
63 | new HashMap<Integer, O> refs; |
64 | new HashMap<Integer, O> tokrefs; |
65 | endifndef |
66 | |
67 | new HashSet<S> concepts; |
68 | new L<Runnable> stack; |
69 | new SS baseClassMap; |
70 | new HashMap<Class, Constructor> innerClassConstructors; |
71 | S curT; |
72 | char[] unquoteBuf = new char[unstructure_unquoteBufSize]; |
73 | |
74 | // value is a class or a Handler |
75 | final new HashMap<S, O> handlers; |
76 | |
77 | *() { |
78 | pcall { |
79 | Class mc = cast callF(classFinder, "<main>"); |
80 | if (mc != null) mcDollar = mc.getName() + "$"; |
81 | } |
82 | |
83 | makeHandlers(); |
84 | } |
85 | |
86 | replace HandlerArgs with (Handler) (refID, tokIndex, out). |
87 | |
88 | void makeHandlers { |
89 | Handler h; |
90 | |
91 | handlers.put("bigint", HandlerArgs |
92 | -> out.set(parseBigInt())); |
93 | |
94 | handlers.put("d", HandlerArgs |
95 | -> out.set(parseDouble())); |
96 | |
97 | handlers.put("fl", HandlerArgs |
98 | -> out.set(parseFloat())); |
99 | |
100 | handlers.put("sh", HandlerArgs -> { |
101 | consume(); |
102 | S t = tpp(); |
103 | if (t.equals("-")) { |
104 | t = tpp(); |
105 | out.set((short) (-parseInt(t)); ret; |
106 | } |
107 | out.set((short) parseInt(t)); |
108 | }); |
109 | |
110 | handlers.put("enum", HandlerArgs -> { |
111 | consume(); |
112 | S t = tpp(); |
113 | assertTrue(isJavaIdentifier(t)); |
114 | S fullClassName = mcDollar + t; |
115 | Class _c = findAClass(fullClassName); |
116 | if (_c == null) fail("Enum class not found: " + fullClassName); |
117 | int ordinal = parseInt(tpp()); |
118 | out.set(_c.getEnumConstants()[ordinal]); |
119 | }); |
120 | |
121 | handlers.put("false", h = HandlerArgs -> { |
122 | consume(); out.set(false); |
123 | }); |
124 | handlers.put("f", h); |
125 | |
126 | handlers.put("true", h = HandlerArgs -> { |
127 | consume(); out.set(true); |
128 | }); |
129 | handlers.put("t", h); |
130 | |
131 | handlers.put("{", HandlerArgs -> parseMap(out)); |
132 | |
133 | handlers.put("[", HandlerArgs -> { |
134 | new ArrayList l; |
135 | if (refID >= 0) refs.put(refID, l); |
136 | this.parseList(l, out); |
137 | }); |
138 | |
139 | handlers.put("bitset", HandlerArgs -> parseBitSet(out)); |
140 | |
141 | handlers.put("array", h = HandlerArgs -> parseArray(out)); |
142 | handlers.put("intarray", h); |
143 | handlers.put("dblarray", h); |
144 | handlers.put("floatarray", h); |
145 | |
146 | handlers.put("shortarray", HandlerArgs -> { |
147 | consume(); |
148 | S hex = trivialUnquote(tpp()); |
149 | out.set(shortArrayFromBytes(hexToBytes(hex))); |
150 | }); |
151 | |
152 | handlers.put("longarray", HandlerArgs -> { |
153 | consume(); |
154 | S hex = trivialUnquote(tpp()); |
155 | out.set(longArrayFromBytes(hexToBytes(hex))); |
156 | }); |
157 | } // end of makeHandlers - add more handlers here |
158 | |
159 | Class findAClass(S fullClassName) null on exception { |
160 | ret classFinder != null ? (Class) callF(classFinder, fullClassName) : findClass_fullName(fullClassName); |
161 | } |
162 | |
163 | S unquote(S s) { |
164 | ret unquoteUsingCharArray(s, unquoteBuf); |
165 | } |
166 | |
167 | // look at current token |
168 | S t() { |
169 | ret curT; |
170 | } |
171 | |
172 | // get current token, move to next |
173 | S tpp() { |
174 | S t = curT; |
175 | consume(); |
176 | ret t; |
177 | } |
178 | |
179 | void parse(final unstructure_Receiver out) { |
180 | S t = t(); |
181 | |
182 | int refID; |
183 | if (structure_isMarker(t, 0, l(t))) { |
184 | refID = parseInt(t.substring(1)); |
185 | consume(); |
186 | } else refID = -1; |
187 | |
188 | // if (debug) print("parse: " + quote(t)); |
189 | |
190 | final int tokIndex = i; |
191 | parse_inner(refID, tokIndex, new unstructure_Receiver { |
192 | void set(O o) { |
193 | if (refID >= 0) |
194 | refs.put(refID, o); |
195 | if (o != null) |
196 | tokrefs.put(tokIndex, o); |
197 | out.set(o); |
198 | } |
199 | }); |
200 | } |
201 | |
202 | void parse_inner(int refID, int tokIndex, unstructure_Receiver out) { |
203 | S t = t(); |
204 | |
205 | // if (debug) print("parse_inner: " + quote(t)); |
206 | |
207 | O handler = handlers.get(t); |
208 | if (handler cast Handler) |
209 | ret with handler.parse(refID, tokIndex, out); |
210 | |
211 | Class c = cast handler; |
212 | if (c == null) { |
213 | if (t.startsWith("\"")) { |
214 | S s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan); |
215 | out.set(s); ret; |
216 | } |
217 | |
218 | if (t.startsWith("'")) { |
219 | out.set(unquoteCharacter(tpp())); ret; |
220 | } |
221 | if (t.equals("-")) { |
222 | consume(); |
223 | t = tpp(); |
224 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
225 | } |
226 | if (isInteger(t) || isLongConstant(t)) { |
227 | consume(); |
228 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); |
229 | if (isLongConstant(t)) { |
230 | out.set(parseLong(t)); ret; |
231 | } |
232 | long l = parseLong(t); |
233 | bool isInt = l == (int) l; |
234 | ifdef unstructure_debug |
235 | print("l=" + l + ", isInt: " + isInt); |
236 | endifdef |
237 | out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret; |
238 | } |
239 | if (t.equals("-")) { |
240 | consume(); |
241 | t = tpp(); |
242 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
243 | } |
244 | if (isInteger(t) || isLongConstant(t)) { |
245 | consume(); |
246 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); |
247 | if (isLongConstant(t)) { |
248 | out.set(parseLong(t)); ret; |
249 | } |
250 | long l = parseLong(t); |
251 | bool isInt = l == (int) l; |
252 | ifdef unstructure_debug |
253 | print("l=" + l + ", isInt: " + isInt); |
254 | endifdef |
255 | out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret; |
256 | } |
257 | |
258 | if (t.equals("File")) { |
259 | consume(); |
260 | File f = new File(unquote(tpp())); |
261 | out.set(f); ret; |
262 | } |
263 | |
264 | if (t.startsWith("r") && isInteger(t.substring(1))) { |
265 | consume(); |
266 | int ref = Integer.parseInt(t.substring(1)); |
267 | O o = refs.get(ref); |
268 | if (o == null) |
269 | warn("unsatisfied back reference " + ref); |
270 | out.set(o); ret; |
271 | } |
272 | |
273 | if (t.startsWith("t") && isInteger(t.substring(1))) { |
274 | consume(); |
275 | int ref = Integer.parseInt(t.substring(1)); |
276 | O o = tokrefs.get(ref); |
277 | if (o == null) |
278 | warn("unsatisfied token reference " + ref + " at " + tokIndex); |
279 | out.set(o); ret; |
280 | } |
281 | |
282 | if (t.equals("hashset")) ret with parseHashSet(out); |
283 | if (t.equals("lhs")) ret with parseLinkedHashSet(out); |
284 | if (t.equals("treeset")) ret with parseTreeSet(out); |
285 | if (t.equals("ciset")) ret with parseCISet(out); |
286 | |
287 | if (eqOneOf(t, "hashmap", "hm")) { |
288 | consume(); |
289 | parseMap(new HashMap, out); |
290 | ret; |
291 | } |
292 | if (t.equals("lhm")) { |
293 | consume(); |
294 | parseMap(new LinkedHashMap, out); |
295 | ret; |
296 | } |
297 | if (t.equals("tm")) { |
298 | consume(); |
299 | parseMap(new TreeMap, out); |
300 | ret; |
301 | } |
302 | if (t.equals("cimap")) { |
303 | consume(); |
304 | parseMap(ciMap(), out); |
305 | ret; |
306 | } |
307 | |
308 | if (t.equals("ll")) { |
309 | consume(); |
310 | new LinkedList l; |
311 | if (refID >= 0) refs.put(refID, l); |
312 | ret with parseList(l, out); |
313 | } |
314 | |
315 | if (t.equals("syncLL")) { // legacy |
316 | consume(); |
317 | ret with parseList(synchroLinkedList(), out); |
318 | } |
319 | |
320 | if (t.equals("sync")) { |
321 | consume(); |
322 | ret with parse(new unstructure_Receiver { |
323 | void set(O value) { |
324 | if (value instanceof Map) { |
325 | ifndef Android // Java 7 |
326 | if (value cast NavigableMap) |
327 | ret with out.set(synchroNavigableMap(value); |
328 | endifndef |
329 | if (value cast SortedMap) |
330 | ret with out.set(synchroSortedMap(value); |
331 | ret with out.set(synchroMap((Map) value)); |
332 | } else |
333 | ret with out.set(synchroList((L) value); |
334 | } |
335 | }); |
336 | } |
337 | |
338 | if (t.equals("ba")) { |
339 | consume(); |
340 | S hex = trivialUnquote(tpp()); |
341 | out.set(hexToBytes(hex)); ret; |
342 | } |
343 | if (t.equals("boolarray")) { |
344 | consume(); |
345 | int n = parseInt(tpp()); |
346 | S hex = trivialUnquote(tpp()); |
347 | out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret; |
348 | } |
349 | if (t.equals("class")) { |
350 | out.set(parseClass()); ret; |
351 | } |
352 | if (t.equals("l")) { |
353 | parseLisp(out); ret; |
354 | } |
355 | if (t.equals("null")) { |
356 | consume(); out.set(null); ret; |
357 | } |
358 | |
359 | if (eq(t, "c")) { |
360 | consume(); |
361 | t = t(); |
362 | assertTrue(isJavaIdentifier(t)); |
363 | concepts.add(t); |
364 | } |
365 | |
366 | // custom deserialization (new static method method) |
367 | if (eq(t, "cu")) { |
368 | consume(); |
369 | t = tpp(); |
370 | assertTrue(isJavaIdentifier(t)); |
371 | S fullClassName = mcDollar + t; |
372 | Class _c = findAClass(fullClassName); |
373 | if (_c == null) fail("Class not found: " + fullClassName); |
374 | parse(new unstructure_Receiver { |
375 | void set(O value) { |
376 | ifdef unstructure_debug |
377 | print("Consumed custom object, next token: " + t()); |
378 | endifdef |
379 | out.set(call(_c, "_deserialize", value); |
380 | } |
381 | }); |
382 | ret; |
383 | } |
384 | } |
385 | |
386 | if (eq(t, "j")) { |
387 | consume(); |
388 | out.set(parseJava()); ret; |
389 | } |
390 | |
391 | if (eq(t, "bc")) { |
392 | consume(); |
393 | S c1 = tpp(); |
394 | S c2 = tpp(); |
395 | baseClassMap.put(c1, c2); |
396 | ret with parse_inner(refID, i, out); |
397 | } |
398 | |
399 | // add more tokens here |
400 | |
401 | // Now we want to find our target class c |
402 | // Have we failed to look up the class before? |
403 | //bool seenBefore = handlers.containsKey(cname); |
404 | |
405 | // If we have seen the class before, we skip all of this |
406 | // and simply leave c as null |
407 | // TODO - how do we fill className? |
408 | //if (!seenBefore) { |
409 | if (c == null && !isJavaIdentifier(t)) |
410 | throw new RuntimeException("Unknown token " + (i+1) + ": " + quote(t)); |
411 | |
412 | // any other class name (or package name) |
413 | consume(); |
414 | S className, fullClassName; |
415 | |
416 | // Is it a package name? |
417 | if (eq(t(), ".")) { |
418 | className = t; |
419 | do { |
420 | consume(); |
421 | className += "." + assertIdentifier(tpp()); |
422 | } while (eq(t(), ".")); |
423 | fullClassName = className; |
424 | } else { |
425 | className = t; |
426 | fullClassName = mcDollar + t; |
427 | } |
428 | |
429 | if (c == null && !allDynamic) { |
430 | // First, find class |
431 | c = findAClass(fullClassName); |
432 | handlers.put(className, c); |
433 | } |
434 | |
435 | // check for existing base class |
436 | if (c == null && !allDynamic) { |
437 | new Set<S> seen; |
438 | S parent = className; |
439 | while true { |
440 | S baseName = baseClassMap.get(parent); |
441 | if (baseName == null) |
442 | break; |
443 | if (!seen.add(baseName)) |
444 | fail("Cyclic superclass info: " + baseName); |
445 | c = findAClass(mcDollar + baseName); |
446 | if (c == null) |
447 | print("Base class " + baseName + " of " + parent + " doesn't exist either"); |
448 | else if (isAbstract(c)) |
449 | print("Can't instantiate abstract base class: " + c); |
450 | else { |
451 | printVars_str("Reverting to base class", +className, +baseName, +c); |
452 | handlers.put(className, c); |
453 | break; |
454 | } |
455 | parent = baseName; |
456 | } |
457 | } |
458 | //} |
459 | |
460 | // Check if it has an outer reference |
461 | bool hasBracket = eq(t(), "("); |
462 | if (hasBracket) consume(); |
463 | bool hasOuter = hasBracket && startsWith(t(), "this$"); |
464 | |
465 | DynamicObject dO = null; |
466 | O o = null; |
467 | fS thingName = t; |
468 | pcall { |
469 | if (c != null) { |
470 | if (hasOuter) try { |
471 | Constructor ctor = innerClassConstructors.get(c); |
472 | if (ctor == null) |
473 | innerClassConstructors.put(c, ctor = nuStubInnerObject_findConstructor(c, classFinder)); |
474 | o = ctor.newInstance(new O[] {null}); |
475 | } catch Exception e { |
476 | print("Error deserializing " + c + ": " + e); |
477 | o = nuEmptyObject(c); |
478 | } else |
479 | o = nuEmptyObject(c); |
480 | if (o instanceof DynamicObject) dO = (DynamicObject) o; |
481 | } else { |
482 | if (concepts.contains(t) && (c = findAClass(mcDollar + "Concept")) != null) |
483 | o = dO = (DynamicObject) nuEmptyObject(c); |
484 | else |
485 | dO = new DynamicObject; |
486 | dO.className = className; |
487 | ifdef unstructure_debug |
488 | print("Made dynamic object " + t + " " + shortClassName(dO)); |
489 | endifdef |
490 | } |
491 | } // end of pcall |
492 | |
493 | // Creating instance failed? Use DynamicObject |
494 | if (o == null && dO == null) |
495 | dO = new DynamicObject; |
496 | |
497 | // Save in references list early because contents of object |
498 | // might link back to main object |
499 | |
500 | if (refID >= 0) |
501 | refs.put(refID, o != null ? o : dO); |
502 | tokrefs.put(tokIndex, o != null ? o : dO); |
503 | |
504 | // NOW parse the fields! |
505 | |
506 | new /*Linked*/HashMap<S, O> fields; // no longer preserving order (why did we do this?) |
507 | O _o = o; |
508 | DynamicObject _dO = dO; |
509 | if (hasBracket) { |
510 | stack.add(r { |
511 | ifdef unstructure_debug |
512 | print("in object values, token: " + t()); |
513 | endifdef |
514 | if (eq(t(), ",")) consume(); |
515 | if (eq(t(), ")")) { |
516 | consume(")"); |
517 | objRead(_o, _dO, fields, hasOuter); |
518 | out.set(_o != null ? _o : _dO); |
519 | } else { |
520 | final S key = unquote(tpp()); |
521 | S t = tpp(); |
522 | if (!eq(t, "=")) |
523 | fail("= expected, got " + t + " after " + quote(key) + " in object " + thingName /*+ " " + sfu(fields)*/); |
524 | stack.add(this); |
525 | parse(new unstructure_Receiver { |
526 | void set(O value) { |
527 | fields.put(key, value); |
528 | /*ifdef unstructure_debug |
529 | print("Got field value " + value + ", next token: " + t()); |
530 | endifdef*/ |
531 | //if (eq(t(), ",")) consume(); |
532 | } |
533 | }); |
534 | } |
535 | }); |
536 | } else { |
537 | objRead(o, dO, fields, hasOuter); |
538 | out.set(o != null ? o : dO); |
539 | } |
540 | } |
541 | |
542 | void objRead(O o, DynamicObject dO, MapSO fields, bool hasOuter) { |
543 | ifdef unstructure_debug |
544 | print("objRead " + className(o) + " " + className(dO) + " " + struct(fields)); |
545 | endifdef |
546 | |
547 | // translate between diferent compilers (this$0 vs this$1) |
548 | O outer = fields.get("this$0"); |
549 | if (outer != null) fields.put("this$1", outer); |
550 | else { |
551 | outer = fields.get("this$1"); |
552 | if (outer != null) fields.put("this$0", outer); |
553 | } |
554 | |
555 | if (o != null) { |
556 | if (dO != null) { |
557 | ifdef unstructure_debug |
558 | printStructure("setOptAllDyn", fields); |
559 | endifdef |
560 | setOptAllDyn_pcall(dO, fields); |
561 | } else { |
562 | setOptAll_pcall(o, fields); |
563 | ifdef unstructure_debug |
564 | print("objRead now: " + struct(o)); |
565 | endifdef |
566 | } |
567 | if (hasOuter) |
568 | fixOuterRefs(o); |
569 | } else for (Map.Entry<S, O> e : fields.entrySet()) |
570 | setDynObjectValue(dO, intern(e.getKey()), e.getValue()); |
571 | |
572 | if (o != null) |
573 | pcallOpt_noArgs(o, "_doneLoading"); |
574 | } |
575 | |
576 | void parseSet(final Set set, final unstructure_Receiver out) { |
577 | this.parseList(new ArrayList, new unstructure_Receiver { |
578 | void set(O o) { |
579 | set.addAll((L) o); |
580 | out.set(set); |
581 | } |
582 | }); |
583 | } |
584 | |
585 | void parseLisp(final unstructure_Receiver out) { |
586 | ifclass Lisp |
587 | consume("l"); |
588 | consume("("); |
589 | final new ArrayList list; |
590 | stack.add(r { |
591 | if (eq(t(), ")")) { |
592 | consume(")"); |
593 | out.set(Lisp((S) list.get(0), subList(list, 1))); |
594 | } else { |
595 | stack.add(this); |
596 | parse(new unstructure_Receiver { |
597 | void set(O o) { |
598 | list.add(o); |
599 | if (eq(t(), ",")) consume(); |
600 | } |
601 | }); |
602 | } |
603 | }); |
604 | if (false) // skip fail line |
605 | endif |
606 | |
607 | fail("class Lisp not included"); |
608 | } |
609 | |
610 | void parseBitSet(final unstructure_Receiver out) { |
611 | consume("bitset"); |
612 | consume("{"); |
613 | final new BitSet bs; |
614 | stack.add(r { |
615 | if (eq(t(), "}")) { |
616 | consume("}"); |
617 | out.set(bs); |
618 | } else { |
619 | stack.add(this); |
620 | parse(new unstructure_Receiver { |
621 | void set(O o) { |
622 | bs.set((Integer) o); |
623 | if (eq(t(), ",")) consume(); |
624 | } |
625 | }); |
626 | } |
627 | }); |
628 | } |
629 | |
630 | void parseList(final L list, final unstructure_Receiver out) { |
631 | tokrefs.put(i, list); |
632 | consume("["); |
633 | stack.add(r { |
634 | if (eq(t(), "]")) { |
635 | consume(); |
636 | ifdef unstructure_debug |
637 | print("Consumed list, next token: " + t()); |
638 | endifdef |
639 | out.set(list); |
640 | } else { |
641 | stack.add(this); |
642 | parse(new unstructure_Receiver { |
643 | void set(O o) { |
644 | //if (debug) print("List element type: " + getClassName(o)); |
645 | list.add(o); |
646 | if (eq(t(), ",")) consume(); |
647 | } |
648 | }); |
649 | } |
650 | }); |
651 | } |
652 | |
653 | void parseArray(unstructure_Receiver out) { |
654 | S _type = tpp(); |
655 | int dims; |
656 | |
657 | if (eq(t(), "S")) { // string array |
658 | _type = "S"; |
659 | consume(); |
660 | } |
661 | |
662 | if (eq(t(), "/")) { // multi-dimensional array |
663 | consume(); |
664 | dims = parseInt(tpp()); |
665 | } else |
666 | dims = 1; |
667 | |
668 | consume("{"); |
669 | List list = new ArrayList; |
670 | S type = _type; |
671 | |
672 | stack.add(r { |
673 | if (eq(t(), "}")) { |
674 | consume("}"); |
675 | if (dims > 1) { |
676 | Class atype; |
677 | if (type.equals("intarray")) atype = int.class; |
678 | else if (type.equals("S")) atype = S.class; |
679 | else todo("multi-dimensional arrays of other types"); |
680 | |
681 | out.set(list.toArray((O[]) newMultiDimensionalOuterArray(atype, dims, l(list)))); |
682 | } else |
683 | out.set( |
684 | type.equals("intarray") ? toIntArray(list) |
685 | : type.equals("dblarray") ? toDoubleArray(list) |
686 | : type.equals("floatarray") ? toFloatArray(list) |
687 | : type.equals("S") ? toStringArray(list) |
688 | : list.toArray()); |
689 | } else { |
690 | stack.add(this); |
691 | parse(new unstructure_Receiver { |
692 | void set(O o) { |
693 | list.add(o); |
694 | if (eq(t(), ",")) consume(); |
695 | } |
696 | }); |
697 | } |
698 | }); |
699 | } |
700 | |
701 | Object parseClass() { |
702 | consume("class"); |
703 | consume("("); |
704 | S name = unquote(tpp()); |
705 | consume(")"); |
706 | Class c = allDynamic ? null : findAClass(name); |
707 | if (c != null) ret c; |
708 | new DynamicObject dO; |
709 | dO.className = "java.lang.Class"; |
710 | name = dropPrefix(mcDollar, name); |
711 | dynamicObject_setRawFieldValue(dO, +name); |
712 | ret dO; |
713 | } |
714 | |
715 | Object parseBigInt() { |
716 | consume("bigint"); |
717 | consume("("); |
718 | S val = tpp(); |
719 | if (eq(val, "-")) |
720 | val = "-" + tpp(); |
721 | consume(")"); |
722 | ret new BigInteger(val); |
723 | } |
724 | |
725 | Object parseDouble() { |
726 | consume("d"); |
727 | consume("("); |
728 | S val = unquote(tpp()); |
729 | consume(")"); |
730 | ret Double.parseDouble(val); |
731 | } |
732 | |
733 | Object parseFloat() { |
734 | consume("fl"); |
735 | S val; |
736 | if (eq(t(), "(")) { |
737 | consume("("); |
738 | val = unquote(tpp()); |
739 | consume(")"); |
740 | } else { |
741 | val = unquote(tpp()); |
742 | } |
743 | ret Float.parseFloat(val); |
744 | } |
745 | |
746 | void parseHashSet(unstructure_Receiver out) { |
747 | consume("hashset"); |
748 | parseSet(new HashSet, out); |
749 | } |
750 | |
751 | void parseLinkedHashSet(unstructure_Receiver out) { |
752 | consume("lhs"); |
753 | parseSet(new LinkedHashSet, out); |
754 | } |
755 | |
756 | void parseTreeSet(unstructure_Receiver out) { |
757 | consume("treeset"); |
758 | parseSet(new TreeSet, out); |
759 | } |
760 | |
761 | void parseCISet(unstructure_Receiver out) { |
762 | consume("ciset"); |
763 | parseSet(ciSet(), out); |
764 | } |
765 | |
766 | void parseMap(unstructure_Receiver out) { |
767 | parseMap(new TreeMap, out); |
768 | } |
769 | |
770 | O parseJava() { |
771 | S j = unquote(tpp()); |
772 | new Matches m; |
773 | if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m)) |
774 | ret nuObject("java.awt.Color", parseInt($1), parseInt($2), parseInt($3)); |
775 | else { |
776 | warn("Unknown Java object: " + j); |
777 | null; |
778 | } |
779 | } |
780 | |
781 | void parseMap(final Map map, final unstructure_Receiver out) { |
782 | consume("{"); |
783 | stack.add(new Runnable { |
784 | bool v; |
785 | O key; |
786 | |
787 | public void run() { |
788 | if (v) { |
789 | v = false; |
790 | stack.add(this); |
791 | if (!eq(tpp(), "=")) |
792 | fail("= expected, got " + t() + " in map of size " + l(map)); |
793 | |
794 | parse(new unstructure_Receiver { |
795 | void set(O value) { |
796 | map.put(key, value); |
797 | ifdef unstructure_debug |
798 | print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(t())); |
799 | endifdef |
800 | if (eq(t(), ",")) consume(); |
801 | } |
802 | }); |
803 | } else { |
804 | if (eq(t(), "}")) { |
805 | consume("}"); |
806 | out.set(map); |
807 | } else { |
808 | v = true; |
809 | stack.add(this); |
810 | parse(new unstructure_Receiver { |
811 | void set(O o) { |
812 | key = o; |
813 | } |
814 | }); |
815 | } |
816 | } // if v else |
817 | } // run() |
818 | }); |
819 | } |
820 | |
821 | /*void parseSub(unstructure_Receiver out) { |
822 | int n = l(stack); |
823 | parse(out); |
824 | while (l(stack) > n) |
825 | stack |
826 | }*/ |
827 | |
828 | void consume() { curT = tok.next(); ++i; } |
829 | |
830 | void consume(S s) { |
831 | if (!eq(t(), s)) { |
832 | /*S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; |
833 | S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); |
834 | fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");*/ |
835 | fail(quote(s) + " expected, got " + quote(t())); |
836 | } |
837 | consume(); |
838 | } |
839 | |
840 | // outer wrapper function getting first token and unwinding the stack |
841 | void parse_initial(unstructure_Receiver out) { |
842 | consume(); // get first token |
843 | parse(out); |
844 | while (nempty(stack)) |
845 | popLast(stack).run(); |
846 | } |
847 | } |
848 | |
849 | sO unstructure_tok(Producer<S> tok, bool allDynamic, O classFinder) { |
850 | bool debug = unstructure_debug; |
851 | temp tempSetTL(dynamicObjectIsLoading_threadLocal(), true); |
852 | new Var v; |
853 | var unstructurer = new Unstructurer() |
854 | .tok(tok) |
855 | .allDynamic(allDynamic) |
856 | .classFinder(classFinder); |
857 | unstructurer.parse_initial(new unstructure_Receiver { |
858 | void set(O o) { v.set(o); } |
859 | }); |
860 | unstructure_tokrefs = unstructurer.tokrefs.size(); |
861 | ret v!; |
862 | } |
863 | |
864 | static boolean unstructure_debug; |
Began life as a copy of #1035484
download show line numbers debug dex old transpilations
Travelled to 1 computer(s): mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1035798 |
Snippet name: | unstructure (v20, introducing the Unstructurer class, LIVE) |
Eternal ID of this version: | #1035798/12 |
Text MD5: | c922d06d23970887ad522d3f99d34836 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-03-20 20:54:33 |
Source code size: | 24347 bytes / 864 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 230 / 305 |
Version history: | 11 change(s) |
Referenced in: | [show references] |