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