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: | 605 / 747 |
| Version history: | 11 change(s) |
| Referenced in: | [show references] |