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