Libraryless. Click here for Pure Java version (4392L/27K).
1 | static Object unstructure(String text) {
|
2 | ret unstructure(text, false); |
3 | } |
4 | |
5 | static Object unstructure(String text, final boolean allDynamic) {
|
6 | ret unstructure(text, allDynamic, null); |
7 | } |
8 | |
9 | static int structure_internStringsLongerThan = 50; |
10 | static int unstructure_unquoteBufSize = 100; |
11 | |
12 | static int unstructure_tokrefs; // stats |
13 | |
14 | abstract sclass unstructure_Receiver {
|
15 | abstract void set(O o); |
16 | } |
17 | |
18 | // classFinder: func(name) -> class (optional) |
19 | static Object unstructure(String text, boolean allDynamic, |
20 | O classFinder) {
|
21 | if (text == null) ret null; |
22 | ret unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder); |
23 | } |
24 | |
25 | static O unstructure_reader(BufferedReader reader) {
|
26 | ret unstructure_tok(javaTokC_noMLS_onReader(reader), false, null); |
27 | } |
28 | |
29 | static O unstructure_tok(final Producer<S> tok, final boolean allDynamic, final O _classFinder) {
|
30 | final boolean debug = unstructure_debug; |
31 | |
32 | final class X {
|
33 | int i = -1; |
34 | final O classFinder = _classFinder != null ? _classFinder : _defaultClassFinder(); |
35 | new HashMap<Integer, O> refs; |
36 | new HashMap<Integer, O> tokrefs; |
37 | new HashSet<S> concepts; |
38 | new HashMap<S, Class> classesMap; |
39 | new L<Runnable> stack; |
40 | S curT; |
41 | char[] unquoteBuf = new char[unstructure_unquoteBufSize]; |
42 | |
43 | S unquote(S s) {
|
44 | ret unquoteUsingCharArray(s, unquoteBuf); |
45 | } |
46 | |
47 | // look at current token |
48 | S t() {
|
49 | ret curT; |
50 | } |
51 | |
52 | // get current token, move to next |
53 | S tpp() {
|
54 | S t = curT; |
55 | consume(); |
56 | ret t; |
57 | } |
58 | |
59 | void parse(final unstructure_Receiver out) {
|
60 | S t = t(); |
61 | |
62 | int refID = 0; |
63 | if (structure_isMarker(t, 0, l(t))) {
|
64 | refID = parseInt(t.substring(1)); |
65 | consume(); |
66 | } |
67 | final int _refID = refID; |
68 | |
69 | // if (debug) print("parse: " + quote(t));
|
70 | |
71 | final int tokIndex = i; |
72 | parse_inner(refID, tokIndex, new unstructure_Receiver {
|
73 | void set(O o) {
|
74 | if (_refID != 0) |
75 | refs.put(_refID, o); |
76 | if (o != null) |
77 | tokrefs.put(tokIndex, o); |
78 | out.set(o); |
79 | } |
80 | }); |
81 | } |
82 | |
83 | void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) {
|
84 | S t = t(); |
85 | |
86 | // if (debug) print("parse_inner: " + quote(t));
|
87 | |
88 | Class c = classesMap.get(t); |
89 | if (c == null) {
|
90 | if (t.startsWith("\"")) {
|
91 | S s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan); |
92 | out.set(s); ret; |
93 | } |
94 | |
95 | if (t.startsWith("'")) {
|
96 | out.set(unquoteCharacter(tpp())); ret; |
97 | } |
98 | if (t.equals("bigint")) {
|
99 | out.set(parseBigInt()); ret; |
100 | } |
101 | if (t.equals("d")) {
|
102 | out.set(parseDouble()); ret; |
103 | } |
104 | if (t.equals("fl")) {
|
105 | out.set(parseFloat()); ret; |
106 | } |
107 | if (t.equals("sh")) {
|
108 | consume(); |
109 | t = tpp(); |
110 | if (t.equals("-")) {
|
111 | t = tpp(); |
112 | out.set((short) (-parseInt(t)); ret; |
113 | } |
114 | out.set((short) parseInt(t)); ret; |
115 | } |
116 | if (t.equals("-")) {
|
117 | consume(); |
118 | t = tpp(); |
119 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
120 | } |
121 | if (isInteger(t) || isLongConstant(t)) {
|
122 | consume(); |
123 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
|
124 | if (isLongConstant(t)) {
|
125 | out.set(parseLong(t)); ret; |
126 | } |
127 | long l = parseLong(t); |
128 | bool isInt = l == (int) l; |
129 | ifdef unstructure_debug |
130 | print("l=" + l + ", isInt: " + isInt);
|
131 | endifdef |
132 | out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret; |
133 | } |
134 | if (t.equals("false") || t.equals("f")) {
|
135 | consume(); out.set(false); ret; |
136 | } |
137 | if (t.equals("true") || t.equals("t")) {
|
138 | consume(); out.set(true); ret; |
139 | } |
140 | if (t.equals("-")) {
|
141 | consume(); |
142 | t = tpp(); |
143 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
144 | } |
145 | if (isInteger(t) || isLongConstant(t)) {
|
146 | consume(); |
147 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
|
148 | if (isLongConstant(t)) {
|
149 | out.set(parseLong(t)); ret; |
150 | } |
151 | long l = parseLong(t); |
152 | bool isInt = l == (int) l; |
153 | ifdef unstructure_debug |
154 | print("l=" + l + ", isInt: " + isInt);
|
155 | endifdef |
156 | out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret; |
157 | } |
158 | |
159 | if (t.equals("File")) {
|
160 | consume(); |
161 | File f = new File(unquote(tpp())); |
162 | out.set(f); ret; |
163 | } |
164 | |
165 | if (t.startsWith("r") && isInteger(t.substring(1))) {
|
166 | consume(); |
167 | int ref = Integer.parseInt(t.substring(1)); |
168 | O o = refs.get(ref); |
169 | if (o == null) |
170 | fail("unsatisfied back reference " + ref);
|
171 | out.set(o); ret; |
172 | } |
173 | |
174 | if (t.startsWith("t") && isInteger(t.substring(1))) {
|
175 | consume(); |
176 | int ref = Integer.parseInt(t.substring(1)); |
177 | O o = tokrefs.get(ref); |
178 | if (o == null) |
179 | fail("unsatisfied token reference " + ref + " at " + tokIndex);
|
180 | out.set(o); ret; |
181 | } |
182 | |
183 | if (t.equals("hashset")) ret with parseHashSet(out);
|
184 | if (t.equals("lhs")) ret with parseLinkedHashSet(out);
|
185 | if (t.equals("treeset")) ret with parseTreeSet(out);
|
186 | if (t.equals("ciset")) ret with parseCISet(out);
|
187 | |
188 | if (eqOneOf(t, "hashmap", "hm")) {
|
189 | consume(); |
190 | parseMap(new HashMap, out); |
191 | ret; |
192 | } |
193 | if (t.equals("lhm")) {
|
194 | consume(); |
195 | parseMap(new LinkedHashMap, out); |
196 | ret; |
197 | } |
198 | if (t.equals("tm")) {
|
199 | consume(); |
200 | parseMap(new TreeMap, out); |
201 | ret; |
202 | } |
203 | if (t.equals("cimap")) {
|
204 | consume(); |
205 | parseMap(ciMap(), out); |
206 | ret; |
207 | } |
208 | |
209 | if (t.equals("ll")) {
|
210 | consume(); |
211 | ret with parseList(new LinkedList, out); |
212 | } |
213 | |
214 | if (t.equals("syncLL")) {
|
215 | consume(); |
216 | ret with parseList(synchroLinkedList(), out); |
217 | } |
218 | |
219 | if (t.equals("sync")) {
|
220 | consume(); |
221 | if (t().equals("tm")) {
|
222 | consume(); |
223 | ret with parseMap(synchronizedTreeMap(), out); |
224 | } |
225 | if (t().equals("["))
|
226 | ret with parseList(synchroList(), out); |
227 | ret with parseMap(synchronizedMap(), out); |
228 | } |
229 | if (t.equals("{")) {
|
230 | parseMap(out); ret; |
231 | } |
232 | if (t.equals("[")) {
|
233 | this.parseList(new ArrayList, out); ret; |
234 | } |
235 | if (t.equals("bitset")) {
|
236 | parseBitSet(out); ret; |
237 | } |
238 | if (t.equals("array") || t.equals("intarray")) {
|
239 | parseArray(out); ret; |
240 | } |
241 | if (t.equals("ba")) {
|
242 | consume(); |
243 | S hex = unquote(tpp()); |
244 | out.set(hexToBytes(hex)); ret; |
245 | } |
246 | if (t.equals("boolarray")) {
|
247 | consume(); |
248 | int n = parseInt(tpp()); |
249 | S hex = unquote(tpp()); |
250 | out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret; |
251 | } |
252 | if (t.equals("class")) {
|
253 | out.set(parseClass()); ret; |
254 | } |
255 | if (t.equals("l")) {
|
256 | parseLisp(out); ret; |
257 | } |
258 | if (t.equals("null")) {
|
259 | consume(); out.set(null); ret; |
260 | } |
261 | |
262 | if (eq(t, "c")) {
|
263 | consume("c");
|
264 | t = t(); |
265 | assertTrue(isJavaIdentifier(t)); |
266 | concepts.add(t); |
267 | } |
268 | } |
269 | |
270 | if (eq(t, "j")) {
|
271 | consume("j");
|
272 | out.set(parseJava()); ret; |
273 | } |
274 | |
275 | if (c == null && !isJavaIdentifier(t)) |
276 | throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
|
277 | |
278 | // any other class name (or package name) |
279 | consume(); |
280 | S className, fullClassName; |
281 | |
282 | // Is it a package name? |
283 | if (eq(t(), ".")) {
|
284 | consume(); |
285 | className = fullClassName = t + "." + assertIdentifier(tpp()); |
286 | } else {
|
287 | className = t; |
288 | fullClassName = "main$" + t; |
289 | } |
290 | |
291 | if (c == null) {
|
292 | // First, find class |
293 | if (allDynamic) c = null; |
294 | else c = classFinder != null ? (Class) callF(classFinder, fullClassName) : findClass_fullName(fullClassName); |
295 | if (c != null) |
296 | classesMap.put(className, c); |
297 | } |
298 | |
299 | // Check if it has an outer reference |
300 | bool hasBracket = eq(t(), "(");
|
301 | if (hasBracket) consume(); |
302 | bool hasOuter = hasBracket && eq(t(), "this$1"); |
303 | |
304 | DynamicObject dO = null; |
305 | O o = null; |
306 | fS thingName = t; |
307 | if (c != null) {
|
308 | o = hasOuter ? nuStubInnerObject(c, classFinder) : nuEmptyObject(c); |
309 | if (o instanceof DynamicObject) dO = (DynamicObject) o; |
310 | } else {
|
311 | if (concepts.contains(t) && (c = findClass("Concept")) != null)
|
312 | o = dO = (DynamicObject) nuEmptyObject(c); |
313 | else |
314 | dO = new DynamicObject; |
315 | dO.className = className; |
316 | ifdef unstructure_debug |
317 | print("Made dynamic object " + t + " " + shortClassName(dO));
|
318 | endifdef |
319 | } |
320 | |
321 | // Save in references list early because contents of object |
322 | // might link back to main object |
323 | |
324 | if (refID != 0) |
325 | refs.put(refID, o != null ? o : dO); |
326 | tokrefs.put(tokIndex, o != null ? o : dO); |
327 | |
328 | // NOW parse the fields! |
329 | |
330 | final new LinkedHashMap<S, O> fields; // preserve order |
331 | final O _o = o; |
332 | final DynamicObject _dO = dO; |
333 | if (hasBracket) {
|
334 | stack.add(r {
|
335 | if (eq(t(), ")")) {
|
336 | consume(")");
|
337 | objRead(_o, _dO, fields); |
338 | out.set(_o != null ? _o : _dO); |
339 | } else {
|
340 | final S key = unquote(tpp()); |
341 | if (!eq(tpp(), "=")) |
342 | fail("= expected, got " + t() + " after " + quote(key) + " in object " + thingName /*+ " " + sfu(fields)*/);
|
343 | stack.add(this); |
344 | parse(new unstructure_Receiver {
|
345 | void set(O value) {
|
346 | fields.put(key, value); |
347 | if (eq(t(), ",")) consume(); |
348 | } |
349 | }); |
350 | } |
351 | }); |
352 | } else {
|
353 | objRead(o, dO, fields); |
354 | out.set(o != null ? o : dO); |
355 | } |
356 | } |
357 | |
358 | void objRead(O o, DynamicObject dO, Map<S, O> fields) {
|
359 | ifdef unstructure_debug |
360 | print("objRead " + className(o) + " " + className(dO) + " " + struct(fields));
|
361 | endifdef |
362 | if (o != null) |
363 | if (dO != null) {
|
364 | ifdef unstructure_debug |
365 | printStructure("setOptAllDyn", fields);
|
366 | endifdef |
367 | setOptAllDyn(dO, fields); |
368 | } else {
|
369 | setOptAll_pcall(o, fields); |
370 | ifdef unstructure_debug |
371 | print("objRead now: " + struct(o));
|
372 | endifdef |
373 | } |
374 | else for (Map.Entry<S, O> e : fields.entrySet()) |
375 | setDynObjectValue(dO, intern(e.getKey()), e.getValue()); |
376 | |
377 | if (o != null) |
378 | pcallOpt_noArgs(o, "_doneLoading"); |
379 | } |
380 | |
381 | void parseSet(final Set set, final unstructure_Receiver out) {
|
382 | this.parseList(new ArrayList, new unstructure_Receiver {
|
383 | void set(O o) {
|
384 | set.addAll((L) o); |
385 | out.set(set); |
386 | } |
387 | }); |
388 | } |
389 | |
390 | void parseLisp(final unstructure_Receiver out) {
|
391 | ifclass Lisp |
392 | consume("l");
|
393 | consume("(");
|
394 | final new ArrayList list; |
395 | stack.add(r {
|
396 | if (eq(t(), ")")) {
|
397 | consume(")");
|
398 | out.set(Lisp((S) list.get(0), subList(list, 1))); |
399 | } else {
|
400 | stack.add(this); |
401 | parse(new unstructure_Receiver {
|
402 | void set(O o) {
|
403 | list.add(o); |
404 | if (eq(t(), ",")) consume(); |
405 | } |
406 | }); |
407 | } |
408 | }); |
409 | if (false) // skip fail line |
410 | endif |
411 | |
412 | fail("class Lisp not included");
|
413 | } |
414 | |
415 | void parseBitSet(final unstructure_Receiver out) {
|
416 | consume("bitset");
|
417 | consume("{");
|
418 | final new BitSet bs; |
419 | stack.add(r {
|
420 | if (eq(t(), "}")) {
|
421 | consume("}");
|
422 | out.set(bs); |
423 | } else {
|
424 | stack.add(this); |
425 | parse(new unstructure_Receiver {
|
426 | void set(O o) {
|
427 | bs.set((Integer) o); |
428 | if (eq(t(), ",")) consume(); |
429 | } |
430 | }); |
431 | } |
432 | }); |
433 | } |
434 | |
435 | void parseList(final L list, final unstructure_Receiver out) {
|
436 | consume("[");
|
437 | stack.add(r {
|
438 | if (eq(t(), "]")) {
|
439 | consume("]");
|
440 | out.set(list); |
441 | } else {
|
442 | stack.add(this); |
443 | parse(new unstructure_Receiver {
|
444 | void set(O o) {
|
445 | //if (debug) print("List element type: " + getClassName(o));
|
446 | list.add(o); |
447 | if (eq(t(), ",")) consume(); |
448 | } |
449 | }); |
450 | } |
451 | }); |
452 | } |
453 | |
454 | void parseArray(final unstructure_Receiver out) {
|
455 | final S type = tpp(); |
456 | consume("{");
|
457 | final List list = new ArrayList; |
458 | |
459 | stack.add(r {
|
460 | if (eq(t(), "}")) {
|
461 | consume("}");
|
462 | out.set(type.equals("intarray") ? toIntArray(list) : list.toArray());
|
463 | } else {
|
464 | stack.add(this); |
465 | parse(new unstructure_Receiver {
|
466 | void set(O o) {
|
467 | list.add(o); |
468 | if (eq(t(), ",")) consume(); |
469 | } |
470 | }); |
471 | } |
472 | }); |
473 | } |
474 | |
475 | Object parseClass() {
|
476 | consume("class");
|
477 | consume("(");
|
478 | S name = unquote(tpp()); |
479 | consume(")");
|
480 | Class c = allDynamic ? null : classFinder != null ? (Class) callF(classFinder, name) : findClass_fullName(name); |
481 | if (c != null) ret c; |
482 | new DynamicObject dO; |
483 | dO.className = "java.lang.Class"; |
484 | name = dropPrefix("main$", name);
|
485 | dO.fieldValues.put("name", name);
|
486 | ret dO; |
487 | } |
488 | |
489 | Object parseBigInt() {
|
490 | consume("bigint");
|
491 | consume("(");
|
492 | S val = tpp(); |
493 | if (eq(val, "-")) |
494 | val = "-" + tpp(); |
495 | consume(")");
|
496 | ret new BigInteger(val); |
497 | } |
498 | |
499 | Object parseDouble() {
|
500 | consume("d");
|
501 | consume("(");
|
502 | S val = unquote(tpp()); |
503 | consume(")");
|
504 | ret Double.parseDouble(val); |
505 | } |
506 | |
507 | Object parseFloat() {
|
508 | consume("fl");
|
509 | S val; |
510 | if (eq(t(), "(")) {
|
511 | consume("(");
|
512 | val = unquote(tpp()); |
513 | consume(")");
|
514 | } else {
|
515 | val = unquote(tpp()); |
516 | } |
517 | ret Float.parseFloat(val); |
518 | } |
519 | |
520 | void parseHashSet(unstructure_Receiver out) {
|
521 | consume("hashset");
|
522 | parseSet(new HashSet, out); |
523 | } |
524 | |
525 | void parseLinkedHashSet(unstructure_Receiver out) {
|
526 | consume("lhs");
|
527 | parseSet(new LinkedHashSet, out); |
528 | } |
529 | |
530 | void parseTreeSet(unstructure_Receiver out) {
|
531 | consume("treeset");
|
532 | parseSet(new TreeSet, out); |
533 | } |
534 | |
535 | void parseCISet(unstructure_Receiver out) {
|
536 | consume("ciset");
|
537 | parseSet(ciSet(), out); |
538 | } |
539 | |
540 | void parseMap(unstructure_Receiver out) {
|
541 | parseMap(new TreeMap, out); |
542 | } |
543 | |
544 | O parseJava() {
|
545 | S j = unquote(tpp()); |
546 | new Matches m; |
547 | if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m))
|
548 | ret nuObject("java.awt.Color", parseInt($1), parseInt($2), parseInt($3));
|
549 | else {
|
550 | warn("Unknown Java object: " + j);
|
551 | null; |
552 | } |
553 | } |
554 | |
555 | void parseMap(final Map map, final unstructure_Receiver out) {
|
556 | consume("{");
|
557 | stack.add(new Runnable {
|
558 | bool v; |
559 | O key; |
560 | |
561 | public void run() {
|
562 | if (v) {
|
563 | v = false; |
564 | stack.add(this); |
565 | if (!eq(tpp(), "=")) |
566 | fail("= expected, got " + t() + " in map of size " + l(map));
|
567 | |
568 | parse(new unstructure_Receiver {
|
569 | void set(O value) {
|
570 | map.put(key, value); |
571 | ifdef unstructure_debug |
572 | print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(t()));
|
573 | endifdef |
574 | if (eq(t(), ",")) consume(); |
575 | } |
576 | }); |
577 | } else {
|
578 | if (eq(t(), "}")) {
|
579 | consume("}");
|
580 | out.set(map); |
581 | } else {
|
582 | v = true; |
583 | stack.add(this); |
584 | parse(new unstructure_Receiver {
|
585 | void set(O o) {
|
586 | key = o; |
587 | } |
588 | }); |
589 | } |
590 | } // if v else |
591 | } // run() |
592 | }); |
593 | } |
594 | |
595 | /*void parseSub(unstructure_Receiver out) {
|
596 | int n = l(stack); |
597 | parse(out); |
598 | while (l(stack) > n) |
599 | stack |
600 | }*/ |
601 | |
602 | void consume() { curT = tok.next(); ++i; }
|
603 | |
604 | void consume(S s) {
|
605 | if (!eq(t(), s)) {
|
606 | /*S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; |
607 | S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); |
608 | fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");*/
|
609 | fail(quote(s) + " expected, got " + quote(t())); |
610 | } |
611 | consume(); |
612 | } |
613 | |
614 | void parse_x(unstructure_Receiver out) {
|
615 | consume(); // get first token |
616 | parse(out); |
617 | while (nempty(stack)) |
618 | popLast(stack).run(); |
619 | } |
620 | } |
621 | |
622 | Bool b = DynamicObject_loading!; |
623 | DynamicObject_loading.set(true); |
624 | try {
|
625 | final new Var v; |
626 | new X x; |
627 | x.parse_x(new unstructure_Receiver {
|
628 | void set(O o) { v.set(o); }
|
629 | }); |
630 | unstructure_tokrefs = x.tokrefs.size(); |
631 | ret v.get(); |
632 | } finally {
|
633 | DynamicObject_loading.set(b); |
634 | } |
635 | } |
636 | |
637 | static boolean unstructure_debug; |
Began life as a copy of #1005980
download show line numbers debug dex old transpilations
Travelled to 10 computer(s): bhatertpkbcr, cfunsshuasjs, gwrvuhgaqvyk, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, whxojlpjdney, yanjaxplzisb
No comments. add comment
| Snippet ID: | #1020754 |
| Snippet name: | unstructure (v12, with packages) |
| Eternal ID of this version: | #1020754/20 |
| Text MD5: | 127a995ef91d3d7765425c36954f58d3 |
| Transpilation MD5: | a05c32bcdbe3568605cd1ba2dc585d96 |
| Author: | stefan |
| Category: | javax |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2019-08-27 22:34:10 |
| Source code size: | 18493 bytes / 637 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 561 / 839 |
| Version history: | 19 change(s) |
| Referenced in: | [show references] |