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