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: | 814 / 817 |
| Referenced in: | [show references] |