commit 69640b8ad79b8112d5ace2409934d3e8eba71c43
parent f829c1790b61532efbbdc62fc74ebf91b642f3b1
Author: tomas <tomas@logand.com>
Date: Tue, 6 Oct 2009 21:07:33 +0200
generic Any used
Diffstat:
M | wl.java | | | 575 | ++++++++++++++++++++++++++----------------------------------------------------- |
1 file changed, 189 insertions(+), 386 deletions(-)
diff --git a/wl.java b/wl.java
@@ -5,17 +5,36 @@ import java.util.HashMap;
class wl {
+ void err(Object X, String M) {
+ if(X instanceof Any) throw new RuntimeException(M + ": " + str((Any) X));
+ throw new RuntimeException(M + ": " + X);
+ }
+ void err(String M) {throw new RuntimeException(M);}
+
+ static interface Fn {
+ public Any fn(Any E);
+ }
+
static class Any {
public String nm;
- public Object car, cdr;
- public Any(String n, Object a, Object d) {nm = n; car = a; cdr = d;}
- public isSym() {return null != nm;}
- public isCons() {return null == nm;}
+ public Any car, cdr;
+ public Object cxr;
+ public Any(String n, Any a, Any d, Object x) {
+ nm = n; car = a; cdr = d; cxr = x;
+ }
+ public boolean isSym() {return null != nm;}
+ public boolean isCons() {return null == nm && null != car && null != cdr;}
+ public boolean isStr() {return null == nm && cxr instanceof String;}
+ public boolean isInt() {return null == nm && cxr instanceof Integer;}
+ public boolean isFn() {return cxr instanceof Fn;}
}
- static Any cons(Any a, Any d) {return new Any(null, a, d);}
+ static Any cons(Any a, Any d) {return new Any(null, a, d, null);}
+ static Any mkInt(String x) {return new Any(null, null, null, Integer.parseInt(x));}
+ static Any mkFix(String x) {return new Any(null, null, null, Float.parseFloat(x));}
+ static Any mkStr(String x) {return new Any(null, null, null, x);}
- final static Any NIL = new Any("NIL", null, null);
- final static Any T = new Any("T", NIL, null);
+ final static Any NIL = new Any("NIL", null, null, null);
+ final static Any T = new Any("T", NIL, null, null);
static {
NIL.car = NIL;
@@ -23,31 +42,10 @@ class wl {
T.cdr = T;
}
- // static class Cons {
- // public Object car, cdr;
- // public Cons(Object a, Object d) {car = a; cdr = d;}
- // }
- // static Cons cons(Object a, Object d) {return new Cons(a, d);}
-
- // static class Sym {
- // public String nm;
- // public Object car, cdr;
- // public Sym(String n, Object a, Object d) {nm = n; car = a; cdr = d;}
- // }
-
- // final static Sym NIL = new Sym("NIL", null, null);
- // final static Sym T = new Sym("T", NIL, null);
-
- // static {
- // NIL.car = NIL;
- // NIL.cdr = NIL;
- // T.cdr = T;
- // }
-
// reader
- final static Object Qte = new Object();
- final static Object Lp = new Object();
- final static Object Rp = new Object();
+ final static Any Qte = new Any(null, null, null, null);
+ final static Any Lp = new Any(null, null, null, null);
+ final static Any Rp = new Any(null, null, null, null);
String L;
int N, I, D;
@@ -69,7 +67,7 @@ class wl {
skip();
}
}
- String text() {
+ Any text() {
StringBuffer L = new StringBuffer();
while('"' != peek()) {
Character C = xchar();
@@ -83,14 +81,13 @@ class wl {
}
L.append(C);
}
- if('"' != xchar()) throw new RuntimeException("Unbalanced double quote");
- if(0 < L.length()) return L.toString(); //.replace(/\r\n/g, "\n");
- return "";
+ if('"' != xchar()) err("Unbalanced double quote");
+ if(0 < L.length()) return mkStr(L.toString()); //.replace(/\r\n/g, "\n");
+ return mkStr("");
}
- Object symbol() {
+ Any symbol() {
Character C = xchar();
- if(charIn(C, "()# \t\n"))
- throw new RuntimeException("Symbol expected, got " + C);
+ if(charIn(C, "()# \t\n")) err(C, "Symbol expected");
boolean N = charIn(C, "+-0123456789.");
boolean F = ('.' == C);
StringBuffer L = new StringBuffer();
@@ -106,9 +103,9 @@ class wl {
}
String M = L.toString();
if((1 == M.length()) && charIn(M.charAt(0), "+-.")) N = false;
- return N ? (F ? Float.parseFloat(M) : Integer.parseInt(M, 10)) : intern(M);
+ return N ? (F ? mkFix(M) : mkInt(M)) : intern(M);
}
- Object token() {
+ Any token() {
skip();
Character X = peek();
if(null == X) return null;
@@ -124,127 +121,212 @@ class wl {
}
// parser
- Object parseBuild(Stack Os) {
- Object Z = null;
- Object Dot = null;
+ Any parseBuild(Stack<Any> Os) {
+ Any Z = NIL;
+ Any Dot = null;
while(0 < Os.size()) {
- Object X = Os.pop();
+ Any X = Os.pop();
if(Lp == X) return Dot != null ? cons(Dot, cons(Z, NIL)) : Z;
Dot = null;
- if((X instanceof Sym) && (".".equals(((Sym) X).nm))) {
- if((Z instanceof Cons) && (null == ((Cons) Z).cdr)) {
- Z = ((Cons) Z).car;
+ if(X.isSym() && (".".equals(X.nm))) {
+ if(Z.isCons() && NIL == Z.cdr) {
+ Z = Z.car;
Dot = X;
- } else throw new RuntimeException("Bad dotted pair");
+ } else err("Bad dotted pair");
} else if(X == Qte)
- Z = cons(cons(this.Sd.get("quote"), ((Cons) Z).car), ((Cons) Z).cdr);
- else Z = cons(X, Z == null ? NIL : Z);
+ Z = cons(cons(this.Sd.get("quote"), Z.car), Z.cdr);
+ else Z = cons(X, Z);
}
- throw new RuntimeException("Missing mark");
+ err("Missing mark");
+ return NIL; // make compiler happy:-{
}
- Object parse(String L) {
+ public Any parse(String L) {
init(L);
- Stack Os = new Stack();
+ Stack<Any> Os = new Stack<Any>();
Os.push(Lp);
// TODO circular list .
// TODO interpret while reading ~ for each top-level sexp
// TODO no wasteful consing
while(null != peek()) {
- Object X = token();
+ Any X = token();
if(null != X) {
if(Rp == X) Os.push(parseBuild(Os));
else Os.push(X);
}
}
- Object Z = parseBuild(Os);
- if(0 < Os.size())
- throw new RuntimeException("Incomplete input, left with " + Os);
+ Any Z = parseBuild(Os);
+ if(0 < Os.size()) err(Os, "Incomplete input");
return Z;
}
// printer
- String str(Object L) {
+ public String str(Any L) {
StringBuilder A = new StringBuilder();
- if(L instanceof Sym) A.append(L.nm);
- else if(L instanceof Cons) {
+ if(L.isSym()) A.append(L.nm);
+ else if(L.isInt()) A.append(L.cxr.toString());
+ else if(L.isCons()) {
if(this.Sd.get("quote") == L.car) {
A.append('\'');
A.append(str(L.cdr));
} else {
A.append('(');
- while(L instanceof Cons) {
+ while(L.isCons()) {
A.append(str(L.car));
L = L.cdr;
- if(NIL !== L) A.append(' ');
+ if(NIL != L) A.append(' ');
}
- if(NIL !== L) {
+ if(NIL != L) {
A.append(". ");
A.append(str(L));
}
A.append(')');
}
- } else if(L instanceof String) {
- var Y = L.split("");
- for(var I = 0; I < Y.length; I++) {
- if(Y[I] == "\\") Y[I] = "\\\\";
- else if(Y[I] == '"') Y[I] = '\\"';
- }
- var S = Y.join("");
- //var S = L.replace(/\"/g, "\\\"").replace(/\\/g, "\\\\");
+ } else if(L.isStr()) {
A.append('"');
- A.append(S);
+ String S = (String) L.cxr;
+ for(int I = 0; I < S.length(); I++) {
+ Character C = S.charAt(I);
+ if('\\' == C) A.append("\\\\");
+ else if('"' == C) A.append("\\\"");
+ else A.append(C);
+ }
A.append('"');
- } else A.append(L);
+ } else err(L, "Don't know how to print");
return A.toString();
}
// evaluator
- HashMap Sd = new HashMap();
+ HashMap<String, Any> Sd = new HashMap<String, Any>();
- Sym intern(String Nm) {
- if(!this.Sd.containsKey(Nm)) this.Sd.put(Nm, new Sym(Nm, NIL, NIL));
- return (Sym) this.Sd.get(Nm);
+ Any intern(String Nm) {
+ if(!this.Sd.containsKey(Nm)) this.Sd.put(Nm, new Any(Nm, NIL, NIL, null));
+ return this.Sd.get(Nm);
}
- void def(String Nm, Object Val) {
- if(this.Sd.containsKey(Nm)) ((Sym) this.Sd.get(Nm)).cdr = Val;
- else this.Sd.put(Nm, new Sym(Nm, Val, NIL));
+ // void def(String Nm, Fn F) {
+ // if(this.Sd.containsKey(Nm)) this.Sd.get(Nm).cxr = F;
+ // else this.Sd.put(Nm, new Sym(Nm, null, null, F));
+ // }
+
+ Any run(Any E) {
+ System.out.println("run: " + str(E));
+ Any Z = NIL;
+ while(NIL != E) {
+ Z = eval(E.car);
+ E = E.cdr;
+ }
+ return Z;
+ }
+ Any eval(Any E) {
+ System.out.println("eval: " + str(E));
+ Any Z = NIL;
+ if(E.isInt()) Z = E;
+ else if(E.isSym()) Z = E.cdr;
+ else if(E.isCons()) {
+ Any X = E.car;
+ if(X.isInt()) Z = E;
+ else if(X.isSym()) {
+ if(X.isFn()) Z = ((Fn) X.cxr).fn(E);
+ else err(E, "TODO ap"); //Z = ap(E);
+ } else err(E, "Unexpected function type");
+ } else Z = E; // string
+ //alert("ev: " + str(E) + " => " + Z);
+ return Z;
+ }
+
+ void fn(String Nm, Fn F) {this.Sd.put(Nm, new Any(Nm, null, null, F));}
+
+ public wl() {
+ Sd.put("NIL", NIL);
+ Sd.put("T", T);
+
+ fn("run", new Fn() {public Any fn(Any E) {return run(E);}});
+ fn("eval", new Fn() {public Any fn(Any E) {return eval(E);}});
+ fn("quote", new Fn() {public Any fn(Any E) {return E.cdr;}});
+ fn("car", new Fn() {public Any fn(Any E) {return eval(E.cdr.car).car;}});
+ fn("cdr", new Fn() {public Any fn(Any E) {return eval(E.cdr.car).cdr;}});
+ fn("-", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any Z = eval(X.car);
+ if(NIL == Z) return NIL;
+ if(NIL == X.cdr) Z.cxr = -((Integer) Z.cxr);
+ else
+ while(NIL != X.cdr) {
+ X = X.cdr;
+ Any Y = eval(X.car);
+ if(NIL == Y) return NIL;
+ Z.cxr = (Integer) Z.cxr - (Integer) Y.cxr;
+ }
+ return Z;
+ }});
+ fn("*", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any Z = eval(X.car);
+ if(NIL == Z) return NIL;
+ while(NIL != X.cdr) {
+ X = X.cdr;
+ Any Y = eval(X.car);
+ if(NIL == Y) return NIL;
+ Z.cxr = (Integer) Z.cxr * (Integer) Y.cxr;
+ }
+ return Z;
+ }});
+ fn("/", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any Z = eval(X.car);
+ if(NIL == Z) return NIL;
+ while(NIL != X.cdr) {
+ X = X.cdr;
+ Any Y = eval(X.car);
+ if(NIL == Y) return NIL;
+ Z.cxr = (Integer) Z.cxr / (Integer) Y.cxr;
+ }
+ return Z;
+ }});
+ fn("loop", new Fn() {public Any fn(Any E) {
+ // TODO @
+ while(true) {
+ for(Any X = E.cdr; NIL != X.cdr; X = X.cdr) {
+ Any Y = X.car;
+ if(Y.isCons() && NIL == Y) {
+ Y = Y.cdr;
+ if(NIL == eval(Y.car)) return run(Y.cdr);
+ } else if(Y.isCons() && T == Y) {
+ Y = Y.cdr;
+ if(NIL != eval(Y.car)) return run(Y.cdr);
+ } else eval(Y);
+ }
+ }
+ }});
+ fn("==", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ return eval(X.car) == eval(X.cdr.car) ? T : NIL;
+ }});
+
+ fn("in", new Fn() {public Any fn(Any E) {
+ Any X = E.cdr;
+ Any N = eval(E.car);
+ String F;
+ if(N.isStr()) F = (String) N.cxr;
+ else if(N.isSym()) F = N.nm;
+ else err(E, "File name expected");
+ //FileInputStream S = new FileInputStream(N);
+ //InputStreamReader R = new InputStreamReader(S, "UTF-8");
+ return NIL;
+ }});
+ //FileOutputStream fos = new FileOutputStream("test.txt");
+ //OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
}
public static void main(String args[]) {
wl X = new wl();
- //wl.init("(+ 1 2 3)");
+ System.out.println(X.str(X.parse("(- 1 2 3)")));
+ System.out.println(X.str(X.run(X.parse("(- 1 2 3)(- 3 5)(/ "))));
}
}
-// // TODO fix E ~ whole sexp fn
-
-// function run(E) {
-// var Z;
-// while(NIL !== E) {
-// Z = ev(E.car);
-// E = E.cdr;
-// }
-// return Z;
-// }
-// function ev(E) { // eval
-// var Z;
-// if(typeof E == "number") Z = E;
-// else if(isSym(E)) Z = E.cdr;
-// else if(isCons(E)) {
-// var X = E.car;
-// if(typeof X == "number") Z = E;
-// else if(isSym(X)) {
-// if(typeof X.cdr == "function") Z = X.cdr(E);
-// else throw "TODO ap"; //Z = ap(E);
-// } else throw "Unexpected function type";
-// } else Z = E; // string
-// //alert("ev: " + str(E) + " => " + Z);
-// return Z;
-// }
-
// // TODO ap
// function ap(E) { // apply
// var Z;
@@ -261,10 +343,7 @@ class wl {
// } else throw "Function expected";
// }
-// //def("run", run);
-// //def("eval", ev);
// //def("apply", ap);
-// def("quote", function(E) {return E.cdr;});
// def("val", function(E) {
// var Z;
@@ -280,289 +359,13 @@ class wl {
// // TODO def !!!!!!!!!!!!!
// // OK
-// def("car", function(E) {return ev(E.cdr.car).car;});
-// def("cdr", function(E) {return ev(E.cdr.car).cdr;});
-// def("-", function(E) {
-// var X = E.cdr;
-// var Z = ev(X.car);
-// if(NIL === Z) return NIL;
-// if(NIL === X.cdr) Z = -Z;
-// else
-// while(NIL !== X.cdr) {
-// X = X.cdr;
-// var Y = ev(X.car);
-// if(NIL === Y) return NIL;
-// Z -= Y;
-// }
-// return Z;
-// });
-// def("*", function(E) {
-// var X = E.cdr;
-// var Z = ev(X.car);
-// if(NIL === Z) return NIL;
-// while(NIL !== X.cdr) {
-// X = X.cdr;
-// var Y = ev(X.car);
-// if(NIL === Y) return NIL;
-// Z *= Y;
-// }
-// return Z;
-// });
-// def("/", function(E) {
-// var X = E.cdr;
-// var Z = ev(X.car);
-// if(NIL === Z) return NIL;
-// while(NIL !== X.cdr) {
-// X = X.cdr;
-// var Y = ev(X.car);
-// if(NIL === Y) return NIL;
-// Z /= Y;
-// }
-// return Z;
-// });
// // Sd["%"] = function(E) {var X = Os.pop(); Os.push(Os.pop() % X);};
// // 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);};
-// wl.prototype.parse = parse;
-// wl.prototype.str = str;
-// wl.prototype.run = run;
-// return this;
-// }
-
-
-
-
-
-
-
-
-// // Sd["if"] = function() {
-// // var N = Os.pop();
-// // var P = Os.pop();
-// // var C = Os.pop();
-// // Es.push([false, C === true ? P : N]);
-// // };
-
-// // // Sd[".call"] = function() {
-// // // var N = Os.pop();
-// // // var K = Os.pop();
-// // // var D = Os.pop();
-// // // var X = [];
-// // // for(var I = 0; I < N; I++) X.unshift(Os.pop());
-// // // Os.push(D[K].apply(D, X));
-// // // };
-// // Sd[".date"] = function(E) {return new Date();}; // TODO split new and Date
-// // // Sd[".callback"] = function() { // TODO event arg?
-// // // var X = Os.pop();
-// // // Os.push(function() {
-// // // Ps.run(X, true);
-// // // while(0 < Es.length)
-// // // Ps.step();
-// // // });
-// // // };
-
-
-// // Sd["list2array"] = function list2array(E) {
-// // var Z = [];
-// // while(!isNil(E)) {
-// // Z.push(E.car);
-// // E = E.cdr;
-// // }
-// // return Z;
-// // };
-// // // Sd["array2list"] = function array2list(A) {
-// // // var Z = NIL;
-// // // for(var I = A.length - 1; 0 <= I; I--)
-// // // Z = cons(A[I], Z);
-// // // return Z;
-// // // };
-// // // Sd["object2list"] = function object2list(O) {
-// // // var Z = NIL;
-// // // for(var I in O)
-// // // Z = cons(cons(I, O[I]), Z);
-// // // return Z;
-// // // };
-
-// // function parse() {
-// // var Z;
-// // var A = arguments;
-// // if(A.length)
-// // for(var I = 0; I < A.length; I++)
-// // Z = Rd.parse(A[I]);
-// // else Z = Rd.parse(A);
-// // return Z;
-// // }
-// // wl.prototype.parse = parse;
-// // return this;
-// // }
-
-// // /// lisp
-
-// // // function format(N, S) {
-// // // var X = "" + N;
-// // // var L = X.length;
-// // // return X.slice(0, L - S) + "." + X.slice(L - S, L);
-// // // }
-
-// // // function real(N, S) {
-// // // return N / Math.pow(10, S);
-// // // }
-
-// // var Syms = {};
-
-// // function mkSym(Nm, Val, Prop) {
-// // var X = new Sym(Nm, Val, Prop);
-// // Syms[Nm] = X;
-// // return X;
-// // }
-
-// // function xget(Sym) {
-// // return isSym(Sym) ? Sym._val : Sym;
-// // }
-
-// // function xset(Sym, Val) {
-// // if(!isSym(Sym)) throw "Sym expected";
-// // Sym._val = Val;
-// // return Sym._val;
-// // }
-
-// // //var NIL = mkSym("NIL");
-// // var T = mkSym("T");
-
-// // //xset(NIL, NIL);
-// // xset(T, T);
-// // // TODO set props for NIL and T
-
-// // function intern(Sym) {
-// // //if(!(Sym in Syms)) Syms[Sym] = mkSym(Sym, NIL, NIL);
-// // return Syms[Sym] || (Syms[Sym] = mkSym(Sym, NIL, NIL));
-// // }
-
-
-// // function isT(X) {
-// // return X === T;
-// // }
-
-
-
-
-
-
-
-
// // function eq(X, Y) {
// // if(X === Y) return T;
// // //if(X == Y) return T;
// // return NIL;
// // }
-
-// // function xdelete(A, L) {
-// // var X = NIL;
-// // while(!isNil(L)) {
-// // if(isNil(eq(A, L.car))) X = cons(L.car, X);
-// // L = L.cdr;
-// // }
-// // return reverse(X);
-// // }
-
-// // function lsApply(Fn, Args) {
-// // }
-
-// // function jsFn(Fn) {
-// // var F = function() {
-// // return lsApply(Fn, list2array(arguments));
-// // };
-// // return F;
-// // }
-
-// // function jsApply() {
-// // var Fn = arguments.shift();
-// // var Args = arguments.shift();
-// // var Rest = arguments;
-// // return Fn.apply(list2array(Args).unshift.apply(list2array(Rest)));
-// // }
-
-// // var Xeval = {};
-
-// // function xdef(Nm, Fn) {
-// // if(!(Nm in Syms)) intern(Nm);
-// // Xeval[Nm] = Fn;
-// // }
-
-// // xdef("quote", function(E) {
-// // return cdr(E); // or cdr?
-// // });
-// // xdef("if", function(E) {
-// // if(!isNil(xeval(cadr(E)))) return xeval(caddr(E));
-// // else return xeval(cadddr(E));
-// // });
-// // xdef("prog", function(E) {
-// // var L = cdr(E);
-// // var X = NIL;
-// // while(!isNil(L)) {
-// // X = xeval(L.car);
-// // L = L.cdr;
-// // }
-// // return X;
-// // });
-
-// // function xeval(E) {
-// // if(isSym(E)) return xget(E);
-// // else if(!isCons(E)) return E;
-// // else if(car(E)._nm in Xeval) return Xeval[car(E)._nm](E);
-// // else return xapply(xeval(car(E)), map(xeval, cdr(E)));
-// // }
-
-// // function initLisp() {
-// // //xalert(xeval(NIL), xeval(T), xeval(12), xeval(12.3), xeval({x: "hi"}), xeval([1, 2]));
-// // //xalert(xeval(cons(intern("quote"), cons("whoa", NIL))));
-// // //xalert(xeval(cons(intern("quote"), cons("whoa", cons("b", NIL)))));
-// // //xalert(intern("if"));
-// // //xalert(object2list(Syms));
-// // //xalert(object2list(Xeval));
-// // //xalert(xeval(cons(intern("if"), cons(T, cons("yes", cons("no", NIL))))));
-// // //xalert(xeval(cons(intern("if"), cons(NIL, cons("yes", cons("no", NIL))))));
-// // //xalert(xeval(cons(intern("quote"), intern("whoa"))));
-// // }
-
-// // // parser
-
-// // function isArray(A) {
-// // return A && A.constructor == Array;
-// // }
-
-// // function flatten(A) {
-// // var X = [];
-// // function rec(B) {
-// // var N = B.length;
-// // var I;
-// // for(I = 0; I < N; I++) {
-// // if(isArray(B[I])) rec(B[I]);
-// // else X.push(B[I]);
-// // }
-// // }
-// // rec(A);
-// // return X;
-// // }
-
-// // function lisp2string(Any) {
-// // return flatten(unparse(Any)).join("");
-// // }
-
-// // function xalert() {
-// // var X = [];
-// // var N = arguments.length;
-// // var I;
-// // for(I = 0; I < N; I++) {
-// // X.push(flatten(unparse(arguments[I])).join(""));
-// // }
-// // alert(X.join(" "));
-// // }
-
-// // function xmsg(A) {
-// // var B = parse(A);
-// // var X = flatten(unparse(B)).join("");
-// // mk(w("test"), "pre", {}, {}, "'" + A + "' => " + X);
-// // }