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