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