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 | |
11 | abstract sclass unstructure_Receiver {
|
12 | abstract void set(O o); |
13 | } |
14 | |
15 | // classFinder: func(name) -> class (optional) |
16 | static Object unstructure(String text, boolean allDynamic, |
17 | O classFinder) {
|
18 | if (text == null) ret null; |
19 | final L<S> tok = javaTokC(text); |
20 | ret unstructure_tok(tok, allDynamic, classFinder); |
21 | } |
22 | |
23 | // so text can be freed |
24 | static Object unstructure_tempVar(Var<S> text) {
|
25 | L<S> tok = javaTokC(text.get()); |
26 | text.clear(); |
27 | ret unstructure_tok(tok, false, null); |
28 | } |
29 | |
30 | static O unstructure_tok(final L<S> tok, final boolean allDynamic, final O classFinder) {
|
31 | final boolean debug = unstructure_debug; |
32 | |
33 | class X {
|
34 | int i = 0; |
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 | |
41 | void parse(final unstructure_Receiver out) {
|
42 | S t = tok.get(i); |
43 | |
44 | int refID = 0; |
45 | if (structure_isMarker(t, 0, l(t))) {
|
46 | refID = parseInt(t.substring(1)); |
47 | i++; |
48 | } |
49 | final int _refID = refID; |
50 | |
51 | // if (debug) print("parse: " + quote(t));
|
52 | |
53 | final int tokIndex = i; |
54 | parse_inner(refID, tokIndex, new unstructure_Receiver {
|
55 | void set(O o) {
|
56 | if (_refID != 0) |
57 | refs.put(_refID, o); |
58 | if (o != null) |
59 | tokrefs.put(tokIndex, o); |
60 | out.set(o); |
61 | } |
62 | }); |
63 | } |
64 | |
65 | void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) {
|
66 | S t = tok.get(i); |
67 | |
68 | // if (debug) print("parse_inner: " + quote(t));
|
69 | |
70 | Class c = classesMap.get(t); |
71 | if (c == null) {
|
72 | if (t.startsWith("\"")) {
|
73 | S s = internIfLongerThan(unquote(tok.get(i)), structure_internStringsLongerThan); |
74 | i++; |
75 | out.set(s); ret; |
76 | } |
77 | |
78 | if (t.startsWith("'")) {
|
79 | out.set(unquoteCharacter(tok.get(i++))); ret; |
80 | } |
81 | if (t.equals("bigint")) {
|
82 | out.set(parseBigInt()); ret; |
83 | } |
84 | if (t.equals("d")) {
|
85 | out.set(parseDouble()); ret; |
86 | } |
87 | if (t.equals("fl")) {
|
88 | out.set(parseFloat()); ret; |
89 | } |
90 | if (t.equals("false") || t.equals("f")) {
|
91 | i++; out.set(false); ret; |
92 | } |
93 | if (t.equals("true") || t.equals("t")) {
|
94 | i++; out.set(true); ret; |
95 | } |
96 | if (t.equals("-")) {
|
97 | t = tok.get(i+1); |
98 | i += 2; |
99 | out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret; |
100 | } |
101 | if (isInteger(t) || isLongConstant(t)) {
|
102 | i++; |
103 | //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
|
104 | if (isLongConstant(t)) {
|
105 | out.set(parseLong(t)); ret; |
106 | } |
107 | long l = parseLong(t); |
108 | bool isInt = l == (int) l; |
109 | if (debug) |
110 | print("l=" + l + ", isInt: " + isInt);
|
111 | out.set(isInt ? (O) new Integer((int) l) : (O) new Long(l)); ret; |
112 | } |
113 | |
114 | if (t.equals("File")) {
|
115 | File f = new File(unquote(tok.get(i+1))); |
116 | i += 2; |
117 | out.set(f); ret; |
118 | } |
119 | |
120 | if (t.startsWith("r") && isInteger(t.substring(1))) {
|
121 | i++; |
122 | int ref = Integer.parseInt(t.substring(1)); |
123 | O o = refs.get(ref); |
124 | if (o == null) |
125 | print("Warning: unsatisfied back reference " + ref);
|
126 | out.set(o); ret; |
127 | } |
128 | |
129 | if (t.startsWith("t") && isInteger(t.substring(1))) {
|
130 | i++; |
131 | int ref = Integer.parseInt(t.substring(1)); |
132 | O o = tokrefs.get(ref); |
133 | if (o == null) |
134 | print("Warning: unsatisfied token reference " + ref);
|
135 | out.set(o); ret; |
136 | } |
137 | |
138 | if (t.equals("hashset")) {
|
139 | parseHashSet(out); ret; |
140 | } |
141 | if (t.equals("treeset")) {
|
142 | parseTreeSet(out); ret; |
143 | } |
144 | if (eqOneOf(t, "hashmap", "hm")) {
|
145 | parseHashMap(out); ret; |
146 | } |
147 | if (t.equals("{")) {
|
148 | parseMap(out); ret; |
149 | } |
150 | if (t.equals("[")) {
|
151 | parseList(out); ret; |
152 | } |
153 | if (t.equals("bitset")) {
|
154 | parseBitSet(out); ret; |
155 | } |
156 | if (t.equals("array") || t.equals("intarray")) {
|
157 | parseArray(out); ret; |
158 | } |
159 | if (t.equals("ba")) {
|
160 | S hex = unquote(tok.get(i+1)); |
161 | i += 2; |
162 | out.set(hexToBytes(hex)); ret; |
163 | } |
164 | if (t.equals("boolarray")) {
|
165 | int n = parseInt(tok.get(i+1)); |
166 | S hex = unquote(tok.get(i+2)); |
167 | i += 6; |
168 | out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret; |
169 | } |
170 | if (t.equals("class")) {
|
171 | out.set(parseClass()); ret; |
172 | } |
173 | if (t.equals("l")) {
|
174 | parseLisp(out); ret; |
175 | } |
176 | if (t.equals("null")) {
|
177 | i++; out.set(null); ret; |
178 | } |
179 | |
180 | if (eq(t, "c")) {
|
181 | consume("c");
|
182 | t = tok.get(i); |
183 | assertTrue(isJavaIdentifier(t)); |
184 | concepts.add(t); |
185 | } |
186 | } |
187 | |
188 | if (c == null && !isJavaIdentifier(t)) |
189 | throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
|
190 | |
191 | // any other class name |
192 | if (c == null) {
|
193 | // First, find class |
194 | if (allDynamic) c = null; |
195 | else if (classFinder != null) |
196 | c = (Class) callF(classFinder, t); |
197 | else |
198 | c = findClass(t); |
199 | if (c != null) |
200 | classesMap.put(t, c); |
201 | } |
202 | |
203 | // Check if it has an outer reference |
204 | i++; |
205 | bool hasOuter = eq(get(tok, i), "(") && eq(get(tok, i+1), "this$1");
|
206 | |
207 | DynamicObject dO = null; |
208 | O o = null; |
209 | if (c != null) |
210 | o = hasOuter ? nuStubInnerObject(c) : nuEmptyObject(c); |
211 | else {
|
212 | if (concepts.contains(t) && (c = findClass("Concept")) != null)
|
213 | o = dO = (DynamicObject) nuEmptyObject(c); |
214 | else |
215 | dO = new DynamicObject; |
216 | dO.className = t; |
217 | if (debug) print("Made dynamic object " + t + " " + shortClassName(dO));
|
218 | } |
219 | |
220 | // Save in references list early because contents of object |
221 | // might link back to main object |
222 | |
223 | if (refID != 0) |
224 | refs.put(refID, o != null ? o : dO); |
225 | tokrefs.put(tokIndex, o != null ? o : dO); |
226 | |
227 | // NOW parse the fields! |
228 | |
229 | final new HashMap<S, O> fields; |
230 | final O _o = o; |
231 | final DynamicObject _dO = dO; |
232 | if (i < tok.size() && tok.get(i).equals("(")) {
|
233 | consume("(");
|
234 | stack.add(r {
|
235 | if (tok.get(i).equals(")")) {
|
236 | consume(")");
|
237 | objRead(_o, _dO, fields); |
238 | out.set(_o != null ? _o : _dO); |
239 | } else {
|
240 | final S key = unquote(tok.get(i++)); |
241 | consume("=");
|
242 | stack.add(this); |
243 | parse(new unstructure_Receiver {
|
244 | void set(O value) {
|
245 | fields.put(key, value); |
246 | if (tok.get(i).equals(",")) i++;
|
247 | } |
248 | }); |
249 | } |
250 | }); |
251 | } else |
252 | objRead(o, dO, fields); |
253 | } |
254 | |
255 | void objRead(O o, DynamicObject dO, Map<S, O> fields) {
|
256 | if (o != null) |
257 | if (dO != null) {
|
258 | if (debug) |
259 | printStructure("setOptAllDyn", fields);
|
260 | setOptAllDyn(dO, fields); |
261 | } else |
262 | setOptAll(o, fields); |
263 | else for (S field : keys(fields)) |
264 | dO.fieldValues.put(field.intern(), fields.get(field)); |
265 | |
266 | if (o != null) |
267 | pcallOpt_noArgs(o, "_doneLoading"); |
268 | } |
269 | |
270 | void parseSet(final Set set, final unstructure_Receiver out) {
|
271 | parseList(new unstructure_Receiver {
|
272 | void set(O o) {
|
273 | set.addAll((L) o); |
274 | out.set(set); |
275 | } |
276 | }); |
277 | } |
278 | |
279 | void parseLisp(final unstructure_Receiver out) {
|
280 | consume("l");
|
281 | consume("(");
|
282 | final new ArrayList list; |
283 | stack.add(r {
|
284 | if (tok.get(i).equals(")")) {
|
285 | consume(")");
|
286 | out.set(newObject("main$Lisp", (S) list.get(0), subList(list, 1)));
|
287 | } else {
|
288 | stack.add(this); |
289 | parse(new unstructure_Receiver {
|
290 | void set(O o) {
|
291 | list.add(o); |
292 | if (tok.get(i).equals(",")) i++;
|
293 | } |
294 | }); |
295 | } |
296 | }); |
297 | } |
298 | |
299 | void parseBitSet(final unstructure_Receiver out) {
|
300 | consume("bitset");
|
301 | consume("{");
|
302 | final new BitSet bs; |
303 | stack.add(r {
|
304 | if (tok.get(i).equals("}")) {
|
305 | consume("}");
|
306 | out.set(bs); |
307 | } else {
|
308 | stack.add(this); |
309 | parse(new unstructure_Receiver {
|
310 | void set(O o) {
|
311 | bs.set((Integer) o); |
312 | if (tok.get(i).equals(",")) i++;
|
313 | } |
314 | }); |
315 | } |
316 | }); |
317 | } |
318 | |
319 | void parseList(final unstructure_Receiver out) {
|
320 | consume("[");
|
321 | final new ArrayList list; |
322 | stack.add(r {
|
323 | if (tok.get(i).equals("]")) {
|
324 | consume("]");
|
325 | out.set(list); |
326 | } else {
|
327 | stack.add(this); |
328 | parse(new unstructure_Receiver {
|
329 | void set(O o) {
|
330 | //if (debug) print("List element type: " + getClassName(o));
|
331 | list.add(o); |
332 | if (tok.get(i).equals(",")) i++;
|
333 | } |
334 | }); |
335 | } |
336 | }); |
337 | } |
338 | |
339 | void parseArray(final unstructure_Receiver out) {
|
340 | final S type = tok.get(i); |
341 | i++; |
342 | consume("{");
|
343 | final List list = new ArrayList; |
344 | |
345 | stack.add(r {
|
346 | if (tok.get(i).equals("}")) {
|
347 | consume("}");
|
348 | out.set(type.equals("intarray") ? toIntArray(list) : list.toArray());
|
349 | } else {
|
350 | stack.add(this); |
351 | parse(new unstructure_Receiver {
|
352 | void set(O o) {
|
353 | list.add(o); |
354 | if (tok.get(i).equals(",")) i++;
|
355 | } |
356 | }); |
357 | } |
358 | }); |
359 | } |
360 | |
361 | Object parseClass() {
|
362 | consume("class");
|
363 | consume("(");
|
364 | S name = tok.get(i); |
365 | i++; |
366 | consume(")");
|
367 | Class c = allDynamic ? null : findClass(name); |
368 | if (c != null) ret c; |
369 | new DynamicObject dO; |
370 | dO.className = "java.lang.Class"; |
371 | dO.fieldValues.put("name", name);
|
372 | ret dO; |
373 | } |
374 | |
375 | Object parseBigInt() {
|
376 | consume("bigint");
|
377 | consume("(");
|
378 | S val = tok.get(i); |
379 | i++; |
380 | if (eq(val, "-")) {
|
381 | val = "-" + tok.get(i); |
382 | i++; |
383 | } |
384 | consume(")");
|
385 | ret new BigInteger(val); |
386 | } |
387 | |
388 | Object parseDouble() {
|
389 | consume("d");
|
390 | consume("(");
|
391 | S val = unquote(tok.get(i)); |
392 | i++; |
393 | consume(")");
|
394 | ret Double.parseDouble(val); |
395 | } |
396 | |
397 | Object parseFloat() {
|
398 | consume("fl");
|
399 | S val; |
400 | if (eq(tok.get(i), "(")) {
|
401 | consume("(");
|
402 | val = unquote(tok.get(i)); |
403 | i++; |
404 | consume(")");
|
405 | } else {
|
406 | val = unquote(tok.get(i)); |
407 | i++; |
408 | } |
409 | ret Float.parseFloat(val); |
410 | } |
411 | |
412 | void parseHashMap(unstructure_Receiver out) {
|
413 | i++; |
414 | parseMap(new HashMap, out); |
415 | } |
416 | |
417 | void parseHashSet(unstructure_Receiver out) {
|
418 | consume("hashset");
|
419 | parseSet(new HashSet, out); |
420 | } |
421 | |
422 | void parseTreeSet(unstructure_Receiver out) {
|
423 | consume("treeset");
|
424 | parseSet(new TreeSet, out); |
425 | } |
426 | |
427 | void parseMap(unstructure_Receiver out) {
|
428 | parseMap(new TreeMap, out); |
429 | } |
430 | |
431 | void parseMap(final Map map, final unstructure_Receiver out) {
|
432 | consume("{");
|
433 | stack.add(new Runnable {
|
434 | bool v; |
435 | O key; |
436 | |
437 | public void run() {
|
438 | if (v) {
|
439 | v = false; |
440 | stack.add(this); |
441 | consume("=");
|
442 | parse(new unstructure_Receiver {
|
443 | void set(O value) {
|
444 | map.put(key, value); |
445 | if (debug) |
446 | print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(tok.get(i)));
|
447 | if (tok.get(i).equals(",")) i++;
|
448 | } |
449 | }); |
450 | } else {
|
451 | if (tok.get(i).equals("}")) {
|
452 | consume("}");
|
453 | out.set(map); |
454 | } else {
|
455 | v = true; |
456 | stack.add(this); |
457 | parse(new unstructure_Receiver {
|
458 | void set(O o) {
|
459 | key = o; |
460 | } |
461 | }); |
462 | } |
463 | } // if v else |
464 | } // run() |
465 | }); |
466 | } |
467 | |
468 | /*void parseSub(unstructure_Receiver out) {
|
469 | int n = l(stack); |
470 | parse(out); |
471 | while (l(stack) > n) |
472 | stack |
473 | }*/ |
474 | |
475 | void consume(String s) {
|
476 | if (!tok.get(i).equals(s)) {
|
477 | S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; |
478 | S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); |
479 | fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");
|
480 | } |
481 | i++; |
482 | } |
483 | |
484 | void parse_x(unstructure_Receiver out) {
|
485 | parse(out); |
486 | while (nempty(stack)) |
487 | popLast(stack).run(); |
488 | } |
489 | } |
490 | |
491 | final new Var v; |
492 | new X().parse_x(new unstructure_Receiver {
|
493 | void set(O o) { v.set(o); }
|
494 | }); |
495 | ret v.get(); |
496 | } |
497 | |
498 | static boolean unstructure_debug; |
Began life as a copy of #1005658
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
| Snippet ID: | #1005973 |
| Snippet name: | unstructure (v9, working virtual stack) |
| Eternal ID of this version: | #1005973/1 |
| Text MD5: | 412a9ac718f792869377c92067832700 |
| Author: | stefan |
| Category: | javax |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2016-12-13 18:20:20 |
| Source code size: | 13925 bytes / 498 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 815 / 815 |
| Referenced in: | [show references] |