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