Libraryless. Click here for Pure Java version (1889L/13K/41K).
1 | !636 (modern) |
2 | |
3 | public class main { |
4 | !include #1001496 // Matches |
5 | !include #1001065 // DialogIO |
6 | |
7 | static boolean debug = false; |
8 | |
9 | static new Map<S, S> cache; |
10 | |
11 | public static void main(String[] args) throws IOException { |
12 | L<S> standardFunctions = (L) loadVariableDefinition( |
13 | cacheGet("#761"), "standardFunctions"); |
14 | long startTime = now(); |
15 | String s = loadMainJava(); |
16 | |
17 | Map<String, String> sf = new HashMap(); |
18 | for (String x : standardFunctions) { |
19 | String[] f = x.split("/"); |
20 | sf.put(f[1], f[0]); |
21 | } |
22 | |
23 | for (int i = 0; ; i++) { |
24 | Set<String> defd = new HashSet(findFunctions(s)); |
25 | List<String> tok = javaTok(s); |
26 | |
27 | // changes tok |
28 | Set<String> invocations = findFunctionInvocations(tok, sf); |
29 | s = join(tok); |
30 | |
31 | print("Functions invoked: " + structure(invocations)); |
32 | List<String> needed = diff(invocations, defd); |
33 | print("Functions needed: " + structure(needed)); |
34 | if (needed.isEmpty()) |
35 | break; |
36 | |
37 | new L<S> added; |
38 | new StringBuilder buf; |
39 | for (String x : needed) { |
40 | if (defd.contains(x)) continue; |
41 | |
42 | String id = sf.get(x); |
43 | //print("Adding function: " + x + " (" + id + ")"); |
44 | |
45 | S function = cacheGet(id); |
46 | if (("\n" + function).contains("\n!")) print("Warning: " + id + " contains translators."); |
47 | |
48 | buf.append(function).append("\n"); |
49 | added.add(x); |
50 | defd.addAll(findFunctions(function)); |
51 | } |
52 | s = addFunctions(s, str(buf)); |
53 | defd = new HashSet(findFunctions(s)); |
54 | print("Functions added: " + structure(added)); |
55 | |
56 | for (String x : needed) |
57 | if (!defd.contains(x)) |
58 | fail("Function not defined properly: " + x); |
59 | print("Iteration " + (i+2)); |
60 | if (i >= 1000) fail("Too many iterations"); |
61 | } |
62 | saveMainJava(s); |
63 | print("629: " + (now()-startTime) + " ms"); |
64 | } |
65 | |
66 | static boolean substringIs(String s, int i, String pat) { |
67 | return i >= 0 && i+pat.length() < s.length() && s.substring(i, i+pat.length()).equals(pat); |
68 | } |
69 | |
70 | // OK, this should be fast enough. |
71 | static List<String> findFunctions(String src) { |
72 | int idx = src.indexOf("main {"); // yes it's a hack... |
73 | if (idx >= 0) src = src.substring(idx); |
74 | |
75 | return findFunctionDefinitions(src); |
76 | } |
77 | |
78 | public static String addFunction(String s, String fID) throws IOException { |
79 | int i = s.lastIndexOf('}'); |
80 | S function = cacheGet(fID); |
81 | if (("\n" + function).contains("\n!")) print("Warning: " + fID + " contains translators."); |
82 | return s.substring(0, i) + "\n" + function +"\n" + s.substring(i); |
83 | } |
84 | |
85 | public static String addFunctions(String s, String functions) throws IOException { |
86 | int i = s.lastIndexOf('}'); |
87 | return s.substring(0, i) + "\n" + functions + s.substring(i); |
88 | } |
89 | |
90 | public static List<String> toLines(String s) { |
91 | List<String> lines = new ArrayList<String>(); |
92 | int start = 0; |
93 | while (true) { |
94 | int i = toLines_nextLineBreak(s, start); |
95 | if (i < 0) { |
96 | if (s.length() > start) lines.add(s.substring(start)); |
97 | break; |
98 | } |
99 | |
100 | lines.add(s.substring(start, i)); |
101 | if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n') |
102 | i += 2; |
103 | else |
104 | ++i; |
105 | |
106 | start = i; |
107 | } |
108 | return lines; |
109 | } |
110 | |
111 | private static int toLines_nextLineBreak(String s, int start) { |
112 | for (int i = start; i < s.length(); i++) { |
113 | char c = s.charAt(i); |
114 | if (c == '\r' || c == '\n') |
115 | return i; |
116 | } |
117 | return -1; |
118 | } |
119 | |
120 | static String mainJava; |
121 | |
122 | static String loadMainJava() throws IOException { |
123 | if (mainJava != null) return mainJava; |
124 | return loadTextFile("input/main.java", ""); |
125 | } |
126 | |
127 | static void saveMainJava(String s) throws IOException { |
128 | if (mainJava != null) |
129 | mainJava = s; |
130 | else |
131 | saveTextFile("output/main.java", s); |
132 | } |
133 | |
134 | static void saveMainJava(List<String> tok) throws IOException { |
135 | saveMainJava(join(tok)); |
136 | } |
137 | |
138 | public static long parseSnippetID(String snippetID) { |
139 | return Long.parseLong(shortenSnippetID(snippetID)); |
140 | } |
141 | |
142 | private static String shortenSnippetID(String snippetID) { |
143 | if (snippetID.startsWith("#")) |
144 | snippetID = snippetID.substring(1); |
145 | String httpBlaBla = "http://tinybrain.de/"; |
146 | if (snippetID.startsWith(httpBlaBla)) |
147 | snippetID = snippetID.substring(httpBlaBla.length()); |
148 | return snippetID; |
149 | } |
150 | |
151 | public static boolean isSnippetID(String snippetID) { |
152 | snippetID = shortenSnippetID(snippetID); |
153 | return isInteger(snippetID) && Long.parseLong(snippetID) != 0; |
154 | } |
155 | |
156 | public static boolean isInteger(String s) { |
157 | return Pattern.matches("\\-?\\d+", s); |
158 | } |
159 | |
160 | private static String loadPage(URL url) throws IOException { |
161 | print("Loading: " + url.toExternalForm()); |
162 | URLConnection con = url.openConnection(); |
163 | return loadPage(con, url); |
164 | } |
165 | |
166 | public static String loadPage(URLConnection con, URL url) throws IOException { |
167 | String contentType = con.getContentType(); |
168 | if (contentType == null) |
169 | throw new IOException("Page could not be read: " + url); |
170 | //Log.info("Content-Type: " + contentType); |
171 | String charset = guessCharset(contentType); |
172 | Reader r = new InputStreamReader(con.getInputStream(), charset); |
173 | StringBuilder buf = new StringBuilder(); |
174 | while (true) { |
175 | int ch = r.read(); |
176 | if (ch < 0) |
177 | break; |
178 | //Log.info("Chars read: " + buf.length()); |
179 | buf.append((char) ch); |
180 | } |
181 | return buf.toString(); |
182 | } |
183 | |
184 | public static String guessCharset(String contentType) { |
185 | Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*"); |
186 | Matcher m = p.matcher(contentType); |
187 | /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ |
188 | return m.matches() ? m.group(1) : "ISO-8859-1"; |
189 | } |
190 | |
191 | static RuntimeException fail() { |
192 | throw new RuntimeException("fail"); |
193 | } |
194 | |
195 | static RuntimeException fail(Object msg) { |
196 | throw new RuntimeException(String.valueOf(msg)); |
197 | } |
198 | |
199 | // replacement for class JavaTok |
200 | // maybe incomplete, might want to add floating point numbers |
201 | // todo also: extended multi-line strings |
202 | |
203 | static List<String> javaTok(String s) { |
204 | List<String> tok = new ArrayList<String>(); |
205 | int l = s.length(); |
206 | |
207 | int i = 0; |
208 | while (i < l) { |
209 | int j = i; |
210 | char c; String cc; |
211 | |
212 | // scan for whitespace |
213 | while (j < l) { |
214 | c = s.charAt(j); |
215 | cc = s.substring(j, Math.min(j+2, l)); |
216 | if (c == ' ' || c == '\t' || c == '\r' || c == '\n') |
217 | ++j; |
218 | else if (cc.equals("/*")) { |
219 | do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); |
220 | j = Math.min(j+2, l); |
221 | } else if (cc.equals("//")) { |
222 | do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); |
223 | } else |
224 | break; |
225 | } |
226 | |
227 | tok.add(s.substring(i, j)); |
228 | i = j; |
229 | if (i >= l) break; |
230 | c = s.charAt(i); // cc is not needed in rest of loop body |
231 | cc = s.substring(i, Math.min(i+2, l)); |
232 | |
233 | // scan for non-whitespace |
234 | if (c == '\'' || c == '"') { |
235 | char opener = c; |
236 | ++j; |
237 | while (j < l) { |
238 | if (s.charAt(j) == opener) { |
239 | ++j; |
240 | break; |
241 | } else if (s.charAt(j) == '\\' && j+1 < l) |
242 | j += 2; |
243 | else |
244 | ++j; |
245 | } |
246 | } else if (Character.isJavaIdentifierStart(c)) |
247 | do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))); |
248 | else if (Character.isDigit(c)) { |
249 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
250 | if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L |
251 | } else if (cc.equals("[[")) { |
252 | do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); |
253 | j = Math.min(j+2, l); |
254 | } else |
255 | ++j; |
256 | |
257 | tok.add(s.substring(i, j)); |
258 | i = j; |
259 | } |
260 | |
261 | if ((tok.size() % 2) == 0) tok.add(""); |
262 | return tok; |
263 | } |
264 | |
265 | static List<String> javaTok(List<String> tok) { |
266 | return javaTok(join(tok)); |
267 | } |
268 | |
269 | public static String join(String glue, Iterable<String> strings) { |
270 | StringBuilder buf = new StringBuilder(); |
271 | Iterator<String> i = strings.iterator(); |
272 | if (i.hasNext()) { |
273 | buf.append(i.next()); |
274 | while (i.hasNext()) |
275 | buf.append(glue).append(i.next()); |
276 | } |
277 | return buf.toString(); |
278 | } |
279 | |
280 | public static String join(String glue, String[] strings) { |
281 | return join(glue, Arrays.asList(strings)); |
282 | } |
283 | |
284 | public static String join(Iterable<String> strings) { |
285 | return join("", strings); |
286 | } |
287 | |
288 | public static String join(String[] strings) { |
289 | return join("", strings); |
290 | } |
291 | |
292 | // leaves tok properly tokenized |
293 | // returns true iff anything was replaced |
294 | static boolean jreplace(List<String> tok, String in, String out) { |
295 | return jreplace(tok, in, out, false, true); |
296 | } |
297 | |
298 | static boolean jreplace(List<String> tok, String in, String out, boolean ignoreCase, boolean reTok) { |
299 | List<String> tokin = javaTok(in); |
300 | replaceSublist(tokin, litlist("<", "", "quoted", "", ">"), litlist("<quoted>")); |
301 | replaceSublist(tokin, litlist("<", "", "id", "", ">"), litlist("<id>")); |
302 | |
303 | boolean anyChange = false; |
304 | for (int n = 0; n < 10000; n++) { |
305 | int i = findCodeTokens(tok, ignoreCase, toStringArray(codeTokensOnly(tokin))); |
306 | if (i < 0) { |
307 | if (anyChange && reTok) |
308 | replaceCollection(tok, javaTok(tok)); |
309 | return anyChange; |
310 | } |
311 | List<String> subList = tok.subList(i-1, i+l(tokin)-1); // N to N |
312 | String expansion = jreplace_expandRefs(out, subList); |
313 | clearAllTokens(tok.subList(i, i+l(tokin)-2)); // code to code |
314 | tok.set(i, expansion); |
315 | anyChange = true; |
316 | } |
317 | throw fail("woot? 10000!"); |
318 | } |
319 | |
320 | // "$1" is first code token, "$2" second code token etc. |
321 | static String jreplace_expandRefs(String s, List<String> tokref) { |
322 | List<String> tok = javaTok(s); |
323 | for (int i = 1; i < l(tok)-2; i += 2) { |
324 | if (tok.get(i).startsWith("$") && isInteger(tok.get(i).substring(1))) { |
325 | String x = tokref.get(-1+parseInt(tok.get(i).substring(1))*2); |
326 | tok.set(i, x); |
327 | } |
328 | } |
329 | return join(tok); |
330 | } |
331 | |
332 | static void replaceToken(List<String> tok, String in, String out) { |
333 | renameToken(tok, in, out); |
334 | } |
335 | |
336 | static <A> void replaceCollection(Collection<A> dest, Collection<A> src) { |
337 | dest.clear(); |
338 | dest.addAll(src); |
339 | } |
340 | |
341 | static <A> ArrayList<A> litlist(A... a) { |
342 | return new ArrayList<A>(Arrays.asList(a)); |
343 | } |
344 | static List<String> codeTokensOnly(List<String> tok) { |
345 | List<String> l = new ArrayList<String>(); |
346 | for (int i = 1; i < tok.size(); i += 2) |
347 | l.add(tok.get(i)); |
348 | return l; |
349 | } |
350 | |
351 | static void replaceSublist(List<String> l, List<String> x, List<String> y) { |
352 | int i = 0; |
353 | while (true) { |
354 | i = indexOfSubList(l, x, i); |
355 | if (i < 0) return; |
356 | |
357 | // It's inefficient :D |
358 | for (int j = 0; j < l(x); j++) l.remove(i); |
359 | l.addAll(i, y); |
360 | i += l(y); |
361 | } |
362 | } |
363 | |
364 | static int l(Object[] array) { |
365 | return array == null ? 0 : array.length; |
366 | } |
367 | |
368 | static int l(Collection c) { |
369 | return c == null ? 0 : c.size(); |
370 | } |
371 | |
372 | static int l(Map m) { |
373 | return m == null ? 0 : m.size(); |
374 | } |
375 | |
376 | static int l(String s) { |
377 | return s == null ? 0 : s.length(); |
378 | } |
379 | |
380 | |
381 | static int parseInt(String s) { |
382 | return Integer.parseInt(s); |
383 | } |
384 | |
385 | static void renameToken(List<String> tok, String in, String out) { |
386 | int renames = 0; |
387 | for (int i = 1; i < tok.size(); i += 2) { |
388 | if (tok.get(i).equals(in)) { |
389 | tok.set(i, out); |
390 | ++renames; |
391 | } |
392 | } |
393 | } |
394 | |
395 | |
396 | static String[] toStringArray(List<String> list) { |
397 | return list.toArray(new String[list.size()]); |
398 | } |
399 | |
400 | static String[] toStringArray(Object o) { |
401 | if (o instanceof String[]) |
402 | return (String[]) o; |
403 | else if (o instanceof List) |
404 | return toStringArray((List<String>) o); |
405 | else |
406 | throw fail("Not a list or array: " + o); |
407 | } |
408 | |
409 | static int findCodeTokens(List<String> tok, String... tokens) { |
410 | return findCodeTokens(tok, 1, false, tokens); |
411 | } |
412 | |
413 | static int findCodeTokens(List<String> tok, boolean ignoreCase, String... tokens) { |
414 | return findCodeTokens(tok, 1, ignoreCase, tokens); |
415 | } |
416 | |
417 | static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String... tokens) { |
418 | outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) { |
419 | for (int j = 0; j < tokens.length; j++) { |
420 | String p = tokens[j], t = tok.get(i+j*2); |
421 | boolean match; |
422 | if (eq(p, "*")) match = true; |
423 | else if (eq(p, "<quoted>")) match = isQuoted(t); |
424 | else if (eq(p, "<id>")) match = isIdentifier(t); |
425 | else match = ignoreCase ? eqic(p, t) : eq(p, t); |
426 | |
427 | if (!match) |
428 | continue outer; |
429 | } |
430 | return i; |
431 | } |
432 | return -1; |
433 | } |
434 | |
435 | |
436 | static void clearAllTokens(List<String> tok) { |
437 | for (int i = 0; i < tok.size(); i++) |
438 | tok.set(i, ""); |
439 | } |
440 | |
441 | static void clearAllTokens(List<String> tok, int i, int j) { |
442 | for (; i < j; i++) |
443 | tok.set(i, ""); |
444 | } |
445 | |
446 | static boolean isIdentifier(String s) { |
447 | return isJavaIdentifier(s); |
448 | } |
449 | |
450 | static boolean eqic(String a, String b) { |
451 | if ((a == null) != (b == null)) return false; |
452 | if (a == null) return true; |
453 | return a.equalsIgnoreCase(b); |
454 | } |
455 | |
456 | |
457 | // supports the usual quotings (', ", variable length double brackets) |
458 | static boolean isQuoted(String s) { |
459 | if (s.startsWith("'") || s.startsWith("\"")) return true; |
460 | if (!s.startsWith("[")) return false; |
461 | int i = 1; |
462 | while (i < s.length() && s.charAt(i) == '=') ++i; |
463 | return i < s.length() && s.charAt(i) == '['; |
464 | //return Pattern.compile("^\\[=*\\[").matcher(s).find(); |
465 | } |
466 | |
467 | |
468 | static boolean eq(Object a, Object b) { |
469 | if (a == null) return b == null; |
470 | if (a.equals(b)) return true; |
471 | if (a instanceof BigInteger) { |
472 | if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b)); |
473 | if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b)); |
474 | } |
475 | return false; |
476 | } |
477 | |
478 | static boolean isJavaIdentifier(String s) { |
479 | if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) |
480 | return false; |
481 | for (int i = 1; i < s.length(); i++) |
482 | if (!Character.isJavaIdentifierPart(s.charAt(i))) |
483 | return false; |
484 | return true; |
485 | } |
486 | |
487 | static <A> int indexOfSubList(List<A> x, List<A> y, int i) { |
488 | outer: for (; i+l(y) <= l(x); i++) { |
489 | for (int j = 0; j < l(y); j++) |
490 | if (neq(x.get(i+j), y.get(j))) |
491 | continue outer; |
492 | return i; |
493 | } |
494 | return -1; |
495 | } |
496 | |
497 | static boolean neq(Object a, Object b) { |
498 | return !eq(a, b); |
499 | } |
500 | |
501 | static long now() { |
502 | return System.currentTimeMillis(); |
503 | } |
504 | |
505 | static List<String> diff(Collection<String> a, Set<String> b) { |
506 | List<String> l = new ArrayList(); |
507 | for (String s : a) |
508 | if (!b.contains(s)) |
509 | l.add(s); |
510 | return l; |
511 | } |
512 | |
513 | static int jfind(List<String> tok, String in) { |
514 | List<String> tokin = javaTok(in); |
515 | replaceSublist(tokin, litlist("<", "", "quoted", "", ">"), litlist("<quoted>")); |
516 | replaceSublist(tokin, litlist("<", "", "id", "", ">"), litlist("<id>")); |
517 | |
518 | return findCodeTokens(tok, false, toStringArray(codeTokensOnly(tokin))); |
519 | } |
520 | static S cacheGet(S id) ctex { |
521 | id = formatSnippetID(id); |
522 | S text = cache.get(id); |
523 | if (text != null) { |
524 | //print("Snippet CACHED " + fID); |
525 | } else { |
526 | //print("Snippet LOAD " + fID); |
527 | text = loadSnippet(id, false); |
528 | cache.put(id, text); |
529 | } |
530 | ret text; |
531 | } |
532 | } |
Began life as a copy of #629
download show line numbers debug dex old transpilations
Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, nbgitpuheiab, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1002474 |
Snippet name: | Standard functions (new) |
Eternal ID of this version: | #1002474/1 |
Text MD5: | dc0e2cbb548caae70570d3764e08efec |
Transpilation MD5: | d9eda32662880c79fdf2f9324559eb64 |
Author: | stefan |
Category: | javax |
Type: | JavaX translator |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-07-28 16:25:24 |
Source code size: | 15667 bytes / 532 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 921 / 9689 |
Referenced in: | [show references] |