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