commit 4b48fcb455bd30954d9e801d78ec2058fb31d4e3
parent 60da3e04316b17c98586378ad483100d3712c6f5
Author: tomas <tomas@logand.com>
Date:   Sat, 12 Sep 2009 11:45:35 +0200
working tokenizer, reader, printer
Diffstat:
| M | index.org |  |  | 11 | +++++++++-- | 
| M | wl.js |  |  | 532 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ | 
2 files changed, 296 insertions(+), 247 deletions(-)
diff --git a/index.org b/index.org
@@ -11,8 +11,12 @@ allow sexp based communication between the client and the server.
 #+include "wl.wl" src text
 #+html: </div>
 
+#+html: <div id="test" style="display:none">
+#+include "test.wl" src text
+#+html: </div>
+
 #+begin_html
-<script type="text/javascript" src="nopdf.js"></script>
+<script type="text/javascript" src="wl.js"></script>
 <style>canvas {width:12em;height:12em;border:1px dashed black}</style>
 <script type="text/javascript" src="wps.js"></script>
 <script>
@@ -26,7 +30,10 @@ function $$(Id) {return $(Id).textContent;}
 </textarea>
 </p>
 <script>
-function sandbox() {(new Wps).parse($$("wps"), "(xsandbox) .setGc", $("sandbox").value);}
+function sandbox() {
+  alert(str((new wlR).parse("one \"hi \\\"George\\\" go\" (12 3 (a . b) . 456) 7.8")));
+  alert(str((new wlR).parse("(. (1 . 2))")));
+}
 </script>
 <button onclick="javascript:sandbox();">Run</button> code from sandbox.
 #+end_html
diff --git a/wl.js b/wl.js
@@ -1,44 +1,299 @@
-// ondoc -- Tomas Hlavaty 28feb2009
-
-/// lisp
-
-var Scl = 1;
-
-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);
-}
+// wl.js -- (c) 2009 Tomas Hlavaty
 
 function Cons(Car, Cdr) {
     this.car = Car;
     this.cdr = Cdr;
-    this._isCons = "b92e7eb4b4a84432696d4892e2c114b3";
+    return this;
 }
+function isCons(X) {return X && X.constructor === Cons;}
+function cons(Car, Cdr) {return new Cons(Car, Cdr);}
 
-function isCons(X) {
-    return X && X._isCons == "b92e7eb4b4a84432696d4892e2c114b3";
+function Sym(Nm, Val, Prop) {
+    this.nm = Nm;
+    this.car = Prop;
+    this.cdr = Val;
+    return this;
+}
+function isSym(X) {return X && X.constructor === Sym;}
+function sym(X) {return X.nm;}
+
+function car(X) {return X.car;}
+function cdr(X) {return X.cdr;}
+
+var NIL = new Sym("NIL");
+NIL.car = NIL;
+NIL.cdr = NIL;
+
+function wlT() { // tokenizer
+    var Me = this;
+    Me.Qte = {};
+    Me.Lp = {};
+    Me.Rp = {};
+    function init(L) {
+        Me.L = L;
+        Me.N = L.length;
+        Me.I = 0;
+        Me.D = 0;
+    }
+    function charIn(C, L) {return 0 <= L.indexOf(C);}
+    function peek() {return Me.I < Me.N && Me.L[Me.I];}
+    function xchar() {return Me.I < Me.N && Me.L[Me.I++];}
+    function skip() {
+        while(Me.I < Me.N && charIn(Me.L[Me.I], " \t\n"))
+            Me.I++;
+    }
+    function comment() {
+        while("#" == peek()) {
+            while(peek() && "\n" != peek())
+                xchar();
+            skip();
+        }
+    }
+    function text() {
+        var L = [];
+        while(peek() != '"') {
+            var C = xchar();
+            if(C == "\\") C = xchar();
+            else if(C == "^") {
+                C = xchar();
+                if(C == "I") C = "\t";
+                else if(C == "J") C = "\n";
+                else if(C == "M") C = "\r";
+                else C = String.fromCharCode(C == "?" ? 127 : C & 0x1f);
+            }
+            L.push(C);
+        }
+        if(xchar() != '"') throw "Unbalanced double quote";
+        if(0 < L.length) return L.join(""); //.replace(/\r\n/g, "\n");
+        return "";
+    }
+    function symbol() {
+        var C = xchar();
+        if(charIn(C, "()# \t\n")) throw "Symbol expected, got " + C;
+        var N = charIn(C, "+-0123456789.");
+        var F = "." == C;
+        var L = [C];
+        while(peek() && !charIn(peek(), "()# \t\n")) {
+            C = xchar();
+            L.push(C);
+            if(N && !charIn(C, "0123456789")) {
+                if(!F && "." == C) F = true;
+                else N = false;
+            }
+        }
+        L = L.join("");
+        if(1 == L.length && charIn(L, "+-.")) N = false;
+        return N ? (F ? parseFloat(L) : parseInt(L, 10)) : new Sym(L);
+    }
+    function token() {
+        skip();
+        switch(peek()) {
+        case false: return undefined;
+        case "#": return comment();
+        case '"': xchar(); return text();
+        case "'": xchar(); return Me.Qte;
+        case "(": xchar(); Me.D++; return Me.Lp;
+        case ")": xchar(); Me.D--; return Me.Rp;
+        default: return symbol();
+        }
+    }
+    wlT.prototype.init = init;
+    wlT.prototype.peek = peek;
+    wlT.prototype.token = token;
+    return this;
 }
 
-function cons(A, D) {
-    return new Cons(A, D);
+function wlR(Sd) { // reader
+    var Me = this;
+    Me.Tk = new wlT;
+    function init(L) {
+        Me.Tk.init(L);
+    }
+    function parse(L) {
+        Me.Tk.init(L);
+        var Os = [Me.Tk.Lp];
+        function build() {
+            var Z = NIL;
+            var Dot;
+            while(0 < Os.length) {
+                var X = Os.pop();
+                if(Me.Tk.Lp === X) return Dot ? cons(Dot, cons(Z, NIL)) : Z;
+                Dot = false;
+                if(isSym(X) && "." == sym(X)) {
+                    if(NIL === cdr(Z)) {
+                        Z = car(Z);
+                        Dot = X;
+                    } else throw "Bad dotted pair";
+                } else Z = cons(X, Z);
+            }
+            throw "Missing mark";
+        }
+        while(Me.Tk.peek()) {
+            var X = Me.Tk.token();
+            if(X) {
+                if(Me.Tk.Rp === X) Os.push(build());
+                else Os.push(X);
+            }
+        }
+        Z = build();        
+        if(0 < Os.length) throw "Incomplete input, left with " + Os;
+        return Z;
+    }
+    wlR.prototype.init = init;
+    wlR.prototype.parse = parse;
+    return this;
 }
 
-function Sym(Nm, Val, Prop) {
-    this._nm = Nm;
-    this._val = Val;
-    this._prop = Prop;
-    this._isSym = "b32e74b4b5a844626967489282c194b0";
+function str(L) { // printer
+    var A = [];
+    if(typeof L == "number") A.push(L);
+    else if(isSym(L)) A.push(sym(L));
+    else if(isCons(L)) {
+        A.push("(");
+        while(isCons(L)) {
+            A.push(str(car(L)));
+            L = cdr(L);
+            if(NIL !== L) A.push(" ");
+        }
+        if(NIL !== L) {
+            A.push(". ");
+            A.push(str(L));
+        }
+        A.push(")");
+    } else {
+        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, "\\\\");
+        A.push('"' + S + '"');
+    }
+    return A.join("");
 }
 
-function isSym(X) {
-    return X && X._isSym == "b32e74b4b5a844626967489282c194b0";
+
+
+
+
+
+
+function wl() {
+    var Sd = {};
+    var Rd = new wlR;
+
+    Sd["car"] = function car(E) {return E.car;};
+    Sd["cdr"] = function cdr(E) {return E.cdr;};
+    Sd["cons"] = function cons(E) {return Rd.cons(E.car, E.cdr);};
+    Sd["reverse"] = function reverse(E) {
+        var Z = NIL;
+        while(!isNil(E)) {
+            Z = cons(E.car, Z);
+            E = E.cdr;
+        }
+        return Z;
+    };
+    Sd["member"] = function member(E) {
+        var F = E.car;
+        var R = E.cdr;
+        while(!isNil(R)) {
+            if(!isNil(eq(F, R.car))) return R;
+            R = R.cdr;
+        }
+        return NIL;
+    };
+    // Sd["caar"] = function caar(E) {return car(car(E));};
+    // Sd["cadr"] = function cadr(E) {return car(cdr(E));};
+    // Sd["cdar"] = function cdar(E) {return cdr(car(E));};
+    // Sd["cddr"] = function cddr(E) {return cdr(cdr(E));};
+    // Sd["caddr"] = function caddr(E) {return car(cdr(cdr(E)));};
+    // Sd["cdddr"] = function cdddr(E) {return cdr(cdr(cdr(E)));};
+    // Sd["cadddr"] = function cadddr(E) {return car(cdr(cdr(cdr(E))));};
+    // Sd["cddddr"] = function cddddr(E) {return cdr(cdr(cdr(cdr(E))));};
+
+    Sd["-"] = function(E) {var X = Os.pop(); Os.push(Os.pop() - X);};
+    Sd["*"] = function(E) {Os.push(Os.pop() * Os.pop());};
+    Sd["/"] = function(E) {var X = Os.pop(); Os.push(Os.pop() / X);};
+    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);};
+
+    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[".math"] = function(E) {return Math;};
+    Sd[".date"] = function(E) {return new Date();}; // TODO split new and Date
+    Sd[".window"] = function(E) {return window;};
+    // 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) {
@@ -57,10 +312,10 @@ function xset(Sym, Val) {
     return Sym._val;
 }
 
-var NIL = mkSym("NIL");
+//var NIL = mkSym("NIL");
 var T = mkSym("T");
 
-xset(NIL, NIL);
+//xset(NIL, NIL);
 xset(T, T);
 // TODO set props for NIL and T
 
@@ -69,58 +324,17 @@ function intern(Sym) {
     return Syms[Sym] || (Syms[Sym] = mkSym(Sym, NIL, NIL));
 }
 
-function isNil(X) {
-    return X === NIL;
-}
 
 function isT(X) {
     return X === T;
 }
 
-function car(L) {return isNil(L) ? NIL : L.car;}
-function cdr(L) {return isNil(L) ? NIL : L.cdr;}
-function caar(L) {return car(car(L));}
-function cadr(L) {return car(cdr(L));}
-function cdar(L) {return cdr(car(L));}
-function cddr(L) {return cdr(cdr(L));}
-function caddr(L) {return car(cdr(cdr(L)));}
-function cdddr(L) {return cdr(cdr(cdr(L)));}
-function cadddr(L) {return car(cdr(cdr(cdr(L))));}
-function cddddr(L) {return cdr(cdr(cdr(cdr(L))));}
-
-function array2list(A) {
-    var L = NIL;
-    for(var I = A.length - 1; 0 <= I; I--) {
-        L = cons(A[I], L);
-    }
-    return L;
-}
 
-function list2array(L) {
-    var A = [];
-    while(!isNil(L)) {
-        A.push(L.car);
-        L = L.cdr;
-    }
-    return A;
-}
 
-function object2list(A) {
-    var L = NIL;
-    for(var I in A) {
-        L = cons(cons(I, A[I]), L);
-    }
-    return L;
-}
 
-function reverse(L) {
-    var X = NIL;
-    while(!isNil(L)) {
-        X = cons(L.car, X);
-        L = L.cdr;
-    }
-    return X;
-}
+
+
+
 
 function eq(X, Y) {
     if(X === Y) return T;
@@ -137,14 +351,6 @@ function xdelete(A, L) {
     return reverse(X);
 }
 
-function member(A, L) {
-    while(!isNil(L)) {
-        if(!isNil(eq(A, L.car))) return L;
-        L = L.cdr;
-    }
-    return NIL;
-}
-
 function lsApply(Fn, Args) {
 }
 
@@ -207,144 +413,6 @@ function initLisp() {
 
 // parser
 
-function isWhite(C) {
-    return isNil(C) ? false : 0 <= " \t\n\r".indexOf(C);
-}
-
-function parse(S) { // TODO cons . notation
-    var L = S.split("");
-    function peek() {
-        return 0 < L.length ? L[0] : NIL;
-    }
-    function xchar() {
-        return 0 < L.length ? L.shift() : NIL;
-    }
-    function skip() {
-        while(isWhite(peek())) xchar();
-    }
-    function many() {
-        var X;
-        while(!isNil(peek()) && peek() != ")") {
-            var O = one();
-            if(O || typeof O == "number") X = cons(O, X ? X : NIL);
-        }
-        if(X) X = reverse(X);
-        return X;
-    }
-    function tok() {
-        var Tok = [];
-        var N = true;
-        var F = false;
-        var S;
-        if(peek() == "+" || peek() == "-") S = xchar();
-        while(!isNil(peek()) && peek() != ")" && !isWhite(peek())) {
-            var C = xchar();
-            if(N && C == ".") break;
-            if(!(0 <= "0123456789".indexOf(C))) N = false;
-            Tok.push(C);
-        }
-        if(N && C == ".") {
-            var Tok2 = [];
-            while(!isNil(peek()) && peek() != ")" && !isWhite(peek())) {
-                var C = xchar();
-                if(!(0 <= "0123456789".indexOf(C))) N = false;
-                Tok2.push(C);
-            }
-            if(isNil(Scl || NIL)) {
-                Tok2.unshift(".");
-                Tok = Tok.concat(Tok2);
-                if(N) F = true;
-            } else {
-                if(N) {
-                    if(Tok.length == 0 && Tok2.length == 0) Tok = ["."];
-                    else for(var I = 0; I < Scl; I++)
-                             Tok.push(Tok2.shift() || "0");
-                } else {
-                    Tok2.unshift(".");
-                    Tok = Tok.concat(Tok2);
-                }
-            }
-        }
-        if(0 < Tok.length) {
-            var X = Tok.join("");
-            if(X == ".") return X;
-            if(N) {
-                X = F ? parseFloat(X) : parseInt(X);
-                if(S == "-") X = -X;
-            } else X = intern(S ? S + X : X);
-            return X;
-        }
-    }
-    function str() {
-        var Tok = [];
-        while(peek() != '"') {
-            var C = xchar();
-            if(C == "\\") C = xchar();
-            else if(C == "^") {
-                C = xchar();
-                if(C == "I") C = "\t";
-                else if(C == "J") C = "\n";
-                else if(C == "M") C = "\r";
-                else C = String.fromCharCode(C == "?" ? 127 : C & 0x1f);
-            }
-            Tok.push(C);
-        }
-        if(xchar() != '"') throw "Unbalanced double quote";
-        if(0 < Tok.length) return Tok.join(""); //.replace(/\r\n/g, "\n");
-    }
-    function one() {
-        skip();
-        var X;
-        var C = peek();
-        if(!isNil(C) && C != ")") {
-            if(C == "(") {
-                xchar();
-                X = many() || NIL;
-                if(xchar() != ")") throw "Unbalanced parenthesis";
-            } else if(C == '"') {
-                xchar();
-                X = str();
-            } else X = tok();
-        }
-        return X;
-    }
-    var X = many();
-    if(0 < L.length) throw "Parsing not completed";
-    return X ? X : NIL;
-}
-
-function unparse(X) {
-    var A = [];
-    if(isSym(X)) {
-        A.push(X._nm);
-    } else if(isCons(X)) {
-        A.push("(");
-        while(isCons(X)) {
-            A.push(unparse(X.car));
-            X = X.cdr;
-            if(!isNil(X)) A.push(" ");
-        }
-        if(!isNil(X)) {
-            A.push(". ");
-            A.push(unparse(X));
-        }
-        A.push(")");
-    } else {
-        if(typeof X == "number") A.push(X);
-        else {
-            var Y = X.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 = X.replace(/\"/g, "\\\"").replace(/\\/g, "\\\\");
-            A.push("\"" + S + "\"");
-        }
-    }
-    return A;
-}
-
 function isArray(A) {
     return A && A.constructor == Array;
 }
@@ -382,29 +450,3 @@ function xmsg(A) {
     var X = flatten(unparse(B)).join("");
     mk(w("test"), "pre", {}, {}, "'" + A + "' => " + X);
 }
-
-function initLisp() {
-    xmsg("");
-    xmsg("  ");
-    xmsg("1");
-    xmsg("1 \"string\" a 2.3");
-    xmsg("NIL");
-    xmsg("T");
-    xmsg("()");
-    xmsg("1 ()");
-    xmsg("1 () (())");
-    xmsg("1 ( ) (( )) ((( ))) (( )) ( ) 2");
-    xmsg("(-213cons 1 NIL)");
-    xmsg("(cons 1 NIL) 2 (-3 b c ) \"st\\\"r^Ii\\\"ng^M^J2\" () 4.5678 9");
-    xmsg("(cons T T)");
-    xmsg("(list)");
-    xmsg("(list 1 -2 -3.4 5 6.7 9. .23 -0 -0.0)");
-    xmsg("1 (NIL (T 2 3.5 ) if)");
-    xmsg("1 (NIL (T 2 . 3.5) if)");
-    xmsg("1 (NIL . (T 2 . 3.5 6) if)");
-    xmsg("1 (NIL (T 2 (. 3.5 . 6)) if)");
-    //xalert(xeval(NIL), xeval(T), xeval(12), xeval(12.3), xeval({x: "hi"}));
-    //xalert(xeval(cons(intern("if"), NIL)));
-    //xalert(cons(NIL, "if"));
-    xmsg("(595 842) (20 12 0 0 0 NIL NIL) (NIL NIL NIL NIL NIL NIL NIL) ("hallo second page^M^Jsecond line" 35 24 NIL 65 154 205 50 NIL NIL) ("hello^M^Jtomas" 340 260 NIL NIL NIL NIL NIL NIL NIL)");
-}