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);};