1 | import java.math.*; |
2 | import javax.imageio.*; |
3 | import java.awt.image.*; |
4 | import java.awt.event.*; |
5 | import java.awt.*; |
6 | import java.security.spec.*; |
7 | import java.security.*; |
8 | import java.lang.management.*; |
9 | import java.lang.ref.*; |
10 | import java.lang.reflect.*; |
11 | import java.net.*; |
12 | import java.io.*; |
13 | import javax.swing.table.*; |
14 | import javax.swing.text.*; |
15 | import javax.swing.event.*; |
16 | import javax.swing.*; |
17 | import java.util.concurrent.atomic.*; |
18 | import java.util.concurrent.*; |
19 | import java.util.regex.*; |
20 | import java.util.List; |
21 | import java.util.zip.*; |
22 | import java.util.*; |
23 | public class main { |
24 | static String formatSnippetID(String id) { |
25 | return "#" + parseSnippetID(id); |
26 | } |
27 | |
28 | static String formatSnippetID(long id) { |
29 | return "#" + id; |
30 | } |
31 | |
32 | public static String unquote(String s) { |
33 | if (s.startsWith("[")) { |
34 | int i = 1; |
35 | while (i < s.length() && s.charAt(i) == '=') ++i; |
36 | if (i < s.length() && s.charAt(i) == '[') { |
37 | String m = s.substring(1, i); |
38 | if (s.endsWith("]" + m + "]")) |
39 | return s.substring(i+1, s.length()-i-1); |
40 | } |
41 | } |
42 | |
43 | if (s.startsWith("\"") && s.endsWith("\"") && s.length() > 1) { |
44 | String st = s.substring(1, s.length()-1); |
45 | StringBuilder sb = new StringBuilder(st.length()); |
46 | |
47 | for (int i = 0; i < st.length(); i++) { |
48 | char ch = st.charAt(i); |
49 | if (ch == '\\') { |
50 | char nextChar = (i == st.length() - 1) ? '\\' : st |
51 | .charAt(i + 1); |
52 | // Octal escape? |
53 | if (nextChar >= '0' && nextChar <= '7') { |
54 | String code = "" + nextChar; |
55 | i++; |
56 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' |
57 | && st.charAt(i + 1) <= '7') { |
58 | code += st.charAt(i + 1); |
59 | i++; |
60 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' |
61 | && st.charAt(i + 1) <= '7') { |
62 | code += st.charAt(i + 1); |
63 | i++; |
64 | } |
65 | } |
66 | sb.append((char) Integer.parseInt(code, 8)); |
67 | continue; |
68 | } |
69 | switch (nextChar) { |
70 | case '\\': |
71 | ch = '\\'; |
72 | break; |
73 | case 'b': |
74 | ch = '\b'; |
75 | break; |
76 | case 'f': |
77 | ch = '\f'; |
78 | break; |
79 | case 'n': |
80 | ch = '\n'; |
81 | break; |
82 | case 'r': |
83 | ch = '\r'; |
84 | break; |
85 | case 't': |
86 | ch = '\t'; |
87 | break; |
88 | case '\"': |
89 | ch = '\"'; |
90 | break; |
91 | case '\'': |
92 | ch = '\''; |
93 | break; |
94 | // Hex Unicode: u???? |
95 | case 'u': |
96 | if (i >= st.length() - 5) { |
97 | ch = 'u'; |
98 | break; |
99 | } |
100 | int code = Integer.parseInt( |
101 | "" + st.charAt(i + 2) + st.charAt(i + 3) |
102 | + st.charAt(i + 4) + st.charAt(i + 5), 16); |
103 | sb.append(Character.toChars(code)); |
104 | i += 5; |
105 | continue; |
106 | default: |
107 | ch = nextChar; // added by Stefan |
108 | } |
109 | i++; |
110 | } |
111 | sb.append(ch); |
112 | } |
113 | return sb.toString(); |
114 | } else |
115 | return s; // return original |
116 | } |
117 | |
118 | static class Matches { |
119 | String[] m; |
120 | String get(int i) { return m[i]; } |
121 | String unq(int i) { return unquote(m[i]); } |
122 | String fsi(int i) { return formatSnippetID(unq(i)); } |
123 | boolean bool(int i) { return "true".equals(unq(i)); } |
124 | String rest() { return m[m.length-1]; } // for matchStart |
125 | int psi(int i) { return Integer.parseInt(unq(i)); } |
126 | } |
127 | |
128 | |
129 | |
130 | static String answer(String s) { |
131 | Matches m = new Matches(); |
132 | |
133 | if (match("get transpilation of snippet *", s, m)) |
134 | return dropFirstLine(getServerTranspiled(m.fsi(0))); |
135 | |
136 | if (match("get libraries of snippet *", s, m)) |
137 | return quote(firstLine(getServerTranspiled(m.fsi(0)))); |
138 | |
139 | return null; |
140 | } |
141 | |
142 | |
143 | // returns libs in line 1, then transpiled souce |
144 | static String getServerTranspiled(String snippetID) { try { |
145 | |
146 | long id = parseSnippetID(snippetID); |
147 | URL url = new URL("http://tinybrain.de:8080/tb-int/get-transpiled.php?raw=1&withlibs=1&id=" + id); |
148 | return loadPage(url); |
149 | |
150 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
151 | |
152 | |
153 | static String quote(String s) { |
154 | if (s == null) return "null"; |
155 | return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\""; |
156 | } |
157 | |
158 | static String quote(long l) { |
159 | return quote("" + l); |
160 | } |
161 | |
162 | |
163 | static String dropFirstLine(String text) { |
164 | int i = text.indexOf('\n'); |
165 | return i >= 0 ? text.substring(i+1) : ""; |
166 | } |
167 | |
168 | static String firstLine(String text) { |
169 | int i = text.indexOf('\n'); |
170 | return i >= 0 ? text.substring(0, i) : text; |
171 | } |
172 | |
173 | public static long parseSnippetID(String snippetID) { |
174 | long id = Long.parseLong(shortenSnippetID(snippetID)); |
175 | if (id == 0) fail("0 is not a snippet ID"); |
176 | return id; |
177 | } |
178 | |
179 | public static String loadPageSilently(String url) { |
180 | try { |
181 | return loadPageSilently(new URL(loadPage_preprocess(url))); |
182 | } catch (IOException e) { throw new RuntimeException(e); } |
183 | } |
184 | |
185 | public static String loadPageSilently(URL url) { |
186 | try { |
187 | IOException e = null; |
188 | for (int tries = 0; tries < 60; tries++) |
189 | try { |
190 | URLConnection con = url.openConnection(); |
191 | return loadPage(con, url); |
192 | } catch (IOException _e) { |
193 | e = _e; |
194 | print("Retrying because of: " + e); |
195 | sleepSeconds(1); |
196 | } |
197 | throw e; |
198 | } catch (IOException e) { throw new RuntimeException(e); } |
199 | } |
200 | |
201 | static String loadPage_preprocess(String url) { |
202 | if (url.startsWith("tb/")) |
203 | url = "tinybrain.de:8080/" + url; |
204 | if (url.indexOf("://") < 0) |
205 | url = "http://" + url; |
206 | return url; |
207 | } |
208 | |
209 | public static String loadPage(String url) { |
210 | try { |
211 | return loadPage(new URL(loadPage_preprocess(url))); |
212 | } catch (IOException e) { throw new RuntimeException(e); } |
213 | } |
214 | |
215 | public static String loadPage(URL url) { |
216 | print("Loading: " + url.toExternalForm()); |
217 | return loadPageSilently(url); |
218 | } |
219 | |
220 | public static String loadPage(URLConnection con, URL url) throws IOException { |
221 | String contentType = con.getContentType(); |
222 | if (contentType == null) |
223 | throw new IOException("Page could not be read: " + url); |
224 | //Log.info("Content-Type: " + contentType); |
225 | String charset = loadPage_guessCharset(contentType); |
226 | Reader r = new InputStreamReader(con.getInputStream(), charset); |
227 | StringBuilder buf = new StringBuilder(); |
228 | while (true) { |
229 | int ch = r.read(); |
230 | if (ch < 0) |
231 | break; |
232 | //Log.info("Chars read: " + buf.length()); |
233 | buf.append((char) ch); |
234 | } |
235 | return buf.toString(); |
236 | } |
237 | |
238 | static String loadPage_guessCharset(String contentType) { |
239 | Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*"); |
240 | Matcher m = p.matcher(contentType); |
241 | /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ |
242 | return m.matches() ? m.group(1) : "ISO-8859-1"; |
243 | } |
244 | |
245 | |
246 | static RuntimeException fail() { |
247 | throw new RuntimeException("fail"); |
248 | } |
249 | |
250 | static RuntimeException fail(Object msg) { |
251 | throw new RuntimeException(String.valueOf(msg)); |
252 | } |
253 | |
254 | static RuntimeException fail(String msg) { |
255 | throw new RuntimeException(unnull(msg)); |
256 | } |
257 | |
258 | static RuntimeException fail(String msg, Object... args) { |
259 | throw new RuntimeException(format(msg, args)); |
260 | } |
261 | |
262 | static StringBuffer print_log; |
263 | |
264 | static void print() { |
265 | print(""); |
266 | } |
267 | |
268 | static void print(Object o) { |
269 | String s = String.valueOf(o) + "\n"; |
270 | synchronized(StringBuffer.class) { |
271 | if (print_log == null) print_log = new StringBuffer(); |
272 | } |
273 | print_log.append(s); |
274 | System.out.print(s); |
275 | } |
276 | |
277 | static void print(long l) { |
278 | print(String.valueOf(l)); |
279 | } |
280 | |
281 | static void sleepSeconds(long s) { |
282 | if (s > 0) sleep(s*1000); |
283 | } |
284 | |
285 | static String shortenSnippetID(String snippetID) { |
286 | if (snippetID.startsWith("#")) |
287 | snippetID = snippetID.substring(1); |
288 | String httpBlaBla = "http://tinybrain.de/"; |
289 | if (snippetID.startsWith(httpBlaBla)) |
290 | snippetID = snippetID.substring(httpBlaBla.length()); |
291 | return snippetID; |
292 | } |
293 | |
294 | |
295 | static String unnull(String s) { |
296 | return s == null ? "" : s; |
297 | } |
298 | |
299 | static List unnull(List l) { |
300 | return l == null ? emptyList() : l; |
301 | } |
302 | |
303 | static String format(String pat, Object... args) { |
304 | return format3(pat, args); |
305 | } |
306 | |
307 | |
308 | static void sleep(long ms) { |
309 | try { |
310 | Thread.sleep(ms); |
311 | } catch (Exception e) { throw new RuntimeException(e); } |
312 | } |
313 | |
314 | static void sleep() { try { |
315 | |
316 | print("Sleeping."); |
317 | synchronized(main.class) { main.class.wait(); } |
318 | |
319 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
320 | |
321 | static String format3(String pat, Object... args) { |
322 | if (args.length == 0) return pat; |
323 | |
324 | List<String> tok = javaTokPlusPeriod(pat); |
325 | int argidx = 0; |
326 | for (int i = 1; i < tok.size(); i += 2) |
327 | if (tok.get(i).equals("*")) |
328 | tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null")); |
329 | return join(tok); |
330 | } |
331 | |
332 | static String format3_formatArg(Object arg) { |
333 | if (arg == null) return "null"; |
334 | if (arg instanceof String) { |
335 | String s = (String) arg; |
336 | return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s); |
337 | } |
338 | if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg); |
339 | return quote(structure(arg)); |
340 | } |
341 | |
342 | |
343 | |
344 | static List emptyList() { |
345 | return Collections.emptyList(); |
346 | } |
347 | |
348 | static boolean isIdentifier(String s) { |
349 | return isJavaIdentifier(s); |
350 | } |
351 | |
352 | static boolean isNonNegativeInteger(String s) { |
353 | return s != null && Pattern.matches("\\d+", s); |
354 | } |
355 | |
356 | static String structure(Object o) { |
357 | return structure(o, 0); |
358 | } |
359 | |
360 | // leave to false, unless unstructure() breaks |
361 | static boolean structure_allowShortening = false; |
362 | |
363 | static String structure(Object o, int stringSizeLimit) { |
364 | if (o == null) return "null"; |
365 | String name = o.getClass().getName(); |
366 | |
367 | StringBuilder buf = new StringBuilder(); |
368 | |
369 | if (o instanceof Collection) { // TODO: store the type (e.g. HashSet/TreeSet) |
370 | for (Object x : (Collection) o) { |
371 | if (buf.length() != 0) buf.append(", "); |
372 | buf.append(structure(x, stringSizeLimit)); |
373 | } |
374 | return "[" + buf + "]"; |
375 | } |
376 | |
377 | if (o instanceof Map) { |
378 | for (Object e : ((Map) o).entrySet()) { |
379 | if (buf.length() != 0) buf.append(", "); |
380 | buf.append(structure(((Map.Entry) e).getKey(), stringSizeLimit)); |
381 | buf.append("="); |
382 | buf.append(structure(((Map.Entry) e).getValue(), stringSizeLimit)); |
383 | } |
384 | return (o instanceof HashMap ? "hashmap" : "") + "{" + buf + "}"; |
385 | } |
386 | |
387 | if (o.getClass().isArray()) { |
388 | int n = Array.getLength(o); |
389 | for (int i = 0; i < n; i++) { |
390 | if (buf.length() != 0) buf.append(", "); |
391 | buf.append(structure(Array.get(o, i), stringSizeLimit)); |
392 | } |
393 | return "array{" + buf + "}"; |
394 | } |
395 | |
396 | if (o instanceof String) |
397 | return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o); |
398 | |
399 | if (o instanceof Class) |
400 | return "class(" + quote(((Class) o).getName()) + ")"; |
401 | |
402 | if (o instanceof Throwable) |
403 | return "exception(" + quote(((Throwable) o).getMessage()) + ")"; |
404 | |
405 | if (o instanceof BigInteger) |
406 | return "bigint(" + o + ")"; |
407 | |
408 | if (o instanceof Double) |
409 | return "d(" + quote(str(o)) + ")"; |
410 | |
411 | if (o instanceof Long) |
412 | return o + "L"; |
413 | |
414 | // Need more cases? This should cover all library classes... |
415 | if (name.startsWith("java.") || name.startsWith("javax.")) |
416 | return String.valueOf(o); |
417 | |
418 | String shortName = o.getClass().getName().replaceAll("^main\\$", ""); |
419 | |
420 | int numFields = 0; |
421 | String fieldName = ""; |
422 | if (shortName.equals("DynamicObject")) { |
423 | shortName = (String) get(o, "className"); |
424 | Map<String, Object> fieldValues = (Map) get(o, "fieldValues"); |
425 | |
426 | for (String _fieldName : fieldValues.keySet()) { |
427 | fieldName = _fieldName; |
428 | Object value = fieldValues.get(fieldName); |
429 | if (value != null) { |
430 | if (buf.length() != 0) buf.append(", "); |
431 | buf.append(fieldName + "=" + structure(value, stringSizeLimit)); |
432 | } |
433 | ++numFields; |
434 | } |
435 | } else { |
436 | // regular class |
437 | // TODO: go to superclasses too |
438 | Field[] fields = o.getClass().getDeclaredFields(); |
439 | for (Field field : fields) { |
440 | if ((field.getModifiers() & Modifier.STATIC) != 0) |
441 | continue; |
442 | Object value; |
443 | try { |
444 | field.setAccessible(true); |
445 | value = field.get(o); |
446 | } catch (Exception e) { |
447 | value = "?"; |
448 | } |
449 | |
450 | fieldName = field.getName(); |
451 | |
452 | // put special cases here... |
453 | |
454 | if (value != null) { |
455 | if (buf.length() != 0) buf.append(", "); |
456 | buf.append(fieldName + "=" + structure(value, stringSizeLimit)); |
457 | } |
458 | ++numFields; |
459 | } |
460 | } |
461 | |
462 | String b = buf.toString(); |
463 | |
464 | if (numFields == 1 && structure_allowShortening) |
465 | b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one |
466 | String s = shortName; |
467 | if (buf.length() != 0) |
468 | s += "(" + b + ")"; |
469 | return s; |
470 | } |
471 | |
472 | // This is made for NL parsing. |
473 | // It's javaTok extended with "..." token, "$n" and "#n" and |
474 | // special quotes (which are converted to normal ones). |
475 | |
476 | static List<String> javaTokPlusPeriod(String s) { |
477 | List<String> tok = new ArrayList<String>(); |
478 | int l = s.length(); |
479 | |
480 | int i = 0; |
481 | while (i < l) { |
482 | int j = i; |
483 | char c; String cc; |
484 | |
485 | // scan for whitespace |
486 | while (j < l) { |
487 | c = s.charAt(j); |
488 | cc = s.substring(j, Math.min(j+2, l)); |
489 | if (c == ' ' || c == '\t' || c == '\r' || c == '\n') |
490 | ++j; |
491 | else if (cc.equals("/*")) { |
492 | do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); |
493 | j = Math.min(j+2, l); |
494 | } else if (cc.equals("//")) { |
495 | do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); |
496 | } else |
497 | break; |
498 | } |
499 | |
500 | tok.add(s.substring(i, j)); |
501 | i = j; |
502 | if (i >= l) break; |
503 | c = s.charAt(i); |
504 | cc = s.substring(i, Math.min(i+2, l)); |
505 | |
506 | // scan for non-whitespace |
507 | if (c == '\u201C' || c == '\u201D') c = '"'; // normalize quotes |
508 | if (c == '\'' || c == '"') { |
509 | char opener = c; |
510 | ++j; |
511 | while (j < l) { |
512 | char _c = s.charAt(j); |
513 | if (_c == '\u201C' || _c == '\u201D') _c = '"'; // normalize quotes |
514 | if (_c == opener) { |
515 | ++j; |
516 | break; |
517 | } else if (s.charAt(j) == '\\' && j+1 < l) |
518 | j += 2; |
519 | else |
520 | ++j; |
521 | } |
522 | if (j-1 >= i+1) { |
523 | tok.add(opener + s.substring(i+1, j-1) + opener); |
524 | i = j; |
525 | continue; |
526 | } |
527 | } else if (Character.isJavaIdentifierStart(c)) |
528 | do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's" |
529 | else if (Character.isDigit(c)) |
530 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
531 | else if (cc.equals("[[")) { |
532 | do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); |
533 | j = Math.min(j+2, l); |
534 | } else if (s.substring(j, Math.min(j+3, l)).equals("...")) |
535 | j += 3; |
536 | else if (c == '$' || c == '#') |
537 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
538 | else |
539 | ++j; |
540 | |
541 | tok.add(s.substring(i, j)); |
542 | i = j; |
543 | } |
544 | |
545 | if ((tok.size() % 2) == 0) tok.add(""); |
546 | return tok; |
547 | } |
548 | |
549 | |
550 | public static String join(String glue, Iterable<String> strings) { |
551 | StringBuilder buf = new StringBuilder(); |
552 | Iterator<String> i = strings.iterator(); |
553 | if (i.hasNext()) { |
554 | buf.append(i.next()); |
555 | while (i.hasNext()) |
556 | buf.append(glue).append(i.next()); |
557 | } |
558 | return buf.toString(); |
559 | } |
560 | |
561 | public static String join(String glue, String[] strings) { |
562 | return join(glue, Arrays.asList(strings)); |
563 | } |
564 | |
565 | public static String join(Iterable<String> strings) { |
566 | return join("", strings); |
567 | } |
568 | |
569 | public static String join(String[] strings) { |
570 | return join("", strings); |
571 | } |
572 | |
573 | |
574 | static String shorten(String s, int max) { |
575 | if (s == null) return ""; |
576 | return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "..."; |
577 | } |
578 | |
579 | // get purpose 1: access a list/array (safer version of x.get(y)) |
580 | |
581 | static <A> A get(List<A> l, int idx) { |
582 | return idx >= 0 && idx < l(l) ? l.get(idx) : null; |
583 | } |
584 | |
585 | static <A> A get(A[] l, int idx) { |
586 | return idx >= 0 && idx < l(l) ? l[idx] : null; |
587 | } |
588 | |
589 | // get purpose 2: access a field by reflection |
590 | |
591 | static Object get(Object o, String field) { |
592 | if (o instanceof Class) return get((Class) o, field); |
593 | |
594 | if (o.getClass().getName().equals("main$DynamicObject")) |
595 | return call(get_raw(o, "fieldValues"), "get", field); |
596 | |
597 | return get_raw(o, field); |
598 | } |
599 | |
600 | static Object get_raw(Object o, String field) { |
601 | try { |
602 | Field f = get_findField(o.getClass(), field); |
603 | f.setAccessible(true); |
604 | return f.get(o); |
605 | } catch (Exception e) { |
606 | throw new RuntimeException(e); |
607 | } |
608 | } |
609 | |
610 | static Object get(Class c, String field) { |
611 | try { |
612 | Field f = get_findStaticField(c, field); |
613 | f.setAccessible(true); |
614 | return f.get(null); |
615 | } catch (Exception e) { |
616 | throw new RuntimeException(e); |
617 | } |
618 | } |
619 | |
620 | static Field get_findStaticField(Class<?> c, String field) { |
621 | Class _c = c; |
622 | do { |
623 | for (Field f : _c.getDeclaredFields()) |
624 | if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) |
625 | return f; |
626 | _c = _c.getSuperclass(); |
627 | } while (_c != null); |
628 | throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); |
629 | } |
630 | |
631 | static Field get_findField(Class<?> c, String field) { |
632 | Class _c = c; |
633 | do { |
634 | for (Field f : _c.getDeclaredFields()) |
635 | if (f.getName().equals(field)) |
636 | return f; |
637 | _c = _c.getSuperclass(); |
638 | } while (_c != null); |
639 | throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); |
640 | } |
641 | |
642 | static String str(Object o) { |
643 | return String.valueOf(o); |
644 | } |
645 | |
646 | static boolean isJavaIdentifier(String s) { |
647 | if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) |
648 | return false; |
649 | for (int i = 1; i < s.length(); i++) |
650 | if (!Character.isJavaIdentifierPart(s.charAt(i))) |
651 | return false; |
652 | return true; |
653 | } |
654 | |
655 | static int l(Object[] array) { |
656 | return array == null ? 0 : array.length; |
657 | } |
658 | |
659 | static int l(byte[] array) { |
660 | return array == null ? 0 : array.length; |
661 | } |
662 | |
663 | static int l(int[] array) { |
664 | return array == null ? 0 : array.length; |
665 | } |
666 | |
667 | static int l(char[] array) { |
668 | return array == null ? 0 : array.length; |
669 | } |
670 | |
671 | static int l(Collection c) { |
672 | return c == null ? 0 : c.size(); |
673 | } |
674 | |
675 | static int l(Map m) { |
676 | return m == null ? 0 : m.size(); |
677 | } |
678 | |
679 | static int l(String s) { |
680 | return s == null ? 0 : s.length(); |
681 | } |
682 | |
683 | |
684 | |
685 | // varargs assignment fixer for a single string array argument |
686 | static Object call(Object o, String method, String[] arg) { |
687 | return call(o, method, new Object[] {arg}); |
688 | } |
689 | |
690 | static Object call(Object o, String method, Object... args) { |
691 | try { |
692 | if (o instanceof Class) { |
693 | Method m = call_findStaticMethod((Class) o, method, args, false); |
694 | m.setAccessible(true); |
695 | return m.invoke(null, args); |
696 | } else { |
697 | Method m = call_findMethod(o, method, args, false); |
698 | m.setAccessible(true); |
699 | return m.invoke(o, args); |
700 | } |
701 | } catch (Exception e) { |
702 | throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); |
703 | } |
704 | } |
705 | |
706 | static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { |
707 | Class _c = c; |
708 | while (c != null) { |
709 | for (Method m : c.getDeclaredMethods()) { |
710 | if (debug) |
711 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
712 | if (!m.getName().equals(method)) { |
713 | if (debug) System.out.println("Method name mismatch: " + method); |
714 | continue; |
715 | } |
716 | |
717 | if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) |
718 | continue; |
719 | |
720 | return m; |
721 | } |
722 | c = c.getSuperclass(); |
723 | } |
724 | throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); |
725 | } |
726 | |
727 | static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { |
728 | Class c = o.getClass(); |
729 | while (c != null) { |
730 | for (Method m : c.getDeclaredMethods()) { |
731 | if (debug) |
732 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
733 | if (m.getName().equals(method) && call_checkArgs(m, args, debug)) |
734 | return m; |
735 | } |
736 | c = c.getSuperclass(); |
737 | } |
738 | throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); |
739 | } |
740 | |
741 | private static boolean call_checkArgs(Method m, Object[] args, boolean debug) { |
742 | Class<?>[] types = m.getParameterTypes(); |
743 | if (types.length != args.length) { |
744 | if (debug) |
745 | System.out.println("Bad parameter length: " + args.length + " vs " + types.length); |
746 | return false; |
747 | } |
748 | for (int i = 0; i < types.length; i++) |
749 | if (!(args[i] == null || isInstanceX(types[i], args[i]))) { |
750 | if (debug) |
751 | System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); |
752 | return false; |
753 | } |
754 | return true; |
755 | } |
756 | |
757 | |
758 | |
759 | // extended over Class.isInstance() to handle primitive types |
760 | static boolean isInstanceX(Class type, Object arg) { |
761 | if (type == boolean.class) return arg instanceof Boolean; |
762 | if (type == int.class) return arg instanceof Integer; |
763 | if (type == long.class) return arg instanceof Long; |
764 | if (type == float.class) return arg instanceof Float; |
765 | if (type == short.class) return arg instanceof Short; |
766 | if (type == char.class) return arg instanceof Character; |
767 | if (type == byte.class) return arg instanceof Byte; |
768 | if (type == double.class) return arg instanceof Double; |
769 | return type.isInstance(arg); |
770 | } |
771 | |
772 | static boolean match(String pat, String s) { |
773 | return match3(pat, s); |
774 | } |
775 | |
776 | static boolean match(String pat, String s, Matches matches) { |
777 | return match3(pat, s, matches); |
778 | } |
779 | |
780 | |
781 | static String unq(String s) { |
782 | return unquote(s); |
783 | } |
784 | |
785 | // class Matches is added by #752 |
786 | |
787 | static boolean match3(String pat, String s) { |
788 | return match3(pat, s, null); |
789 | } |
790 | |
791 | static boolean match3(String pat, String s, Matches matches) { |
792 | if (s == null) return false; |
793 | return match3(pat, parse3(s), matches); |
794 | } |
795 | |
796 | static boolean match3(String pat, List<String> toks, Matches matches) { |
797 | List<String> tokpat = parse3(pat); |
798 | return match3(tokpat,toks,matches); |
799 | } |
800 | |
801 | static boolean match3(List<String> tokpat, List<String> toks, Matches matches) { |
802 | |
803 | String[] m = match2(tokpat, toks); |
804 | //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m)); |
805 | if (m == null) |
806 | return false; |
807 | else { |
808 | if (matches != null) matches.m = m; |
809 | return true; |
810 | } |
811 | } |
812 | |
813 | // match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens) |
814 | |
815 | static String[] match2(List<String> pat, List<String> tok) { |
816 | // standard case (no ...) |
817 | int i = pat.indexOf("..."); |
818 | if (i < 0) return match2_match(pat, tok); |
819 | |
820 | pat = new ArrayList<String>(pat); // We're modifying it, so copy first |
821 | pat.set(i, "*"); |
822 | while (pat.size() < tok.size()) { |
823 | pat.add(i, "*"); |
824 | pat.add(i+1, ""); // doesn't matter |
825 | } |
826 | |
827 | return match2_match(pat, tok); |
828 | } |
829 | |
830 | static String[] match2_match(List<String> pat, List<String> tok) { |
831 | List<String> result = new ArrayList<String>(); |
832 | if (pat.size() != tok.size()) { |
833 | /*if (debug) |
834 | print("Size mismatch: " + structure(pat) + " vs " + structure(tok));*/ |
835 | return null; |
836 | } |
837 | for (int i = 1; i < pat.size(); i += 2) { |
838 | String p = pat.get(i), t = tok.get(i); |
839 | /*if (debug) |
840 | print("Checking " + p + " against " + t);*/ |
841 | if (eq(p, "*")) |
842 | result.add(t); |
843 | else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now |
844 | return null; |
845 | } |
846 | return result.toArray(new String[result.size()]); |
847 | } |
848 | |
849 | |
850 | static List<String> parse3(String s) { |
851 | return dropPunctuation(javaTokPlusPeriod(s)); |
852 | } |
853 | |
854 | static boolean equalsIgnoreCase(String a, String b) { |
855 | return a == null ? b == null : a.equalsIgnoreCase(b); |
856 | } |
857 | |
858 | static List<String> dropPunctuation_keep = litlist("*", "<", ">"); |
859 | |
860 | static List<String> dropPunctuation(List<String> tok) { |
861 | tok = new ArrayList<String>(tok); |
862 | for (int i = 1; i < tok.size(); i += 2) { |
863 | String t = tok.get(i); |
864 | if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) { |
865 | tok.set(i-1, tok.get(i-1) + tok.get(i+1)); |
866 | tok.remove(i); |
867 | tok.remove(i); |
868 | i -= 2; |
869 | } |
870 | } |
871 | return tok; |
872 | } |
873 | |
874 | static String dropPunctuation(String s) { |
875 | return join(dropPunctuation(nlTok(s))); |
876 | } |
877 | |
878 | static boolean eq(Object a, Object b) { |
879 | if (a == null) return b == null; |
880 | if (a.equals(b)) return true; |
881 | if (a instanceof BigInteger) { |
882 | if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b)); |
883 | if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b)); |
884 | } |
885 | return false; |
886 | } |
887 | |
888 | static <A> ArrayList<A> litlist(A... a) { |
889 | return new ArrayList<A>(Arrays.asList(a)); |
890 | } |
891 | |
892 | static List<String> nlTok(String s) { |
893 | return javaTokPlusPeriod(s); |
894 | } |
895 | } |
Snippet is not live.
Travelled to 12 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #3000187 |
Snippet name: | Answer for stefanreich |
Eternal ID of this version: | #3000187/1 |
Text MD5: | 5b4c7a34021151591396bdda9e89f627 |
Author: | someone |
Category: | |
Type: | New Tinybrain snippet |
Gummipassword: | eleutheria-for-user |
Uploaded from IP: | 69.10.46.185 |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-02-01 21:27:57 |
Source code size: | 25458 bytes / 895 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 444 / 91 |
Referenced in: | [show references] |