commit 01b71465d522197dcb2f1bb16535786b4e058a71
parent 3d41ab29bd5f483d8f46aa7254327ef6e77cf85b
Author: tomas <tomas@logand.com>
Date: Sat, 17 Oct 2009 00:34:37 +0200
runtime dispatch, jproxy, Que + wait, push and other
Diffstat:
M | java.wl | | | 26 | +++++++++++++++----------- |
M | wl.java | | | 149 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
2 files changed, 155 insertions(+), 20 deletions(-)
diff --git a/java.wl b/java.wl
@@ -222,16 +222,6 @@
(pass prin)
(prin "^J") )
-(de jclass (N) (java.lang.Class 'forName N))
-
-(de gc () (`((jclass 'java.lang.Runtime) 'getRuntime) 'gc))
-
-(de import L
- (let (P (pop 'L) C)
- (while L
- (setq C (pop 'L))
- (def C (jclass (pack P "." C))) ) ) )
-
(de - L
(let? Z (eval (pop 'L) 1)
(ifn L
@@ -269,7 +259,17 @@
(de + @ (- (pass - 0)))
(de =0 (N) (when (= 0 N) N))
-(de n0 (N) (not(=0 N)))
+(de n0 (N) (not (=0 N)))
+
+(de jclass (N) (java.lang.Class 'forName N))
+
+(de gc () (`((jclass 'java.lang.Runtime) 'getRuntime) 'gc))
+
+(de import L
+ (let (P (pop 'L) C)
+ (while L
+ (setq C (pop 'L))
+ (def C (jclass (pack P "." C))) ) ) )
(de jnum (X)
(jnew `(jclass 'java.math.BigInteger) (X 'toString)) )
@@ -282,3 +282,7 @@
(jnum (R 'maxMemory)) )
(- (jnum (R 'totalMemory)) (jnum (R 'freeMemory))) )
`(* 1024 1024) ) ) )
+
+(def 'true (jfield (jclass 'java.lang.Boolean) 'TRUE))
+(def 'false (jfield (jclass 'java.lang.Boolean) 'FALSE))
+(def 'null (gc))
diff --git a/wl.java b/wl.java
@@ -13,6 +13,14 @@ import java.util.ArrayList;
import java.lang.reflect.Field;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Collections;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
class wl implements Runnable {
@@ -156,7 +164,7 @@ class wl implements Runnable {
static Any mkIsym(String n, Any v) {return new Isym(n, v, NIL);}
static Any mkObj(Object x) {return new Obj(x);}
static Any mkOint(String x) {return mkObj(new BigInteger(x));}
- static Any mkOfix(String x) {err("mkOfix not implemented"); return null;}
+ static Any mkOfix(String x) {err("TODO mkOfix"); return null;}
final static Any NIL = mkIsym("NIL", null);
final static Any T = mkIsym("T", null);
@@ -205,6 +213,7 @@ class wl implements Runnable {
final Any Out = mkIsym("*Out", mkObj(System.out));
final Any Env = mkIsym("*Env", NIL);
final Any Stk = mkIsym("*Stk", NIL);
+ final Any Scl = mkIsym("*Scl", mkObj(BigInteger.ZERO));
Character peek() {return ((In) In.val().obj()).peek();}
Character xchar() {return ((In) In.val().obj()).xchar();}
@@ -386,6 +395,29 @@ class wl implements Runnable {
}
return A.cdr();
}
+
+ // runtime dispatch
+ class MethodComparator implements Comparator<Method> {
+ public int compare(Method l, Method r) {
+ // most specific first
+ Class[] lc = l.getParameterTypes();
+ Class[] rc = r.getParameterTypes();
+ for(int i = 0, j = 0; i < lc.length && j < rc.length; i++, j++)
+ if(!lc[i].equals(rc[i]) && lc[i].isAssignableFrom(rc[i]))
+ return 1;
+ return lc.length < rc.length ? 1 : -1;
+ }
+ }
+ final MethodComparator methodComparator = new MethodComparator();
+ boolean isApplicable(Method m, Object[] args) {
+ Class[] c = m.getParameterTypes();
+ if(c.length != args.length) return false; // nargs must be same
+ for(int i = 0; i < c.length; i++)
+ if(!c[i].isInstance(args[i])) // must be instanceof
+ if(args[i] != null || !Object.class.equals(c[i]))
+ return false;
+ return true;
+ }
Any applyO(Any E, Any O) { // 'obj 'meth [arg ...]
Any I = E.cdr();
Any F = eval(I.car());
@@ -405,11 +437,25 @@ class wl implements Runnable {
Object o = O.obj();
Class c = o instanceof Class ? (Class) o : o.getClass();
String nm = F.isOstr() ? (String) F.obj() : F.nm();
- Method m = c.getMethod(nm, ta);
+ //Method m = c.getMethod(nm, ta);
+ //Object r = m.invoke(o, aa);
+
+ // sort methods
+ final List<Method> methods = new LinkedList<Method>();
+ for(Method m: c.getMethods())
+ if(m.getName().equals(nm))
+ methods.add(m);
+ Collections.sort(methods, methodComparator);
+ // apply first (most specific) applicable method
+ Method m = null;
+ for(Method method: methods)
+ if(isApplicable(method, aa)) {
+ m = method;
+ break;
+ }
+ if(null == m) err(E, "No applicable method");
Object r = m.invoke(o, aa);
Z = mkObj(r);
- } catch(NoSuchMethodException e) {
- err(E, "NoSuchMethodException");
} catch(IllegalAccessException e) {
err(E, "IllegalAccessException");
} catch(InvocationTargetException e) {
@@ -489,6 +535,9 @@ class wl implements Runnable {
return z;
}
+ final wl Wl = this;
+ final BlockingQueue<Any> Que = new LinkedBlockingQueue<Any>();
+
public wl() {
Sd.put("NIL", NIL);
Sd.put("T", T);
@@ -500,6 +549,7 @@ class wl implements Runnable {
Sd.put("*Out", Out);
Sd.put("*Env", Env);
Sd.put("*Stk", Stk);
+ Sd.put("*Scl", Scl);
Sd.put("java.lang.Class", mkIsym("java.lang.Class", mkObj(Class.class)));
fn("run", new Fn() {public Any fn(Any E) {
@@ -627,6 +677,10 @@ class wl implements Runnable {
}
return mkObj(Z);
}});
+ fn("str", new Fn() {public Any fn(Any E) { // TODO
+ Any I = E.cdr();
+ return mkObj(str(eval(I.car())));
+ }});
fn("def", new Fn() {public Any fn(Any E) {
Any X = E.cdr();
Any A = eval(X.car());
@@ -640,7 +694,7 @@ class wl implements Runnable {
Any X = eval(E.cdr().car());
if(X.isCons()) Z = X.car();
else if(X.isSym()) Z = X.val();
- else if(X.isObj()) Z = X;
+ //else if(X.isObj()) Z = X;
else err(E, "Don't know how to val");
return Z;
}});
@@ -665,6 +719,30 @@ class wl implements Runnable {
} else err(E, "Don't know how to pop");
return Z;
}});
+ fn("push", new Fn() {public Any fn(Any E) {
+ Any Z = NIL;
+ Any I = E.cdr();
+ Any K = eval(I.car());
+ I = I.cdr();
+ if(K.isCons()) {
+ Any V = K.car();
+ while(I.isCons()) {
+ Z = eval(I.car());
+ I = I.cdr();
+ V = mkCons(Z, V);
+ }
+ K.car(V);
+ } else if(K.isSym()) {
+ Any V = K.val();
+ while(I.isCons()) {
+ Z = eval(I.car());
+ I = I.cdr();
+ V = mkCons(Z, V);
+ }
+ K.val(V);
+ } else err(E, "Don't know how to push");
+ return Z;
+ }});
fn("con", new Fn() {public Any fn(Any E) {
Any I = E.cdr();
Any L = eval(I.car());
@@ -817,6 +895,7 @@ class wl implements Runnable {
Object[] aa = a.toArray();
Class[] ta = (Class[]) t.toArray(new Class[aa.length]);
try {
+ // TODO might need dynamic dispatch here too
Constructor c = ((Class) C.obj()).getConstructor(ta);
Object r = c.newInstance(aa);
Z = mkObj(r);
@@ -851,8 +930,63 @@ class wl implements Runnable {
}
return Z;
}});
+ fn("jproxy", new Fn() {public Any fn(Any E) { // jproxy 'flg 'fn ['jcls...]
+ Any Z = NIL;
+ Any I = E.cdr();
+ final Any A = eval(I.car());
+ I = I.cdr();
+ final Any F = eval(I.car());
+ I = I.cdr();
+ ArrayList<Class> a = new ArrayList();
+ while(NIL != I) {
+ a.add((Class) eval(I.car()).obj());
+ I = I.cdr();
+ }
+ ClassLoader l = this.getClass().getClassLoader();
+ Class[] c = (Class[]) a.toArray(new Class[a.size()]);
+ InvocationHandler h = new InvocationHandler() {
+ public Object invoke(Object p, Method m, Object[] a)
+ throws Throwable {
+ Any X = NIL;
+ if(null != a)
+ for(int i = a.length - 1; 0 <= i; i--)
+ X = mkCons(mkObj(a[i]), X);
+ //X = mkCons(mkObj(p), X);
+ //System.out.println(p);
+ X = mkCons(mkObj(m.getName()), X);
+ X = mkCons(F, X);
+ Any Z = NIL;
+ if(NIL == A) Z = eval(X);
+ else Que.offer(X);
+ return Z.isObj() ? Z.obj() : null;
+ }
+ };
+ Object r = Proxy.newProxyInstance(l, c, h);
+ Z = mkObj(r);
+ return Z;
+ }});
+ fn("wait", new Fn() {public Any fn(Any E) { // wait ['cnt] . prg
+ Any Z = NIL;
+ // TODO poll from Que with timeout cnt unless run(prg)
+ //Any I = E.cdr();
+ try {
+ while(true) {
+ Any X = Que.take();
+ Z = eval(X);
+ }
+ } catch(InterruptedException e) {
+ dbg("InterruptedException");
+ }
+ return Z;
+ }});
+ fn("bye", new Fn() {public Any fn(Any E) { // bye ['cnt]
+ Any I = E.cdr();
+ Any Z = eval(I.car());
+ System.exit(Z.isOnum() ? ((BigInteger) Z.obj()).intValue() : 0);
+ return Z;
+ }});
}
-
+
void print(Any E) {
PrintStream S = (PrintStream) Out.val().obj();
if(E.isCons()) {
@@ -947,6 +1081,3 @@ class wl implements Runnable {
//(new Thread(new wl())).start();
}
}
-
-// // Sd["eq"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X == Y);};
-// // Sd["lt"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X < Y);};