wl

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

commit 4b48fcb455bd30954d9e801d78ec2058fb31d4e3
parent 60da3e04316b17c98586378ad483100d3712c6f5
Author: tomas <tomas@logand.com>
Date:   Sat, 12 Sep 2009 11:45:35 +0200

working tokenizer, reader, printer

Diffstat:
Mindex.org | 11+++++++++--
Mwl.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) (&quot;hallo second page^M^Jsecond line&quot; 35 24 NIL 65 154 205 50 NIL NIL) (&quot;hello^M^Jtomas&quot; 340 260 NIL NIL NIL NIL NIL NIL NIL)"); -}