// class for linking Java methods to NL static class Native { Lisp snl; SNLMatches m; SNLMatches trans; boolean printExceptions; int exceptions; L ins, strings; *() {} // good to have *(Lisp *snl) {} // assume it's a Lisp structure from another bot - // restructure to import it /* *(O o) { snl = (Lisp) restructure(o); }*/ *(S s) { snl = snlToTree(s); } boolean match(S pat) { m = new SNLMatches; trans = new SNLMatches; Lisp tree = snlToTree_cached(pat); ins = new L; strings = new L; tree = findInVariables(tree, ins, strings); //print("tree now: " + tree); if (!snlMatch2(tree, snl, trans)) ret false; for (S in : ins) if (get(in) == null) ret false; for (S string : strings) if (get(string) == null || !get(string).isEmpty()) ret false; ret true; } Lisp findInVariables(Lisp tree, L ins, L strings) { if (tree == null) ret tree; if (tree.isEmpty()) { if (tree.head.startsWith("in S ")) { S var = dropPrefix("in S ", tree.head); if (startsWithUpperCase(var)) { if (!strings.contains(var)) strings.add(var); ret lisp(var); } } if (tree.head.startsWith("in ")) { S var = dropPrefix("in ", tree.head); if (startsWithUpperCase(var)) { if (!ins.contains(var)) ins.add(var); ret lisp(var); } } ret tree; } else { // recurse Lisp lisp = new Lisp(tree.head); for (Lisp child : tree) lisp.add(findInVariables(child, ins, strings)); ret lisp; } } Lisp get(S var) { Lisp val = trans.get(var); if (!isVar(val)) ret val; ret getOuter(val.raw()); } // if only one in var Lisp get() { ret get(anyInVar()); } // ditto S str() { ret str(anyInVar()); } S anyInVar() { if (!empty(ins)) ret first(ins); ret first(strings); } boolean isVar(Lisp l) { ret l != null && l.isEmpty() && startsWithUpperCase(l.raw()); } // called from outside native Lisp getOuter(S var) { ret m.get(var); } // called from inside native S str(S var) { Lisp val = get(var); if (val == null) fail("variable " + quote(var) + " not set"); if (!val.isEmpty()) fail("variable " + quote(var) + " not a string: " + struct(val)); ret unquote(val.raw()); } S strOuter(S var) { Lisp val = getOuter(var); if (val == null) fail("variable " + quote(var) + " not set"); if (!val.isEmpty()) fail("variable " + quote(var) + " not a string: " + struct(val)); ret unquote(val.raw()); } // may throw an exception if variable problem (already set to different value) void set(S var, O val) { if (val instanceof List) val = structure(val); // TODO Lisp lisp = val instanceof Lisp ? (Lisp) val : lisp(quote(main.str(val))); Lisp outer = trans.get(var); if (isVar(outer)) { if (!m.put(trans.raw(var), lisp)) fail(); } else if (!eq(lisp, outer)) { //print("neq " + lisp + " != " + outer); fail(); } } boolean callExternal(O bot) { try { O copy = newObject(main.getClass(bot, "main$Native"), quickExport(snl, bot)); //O copy = quickExport(this, bot); if (!isTrue(callOpt(bot, "yo", copy))) ret false; m = (SNLMatches) quickImport(main.get(copy, "m")); ret true; } catch (Exception e) { handle(e); ret false; } } boolean callExternal(Method yo) { try { Class c = yo.getDeclaringClass(); //print("Declaring class: " + c + " (" + identityHashCode(c) + ")"); O copy = newObject(main.getClass(c, "main$Native"), quickExport(snl, c)); if (!isTrue(yo.invoke(null, copy))) ret false; m = (SNLMatches) quickImport(main.get(copy, "m")); ret true; } catch (Exception e) { handle(e); ret false; } } void handle(Throwable t) { if (printExceptions) printStackTrace(t); ++exceptions; } }