import java.util.*; import java.util.zip.*; import java.util.List; import java.util.regex.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.table.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import java.lang.ref.*; import java.lang.management.*; import java.security.*; import java.security.spec.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.imageio.*; import java.math.*; class main { static class A { int a; public boolean equals(Object o) { return stdEq2(this, o); } public int hashCode() { return stdHash2(this); } } static class B extends A { int b; public boolean equals(Object o) { return stdEq2(this, o); } public int hashCode() { return stdHash2(this); } } static int n = 200000; public static void main(final String[] args) throws Exception { List l = new ArrayList(); for (int i = 0; i < n; i++) { l.add(nu(A.class, "a" , 1)); l.add(nu(B.class, "a" , 2, "b" , 3)); } print("Objects: " + l(l)); structure_showTiming = true; for (int i = 0; i < 8; i++) { // give Server VM time to optimize String s = testStructureFunction(l); /*print("javaTok_streaming"); time { javaTok_streaming(s, new JavaTok_Stream { void add(int i, int j) {} }); }*/ print("\n==\n"); } print("OK"); } static boolean stdEq2(Object a, Object b) { if (a == null) return b == null; if (b == null) return false; if (a.getClass() != b.getClass()) return false; for (String field : allFields(a)) if (neq(getOpt(a, field), getOpt(b, field))) return false; return true; } static int stdHash2(Object a) { if (a == null) return 0; return stdHash(a, toStringArray(allFields(a))); } static A nu(Class c, Object... values) { A a = nuObject(c); setAll(a, values); return a; } static volatile StringBuffer local_log = new StringBuffer(); // not redirected static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot // in bytes - will cut to half that static volatile int print_log_max = 1024*1024; static volatile int local_log_max = 100*1024; //static int print_maxLineLength = 0; // 0 = unset static boolean print_silent; // total mute if set static Object print_byThread_lock = new Object(); static volatile ThreadLocal print_byThread; // special handling by thread - prefers F1 static volatile Object print_allThreads; static void print() { print(""); } static A print(String s, A o) { print((endsWithLetterOrDigit(s) ? s + ": " : s) + o); return o; } // slightly overblown signature to return original object... static A print(A o) { ping(); if (print_silent) return o; String s = String.valueOf(o) + "\n"; print_noNewLine(s); return o; } static void print_noNewLine(String s) { Object f = print_byThread == null ? null : print_byThread.get(); if (f == null) f = print_allThreads; if (f != null) // We do need the general callF machinery here as print_byThread is sometimes shared between modules if (isFalse( callF(f, s))) return; print_raw(s); } static void print_raw(String s) { s = fixNewLines(s); // TODO if (print_maxLineLength != 0) StringBuffer loc = local_log; Appendable buf = print_log; int loc_max = print_log_max; if (buf != loc && buf != null) { print_append(buf, s, print_log_max); loc_max = local_log_max; } if (loc != null) print_append(loc, s, loc_max); System.out.print(s); } static int l(Object[] a) { return a == null ? 0 : a.length; } static int l(boolean[] a) { return a == null ? 0 : a.length; } static int l(byte[] a) { return a == null ? 0 : a.length; } static int l(short[] a) { return a == null ? 0 : a.length; } static int l(long[] a) { return a == null ? 0 : a.length; } static int l(int[] a) { return a == null ? 0 : a.length; } static int l(float[] a) { return a == null ? 0 : a.length; } static int l(double[] a) { return a == null ? 0 : a.length; } static int l(char[] a) { return a == null ? 0 : a.length; } static int l(Collection c) { return c == null ? 0 : c.size(); } static int l(Map m) { return m == null ? 0 : m.size(); } static int l(CharSequence s) { return s == null ? 0 : s.length(); } static long l(File f) { return f == null ? 0 : f.length(); } static int l(Object o) { return o == null ? 0 : o instanceof String ? l((String) o) : o instanceof Map ? l((Map) o) : o instanceof Collection ? l((Collection) o) : o instanceof Object[] ? l((Object[]) o) : (Integer) call(o, "size"); } static String testStructureFunction(Object input) { return testStructureFunction(input, true); } static String testStructureFunction(Object input, boolean compare) { String s; { long _startTime_3 = sysNow(); try { s = structure(input); } finally { _startTime_3 = sysNow()-_startTime_3; saveTiming(_startTime_3); } } print(shorten(s, 500)); Object o; print("unstructuring " + l(s) + " chars"); { long _startTime_4 = sysNow(); try { o = unstructure(s); } finally { _startTime_4 = sysNow()-_startTime_4; saveTiming(_startTime_4); } } String x = structure(o); assertEquals(s, x); if (compare) assertEquals(input, o); return x; } static Set allFields(Object o) { TreeSet fields = new TreeSet(); Class _c = _getClass(o); do { for (Field f : _c.getDeclaredFields()) fields.add(f.getName()); _c = _c.getSuperclass(); } while (_c != null); return fields; } static boolean neq(Object a, Object b) { return !eq(a, b); } static Object getOpt(Object o, String field) { return getOpt_cached(o, field); } static Object getOpt_raw(Object o, String field) { try { Field f = getOpt_findField(o.getClass(), field); if (f == null) return null; f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(e); } } // access of static fields is not yet optimized static Object getOpt(Class c, String field) { try { if (c == null) return null; Field f = getOpt_findStaticField(c, field); if (f == null) return null; f.setAccessible(true); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field getOpt_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static int stdHash(Object a, String... fields) { if (a == null) return 0; int hash = getClassName(a).hashCode(); for (String field : fields) hash = hash*2+hashCode(getOpt(a, field)); return hash; } static String[] toStringArray(Collection c) { String[] a = new String[l(c)]; Iterator it = c.iterator(); for (int i = 0; i < l(a); i++) a[i] = it.next(); return a; } static String[] toStringArray(Object o) { if (o instanceof String[]) return (String[]) o; else if (o instanceof Collection) return toStringArray((Collection) o); else throw fail("Not a collection or array: " + getClassName(o)); } static Object nuObject(String className, Object... args) { try { return nuObject(classForName(className), args); } catch (Exception __e) { throw rethrow(__e); } } // too ambiguous - maybe need to fix some callers /*static O nuObject(O realm, S className, O... args) { ret nuObject(_getClass(realm, className), args); }*/ static A nuObject(Class c, Object... args) { try { if (args.length == 0) return nuObjectWithoutArguments(c); // cached! Constructor m = nuObject_findConstructor(c, args); m.setAccessible(true); return (A) m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuObject_findConstructor(Class c, Object... args) { for (Constructor m : c.getDeclaredConstructors()) { if (!nuObject_checkArgs(m.getParameterTypes(), args, false)) continue; return m; } throw fail("Constructor " + c.getName() + getClasses(args) + " not found" + (args.length == 0 && (c.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 ? " - hint: it's a non-static class!" : "")); } static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) { if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static void setAll(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) set(o, field, fields.get(field)); } static void setAll(Object o, Object... values) { //values = expandParams(c.getClass(), values); failIfOddCount(values); for (int i = 0; i+1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i+1]; set(o, field, value); } } static boolean endsWithLetterOrDigit(String s) { return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length()-1)); } //sbool ping_actions_shareable = true; static volatile boolean ping_pauseAll; static int ping_sleep = 100; // poll pauseAll flag every 100 static volatile boolean ping_anyActions; static Map ping_actions = newWeakHashMap(); // always returns true static boolean ping() { if (ping_pauseAll || ping_anyActions ) ping_impl(); //ifndef LeanMode ping_impl(); endifndef return true; } // returns true when it slept static boolean ping_impl() { try { if (ping_pauseAll && !isAWTThread()) { do Thread.sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { // don't allow sharing ping_actions Object action = null; synchronized(ping_actions) { if (!ping_actions.isEmpty()) { action = ping_actions.get(currentThread()); if (action instanceof Runnable) ping_actions.remove(currentThread()); if (ping_actions.isEmpty()) ping_anyActions = false; } } if (action instanceof Runnable) ((Runnable) action).run(); else if (eq(action, "cancelled")) throw fail("Thread cancelled."); } return false; } catch (Exception __e) { throw rethrow(__e); } } static boolean isFalse(Object o) { return eq(false, o); } static Map> callF_cache = newDangerousWeakHashMap(); static void callF(VF1 f, A a) { if (f != null) f.get(a); } static Object callF(Object f, Object... args) { try { if (f instanceof String) return callMC((String) f, args); if (f instanceof Runnable) { ((Runnable) f).run(); return null; } if (f == null) return null; Class c = f.getClass(); ArrayList methods; synchronized(callF_cache) { methods = callF_cache.get(c); if (methods == null) methods = callF_makeCache(c); } int n = l(methods); if (n == 0) { throw fail("No get method in " + getClassName(c)); } if (n == 1) return invokeMethod(methods.get(0), f, args); for (int i = 0; i < n; i++) { Method m = methods.get(i); if (call_checkArgs(m, args, false)) return invokeMethod(m, f, args); } throw fail("No matching get method in " + getClassName(c)); } catch (Exception __e) { throw rethrow(__e); } } // used internally static ArrayList callF_makeCache(Class c) { ArrayList l = new ArrayList(); Class _c = c; do { for (Method m : _c.getDeclaredMethods()) if (m.getName().equals("get")) { m.setAccessible(true); l.add(m); } if (!l.isEmpty()) break; _c = _c.getSuperclass(); } while (_c != null); callF_cache.put(c, l); return l; } static String fixNewLines(String s) { int i = indexOf(s, '\r'); if (i < 0) return s; int l = s.length(); StringBuilder out = new StringBuilder(l); out.append(s, 0, i); for (; i < l; i++) { char c = s.charAt(i); if (c != '\r') out.append(c); else { out.append('\n'); if (i+1 < l && s.charAt(i+1) == '\n') ++i; } } return out.toString(); } static void print_append(Appendable _buf, String s, int max) { try { synchronized(_buf) { _buf.append(s); if (!(_buf instanceof StringBuilder)) return; StringBuilder buf = (StringBuilder) ( _buf); max /= 2; if (buf.length() > max) try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } } } catch (Exception __e) { throw rethrow(__e); } } static Object call(Object o) { return callF(o); } // varargs assignment fixer for a single string array argument static Object call(Object o, String method, String[] arg) { return call(o, method, new Object[] {arg}); } static Object call(Object o, String method, Object... args) { return call_cached(o, method, args); } static long sysNow() { return System.nanoTime()/1000000; } static boolean structure_showTiming, structure_checkTokenCount; static String structure(Object o) { return structure(o, new structure_Data()); } static String structure(Object o, structure_Data d) { StringWriter sw = new StringWriter(); d.out = new PrintWriter(sw); structure_go(o, d); String s = str(sw); if (structure_checkTokenCount) { print("token count=" + d.n); assertEquals("token count", l(javaTokC(s)), d.n); } return s; } static void structure_go(Object o, structure_Data d) { structure_1(o, d); while (nempty(d.stack)) popLast(d.stack).run(); } static void structureToPrintWriter(Object o, PrintWriter out) { structure_Data d = new structure_Data(); d.out = out; structure_go(o, d); } // leave to false, unless unstructure() breaks static boolean structure_allowShortening = false; static class structure_Data { PrintWriter out; int stringSizeLimit; int shareStringsLongerThan = 20; boolean noStringSharing; IdentityHashMap seen = new IdentityHashMap(); //new BitSet refd; HashMap strings = new HashMap(); HashSet concepts = new HashSet(); HashMap> fieldsByClass = new HashMap(); HashMap persistenceInfo = new HashMap(); int n; // token count List stack = new ArrayList(); // append single token structure_Data append(String token) { out.print(token); ++n; return this; } structure_Data append(int i) { out.print(i); ++n; return this; } // append multiple tokens structure_Data append(String token, int tokCount) { out.print(token); n += tokCount; return this; } // extend last token structure_Data app(String token) { out.print(token); return this; } structure_Data app(int i) { out.print(i); return this; } } static void structure_1(final Object o, final structure_Data d) { try { if (o == null) { d.append("null"); return; } Class c = o.getClass(); boolean concept = false; List lFields = d.fieldsByClass.get(c); if (lFields == null) { // these are never back-referenced (for readability) if (o instanceof Number) { PrintWriter out = d.out; if (o instanceof Integer) { int i = ((Integer) o).intValue(); out.print(i); d.n += i < 0 ? 2 : 1; return; } if (o instanceof Long) { long l = ((Long) o).longValue(); out.print(l); out.print("L"); d.n += l < 0 ? 2 : 1; return; } if (o instanceof Short) { short s = ((Short) o).shortValue(); d.append("sh ", 2); out.print(s); d.n += s < 0 ? 2 : 1; return; } if (o instanceof Float) { d.append("fl ", 2); quoteToPrintWriter(str(o), out); return; } if (o instanceof Double) { d.append("d(", 3); quoteToPrintWriter(str(o), out); d.append(")"); return; } if (o instanceof BigInteger) { out.print("bigint("); out.print(o); out.print(")"); d.n += ((BigInteger) o).signum() < 0 ? 5 : 4; return; } } if (o instanceof Boolean) { d.append(((Boolean) o).booleanValue() ? "t" : "f"); return; } if (o instanceof Character) { d.append(quoteCharacter((Character) o)); return; } if (o instanceof File) { d.append("File ").append(quote(((File) o).getPath())); return; } // referencable objects follow Integer ref = d.seen.get(o); if (o instanceof String && ref == null) ref = d.strings.get((String) o); if (ref != null) { /*d.refd.set(ref);*/ d.append("t").app(ref); return; } if (!(o instanceof String)) d.seen.put(o, d.n); // record token number else { String s = d.stringSizeLimit != 0 ? shorten((String) o, d.stringSizeLimit) : (String) o; if (!d.noStringSharing) { if (d.shareStringsLongerThan == Integer.MAX_VALUE) d.seen.put(o, d.n); if (l(s) >= d.shareStringsLongerThan) d.strings.put(s, d.n); } quoteToPrintWriter(s, d.out); d.n++; return; } if (o instanceof HashSet) { d.append(o instanceof LinkedHashSet ? "lhs" : "hashset"); structure_1(new ArrayList((Set) o), d); return; } if (o instanceof TreeSet) { d.append("treeset"); structure_1(new ArrayList((Set) o), d); return; } String name = c.getName(); if (o instanceof Collection && !startsWith(name, "main$") /* && neq(name, "main$Concept$RefL") */) { if (name.equals("java.util.Collections$SynchronizedList") || name.equals("java.util.Collections$SynchronizedRandomAccessList")) d.append("sync"); d.append("["); final int l = d.n; final Iterator it = ((Collection) o).iterator(); d.stack.add(new Runnable() { public void run() { try { if (!it.hasNext()) d.append("]"); else { d.stack.add(this); if (d.n != l) d.append(", "); structure_1(it.next(), d); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (!it.hasNext())\r\n d.append(\"]\");\r\n else {\r\n d.sta..."; }}); return; } if (o instanceof Map && !startsWith(name, "main$")) { if (o instanceof LinkedHashMap) d.append("lhm"); else if (o instanceof HashMap) d.append("hm"); else if (name.equals("java.util.Collections$SynchronizedMap")) d.append("sync"); else if (name.equals("java.util.Collections$SynchronizedSortedMap")) { d.append("sync tm", 2); } d.append("{"); final int l = d.n; final Iterator it = ((Map) o).entrySet().iterator(); d.stack.add(new Runnable() { boolean v; Map.Entry e; public void run() { if (v) { d.append("="); v = false; d.stack.add(this); structure_1(e.getValue(), d); } else { if (!it.hasNext()) d.append("}"); else { e = (Map.Entry) it.next(); v = true; d.stack.add(this); if (d.n != l) d.append(", "); structure_1(e.getKey(), d); } } } }); return; } if (c.isArray()) { if (o instanceof byte[]) { d.append("ba ").append(quote(bytesToHex((byte[]) o))); return; } final int n = Array.getLength(o); if (o instanceof boolean[]) { String hex = boolArrayToHex((boolean[]) o); int i = l(hex); while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); return; } String atype = "array", sep = ", "; if (o instanceof int[]) { //ret "intarray " + quote(intArrayToHex((int[]) o)); atype = "intarray"; sep = " "; } d.append(atype).append("{"); d.stack.add(new Runnable() { int i; public void run() { if (i >= n) d.append("}"); else { d.stack.add(this); if (i > 0) d.append(", "); structure_1(Array.get(o, i++), d); } } }); return; } if (o instanceof Class) { d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); return; } if (o instanceof Throwable) { d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); return; } if (o instanceof BitSet) { BitSet bs = (BitSet) o; d.append("bitset{", 2); int l = d.n; for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { if (d.n != l) d.append(", "); d.append(i); } d.append("}"); return; } // Need more cases? This should cover all library classes... if (name.startsWith("java.") || name.startsWith("javax.")) { d.append("j ").append(quote(str(o))); return; // Hm. this is not unstructure-able } /*if (name.equals("main$Lisp")) { fail("lisp not supported right now"); }*/ String dynName = shortDynamicClassName(o); if (concept && !d.concepts.contains(dynName)) { d.concepts.add(dynName); d.append("c "); } // serialize an object with fields. // first, collect all fields and values in fv. TreeSet fields = new TreeSet(new Comparator() { public int compare(Field a, Field b) { return stdcompare(a.getName(), b.getName()); } }); Class cc = c; while (cc != Object.class) { for (Field field : getDeclaredFields_cached(cc)) { String fieldName = field.getName(); if (fieldName.equals("_persistenceInfo")) d.persistenceInfo.put(c, field); if ((field.getModifiers() & (java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.TRANSIENT)) != 0) continue; fields.add(field); // put special cases here...? } cc = cc.getSuperclass(); } // TODO: S fieldOrder = getOpt(c, "_fieldOrder"); lFields = asList(fields); // Render this$1 first because unstructure needs it for constructor call. for (int i = 0; i < l(lFields); i++) { Field f = lFields.get(i); if (f.getName().equals("this$1")) { lFields.remove(i); lFields.add(0, f); break; } } d.fieldsByClass.put(c, lFields); } // << if (lFields == null) else { // ref handling for lFields != null Integer ref = d.seen.get(o); if (ref != null) { /*d.refd.set(ref);*/ d.append("t").app(ref); return; } d.seen.put(o, d.n); // record token number } Field persistenceInfoField = (Field) ( d.persistenceInfo.get(c)); Map persistenceInfo = persistenceInfoField == null ? null : (Map) persistenceInfoField.get(o); LinkedHashMap fv = new LinkedHashMap(); for (Field f : lFields) { Object value; try { value = f.get(o); } catch (Exception e) { value = "?"; } if (value != null && (persistenceInfo == null || !Boolean.FALSE.equals(persistenceInfo.get(f.getName())))) fv.put(f.getName(), value); } String name = c.getName(); String shortName = dropPrefix("main$", name); // Now we have fields & values. Process fieldValues if it's a DynamicObject. // omit field "className" if equal to class's name if (concept && eq(fv.get("className"), shortName)) fv.remove("className"); if (o instanceof DynamicObject) { fv.putAll((Map) fv.get("fieldValues")); fv.remove("fieldValues"); shortName = shortDynamicClassName(o); fv.remove("className"); } String singleField = fv.size() == 1 ? first(fv.keySet()) : null; d.append(shortName); final int l = d.n; final Iterator it = fv.entrySet().iterator(); d.stack.add(new Runnable() { public void run() { try { if (!it.hasNext()) { if (d.n != l) d.append(")"); } else { Map.Entry e = (Map.Entry) it.next(); d.append(d.n == l ? "(" : ", "); d.append((String) e.getKey()).append("="); d.stack.add(this); structure_1(e.getValue(), d); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (!it.hasNext()) {\r\n if (d.n != l)\r\n d.append(\")\");\r\n } else..."; }}); } catch (Exception __e) { throw rethrow(__e); } } static ThreadLocal saveTiming_last = new ThreadLocal(); static void saveTiming(long ms) { print(ms + " ms"); saveTiming_noPrint(ms); } static void saveTiming_noPrint(long ms) { saveTiming_last.set(ms); } static int shorten_default = 100; static String shorten(String s) { return shorten(s, shorten_default); } static String shorten(String s, int max) { return shorten(s, max, "..."); } static String shorten(String s, int max, String shortener) { if (s == null) return ""; if (max < 0) return s; return s.length() <= max ? s : substring(s, 0, min(s.length(), max-l(shortener))) + shortener; } static String shorten(int max, String s) { return shorten(s, max); } static Object unstructure(String text) { return unstructure(text, false); } static Object unstructure(String text, final boolean allDynamic) { return unstructure(text, allDynamic, null); } static int structure_internStringsLongerThan = 50; static int unstructure_unquoteBufSize = 100; static int unstructure_tokrefs; // stats abstract static class unstructure_Receiver { abstract void set(Object o); } // classFinder: func(name) -> class (optional) static Object unstructure(String text, boolean allDynamic, Object classFinder) { if (text == null) return null; return unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder); } static Object unstructure_reader(BufferedReader reader) { return unstructure_tok(javaTokC_noMLS_onReader(reader), false, null); } static Object unstructure_tok(final Producer tok, final boolean allDynamic, final Object classFinder) { final boolean debug = unstructure_debug; final class X { int i = -1; HashMap refs = new HashMap(); HashMap tokrefs = new HashMap(); HashSet concepts = new HashSet(); HashMap classesMap = new HashMap(); List stack = new ArrayList(); String curT; char[] unquoteBuf = new char[unstructure_unquoteBufSize]; String unquote(String s) { return unquoteUsingCharArray(s, unquoteBuf); } // look at current token String t() { return curT; } // get current token, move to next String tpp() { String t = curT; consume(); return t; } void parse(final unstructure_Receiver out) { String t = t(); int refID = 0; if (structure_isMarker(t, 0, l(t))) { refID = parseInt(t.substring(1)); consume(); } final int _refID = refID; // if (debug) print("parse: " + quote(t)); final int tokIndex = i; parse_inner(refID, tokIndex, new unstructure_Receiver() { void set(Object o) { if (_refID != 0) refs.put(_refID, o); if (o != null) tokrefs.put(tokIndex, o); out.set(o); } }); } void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) { String t = t(); // if (debug) print("parse_inner: " + quote(t)); Class c = classesMap.get(t); if (c == null) { if (t.startsWith("\"")) { String s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan); out.set(s); return; } if (t.startsWith("'")) { out.set(unquoteCharacter(tpp())); return; } if (t.equals("bigint")) { out.set(parseBigInt()); return; } if (t.equals("d")) { out.set(parseDouble()); return; } if (t.equals("fl")) { out.set(parseFloat()); return; } if (t.equals("sh")) { consume(); t = tpp(); if (t.equals("-")) { t = tpp(); out.set((short) (-parseInt(t))); return; } out.set((short) parseInt(t)); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; if (debug) print("l=" + l + ", isInt: " + isInt); out.set(isInt ? (Object) new Integer((int) l) : (Object) new Long(l)); return; } if (t.equals("false") || t.equals("f")) { consume(); out.set(false); return; } if (t.equals("true") || t.equals("t")) { consume(); out.set(true); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; if (debug) print("l=" + l + ", isInt: " + isInt); out.set(isInt ? (Object) new Integer((int) l) : (Object) new Long(l)); return; } if (t.equals("File")) { consume(); File f = new File(unquote(tpp())); out.set(f); return; } if (t.startsWith("r") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = refs.get(ref); if (o == null) print("Warning: unsatisfied back reference " + ref); out.set(o); return; } if (t.startsWith("t") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = tokrefs.get(ref); if (o == null) print("Warning: unsatisfied token reference " + ref); out.set(o); return; } if (t.equals("hashset")) { parseHashSet(out); return; } if (t.equals("lhs")) { parseLinkedHashSet(out); return; } if (t.equals("treeset")) { parseTreeSet(out); return; } if (eqOneOf(t, "hashmap", "hm")) { consume(); parseMap(new HashMap(), out); return; } if (t.equals("lhm")) { consume(); parseMap(new LinkedHashMap(), out); return; } if (t.equals("sync")) { consume(); if (t().equals("tm")) { consume(); { parseMap(synchronizedTreeMap(), out); return; } } if (t().equals("[")) { parseList(synchroList(), out); return; } { parseMap(synchronizedMap(), out); return; } } if (t.equals("{")) { parseMap(out); return; } if (t.equals("[")) { this.parseList(new ArrayList(), out); return; } if (t.equals("bitset")) { parseBitSet(out); return; } if (t.equals("array") || t.equals("intarray")) { parseArray(out); return; } if (t.equals("ba")) { consume(); String hex = unquote(tpp()); out.set(hexToBytes(hex)); return; } if (t.equals("boolarray")) { consume(); int n = parseInt(tpp()); String hex = unquote(tpp()); out.set(boolArrayFromBytes(hexToBytes(hex), n)); return; } if (t.equals("class")) { out.set(parseClass()); return; } if (t.equals("l")) { parseLisp(out); return; } if (t.equals("null")) { consume(); out.set(null); return; } if (eq(t, "c")) { consume("c"); t = t(); assertTrue(isJavaIdentifier(t)); concepts.add(t); } } if (eq(t, "j")) { consume("j"); out.set(parseJava()); return; } if (c == null && !isJavaIdentifier(t)) throw new RuntimeException("Unknown token " + (i+1) + ": " + t); // any other class name if (c == null) { // First, find class if (allDynamic) c = null; else c = classFinder != null ? (Class) callF(classFinder, "main$" + t) : findClass(t); if (c != null) classesMap.put(t, c); } // Check if it has an outer reference consume(); boolean hasBracket = eq(t(), "("); if (hasBracket) consume(); boolean hasOuter = hasBracket && eq(t(), "this$1"); DynamicObject dO = null; Object o = null; final String thingName = t; if (c != null) { o = hasOuter ? nuStubInnerObject(c, classFinder) : nuEmptyObject(c); if (o instanceof DynamicObject) dO = (DynamicObject) o; } else { if (concepts.contains(t) && (c = findClass("Concept")) != null) o = dO = (DynamicObject) nuEmptyObject(c); else dO = new DynamicObject(); dO.className = t; if (debug) print("Made dynamic object " + t + " " + shortClassName(dO)); } // Save in references list early because contents of object // might link back to main object if (refID != 0) refs.put(refID, o != null ? o : dO); tokrefs.put(tokIndex, o != null ? o : dO); // NOW parse the fields! final LinkedHashMap fields = new LinkedHashMap(); // preserve order final Object _o = o; final DynamicObject _dO = dO; if (hasBracket) { stack.add(new Runnable() { public void run() { try { if (eq(t(), ")")) { consume(")"); objRead(_o, _dO, fields); out.set(_o != null ? _o : _dO); } else { final String key = unquote(tpp()); if (!eq(tpp(), "=")) throw fail("= expected, got " + t() + " after " + quote(key) + " in object " + thingName /*+ " " + sfu(fields)*/); stack.add(this); parse(new unstructure_Receiver() { void set(Object value) { fields.put(key, value); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \")\")) {\r\n consume(\")\");\r\n objRead(_o, _dO, ..."; }}); } else { objRead(o, dO, fields); out.set(o != null ? o : dO); } } void objRead(Object o, DynamicObject dO, Map fields) { if (o != null) if (dO != null) { if (debug) printStructure("setOptAllDyn", fields); setOptAllDyn(dO, fields); } else { setOptAll_pcall(o, fields); } else for (String field : keys(fields)) dO.fieldValues.put(intern(field), fields.get(field)); if (o != null) pcallOpt_noArgs(o, "_doneLoading"); } void parseSet(final Set set, final unstructure_Receiver out) { this.parseList(new ArrayList(), new unstructure_Receiver() { void set(Object o) { set.addAll((List) o); out.set(set); } }); } void parseLisp(final unstructure_Receiver out) { throw fail("class Lisp not included"); } void parseBitSet(final unstructure_Receiver out) { consume("bitset"); consume("{"); final BitSet bs = new BitSet(); stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); out.set(bs); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { bs.set((Integer) o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n out.set(bs);\r\n ..."; }}); } void parseList(final List list, final unstructure_Receiver out) { consume("["); stack.add(new Runnable() { public void run() { try { if (eq(t(), "]")) { consume("]"); out.set(list); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { //if (debug) print("List element type: " + getClassName(o)); list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"]\")) {\r\n consume(\"]\");\r\n out.set(list);\r\n ..."; }}); } void parseArray(final unstructure_Receiver out) { final String type = tpp(); consume("{"); final List list = new ArrayList(); stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); out.set(type.equals("intarray") ? toIntArray(list) : list.toArray()); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n out.set(type.equals(\"..."; }}); } Object parseClass() { consume("class"); consume("("); String name = unquote(tpp()); consume(")"); name = dropPrefix("main$", name); Class c = allDynamic ? null : classFinder != null ? (Class) callF(classFinder, name) : findClass(name); if (c != null) return c; DynamicObject dO = new DynamicObject(); dO.className = "java.lang.Class"; dO.fieldValues.put("name", name); return dO; } Object parseBigInt() { consume("bigint"); consume("("); String val = tpp(); if (eq(val, "-")) val = "-" + tpp(); consume(")"); return new BigInteger(val); } Object parseDouble() { consume("d"); consume("("); String val = unquote(tpp()); consume(")"); return Double.parseDouble(val); } Object parseFloat() { consume("fl"); String val; if (eq(t(), "(")) { consume("("); val = unquote(tpp()); consume(")"); } else { val = unquote(tpp()); } return Float.parseFloat(val); } void parseHashSet(unstructure_Receiver out) { consume("hashset"); parseSet(new HashSet(), out); } void parseLinkedHashSet(unstructure_Receiver out) { consume("lhs"); parseSet(new LinkedHashSet(), out); } void parseTreeSet(unstructure_Receiver out) { consume("treeset"); parseSet(new TreeSet(), out); } void parseMap(unstructure_Receiver out) { parseMap(new TreeMap(), out); } Object parseJava() { String j = unquote(tpp()); Matches m = new Matches(); if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m)) return nuObject("java.awt.Color", parseInt(m.unq(0)), parseInt(m.unq(1)), parseInt(m.unq(2))); else { warn("Unknown Java object: " + j); return null; } } void parseMap(final Map map, final unstructure_Receiver out) { consume("{"); stack.add(new Runnable() { boolean v; Object key; public void run() { if (v) { v = false; stack.add(this); if (!eq(tpp(), "=")) throw fail("= expected, got " + t() + " in map of size " + l(map)); parse(new unstructure_Receiver() { void set(Object value) { map.put(key, value); if (debug) print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(t())); if (eq(t(), ",")) consume(); } }); } else { if (eq(t(), "}")) { consume("}"); out.set(map); } else { v = true; stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { key = o; } }); } } // if v else } // run() }); } /*void parseSub(unstructure_Receiver out) { int n = l(stack); parse(out); while (l(stack) > n) stack }*/ void consume() { curT = tok.next(); ++i; } void consume(String s) { if (!eq(t(), s)) { /*S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");*/ throw fail(quote(s) + " expected, got " + quote(t())); } consume(); } void parse_x(unstructure_Receiver out) { consume(); // get first token parse(out); while (nempty(stack)) popLast(stack).run(); } } Boolean b = DynamicObject_loading.get(); DynamicObject_loading.set(true); try { final Var v = new Var(); X x = new X(); x.parse_x(new unstructure_Receiver() { void set(Object o) { v.set(o); } }); unstructure_tokrefs = x.tokrefs.size(); return v.get(); } finally { DynamicObject_loading.set(b); } } static boolean unstructure_debug; static A assertEquals(Object x, A y) { return assertEquals(null, x, y); } static A assertEquals(String msg, Object x, A y) { if (assertVerbose()) return assertEqualsVerbose(msg, x, y); if (!(x == null ? y == null : x.equals(y))) throw fail((msg != null ? msg + ": " : "") + y + " != " + x); return y; } static Class _getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; // could optimize this } } static Class _getClass(Object o) { return o == null ? null : o instanceof Class ? (Class) o : o.getClass(); } static Class _getClass(Object realm, String name) { try { return getClass(realm).getClassLoader().loadClass(classNameToVM(name)); } catch (Exception __e) { throw rethrow(__e); } } static boolean eq(Object a, Object b) { return a == null ? b == null : a == b || a.equals(b); } //static final Map> getOpt_cache = newDangerousWeakHashMap(f getOpt_special_init); static class getOpt_Map extends WeakHashMap { getOpt_Map() { if (getOpt_special == null) getOpt_special = new HashMap(); clear(); } public void clear() { super.clear(); //print("getOpt clear"); put(Class.class, getOpt_special); put(String.class, getOpt_special); } } static final Map> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map())); //static final Map> getOpt_cache = _registerWeakMap(synchroMap(new getOpt_Map)); static HashMap getOpt_special; // just a marker /*static void getOpt_special_init(Map map) { map.put(Class.class, getOpt_special); map.put(S.class, getOpt_special); }*/ static Object getOpt_cached(Object o, String field) { try { if (o == null) return null; Class c = o.getClass(); HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } if (map == getOpt_special) { if (o instanceof Class) return getOpt((Class) o, field); /*if (o instanceof S) ret getOpt(getBot((S) o), field);*/ if (o instanceof Map) return ((Map) o).get(field); } Field f = map.get(field); if (f != null) return f.get(o); if (o instanceof DynamicObject) return ((DynamicObject) o).fieldValues.get(field); return null; } catch (Exception __e) { throw rethrow(__e); } } // used internally - we are in synchronized block static HashMap getOpt_makeCache(Class c) { HashMap map; if (isSubtypeOf(c, Map.class)) map = getOpt_special; else { map = new HashMap(); Class _c = c; do { for (Field f : _c.getDeclaredFields()) { f.setAccessible(true); String name = f.getName(); if (!map.containsKey(name)) map.put(name, f); } _c = _c.getSuperclass(); } while (_c != null); } if (getOpt_cache != null) getOpt_cache.put(c, map); return map; } static Field getOpt_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } static int hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Throwable e) { throw asRuntimeException(e); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); } static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); } static Map classForName_cache = synchroHashMap(); static Class classForName(String name) { try { Class c = classForName_cache.get(name); if (c == null) classForName_cache.put(name, c = Class.forName(name)); return c; } catch (Exception __e) { throw rethrow(__e); } } static RuntimeException rethrow(Throwable t) { if (t instanceof Error) _handleError((Error) t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static Map nuObjectWithoutArguments_cache = newDangerousWeakHashMap(); static Object nuObjectWithoutArguments(String className) { try { return nuObjectWithoutArguments(classForName(className)); } catch (Exception __e) { throw rethrow(__e); } } static A nuObjectWithoutArguments(Class c) { try { if (nuObjectWithoutArguments_cache == null) // in class init return (A) nuObjectWithoutArguments_findConstructor(c).newInstance(); Constructor m = nuObjectWithoutArguments_cache.get(c); if (m == null) nuObjectWithoutArguments_cache.put(c, m = nuObjectWithoutArguments_findConstructor(c)); return (A) m.newInstance(); } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuObjectWithoutArguments_findConstructor(Class c) { for (Constructor m : c.getDeclaredConstructors()) if (empty(m.getParameterTypes())) { m.setAccessible(true); return m; } throw fail("No default constructor found in " + c.getName()); } static List getClasses(Object[] array) { List l = new ArrayList(); for (Object o : array) l.add(_getClass(o)); return l; } static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; if (type == double.class) return arg instanceof Double; return type.isInstance(arg); } static Set keys(Map map) { return map == null ? new HashSet() : map.keySet(); } static Set keys(Object map) { return keys((Map) map); } static void set(Object o, String field, Object value) { if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); f.setAccessible(true); smartSet(f, o, value); } catch (Exception e) { throw new RuntimeException(e); } } static void set(Class c, String field, Object value) { try { Field f = set_findStaticField(c, field); f.setAccessible(true); smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field set_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field set_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static void failIfOddCount(Object... list) { if (odd(l(list))) throw fail("Odd list size: " + list); } static Map newWeakHashMap() { return _registerWeakMap(synchroMap(new WeakHashMap())); } // TODO: test if android complains about this static boolean isAWTThread() { if (isAndroid()) return false; if (isHeadless()) return false; return isAWTThread_awt(); } static boolean isAWTThread_awt() { return SwingUtilities.isEventDispatchThread(); } static Thread currentThread() { return Thread.currentThread(); } static Map newDangerousWeakHashMap() { return _registerDangerousWeakMap(synchroMap(new WeakHashMap())); } // initFunction: voidfunc(Map) - is called initially, and after clearing the map static Map newDangerousWeakHashMap(Object initFunction) { return _registerDangerousWeakMap(synchroMap(new WeakHashMap()), initFunction); } static HashMap> callMC_cache = new HashMap(); static String callMC_key; static Method callMC_value; // varargs assignment fixer for a single string array argument static Object callMC(String method, String[] arg) { return callMC(method, new Object[] {arg}); } static Object callMC(String method, Object... args) { try { Method me; if (callMC_cache == null) callMC_cache = new HashMap(); // initializer time workaround synchronized(callMC_cache) { me = method == callMC_key ? callMC_value : null; } if (me != null) try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } List m; synchronized(callMC_cache) { m = callMC_cache.get(method); } if (m == null) { if (callMC_cache.isEmpty()) { callMC_makeCache(); m = callMC_cache.get(method); } if (m == null) throw fail("Method named " + method + " not found in main"); } int n = m.size(); if (n == 1) { me = m.get(0); synchronized(callMC_cache) { callMC_key = method; callMC_value = me; } try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } } for (int i = 0; i < n; i++) { me = m.get(i); if (call_checkArgs(me, args, false)) return invokeMethod(me, null, args); } throw fail("No method called " + method + " with matching arguments found in main"); } catch (Exception __e) { throw rethrow(__e); } } static void callMC_makeCache() { synchronized(callMC_cache) { callMC_cache.clear(); Class _c = (Class) mc(), c = _c; while (c != null) { for (Method m : c.getDeclaredMethods()) if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { m.setAccessible(true); multiMapPut(callMC_cache, m.getName(), m); } c = c.getSuperclass(); } } } static Object invokeMethod(Method m, Object o, Object... args) { try { try { return m.invoke(o, args); } catch (InvocationTargetException e) { throw rethrow(getExceptionCause(e)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static int indexOf(List l, A a, int startIndex) { if (l == null) return -1; for (int i = startIndex; i < l(l); i++) if (eq(l.get(i), a)) return i; return -1; } static int indexOf(List l, int startIndex, A a) { return indexOf(l, a, startIndex); } static int indexOf(List l, A a) { if (l == null) return -1; return l.indexOf(a); } static int indexOf(String a, String b) { return a == null || b == null ? -1 : a.indexOf(b); } static int indexOf(String a, String b, int i) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, char b) { return a == null ? -1 : a.indexOf(b); } static int indexOf(String a, int i, char b) { return indexOf(a, b, i); } static int indexOf(String a, char b, int i) { return a == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, int i, String b) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(A[] x, A a) { if (x == null) return -1; for (int i = 0; i < l(x); i++) if (eq(x[i], a)) return i; return -1; } static Object call_cached(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); // TODO: (super-rare) case where method exists static and non-static // with different args Method me = cache.findMethod(method, args); if (me == null) throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found"); if ((me.getModifiers() & Modifier.STATIC) == 0) throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not static"); return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me == null) throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found"); return invokeMethod(me, o, args); } } catch (Exception __e) { throw rethrow(__e); } } static String str(Object o) { return o == null ? "null" : o.toString(); } static String str(char[] c) { return new String(c); } static List javaTokC(String s) { if (s == null) return null; int l = s.length(); ArrayList tok = new ArrayList(); int i = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); i = j; } return tok; } static boolean nempty(Collection c) { return !empty(c); } static boolean nempty(CharSequence s) { return !empty(s); } static boolean nempty(Object[] o) { return !empty(o); } static boolean nempty(byte[] o) { return !empty(o); } static boolean nempty(int[] o) { return !empty(o); } static boolean nempty(Map m) { return !empty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean nempty(Object o) { return !empty(o); } static A popLast(List l) { return liftLast(l); } static void quoteToPrintWriter(String s, PrintWriter out) { if (s == null) { out.print("null"); return; } out.print('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') { out.print('\\'); out.print(c); } else if (c == '\r') out.print("\\r"); else if (c == '\n') out.print("\\n"); else if (c == '\0') out.print("\\0"); else out.print(c); } out.print('"'); } static String quoteCharacter(char c) { if (c == '\'') return "'\\''"; if (c == '\\') return "'\\\\'"; if (c == '\r') return "'\\r'"; if (c == '\n') return "'\\n'"; if (c == '\t') return "'\\t'"; return "'" + c + "'"; } static String quote(Object o) { if (o == null) return "null"; return quote(str(o)); } static String quote(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s)*1.5+2)); quote_impl(s, out); return out.toString(); } static void quote_impl(String s, StringBuilder out) { out.append('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else if (c == '\0') out.append("\\0"); else out.append(c); } out.append('"'); } static boolean startsWith(String a, String b) { return a != null && a.startsWith(b); } static boolean startsWith(String a, char c) { return nempty(a) && a.charAt(0) == c; } static boolean startsWith(String a, String b, Matches m) { if (!startsWith(a, b)) return false; m.m = new String[] {substring(a, l(b))}; return true; } static boolean startsWith(List a, List b) { if (a == null || l(b) > l(a)) return false; for (int i = 0; i < l(b); i++) if (neq(a.get(i), b.get(i))) return false; return true; } public static String bytesToHex(byte[] bytes) { return bytesToHex(bytes, 0, bytes.length); } public static String bytesToHex(byte[] bytes, int ofs, int len) { StringBuilder stringBuilder = new StringBuilder(len*2); for (int i = 0; i < len; i++) { String s = "0" + Integer.toHexString(bytes[ofs+i]); stringBuilder.append(s.substring(s.length()-2, s.length())); } return stringBuilder.toString(); } static String boolArrayToHex(boolean[] a) { return bytesToHex(boolArrayToBytes(a)); } static String substring(String s, int x) { return substring(s, x, l(s)); } static String substring(String s, int x, int y) { if (s == null) return null; if (x < 0) x = 0; if (x >= s.length()) return ""; if (y < x) y = x; if (y > s.length()) y = s.length(); return s.substring(x, y); } static Iterator emptyIterator() { return Collections.emptyIterator(); } static String shortDynamicClassName(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return ((DynamicObject) o).className; return shortClassName(o); } static int stdcompare(Number a, Number b) { return cmp(a, b); } static int stdcompare(String a, String b) { return cmp(a, b); } static int stdcompare(long a, long b) { return a < b ? -1 : a > b ? 1 : 0; } static int stdcompare(Object a, Object b) { return cmp(a, b); } static Map getDeclaredFields_cache = newDangerousWeakHashMap(); static Field[] getDeclaredFields_cached(Class c) { Field[] fields; synchronized(getDeclaredFields_cache) { fields = getDeclaredFields_cache.get(c); if (fields == null) { getDeclaredFields_cache.put(c, fields = c.getDeclaredFields()); for (Field f : fields) f.setAccessible(true); } } return fields; } static ArrayList asList(A[] a) { return a == null ? new ArrayList() : new ArrayList(Arrays.asList(a)); } static ArrayList asList(int[] a) { ArrayList l = new ArrayList(); for (int i : a) l.add(i); return l; } static ArrayList asList(Iterable s) { if (s instanceof ArrayList) return (ArrayList) s; ArrayList l = new ArrayList(); if (s != null) for (A a : s) l.add(a); return l; } static ArrayList asList(Producer p) { ArrayList l = new ArrayList(); A a; if (p != null) while ((a = p.next()) != null) l.add(a); return l; } static ArrayList asList(Enumeration e) { ArrayList l = new ArrayList(); if (e != null) while (e.hasMoreElements()) l.add(e.nextElement()); return l; } static String dropPrefix(String prefix, String s) { return s == null ? null : s.startsWith(prefix) ? s.substring(l(prefix)) : s; } static Object first(Object list) { return empty((List) list) ? null : ((List) list).get(0); } static A first(List list) { return empty(list) ? null : list.get(0); } static A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static A first(Iterable i) { if (i == null) return null; Iterator it = i.iterator(); return it.hasNext() ? it.next() : null; } static Character first(String s) { return empty(s) ? null : s.charAt(0); } static A first(Pair p) { return p == null ? null : p.a; } static int min(int a, int b) { return Math.min(a, b); } static long min(long a, long b) { return Math.min(a, b); } static float min(float a, float b) { return Math.min(a, b); } static float min(float a, float b, float c) { return min(min(a, b), c); } static double min(double a, double b) { return Math.min(a, b); } static double min(double[] c) { double x = Double.MAX_VALUE; for (double d : c) x = Math.min(x, d); return x; } static float min(float[] c) { float x = Float.MAX_VALUE; for (float d : c) x = Math.min(x, d); return x; } static byte min(byte[] c) { byte x = 127; for (byte d : c) if (d < x) x = d; return x; } static short min(short[] c) { short x = 0x7FFF; for (short d : c) if (d < x) x = d; return x; } static int min(int[] c) { int x = Integer.MAX_VALUE; for (int d : c) if (d < x) x = d; return x; } static Producer javaTokC_noMLS_iterator(final String s) { return javaTokC_noMLS_iterator(s, 0); } static Producer javaTokC_noMLS_iterator(final String s, final int startIndex) { return new Producer() { final int l = s.length(); int i = startIndex; public String next() { if (i >= l) return null; int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) return null; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else ++j; String t = quickSubstring(s, i, j); i = j; return t; } }; } static Producer javaTokC_noMLS_onReader(final BufferedReader r) { final class X implements Producer { StringBuilder buf = new StringBuilder(); // stores from "i" char c, d, e = 'x'; // just not '\0' X() { // fill c, d and e nc(); nc(); nc(); } // get next character(s) into c, d and e void nc() { try { c = d; d = e; if (e == '\0') return; int i = r.read(); e = i < 0 ? '\0' : i == '\0' ? '_' // shouldn't happen anymore : (char) i; } catch (Exception __e) { throw rethrow(__e); } } void ncSave() { if (c != '\0') { buf.append(c); nc(); } } public String next() { // scan for whitespace while (c != '\0') { if (c == ' ' || c == '\t' || c == '\r' || c == '\n') nc(); else if (c == '/' && d == '*') { do nc(); while (c != '\0' && !(c == '*' && d == '/')); nc(); nc(); } else if (c == '/' && d == '/') { do nc(); while (c != '\0' && "\r\n".indexOf(c) < 0); } else break; } if (c == '\0') return null; // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ncSave(); while (c != '\0') { if (c == opener || c == '\n') { // end at \n to not propagate unclosed string literal errors ncSave(); break; } else if (c == '\\') { ncSave(); ncSave(); } else ncSave(); } } else if (Character.isJavaIdentifierStart(c)) do ncSave(); while (Character.isJavaIdentifierPart(c) || c == '\''); // for stuff like "don't" else if (Character.isDigit(c)) { do ncSave(); while (Character.isDigit(c)); if (c == 'L') ncSave(); // Long constants like 1L } else ncSave(); String t = buf.toString(); buf.setLength(0); return t; } } return new X(); } static String unquoteUsingCharArray(String s, char[] buf) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i+1, s.length()-i-1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length()-1 : s.length(); if (l > buf.length) return unquote(s); // fallback int n = 0; for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } buf[n++] = (char) Integer.parseInt(code, 8); continue; } switch (nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); char[] x = Character.toChars(code); int lx = x.length; for (int j = 0; j < lx; j++) buf[n++] = x[j]; i += 5; continue; default: ch = nextChar; // added by Stefan } i++; } buf[n++] = ch; } return new String(buf, 0, n); } } return s; // not quoted - return original } static boolean structure_isMarker(String s, int i, int j) { if (i >= j) return false; if (s.charAt(i) != 'm') return false; ++i; while (i < j) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static int parseInt(String s) { return empty(s) ? 0 : Integer.parseInt(s); } static int parseInt(char c) { return Integer.parseInt(str(c)); } static String internIfLongerThan(String s, int l) { return s == null ? null : l(s) >= l ? intern(s) : s; } static String unquote(String s) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i+1, s.length()-i-1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length()-1 : s.length(); StringBuilder sb = new StringBuilder(l-1); for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch (nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; default: ch = nextChar; // added by Stefan } i++; } sb.append(ch); } return sb.toString(); } } return s; // not quoted - return original } static char unquoteCharacter(String s) { assertTrue(s.startsWith("'") && s.length() > 1); return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length()-1 : s.length()) + "\"").charAt(0); } static double parseDouble(String s) { return Double.parseDouble(s); } static float parseFloat(String s) { return Float.parseFloat(s); } static boolean isLongConstant(String s) { if (!s.endsWith("L")) return false; s = s.substring(0, l(s)-1); return isInteger(s); } static long parseLong(String s) { if (s == null) return 0; return Long.parseLong(dropSuffix("L", s)); } static long parseLong(Object s) { return Long.parseLong((String) s); } static boolean isInteger(String s) { if (s == null) return false; int n = l(s); if (n == 0) return false; int i = 0; if (s.charAt(0) == '-') if (++i >= n) return false; while (i < n) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static boolean eqOneOf(Object o, Object... l) { for (Object x : l) if (eq(o, x)) return true; return false; } static SortedMap synchronizedTreeMap() { return synchroTreeMap(); } static List parseList(String s) { return (List) safeUnstructure(s); } static List synchroList() { return Collections.synchronizedList(new ArrayList()); } static List synchroList(List l) { return Collections.synchronizedList(l); } static Map synchronizedMap() { return synchroMap(); } static byte[] hexToBytes(String s) { if (odd(l(s))) throw fail("Hex string has odd length: " + quote(shorten(10, s))); int n = l(s) / 2; byte[] bytes = new byte[n]; for (int i = 0; i < n; i++) { int a = parseHexChar(s.charAt(i*2)); int b = parseHexChar(s.charAt(i*2+1)); if (a < 0 || b < 0) throw fail("Bad hex byte: " + quote(substring(s, i*2, i*2+2)) + " at " + i*2 + "/" + l(s)); bytes[i] = (byte) ((a << 4) | b); } return bytes; } static boolean[] boolArrayFromBytes(byte[] a, int n) { boolean[] b = new boolean[n]; int m = min(n, l(a)*8); for (int i = 0; i < m; i++) b[i] = (a[i/8] & 1 << (i & 7)) != 0; return b; } static void assertTrue(Object o) { if (!(eq(o, true) /*|| isTrue(pcallF(o))*/)) throw fail(str(o)); } static boolean assertTrue(String msg, boolean b) { if (!b) throw fail(msg); return b; } static boolean assertTrue(boolean b) { if (!b) throw fail("oops"); return b; } static boolean isJavaIdentifier(String s) { if (empty(s) || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i < s.length(); i++) if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; return true; } static HashMap findClass_cache = new HashMap(); // currently finds only inner classes of class "main" // returns null on not found // this is the simple version that is not case-tolerant static Class findClass(String name) { synchronized(findClass_cache) { if (findClass_cache.containsKey(name)) return findClass_cache.get(name); if (!isJavaIdentifier(name)) return null; Class c; try { c = Class.forName("main$" + name); } catch (ClassNotFoundException e) { c = null; } findClass_cache.put(name, c); return c; } } static A nuStubInnerObject(Class c) { return nuStubInnerObject(c, null); } static A nuStubInnerObject(Class c, Object classFinder) { try { Class outerType = getOuterClass(c, classFinder); Constructor m = c.getDeclaredConstructor(outerType); m.setAccessible(true); return (A) m.newInstance(new Object[] {null}); } catch (Exception __e) { throw rethrow(__e); } } static Map nuEmptyObject_cache = newDangerousWeakHashMap(); static A nuEmptyObject(Class c) { try { Constructor ctr; synchronized(nuEmptyObject_cache) { ctr = nuEmptyObject_cache.get(c); if (ctr == null) { nuEmptyObject_cache.put(c, ctr = nuEmptyObject_findConstructor(c)); ctr.setAccessible(true); } } try { return (A) ctr.newInstance(); } catch (InstantiationException e) { if (empty(e.getMessage())) if ((c.getModifiers() & Modifier.ABSTRACT) != 0) throw fail("Can't instantiate abstract class " + className(c), e); else throw fail("Can't instantiate " + className(c), e); else throw rethrow(e); } } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuEmptyObject_findConstructor(Class c) { for (Constructor m : c.getDeclaredConstructors()) if (m.getParameterTypes().length == 0) return m; throw fail("No default constructor declared in " + c.getName()); } static String shortClassName(Object o) { if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return shortenClassName(name); } static void printStructure(String prefix, Object o) { if (endsWithLetter(prefix)) prefix += ": "; print(prefix + structureForUser(o)); } static void printStructure(Object o) { print(structureForUser(o)); } static void setOptAllDyn(DynamicObject o, Map fields) { if (fields == null) return; HashMap fieldMap = instanceFieldsMap(o); for (Map.Entry e : fields.entrySet()) { String field = e.getKey(); Object val = e.getValue(); boolean has = fieldMap.containsKey(field); if (has) setOpt(o, field, val); else { o.fieldValues.put(intern(field), val); } } } static void setOptAll_pcall(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) try { setOpt(o, field, fields.get(field)); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } static void setOptAll_pcall(Object o, Object... values) { //values = expandParams(c.getClass(), values); warnIfOddCount(values); for (int i = 0; i+1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i+1]; try { setOpt(o, field, value); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } } static String intern(String s) { return fastIntern(s); } static void pcallOpt_noArgs(Object o, String method) { try { callOpt_noArgs(o, method); } catch (Throwable __e) { _handleException(__e); } } static List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static List subList(List l, int startIndex, int endIndex) { startIndex = Math.max(0, Math.min(l(l), startIndex)); endIndex = Math.max(0, Math.min(l(l), endIndex)); if (startIndex > endIndex) return litlist(); return l.subList(startIndex, endIndex); } static int[] toIntArray(List l) { int[] a = new int[l(l)]; for (int i = 0; i < a.length; i++) a[i] = l.get(i); return a; } static boolean jmatch(String pat, String s) { return jmatch(pat, s, null); } static boolean jmatch(String pat, String s, Matches matches) { if (s == null) return false; return jmatch(pat, javaTok(s), matches); } static boolean jmatch(String pat, List toks) { return jmatch(pat, toks, null); } static boolean jmatch(String pat, List toks, Matches matches) { List tokpat = javaTok(pat); String[] m = match2(tokpat, toks); //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m)); if (m == null) return false; else { if (matches != null) matches.m = m; return true; } } static boolean warn_on = true; static void warn(String s) { if (warn_on) print("Warning: " + s); } static void warn(String s, List warnings) { warn(s); if (warnings != null) warnings.add(s); } static ThreadLocal assertVerbose_value = new ThreadLocal(); static void assertVerbose(boolean b) { assertVerbose_value.set(b); } static boolean assertVerbose() { return isTrue(assertVerbose_value.get()); } static A assertEqualsVerbose(Object x, A y) { assertEqualsVerbose((String) null, x, y); return y; } static A assertEqualsVerbose(String msg, Object x, A y) { if (!eq(x, y)) { throw fail((msg != null ? msg + ": " : "") + /*sfu*/(y) + " != " + /*sfu*/(x)); } else print("OK: " + /*sfu*/(x)); return y; } static final Map callOpt_cache = newDangerousWeakHashMap(); static Object callOpt_cached(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); // TODO: (super-rare) case where method exists static and non-static // with different args Method me = cache.findMethod(methodName, args); if (me == null || (me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me == null) return null; return invokeMethod(me, o, args); } } catch (Exception __e) { throw rethrow(__e); } } static _MethodCache callOpt_getCache(Class c) { synchronized(callOpt_cache) { _MethodCache cache = callOpt_cache.get(c); if (cache == null) callOpt_cache.put(c, cache = new _MethodCache(c)); return cache; } } static Class getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; } } static Class getClass(Object o) { return o instanceof Class ? (Class) o : o.getClass(); } static Class getClass(Object realm, String name) { try { try { return getClass(realm).getClassLoader().loadClass(classNameToVM(name)); } catch (ClassNotFoundException e) { return null; } } catch (Exception __e) { throw rethrow(__e); } } static String classNameToVM(String name) { return name.replace(".", "$"); } static void clear(Collection c) { if (c != null) c.clear(); } static void put(Map map, A a, B b) { if (map != null) map.put(a, b); } static List _registerDangerousWeakMap_preList; static A _registerDangerousWeakMap(A map) { return _registerDangerousWeakMap(map, null); } static A _registerDangerousWeakMap(A map, Object init) { callF(init, map); if (init instanceof String) { final String f = (String) ( init); init = new VF1() { public void get(Map map) { try { callMC(f, map) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callMC(f, map)"; }}; } if (javax() == null) { // We're in class init if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList(); _registerDangerousWeakMap_preList.add(pair(map, init)); return map; } call(javax(), "_registerDangerousWeakMap", map, init); return map; } static void _onLoad_registerDangerousWeakMap() { assertNotNull(javax()); if (_registerDangerousWeakMap_preList == null) return; for (Pair p : _registerDangerousWeakMap_preList) _registerDangerousWeakMap(p.a, p.b); _registerDangerousWeakMap_preList = null; } static Map synchroMap() { return synchroHashMap(); } static Map synchroMap(Map map) { return Collections.synchronizedMap(map); } static boolean isSubtypeOf(Class a, Class b) { return b.isAssignableFrom(a); // << always hated that method, let's replace it! } static RuntimeException asRuntimeException(Throwable t) { if (t instanceof Error) _handleError((Error) t); return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static Map synchroHashMap() { return Collections.synchronizedMap(new HashMap()); } static void _handleError(Error e) { call(javax(), "_handleError", e); } static boolean empty(Collection c) { return c == null || c.isEmpty(); } static boolean empty(CharSequence s) { return s == null || s.length() == 0; } static boolean empty(Map map) { return map == null || map.isEmpty(); } static boolean empty(Object[] o) { return o == null || o.length == 0; } static boolean empty(Object o) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); if (o instanceof Object[]) return empty((Object[]) o); if (o instanceof byte[]) return empty((byte[]) o); if (o == null) return true; throw fail("unknown type for 'empty': " + getType(o)); } static boolean empty(float[] a) { return a == null || a.length == 0; } static boolean empty(int[] a) { return a == null || a.length == 0; } static boolean empty(long[] a) { return a == null || a.length == 0; } static boolean empty(byte[] a) { return a == null || a.length == 0; } static void smartSet(Field f, Object o, Object value) throws Exception { try { f.set(o, value); } catch (Exception e) { Class type = f.getType(); // take care of common case (long to int) if (type == int.class && value instanceof Long) value = ((Long) value).intValue(); if (type == LinkedHashMap.class && value instanceof Map) { f.set(o, asLinkedHashMap((Map) value)); return; } throw e; } } static boolean odd(int i) { return (i & 1) != 0; } static boolean odd(long i) { return (i & 1) != 0; } static boolean odd(BigInteger i) { return odd(toInt(i)); } static List _registerWeakMap_preList; static A _registerWeakMap(A map) { if (javax() == null) { // We're in class init if (_registerWeakMap_preList == null) _registerWeakMap_preList = synchroList(); _registerWeakMap_preList.add(map); return map; } try { call(javax(), "_registerWeakMap", map); } catch (Throwable e) { printException(e); print("Upgrade JavaX!!"); } return map; } static void _onLoad_registerWeakMap() { assertNotNull(javax()); if (_registerWeakMap_preList == null) return; for (Object o : _registerWeakMap_preList) _registerWeakMap(o); _registerWeakMap_preList = null; } static int isAndroid_flag; static boolean isAndroid() { if (isAndroid_flag == 0) isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1; return isAndroid_flag > 0; } static Boolean isHeadless_cache; static boolean isHeadless() { if (isHeadless_cache != null) return isHeadless_cache; if (isAndroid()) return isHeadless_cache = true; if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true; // Also check if AWT actually works. // If DISPLAY variable is set but no X server up, this will notice. try { SwingUtilities.isEventDispatchThread(); return isHeadless_cache = false; } catch (Throwable e) { return isHeadless_cache = true; } } static List classNames(Collection l) { return getClassNames(l); } static List classNames(Object[] l) { return getClassNames(Arrays.asList(l)); } static Class mc() { return main.class; } static void multiMapPut(Map> map, A a, B b) { List l = map.get(a); if (l == null) map.put(a, l = new ArrayList()); l.add(b); } static Throwable getExceptionCause(Throwable e) { Throwable c = e.getCause(); return c != null ? c : e; } static String joinWithSpace(Collection c) { return join(" ", c); } static String joinWithSpace(String... c) { return join(" ", c); } static String joinWithComma(Collection c) { return join(", ", c); } static String joinWithComma(String... c) { return join(", ", c); } static String joinWithComma(Pair p) { return p == null ? "" : joinWithComma(str(p.a), str(p.b)); } static String javaTok_substringC(String s, int i, int j) { return s.substring(i, j); } static A liftLast(List l) { if (l.isEmpty()) return null; int i = l(l)-1; A a = l.get(i); l.remove(i); return a; } static byte[] boolArrayToBytes(boolean[] a) { byte[] b = new byte[(l(a)+7)/8]; for (int i = 0; i < l(a); i++) if (a[i]) b[i/8] |= 1 << (i & 7); return b; } static int cmp(Number a, Number b) { return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue()); } static int cmp(double a, double b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(String a, String b) { return a == null ? b == null ? 0 : -1 : a.compareTo(b); } static int cmp(Object a, Object b) { if (a == null) return b == null ? 0 : -1; if (b == null) return 1; return ((Comparable) a).compareTo(b); } static String quickSubstring(String s, int i, int j) { if (i == j) return ""; return s.substring(i, j); } static boolean endsWith(String a, String b) { return a != null && a.endsWith(b); } static boolean endsWith(String a, char c) { return nempty(a) && lastChar(a) == c; } static boolean endsWith(String a, String b, Matches m) { if (!endsWith(a, b)) return false; m.m = new String[] {dropLast(l(b), a)}; return true; } static String dropSuffix(String suffix, String s) { return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static SortedMap synchroTreeMap() { return Collections.synchronizedSortedMap(new TreeMap()); } static Object safeUnstructure(String s) { return unstructure(s, true); } static int parseHexChar(char c) { if (c >= '0' && c <= '9') return charDiff(c, '0'); if (c >= 'a' && c <= 'f') return charDiff(c, 'a')+10; if (c >= 'A' && c <= 'F') return charDiff(c, 'A')+10; return -1; } static Class getOuterClass(Class c) { return getOuterClass(c, null); } static Class getOuterClass(Class c, Object classFinder) { try { String s = c.getName(); int i = s.lastIndexOf('$'); String name = substring(s, 0, i); if (classFinder != null) return (Class) callF(classFinder, name); return Class.forName(name); } catch (Exception __e) { throw rethrow(__e); } } static String className(Object o) { return getClassName(o); } static String shortenClassName(String name) { if (name == null) return null; int i = lastIndexOf(name, "$"); if (i < 0) i = lastIndexOf(name, "."); return i < 0 ? name : substring(name, i+1); } static boolean endsWithLetter(String s) { return nempty(s) && isLetter(last(s)); } static String structureForUser(Object o) { return beautifyStructure(struct_noStringSharing(o)); } static HashMap instanceFieldsMap(Object o) { Class c = o.getClass(); HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } return map; } static Field setOpt_findField(Class c, String field) { HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } return map.get(field); } static void setOpt(Object o, String field, Object value) { try { if (o == null) return; Class c = o.getClass(); HashMap map; if (getOpt_cache == null) map = getOpt_makeCache(c); // in class init else synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } if (map == getOpt_special) { if (o instanceof Class) { setOpt((Class) o, field, value); return; } // It's probably a subclass of Map. Use raw method setOpt_raw(o, field, value); return; } Field f = map.get(field); if (f != null) smartSet(f, o, value); // possible improvement: skip setAccessible } catch (Exception __e) { throw rethrow(__e); } } static void setOpt(Class c, String field, Object value) { if (c == null) return; try { Field f = setOpt_findStaticField(c, field); if (f != null) smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field setOpt_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { f.setAccessible(true); return f; } _c = _c.getSuperclass(); } while (_c != null); return null; } static String exceptionToStringShort(Throwable e) { lastException(e); e = getInnerException(e); String msg = hideCredentials(unnull(e.getMessage())); if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0) return baseClassName(e) + prependIfNempty(": ", msg); else return msg; } static void warnIfOddCount(Object... list) { if (odd(l(list))) printStackTrace("Odd list size: " + list); } static Method fastIntern_method; static String fastIntern(String s) { try { if (s == null) return null; if (fastIntern_method == null) { fastIntern_method = findMethodNamed(javax(), "internPerProgram"); if (fastIntern_method == null) upgradeJavaXAndRestart(); } return (String) fastIntern_method.invoke(null, s); } catch (Exception __e) { throw rethrow(__e); } } static Map> callOpt_noArgs_cache = newDangerousWeakHashMap(); static Object callOpt_noArgs(Object o, String method) { try { if (o == null) return null; if (o instanceof Class) return callOpt(o, method); // not optimized Class c = o.getClass(); HashMap map; synchronized(callOpt_noArgs_cache) { map = callOpt_noArgs_cache.get(c); if (map == null) map = callOpt_noArgs_makeCache(c); } Method m = map.get(method); return m != null ? m.invoke(o) : null; } catch (Exception __e) { throw rethrow(__e); } } // used internally - we are in synchronized block static HashMap callOpt_noArgs_makeCache(Class c) { HashMap map = new HashMap(); Class _c = c; do { for (Method m : c.getDeclaredMethods()) if (m.getParameterTypes().length == 0) { m.setAccessible(true); String name = m.getName(); if (!map.containsKey(name)) map.put(name, m); } _c = _c.getSuperclass(); } while (_c != null); callOpt_noArgs_cache.put(c, map); return map; } static volatile PersistableThrowable _handleException_lastException; static List _handleException_onException = synchroList(ll("printStackTrace2")); static void _handleException(Throwable e) { _handleException_lastException = persistableThrowable(e); Throwable e2 = innerException(e); if (e2.getClass() == RuntimeException.class && eq(e2.getMessage(), "Thread cancelled.")) return; for (Object f : cloneList(_handleException_onException)) try { callF(f, e); } catch (Throwable e3) { printStackTrace2(e3); // not using pcall here - it could lead to endless loops } } static ArrayList litlist(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt; static List javaTok(String s) { ++javaTok_n; ArrayList tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0, n = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(javaTok_substringN(s, i, j)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace // Special JavaX syntax: 'identifier if (c == '\'' && Character.isJavaIdentifierStart(d) && i+2 < l && "'\\".indexOf(s.charAt(i+2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { int c2 = s.charAt(j); if (c2 == opener || c2 == '\n' && opener == '\'') { // allow multi-line strings, but not for ' ++j; break; } else if (c2 == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static List javaTok(List tok) { return javaTokWithExisting(join(tok), tok); } // match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens) static String[] match2(List pat, List tok) { // standard case (no ...) int i = pat.indexOf("..."); if (i < 0) return match2_match(pat, tok); pat = new ArrayList(pat); // We're modifying it, so copy first pat.set(i, "*"); while (pat.size() < tok.size()) { pat.add(i, "*"); pat.add(i+1, ""); // doesn't matter } return match2_match(pat, tok); } static String[] match2_match(List pat, List tok) { List result = new ArrayList(); if (pat.size() != tok.size()) { return null; } for (int i = 1; i < pat.size(); i += 2) { String p = pat.get(i), t = tok.get(i); if (eq(p, "*")) result.add(t); else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now return null; } return result.toArray(new String[result.size()]); } static boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; if (o instanceof ThreadLocal) return isTrue(((ThreadLocal) o).get()); throw fail(getClassName(o)); } static Throwable printStackTrace2(Throwable e) { // we go to system.out now - system.err is nonsense print(getStackTrace2(e)); return e; } static void printStackTrace2() { printStackTrace2(new Throwable()); } static void printStackTrace2(String msg) { printStackTrace2(new Throwable(msg)); } static Class javax() { return getJavaX(); } static Pair pair(A a, B b) { return new Pair(a, b); } static Pair pair(A a) { return new Pair(a, a); } static A assertNotNull(A a) { assertTrue(a != null); return a; } static A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static String getType(Object o) { return getClassName(o); } static LinkedHashMap asLinkedHashMap(Map map) { if (map instanceof LinkedHashMap) return (LinkedHashMap) map; LinkedHashMap m = new LinkedHashMap(); if (map != null) synchronized(collectionMutex(map)) { m.putAll(map); } return m; } static int toInt(Object o) { if (o == null) return 0; if (o instanceof Number) return ((Number) o).intValue(); if (o instanceof String) return parseInt((String) o); throw fail("woot not int: " + getClassName(o)); } static int toInt(long l) { if (l != (int) l) throw fail("Too large for int: " + l); return (int) l; } static void printException(Throwable e) { printStackTrace(e); } static List getClassNames(Collection l) { List out = new ArrayList(); if (l != null) for (Object o : l) out.add(o == null ? null : getClassName(o)); return out; } public static String join(String glue, Iterable strings) { if (strings == null) return ""; StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String... strings) { return join(glue, Arrays.asList(strings)); } static String join(Iterable strings) { return join("", strings); } static String join(Iterable strings, String glue) { return join(glue, strings); } public static String join(String[] strings) { return join("", strings); } static String join(String glue, Pair p) { return p == null ? "" : str(p.a) + glue + str(p.b); } static char lastChar(String s) { return empty(s) ? '\0' : s.charAt(l(s)-1); } static String[] dropLast(String[] a, int n) { n = Math.min(n, a.length); String[] b = new String[a.length-n]; System.arraycopy(a, 0, b, 0, b.length); return b; } static List dropLast(List l) { return subList(l, 0, l(l)-1); } static List dropLast(int n, List l) { return subList(l, 0, l(l)-n); } static List dropLast(Iterable l) { return dropLast(asList(l)); } static String dropLast(String s) { return substring(s, 0, l(s)-1); } static String dropLast(String s, int n) { return substring(s, 0, l(s)-n); } static String dropLast(int n, String s) { return dropLast(s, n); } static int charDiff(char a, char b) { return (int) a-(int) b; } static int charDiff(String a, char b) { return charDiff(stringToChar(a), b); } static int lastIndexOf(String a, String b) { return a == null || b == null ? -1 : a.lastIndexOf(b); } static int lastIndexOf(String a, char b) { return a == null ? -1 : a.lastIndexOf(b); } static boolean isLetter(char c) { return Character.isLetter(c); } static A last(List l) { return empty(l) ? null : l.get(l.size()-1); } static char last(String s) { return empty(s) ? '#' : s.charAt(l(s)-1); } static int last(int[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static A last(A[] a) { return l(a) != 0 ? a[l(a)-1] : null; } static A last(Iterator it) { A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static String beautifyStructure(String s) { List tok = javaTok(s); structure_addTokenMarkers(tok); jreplace(tok, "lhm", ""); return join(tok); } static String struct_noStringSharing(Object o) { structure_Data d = new structure_Data(); d.noStringSharing = true; return structure(o, d); } static void setOpt_raw(Object o, String field, Object value) { try { if (o == null) return; if (o instanceof Class) setOpt_raw((Class) o, field, value); else { Field f = setOpt_raw_findField(o.getClass(), field); if (f != null) { f.setAccessible(true); smartSet(f, o, value); } } } catch (Exception __e) { throw rethrow(__e); } } static void setOpt_raw(Class c, String field, Object value) { try { if (c == null) return; Field f = setOpt_raw_findStaticField(c, field); if (f != null) { f.setAccessible(true); smartSet(f, null, value); } } catch (Exception __e) { throw rethrow(__e); } } static Field setOpt_raw_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static Field setOpt_raw_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } // PersistableThrowable doesn't hold GC-disturbing class references in backtrace static volatile PersistableThrowable lastException_lastException; static PersistableThrowable lastException() { return lastException_lastException; } static void lastException(Throwable e) { lastException_lastException = persistableThrowable(e); } static Throwable getInnerException(Throwable e) { if (e == null) return null; while (e.getCause() != null) e = e.getCause(); return e; } static Throwable getInnerException(Runnable r) { return getInnerException(getException(r)); } static String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); } static String hideCredentials(String url) { return url.replaceAll("([&?])(_pass|key)=[^&\\s\"]*", "$1$2="); } static String hideCredentials(Object o) { return hideCredentials(str(o)); } static String unnull(String s) { return s == null ? "" : s; } static List unnull(List l) { return l == null ? emptyList() : l; } static Map unnull(Map l) { return l == null ? emptyMap() : l; } static Iterable unnull(Iterable i) { return i == null ? emptyList() : i; } static A[] unnull(A[] a) { return a == null ? (A[]) new Object[0] : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } //ifclass Symbol static String baseClassName(String className) { return substring(className, className.lastIndexOf('.')+1); } static String baseClassName(Object o) { return baseClassName(getClassName(o)); } static String prependIfNempty(String prefix, String s) { return empty(s) ? s : prefix + s; } static Throwable printStackTrace(Throwable e) { // we go to system.out now - system.err is nonsense print(getStackTrace(e)); return e; } static void printStackTrace() { printStackTrace(new Throwable()); } static void printStackTrace(String msg) { printStackTrace(new Throwable(msg)); } // This is a bit rough... finds static and non-static methods. static Method findMethodNamed(Object obj, String method) { if (obj == null) return null; if (obj instanceof Class) return findMethodNamed((Class) obj, method); return findMethodNamed(obj.getClass(), method); } static Method findMethodNamed(Class c, String method) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method)) { m.setAccessible(true); return m; } c = c.getSuperclass(); } return null; } static void upgradeJavaXAndRestart() { run("#1001639"); restart(); sleep(); } static Object callOpt(Object o) { return callF(o); } static Object callOpt(Object o, String method, Object... args) { return callOpt_cached(o, method, args); } static List ll(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } static PersistableThrowable persistableThrowable(Throwable e) { return e == null ? null : new PersistableThrowable(e); } static Throwable innerException(Throwable e) { return getInnerException(e); } static ArrayList cloneList(Iterable l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static ArrayList cloneList(Collection l) { if (l == null) return new ArrayList(); synchronized(collectionMutex(l)) { return new ArrayList(l); } } static String javaTok_substringN(String s, int i, int j) { if (i == j) return ""; if (j == i+1 && s.charAt(i) == ' ') return " "; return s.substring(i, j); } static List javaTokWithExisting(String s, List existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; ArrayList tok = existing != null ? new ArrayList(nExisting) : new ArrayList(); int l = s.length(); int i = 0, n = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringN(s, i, j)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace // Special JavaX syntax: 'identifier if (c == '\'' && Character.isJavaIdentifierStart(d) && i+2 < l && "'\\".indexOf(s.charAt(i+2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener /*|| s.charAt(j) == '\n'*/) { // allow multi-line strings ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static boolean javaTokWithExisting_isCopyable(String t, String s, int i, int j) { return t.length() == j-i && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave } static boolean equalsIgnoreCase(String a, String b) { return eqic(a, b); } static boolean equalsIgnoreCase(char a, char b) { return eqic(a, b); } static String getStackTrace2(Throwable e) { return hideCredentials(getStackTrace(unwrapTrivialExceptionWraps(e)) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ", hideCredentials(str(getInnerException(e)))) + "\n"); } static Class __javax; static Class getJavaX() { try { return __javax; } catch (Exception __e) { throw rethrow(__e); } } static Object collectionMutex(Object o) { String c = className(o); if (eq(c, "java.util.TreeMap$KeySet")) c = className(o = getOpt(o, "m")); else if (eq(c, "java.util.HashMap$KeySet")) c = className(o = get_raw(o, "this$0")); if (eqOneOf(c, "java.util.TreeMap$AscendingSubMap", "java.util.TreeMap$DescendingSubMap")) c = className(o = get_raw(o, "m")); return o; } static char stringToChar(String s) { if (l(s) != 1) throw fail("bad stringToChar: " + s); return firstChar(s); } static String structure_addTokenMarkers(String s) { return join(structure_addTokenMarkers(javaTok(s))); } static List structure_addTokenMarkers(List tok) { // find references TreeSet refs = new TreeSet(); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("t") && isInteger(t.substring(1))) refs.add(parseInt(t.substring(1))); } if (empty(refs)) return tok; // add markers for (int i : refs) { int idx = i*2+1; String t = ""; if (endsWithLetterOrDigit(tok.get(idx-1))) t = " "; tok.set(idx, t + "m" + i + " " + tok.get(idx)); } return tok; } static String jreplace(String s, String in, String out) { return jreplace(s, in, out, null); } static String jreplace(String s, String in, String out, Object condition) { List tok = javaTok(s); return jreplace(tok, in, out, condition) ? join(tok) : s; } // leaves tok properly tokenized // returns true iff anything was replaced static boolean jreplace(List tok, String in, String out) { return jreplace(tok, in, out, false, true, null); } static boolean jreplace(List tok, String in, String out, Object condition) { return jreplace(tok, in, out, false, true, condition); } static boolean jreplace(List tok, String in, String out, boolean ignoreCase, boolean reTok, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); String[] toks = toStringArray(codeTokensOnly(tokin)); boolean anyChange = false; for (int n = 0; n < 10000; n++) { int i = findCodeTokens(tok, 1, ignoreCase, toks, condition); if (i < 0) return anyChange; List subList = tok.subList(i-1, i+l(tokin)-1); // N to N String expansion = jreplaceExpandRefs(out, subList); int end = i+l(tokin)-2; clearAllTokens(tok, i, end); // C to C tok.set(i, expansion); if (reTok) // would this ever be false?? reTok(tok, i, end); anyChange = true; } throw fail("woot? 10000! " + quote(in) + " => " + quote(out)); } static boolean jreplace_debug; static Throwable getException(Runnable r) { try { callF(r); return null; } catch (Throwable e) { return e; } } static List emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static List emptyList(int capacity) { return new ArrayList(max(0, capacity)); } // Try to match capacity static List emptyList(Iterable l) { return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList(); } // get correct type at once static List emptyList(Class c) { return new ArrayList(); } static Map emptyMap() { return new HashMap(); } static String getStackTrace(Throwable throwable) { lastException(throwable); return getStackTrace_noRecord(throwable); } static String getStackTrace_noRecord(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); return hideCredentials(writer.toString()); } static String getStackTrace() { return getStackTrace_noRecord(new Throwable()); } static Class run(String progID, String... args) { Class main = hotwire(progID); callMain(main, args); return main; } static void restart() { Object j = getJavaX(); call(j, "cleanRestart", get(j, "fullArgs")); } static volatile boolean sleep_noSleep; static void sleep(long ms) { ping(); if (ms < 0) return; // allow spin locks if (isAWTThread() && ms > 100) throw fail("Should not sleep on AWT thread"); try { Thread.sleep(ms); } catch (Exception e) { throw new RuntimeException(e); } } static void sleep() { try { if (sleep_noSleep) throw fail("nosleep"); print("Sleeping."); sleepQuietly(); } catch (Exception __e) { throw rethrow(__e); } } static boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } static boolean eqic(char a, char b) { if (a == b) return true; char u1 = Character.toUpperCase(a); char u2 = Character.toUpperCase(b); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static Throwable unwrapTrivialExceptionWraps(Throwable e) { if (e == null) return e; while (e.getClass() == RuntimeException.class && e.getCause() != null && eq(e.getMessage(), str(e.getCause()))) e = e.getCause(); return e; } static String replacePrefix(String prefix, String replacement, String s) { if (!startsWith(s, prefix)) return s; return replacement + substring(s, l(prefix)); } // get purpose 1: access a list/array/map (safer version of x.get(y)) static A get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } // seems to conflict with other signatures /*static B get(Map map, A key) { ret map != null ? map.get(key) : null; }*/ static A get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } // default to false static boolean get(boolean[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : false; } // get purpose 2: access a field by reflection or a map static Object get(Object o, String field) { try { if (o == null) return null; if (o instanceof Class) return get((Class) o, field); if (o instanceof Map) return ((Map) o).get(field); Field f = getOpt_findField(o.getClass(), field); if (f != null) { f.setAccessible(true); return f.get(o); } if (o instanceof DynamicObject) return ((DynamicObject) o).fieldValues.get(field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } static Object get_raw(Object o, String field) { try { Field f = get_findField(o.getClass(), field); f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); f.setAccessible(true); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field get_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field get_findField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static char firstChar(String s) { return s.charAt(0); } static int jfind(String s, String in) { return jfind(javaTok(s), in); } static int jfind(List tok, String in) { return jfind(tok, 1, in); } static int jfind(List tok, int startIdx, String in) { return jfind(tok, startIdx, in, null); } static int jfind(List tok, String in, Object condition) { return jfind(tok, 1, in, condition); } static int jfind(List tok, int startIdx, String in, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); return jfind(tok, startIdx, tokin, condition); } // assumes you preprocessed tokin static int jfind(List tok, List tokin) { return jfind(tok, 1, tokin); } static int jfind(List tok, int startIdx, List tokin) { return jfind(tok, startIdx, tokin, null); } static int jfind(List tok, int startIdx, List tokin, Object condition) { return findCodeTokens(tok, startIdx, false, toStringArray(codeTokensOnly(tokin)), condition); } static List jfind_preprocess(List tok) { for (String type : litlist("quoted", "id", "int")) replaceSublist(tok, ll("<", "", type, "", ">"), ll("<" + type + ">")); replaceSublist(tok, ll("\\", "", "*"), ll("\\*")); return tok; } static List codeTokensOnly(List tok) { List l = new ArrayList(); for (int i = 1; i < tok.size(); i += 2) l.add(tok.get(i)); return l; } static int findCodeTokens(List tok, String... tokens) { return findCodeTokens(tok, 1, false, tokens); } static int findCodeTokens(List tok, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, 1, ignoreCase, tokens); } static int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, startIdx, ignoreCase, tokens, null); } static List findCodeTokens_specials = litlist("*", "", "", "", "\\*"); static boolean findCodeTokens_debug; static int findCodeTokens_indexed, findCodeTokens_unindexed; static int findCodeTokens_bails, findCodeTokens_nonbails; static int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { if (findCodeTokens_debug) { if (eq(getClassName(tok), "main$IndexedList2")) findCodeTokens_indexed++; else findCodeTokens_unindexed++; } // bail out early if first token not found (works great with IndexedList) if (!findCodeTokens_specials.contains(tokens[0]) && !tok.contains(tokens[0] /*, startIdx << no signature in List for this, unfortunately */)) { ++findCodeTokens_bails; return -1; } ++findCodeTokens_nonbails; outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) { for (int j = 0; j < tokens.length; j++) { String p = tokens[j], t = tok.get(i+j*2); boolean match; if (eq(p, "*")) match = true; else if (eq(p, "")) match = isQuoted(t); else if (eq(p, "")) match = isIdentifier(t); else if (eq(p, "")) match = isInteger(t); else if (eq(p, "\\*")) match = eq("*", t); else match = ignoreCase ? eqic(p, t) : eq(p, t); if (!match) continue outer; } if (condition == null || checkTokCondition(condition, tok, i-1)) // pass N index return i; } return -1; } // "$1" is first code token, "$2" second code token etc. static String jreplaceExpandRefs(String s, List tokref) { List tok = javaTok(s); for (int i = 1; i < l(tok); i += 2) { if (tok.get(i).startsWith("$") && isInteger(tok.get(i).substring(1))) { String x = tokref.get(-1+parseInt(tok.get(i).substring(1))*2); tok.set(i, x); } } return join(tok); } static void clearAllTokens(List tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static void clearAllTokens(List tok, int i, int j) { for (; i < j; i++) tok.set(i, ""); } static List reTok(List tok) { replaceCollection(tok, javaTok(tok)); return tok; } static List reTok(List tok, int i) { return reTok(tok, i, i+1); } static List reTok(List tok, int i, int j) { // extend i to an "N" token // and j to "C" (so j-1 is an "N" token) i = i & ~1; j = j | 1; List t = javaTok(join(subList(tok, i, j))); replaceListPart(tok, i, j, t); // fallback to safety // reTok(tok); return tok; } static int max(int a, int b) { return Math.max(a, b); } static int max(int a, int b, int c) { return max(max(a, b), c); } static long max(int a, long b) { return Math.max((long) a, b); } static long max(long a, long b) { return Math.max(a, b); } static double max(int a, double b) { return Math.max((double) a, b); } static float max(float a, float b) { return Math.max(a, b); } static double max(double a, double b) { return Math.max(a, b); } static int max(Collection c) { int x = Integer.MIN_VALUE; for (int i : c) x = max(x, i); return x; } static double max(double[] c) { if (c.length == 0) return Double.MIN_VALUE; double x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static float max(float[] c) { if (c.length == 0) return Float.MAX_VALUE; float x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static byte max(byte[] c) { byte x = -128; for (byte d : c) if (d > x) x = d; return x; } static short max(short[] c) { short x = -0x8000; for (short d : c) if (d > x) x = d; return x; } static int max(int[] c) { int x = Integer.MIN_VALUE; for (int d : c) if (d > x) x = d; return x; } static Class hotwire(String src) { assertFalse(_inCore()); Class j = getJavaX(); if (isAndroid()) { synchronized(j) { // hopefully this goes well... List libraries = new ArrayList(); File srcDir = (File) call(j, "transpileMain", src, libraries); if (srcDir == null) throw fail("transpileMain returned null (src=" + quote(src) + ")"); Object androidContext = get(j, "androidContext"); return (Class) call(j, "loadx2android", srcDir, src); } } else { Class c = (Class) ( call(j, "hotwire", src)); hotwire_copyOver(c); return c; } } static A callMain(A c, String... args) { callOpt(c, "main", new Object[] {args}); return c; } static void callMain() { callMain(mc()); } static Object sleepQuietly_monitor = new Object(); static void sleepQuietly() { try { assertFalse(isAWTThread()); synchronized(sleepQuietly_monitor) { sleepQuietly_monitor.wait(); } } catch (Exception __e) { throw rethrow(__e); } } static String asString(Object o) { return o == null ? null : o.toString(); } static List replaceSublist(List l, List x, List y) { if (x == null) return l; int i = 0; while (true) { i = indexOfSubList(l, x, i); if (i < 0) break; // It's inefficient :D for (int j = 0; j < l(x); j++) l.remove(i); l.addAll(i, y); i += l(y); } return l; } static List replaceSublist(List l, int fromIndex, int toIndex, List y) { // TODO: optimize more removeSubList(l, fromIndex, toIndex); l.addAll(fromIndex, y); return l; } // supports the usual quotings (", variable length double brackets) except ' quoting static boolean isQuoted(String s) { if (isNormalQuoted(s)) return true; // use the exact version return isMultilineQuoted(s); } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } static boolean checkTokCondition(Object condition, List tok, int i) { if (condition instanceof TokCondition) return ((TokCondition) condition).get(tok, i); return checkCondition(condition, tok, i); } static void replaceCollection(Collection dest, Collection src) { dest.clear(); dest.addAll(src); } static void replaceListPart(List l, int i, int j, List l2) { l.subList(i, j).clear(); l.addAll(i, l2); } static void assertFalse(Object o) { if (!(eq(o, false) /*|| isFalse(pcallF(o))*/)) throw fail(str(o)); } static boolean assertFalse(boolean b) { if (b) throw fail("oops"); return b; } static boolean assertFalse(String msg, boolean b) { if (b) throw fail(msg); return b; } static boolean _inCore() { return false; } static List hotwire_copyOver_after = synchroList(); static void hotwire_copyOver(Class c) { // TODO: make a mechanism for making such "inheritable" fields for (String field : ll("print_log", "print_silent", "androidContext", "_userHome")) setOptIfNotNull(c, field, getOpt(mc(), field)); setOptIfNotNull(c, "mainBot" , getMainBot()); setOpt(c, "creator_class" , new WeakReference(mc())); pcallFAll(hotwire_copyOver_after, c); } static int indexOfSubList(List x, List y) { return indexOfSubList(x, y, 0); } static int indexOfSubList(List x, List y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y.get(j))) continue outer; return i; } return -1; } static int indexOfSubList(List x, A[] y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y[j])) continue outer; return i; } return -1; } static void removeSubList(List l, int from, int to) { if (l != null) subList(l, from, to).clear(); } static void removeSubList(List l, int from) { if (l != null) subList(l, from).clear(); } static boolean isNormalQuoted(String s) { int l = l(s); if (!(l >= 2 && s.charAt(0) == '"' && lastChar(s) == '"')) return false; int j = 1; while (j < l) if (s.charAt(j) == '"') return j == l-1; else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; return false; } static boolean isMultilineQuoted(String s) { if (!startsWith(s, "[")) return false; int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; return i < s.length() && s.charAt(i) == '['; } static boolean checkCondition(Object condition, Object... args) { return isTrue(callF(condition, args)); } static void setOptIfNotNull(Object o, String field, Object value) { if (value != null) setOpt(o, field, value); } static Object mainBot; static Object getMainBot() { return mainBot; } static void pcallFAll(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) pcallF(f, args); } static Object pcallF(Object f, Object... args) { return pcallFunction(f, args); } static Object pcallFunction(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable __e) { _handleException(__e); } return null; } static Object callFunction(Object f, Object... args) { return callF(f, args); } // immutable, has strong refs final static class _MethodCache { final Class c; final HashMap> cache = new HashMap(); _MethodCache(Class c) { this.c = c; _init(); } void _init() { Class _c = c; while (_c != null) { for (Method m : _c.getDeclaredMethods()) { m.setAccessible(true); multiMapPut(cache, m.getName(), m); } _c = _c.getSuperclass(); } } // Returns only matching methods Method findMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } }static abstract class VF1 { abstract void get(A a); }static interface Producer { public A next(); }static ThreadLocal DynamicObject_loading = new ThreadLocal(); static class DynamicObject { String className; // just the name, without the "main$" LinkedHashMap fieldValues = new LinkedHashMap(); DynamicObject() {} // className = just the name, without the "main$" DynamicObject(String className) { this.className = className;} }static class Matches { String[] m; Matches() {} Matches(String... m) { this.m = m;} String get(int i) { return i < m.length ? m[i] : null; } String unq(int i) { return unquote(get(i)); } String fsi(int i) { return formatSnippetID(unq(i)); } String fsi() { return fsi(0); } String tlc(int i) { return unq(i).toLowerCase(); } boolean bool(int i) { return "true".equals(unq(i)); } String rest() { return m[m.length-1]; } // for matchStart int psi(int i) { return Integer.parseInt(unq(i)); } } static class Var implements IVar { A v; // you can access this directly if you use one thread Var() {} Var(A v) { this.v = v;} public synchronized void set(A a) { if (v != a) { v = a; notifyAll(); } } public synchronized A get() { return v; } public synchronized boolean has() { return v != null; } public synchronized void clear() { v = null; } public String toString() { return str(get()); } }static class PersistableThrowable { String className; String msg; String stacktrace; PersistableThrowable() {} PersistableThrowable(Throwable e) { if (e == null) className = "Crazy Null Error"; else { className = getClassName(e).replace('/', '.'); msg = e.getMessage(); stacktrace = getStackTrace_noRecord(e); } } public String toString() { return nempty(msg) ? className + ": " + msg : className; } }static abstract class TokCondition { abstract boolean get(List tok, int i); // i = N Index }static class Pair implements Comparable> { A a; B b; Pair() {} Pair(A a, B b) { this.b = b; this.a = a;} public int hashCode() { return hashCodeFor(a) + 2*hashCodeFor(b); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Pair)) return false; Pair t = (Pair) o; return eq(a, t.a) && eq(b, t.b); } public String toString() { return "<" + a + ", " + b + ">"; } public int compareTo(Pair p) { if (p == null) return 1; int i = ((Comparable) a).compareTo(p.a); if (i != 0) return i; return ((Comparable) b).compareTo(p.b); } } static interface IVar { void set(A a); A get(); boolean has(); void clear(); } static Method findMethod(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Method m = findMethod_static((Class) o, method, args, false); if (m == null) return null; m.setAccessible(true); return m; } else { Method m = findMethod_instance(o, method, args, false); if (m == null) return null; m.setAccessible(true); return m; } } catch (Exception e) { throw new RuntimeException(e); } } static Method findMethod_static(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !findMethod_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } return null; } static Method findMethod_instance(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && findMethod_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } return null; } static boolean findMethod_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static String formatSnippetID(long id) { return "#" + id; } static String fsi(String id) { return formatSnippetID(id); } static int hashCodeFor(Object a) { return a == null ? 0 : a.hashCode(); } public static long parseSnippetID(String snippetID) { long id = Long.parseLong(shortenSnippetID(snippetID)); if (id == 0) throw fail("0 is not a snippet ID"); return id; } static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return "" + parseLong(snippetID); } }