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