wl

Unnamed repository; edit this file 'description' to name the repository.
git clone https://logand.com/git/wl.git/
Log | Files | Refs | LICENSE

commit b8f1f048daff1b016c995c02056eff5c2ee08885
parent 69640b8ad79b8112d5ace2409934d3e8eba71c43
Author: tomas <tomas@logand.com>
Date:   Tue,  6 Oct 2009 21:08:38 +0200

simplified parser and stream io

Diffstat:
Mwl.java | 428++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 295 insertions(+), 133 deletions(-)

diff --git a/wl.java b/wl.java @@ -1,10 +1,22 @@ // wl.java -- (c) 2009 Tomas Hlavaty -import java.util.Stack; import java.util.HashMap; +import java.io.InputStream; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; class wl { + void dbg(String M) {System.out.println(M);} + void dbg(String M, Any E) {System.out.println(M); print(E);} + void dbg(String M, Any E, Any F) {System.out.println(M); print(E); print(F);} + void err(Object X, String M) { if(X instanceof Any) throw new RuntimeException(M + ": " + str((Any) X)); throw new RuntimeException(M + ": " + X); @@ -43,21 +55,42 @@ class wl { } // reader - 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; + final Any Qte = new Any("quote", NIL, NIL, null); + final Any Dot = new Any(".", NIL, NIL, null); + + class In { + Character c; + InputStream s; + public In(InputStream S) {c = null; s = S;} + } + + final Any In = new Any("*In", null, null, new In(System.in)); + final Any Out = new Any("*Out", null, null, System.out); - void init(String L) {this.L = L; this.N = L.length(); this.I = 0; this.D = 0;} + Character peek() { + In I = (In) In.cxr; + try { + if(null == I.c) I.c = (char) I.s.read(); + } catch(Exception e) {} + return I.c; + } + Character xchar() { + peek(); + In I = (In) In.cxr; + Character Z = I.c; + I.c = null; + return Z; + } boolean charIn(Character C, String L) {return 0 <= L.indexOf(C);} - Character peek() {return this.I < this.N ? this.L.charAt(this.I) : null;} - Character xchar() {return this.I < this.N ? this.L.charAt(this.I++) : null;} + void skip() { - while(this.I < this.N && charIn(this.L.charAt(this.I), " \t\n\r")) - this.I++; + Character Z; + while((Z = peek()) != null && charIn(Z, " \t\n\r")) + xchar(); } void comment() { while('#' == peek()) { @@ -114,102 +147,21 @@ class wl { case '#': comment(); return null; case '"': xchar(); return text(); case '\'': xchar(); return Qte; - case '(': xchar(); this.D++; return Lp; - case ')': xchar(); this.D--; return Rp; + case '(': xchar(); return Lp; + case ')': xchar(); return Rp; default: return symbol(); } } - // parser - Any parseBuild(Stack<Any> Os) { - Any Z = NIL; - Any Dot = null; - while(0 < Os.size()) { - Any X = Os.pop(); - if(Lp == X) return Dot != null ? cons(Dot, cons(Z, NIL)) : Z; - Dot = null; - if(X.isSym() && (".".equals(X.nm))) { - if(Z.isCons() && NIL == Z.cdr) { - Z = Z.car; - Dot = X; - } else err("Bad dotted pair"); - } else if(X == Qte) - Z = cons(cons(this.Sd.get("quote"), Z.car), Z.cdr); - else Z = cons(X, Z); - } - err("Missing mark"); - return NIL; // make compiler happy:-{ - } - public Any parse(String L) { - init(L); - 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()) { - Any X = token(); - if(null != X) { - if(Rp == X) Os.push(parseBuild(Os)); - else Os.push(X); - } - } - Any Z = parseBuild(Os); - if(0 < Os.size()) err(Os, "Incomplete input"); - return Z; - } - - // printer - public String str(Any L) { - StringBuilder A = new StringBuilder(); - 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.isCons()) { - A.append(str(L.car)); - L = L.cdr; - if(NIL != L) A.append(' '); - } - if(NIL != L) { - A.append(". "); - A.append(str(L)); - } - A.append(')'); - } - } else if(L.isStr()) { - A.append('"'); - 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 err(L, "Don't know how to print"); - return A.toString(); - } - - // evaluator HashMap<String, Any> Sd = new HashMap<String, Any>(); Any intern(String Nm) { - if(!this.Sd.containsKey(Nm)) this.Sd.put(Nm, new Any(Nm, NIL, NIL, null)); - return this.Sd.get(Nm); + if(!Sd.containsKey(Nm)) Sd.put(Nm, new Any(Nm, NIL, NIL, null)); + return Sd.get(Nm); } - // 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); @@ -218,7 +170,7 @@ class wl { return Z; } Any eval(Any E) { - System.out.println("eval: " + str(E)); + //dbg("eval", E); Any Z = NIL; if(E.isInt()) Z = E; else if(E.isSym()) Z = E.cdr; @@ -229,19 +181,28 @@ class wl { 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); + } else if(E.isStr()) Z = E; + else err(E, "Don't know how to eval"); + //dbg("eval", E, Z); return Z; } - void fn(String Nm, Fn F) {this.Sd.put(Nm, new Any(Nm, null, null, F));} + void fn(String Nm, Fn F) { + Any Z = Sd.get(Nm); + if(null != Z) Z.cxr = F; + else 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);}}); + Sd.put("quote", Qte); + Sd.put(".", Dot); + Sd.put("*In", In); + Sd.put("*Out", Out); + + fn("run", new Fn() {public Any fn(Any E) {return run(E.cdr.car);}}); + fn("eval", new Fn() {public Any fn(Any E) {return eval(eval(E.cdr.car));}}); 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;}}); @@ -283,6 +244,18 @@ class wl { } 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) { @@ -303,27 +276,240 @@ class wl { return eval(X.car) == eval(X.cdr.car) ? T : NIL; }}); + fn("peek", new Fn() {public Any fn(Any E) { + Character X = peek(); + return null == X ? NIL : mkStr(X.toString()); + }}); + fn("char", new Fn() {public Any fn(Any E) { + Character X = xchar(); + return null == X ? NIL : mkStr(X.toString()); + }}); + fn("skip", new Fn() {public Any fn(Any E) {skip(); return NIL;}}); + fn("read", new Fn() {public Any fn(Any E) {return read();}}); + fn("print", new Fn() {public Any fn(Any E) { + PrintStream S = (PrintStream) Out.cxr; + Any Z = NIL; + int I = 0; + for(Any X = E.cdr; NIL != X; X = X.cdr) { + if(0 < I++) S.print(' '); + Z = eval(X.car); + print(Z); + } + return Z; + }}); + fn("in", new Fn() {public Any fn(Any E) { Any X = E.cdr; - Any N = eval(E.car); - String F; + Any N = eval(X.car); + String F = null; 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"); + In S = null; + try { + S = new In(new FileInputStream(F)); + In I = (In) In.cxr; + In.cxr = S; + Any Z = run(X.cdr); + In.cxr = I; + S.s.close(); + return Z; + } catch(FileNotFoundException e) { + err(E, "File not found"); + } catch(IOException e) { + err(E, "Error closing input"); + } + return NIL; // make the compiler happy:-{ + }}); + fn("out", new Fn() {public Any fn(Any E) { + Any X = E.cdr; + Any N = eval(X.car); + String F = null; + if(N.isStr()) F = (String) N.cxr; + else if(N.isSym()) F = N.nm; + else err(E, "File name expected"); + try { + FileOutputStream B = new FileOutputStream(F); + PrintStream S = new PrintStream(B); + OutputStream O = (OutputStream) Out.cxr; + Out.cxr = S; + Any Z = run(X.cdr); + Out.cxr = O; + S.close(); + return Z; + } catch(FileNotFoundException e) { + err(E, "File not found"); + } + return NIL; // make the compiler happy:-{ + }}); + fn("load", new Fn() {public Any fn(Any E) { + Any Z = NIL; + for(Any X = E.cdr; NIL != X; X = X.cdr) { + Any N = eval(X.car); + String F = null; + if(N.isStr()) F = (String) N.cxr; + else if(N.isSym()) F = N.nm; + else err(E, "File name expected"); + In S = null; + try { + S = new In(new FileInputStream(F)); + In I = (In) In.cxr; + In.cxr = S; + do Z = eval(read()); + while(null != peek()); + In.cxr = I; + S.s.close(); + return Z; + } catch(FileNotFoundException e) { + err(E, "File not found"); + } catch(IOException e) { + err(E, "Error closing input"); + } + } + return Z; + }}); + + fn("def", new Fn() {public Any fn(Any E) { + Any X = E.cdr; + Any N = eval(X.car); + if(!N.isSym()) err(E, "Symbol expected"); + if(!Sd.containsKey(N.nm)) err(E, "Symbol not interned"); + Any V = eval(X.cdr.car); + Sd.get(N.nm).cdr = V; + return N; + }}); + fn("val", new Fn() {public Any fn(Any E) { + Any Z = NIL; + Any X = eval(E.cdr.car); + if(X.isSym()) Z = X.cdr; + else if(X.isStr()) Z = X; + else if(X.isCons()) Z = X.car; + else err(E, "Expected sym|str|cell"); + return Z; + }}); + fn("cons", new Fn() {public Any fn(Any E) { + Any X = E.cdr; + return cons(eval(X.car), eval(X.cdr.car)); + }}); + + fn("gc", new Fn() {public Any fn(Any E) { + Runtime r = Runtime.getRuntime(); + r.gc(); return NIL; }}); - //FileOutputStream fos = new FileOutputStream("test.txt"); - //OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8"); + fn("heap", new Fn() {public Any fn(Any E) { + Runtime R = Runtime.getRuntime(); + long A = R.freeMemory(); + long B = R.totalMemory(); + long C = R.maxMemory(); + long Z = B - A; + if(NIL != E.cdr) { + if(T == eval(E.cdr.car)) Z = A; + else Z = C; + } + return mkInt("" + Z / (1024 * 1024)); + }}); } + void repl() { + PrintStream S = (PrintStream) Out.cxr; + do { + prompt(); + Any Z = eval(read()); + // TODO only on terminal + S.print("-> "); + print(Z); + S.println(); + } while(null != peek()); + } + void prompt() { + // TODO only on terminal + PrintStream S = (PrintStream) Out.cxr; + S.print(": "); + } + Any read() { + // TODO handle \n from user + return read1(); + } + Any read1() { + Any Z = token(); + if(Qte == Z) Z = cons(Qte, read1()); + else if(Lp == Z) Z = readL(); + return Z; + } + Any readL() { + // TODO circular list . + // TODO cons . + Any Z = NIL; + Any X; + while(null != (X = read1()) && Rp != X) + Z = cons(X, Z); + return flip(Z); + } + void print(Any E) { + PrintStream S = (PrintStream) Out.cxr; + if(E.isSym()) S.print(E.nm); + else if(E.isInt()) S.print(E.cxr); + else if(E.isCons()) { + if(Qte == E.car) { + S.print('\''); + print(E.cdr); + } else { + S.print('('); + while(E.isCons()) { + print(E.car); + E = E.cdr; + if(NIL != E) S.print(' '); + } + if(NIL != E) { + S.print(". "); + print(E); + } + S.print(')'); + } + } else if(E.isStr()) { + S.print('"'); + String X = (String) E.cxr; + for(int I = 0; I < X.length(); I++) { + Character C = X.charAt(I); + if('\\' == C) S.print("\\\\"); + else if('"' == C) S.print("\\\""); + else S.print(C); + } + S.print('"'); + } else err(E, "Don't know how to print"); + } + String str(Any E) { + ByteArrayOutputStream B = new ByteArrayOutputStream(); + PrintStream S = new PrintStream(B); + PrintStream O = (PrintStream) Out.cxr; + Out.cxr = S; + print(E); + Out.cxr = O; + try { + String Z = B.toString("UTF-8"); + S.close(); + return Z; + } catch(UnsupportedEncodingException e) { + err(E, "Unsupported encoding"); + } + return null; // make the compiler happy:-{ + } + Any flip(Any E) { + Any Z = NIL; + while(E.isCons()) { + Any X = E; + E = E.cdr; + X.cdr = Z; + Z = X; + } + return Z; + } public static void main(String args[]) { wl X = new wl(); - System.out.println(X.str(X.parse("(- 1 2 3)"))); - System.out.println(X.str(X.run(X.parse("(- 1 2 3)(- 3 5)(/ ")))); + X.repl(); } } @@ -343,29 +529,5 @@ class wl { // } else throw "Function expected"; // } -// //def("apply", ap); - -// def("val", function(E) { -// var Z; -// var X = ev(E.cdr.car); -// if(typeof X == "number") throw "Variable expected"; -// else if(isSym(X)) Z = X.cdr; -// else if(isCons(X)) Z = X.car; -// else Z = X; // string -// return Z; -// }); -// def(".cons", function(E) {return cons(ev(E.cdr.car), ev(E.cdr.cdr.car));}); - -// // TODO def !!!!!!!!!!!!! - -// // OK - -// // 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);}; - -// // function eq(X, Y) { -// // if(X === Y) return T; -// // //if(X == Y) return T; -// // return NIL; -// // }