wl

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

wl.js (12115B)


      1 // wl.js -- (c) 2009 Tomas Hlavaty
      2 
      3 function wl() {
      4     var Me = this;
      5 
      6     function Cons(Car, Cdr) {
      7         this.car = Car;
      8         this.cdr = Cdr;
      9         return this;
     10     }
     11     function isCons(X) {return X && X.constructor === Cons;}
     12     function cons(Car, Cdr) {return new Cons(Car, Cdr);}
     13 
     14     function Sym(Nm, Val, Prop) {
     15         this.nm = Nm;
     16         this.car = Prop;
     17         this.cdr = Val;
     18         return this;
     19     }
     20     function isSym(X) {return X && X.constructor === Sym;}
     21     function sym(X) {return X.nm;}
     22 
     23     function car(X) {return X.car;}
     24     function cdr(X) {return X.cdr;}
     25 
     26     var NIL = new Sym("NIL");
     27     NIL.car = NIL;
     28     NIL.cdr = NIL;
     29 
     30     var Qte = {};
     31     var Lp = {};
     32     var Rp = {};
     33 
     34     // reader
     35     function init(L) {
     36         Me.L = L;
     37         Me.N = L.length;
     38         Me.I = 0;
     39         Me.D = 0;
     40     }
     41     function charIn(C, L) {return 0 <= L.indexOf(C);}
     42     function peek() {return Me.I < Me.N && Me.L[Me.I];}
     43     function xchar() {return Me.I < Me.N && Me.L[Me.I++];}
     44     function skip() {
     45         while(Me.I < Me.N && charIn(Me.L[Me.I], " \t\n"))
     46             Me.I++;
     47     }
     48     function comment() {
     49         while("#" == peek()) {
     50             while(peek() && "\n" != peek())
     51                 xchar();
     52             skip();
     53         }
     54     }
     55     function text() {
     56         var L = [];
     57         while(peek() != '"') {
     58             var C = xchar();
     59             if(C == "\\") C = xchar();
     60             else if(C == "^") {
     61                 C = xchar();
     62                 if(C == "I") C = "\t";
     63                 else if(C == "J") C = "\n";
     64                 else if(C == "M") C = "\r";
     65                 else C = String.fromCharCode(C == "?" ? 127 : C & 0x1f);
     66             }
     67             L.push(C);
     68         }
     69         if(xchar() != '"') throw "Unbalanced double quote";
     70         if(0 < L.length) return L.join(""); //.replace(/\r\n/g, "\n");
     71         return "";
     72     }
     73     function symbol() {
     74         var C = xchar();
     75         if(charIn(C, "()# \t\n")) throw "Symbol expected, got " + C;
     76         var N = charIn(C, "+-0123456789.");
     77         var F = "." == C;
     78         var L = [C];
     79         while(peek() && !charIn(peek(), "()# \t\n")) {
     80             C = xchar();
     81             L.push(C);
     82             if(N && !charIn(C, "0123456789")) {
     83                 if(!F && "." == C) F = true;
     84                 else N = false;
     85             }
     86         }
     87         L = L.join("");
     88         if(1 == L.length && charIn(L, "+-.")) N = false;
     89         return N ? (F ? parseFloat(L) : parseInt(L, 10)) : new Sym(L);
     90     }
     91     function token() {
     92         skip();
     93         switch(peek()) {
     94         case false: return undefined;
     95         case "#": return comment();
     96         case '"': xchar(); return text();
     97         case "'": xchar(); return Qte;
     98         case "(": xchar(); Me.D++; return Lp;
     99         case ")": xchar(); Me.D--; return Rp;
    100         default: return symbol();
    101         }
    102     }
    103 
    104     // parser
    105     function parse(L) {
    106         init(L);
    107         var Os = [Lp];
    108         function build() {
    109             var Z = NIL;
    110             var Dot;
    111             while(0 < Os.length) {
    112                 var X = Os.pop();
    113                 if(Lp === X) return Dot ? cons(Dot, cons(Z, NIL)) : Z;
    114                 Dot = false;
    115                 if(isSym(X) && "." == sym(X)) {
    116                     if(NIL === cdr(Z)) {
    117                         Z = car(Z);
    118                         Dot = X;
    119                     } else throw "Bad dotted pair";
    120                 } else Z = cons(X, Z);
    121             }
    122             throw "Missing mark";
    123         }
    124         while(peek()) {
    125             var X = token();
    126             if(X) {
    127                 if(Rp === X) Os.push(build());
    128                 else Os.push(X);
    129             }
    130         }
    131         Z = build();        
    132         if(0 < Os.length) throw "Incomplete input, left with " + Os;
    133         return Z;
    134     }
    135 
    136     // printer
    137     function str(L) {
    138         var A = [];
    139         if(typeof L == "number") A.push(L);
    140         else if(isSym(L)) A.push(sym(L));
    141         else if(isCons(L)) {
    142             A.push("(");
    143             while(isCons(L)) {
    144                 A.push(str(car(L)));
    145                 L = cdr(L);
    146                 if(NIL !== L) A.push(" ");
    147             }
    148             if(NIL !== L) {
    149                 A.push(". ");
    150                 A.push(str(L));
    151             }
    152             A.push(")");
    153         } else {
    154             var Y = L.split("");
    155             for(var I = 0; I < Y.length; I++) {
    156                 if(Y[I] == "\\") Y[I] = "\\\\";
    157                 else if(Y[I] == '"') Y[I] = '\\"';
    158             }
    159             var S = Y.join("");
    160             //var S = L.replace(/\"/g, "\\\"").replace(/\\/g, "\\\\");
    161             A.push('"' + S + '"');
    162         }
    163         return A.join("");
    164     }
    165 
    166     wl.prototype.parse = parse;
    167     wl.prototype.str = str;
    168     return this;
    169 }
    170 
    171 
    172 
    173 
    174 
    175 
    176 // function wl() {
    177 //     var Sd = {};
    178 //     var Rd = new wlR;
    179 
    180 //     Sd["car"] = function car(E) {return E.car;};
    181 //     Sd["cdr"] = function cdr(E) {return E.cdr;};
    182 //     Sd["cons"] = function cons(E) {return Rd.cons(E.car, E.cdr);};
    183 //     Sd["reverse"] = function reverse(E) {
    184 //         var Z = NIL;
    185 //         while(!isNil(E)) {
    186 //             Z = cons(E.car, Z);
    187 //             E = E.cdr;
    188 //         }
    189 //         return Z;
    190 //     };
    191 //     Sd["member"] = function member(E) {
    192 //         var F = E.car;
    193 //         var R = E.cdr;
    194 //         while(!isNil(R)) {
    195 //             if(!isNil(eq(F, R.car))) return R;
    196 //             R = R.cdr;
    197 //         }
    198 //         return NIL;
    199 //     };
    200 //     // Sd["caar"] = function caar(E) {return car(car(E));};
    201 //     // Sd["cadr"] = function cadr(E) {return car(cdr(E));};
    202 //     // Sd["cdar"] = function cdar(E) {return cdr(car(E));};
    203 //     // Sd["cddr"] = function cddr(E) {return cdr(cdr(E));};
    204 //     // Sd["caddr"] = function caddr(E) {return car(cdr(cdr(E)));};
    205 //     // Sd["cdddr"] = function cdddr(E) {return cdr(cdr(cdr(E)));};
    206 //     // Sd["cadddr"] = function cadddr(E) {return car(cdr(cdr(cdr(E))));};
    207 //     // Sd["cddddr"] = function cddddr(E) {return cdr(cdr(cdr(cdr(E))));};
    208 
    209 //     Sd["-"] = function(E) {var X = Os.pop(); Os.push(Os.pop() - X);};
    210 //     Sd["*"] = function(E) {Os.push(Os.pop() * Os.pop());};
    211 //     Sd["/"] = function(E) {var X = Os.pop(); Os.push(Os.pop() / X);};
    212 //     Sd["%"] = function(E) {var X = Os.pop(); Os.push(Os.pop() % X);};
    213 
    214 //     Sd["eq"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X == Y);};
    215 //     Sd["lt"] = function() {var Y = Os.pop(); var X = Os.pop(); Os.push(X < Y);};
    216 
    217 //     Sd["if"] = function() {
    218 //         var N = Os.pop();
    219 //         var P = Os.pop();
    220 //         var C = Os.pop();
    221 //         Es.push([false, C === true ? P : N]);
    222 //     };
    223 
    224 //     // Sd[".call"] = function() {
    225 //     //     var N = Os.pop();
    226 //     //     var K = Os.pop();
    227 //     //     var D = Os.pop();
    228 //     //     var X = [];
    229 //     //     for(var I = 0; I < N; I++) X.unshift(Os.pop());
    230 //     //     Os.push(D[K].apply(D, X));
    231 //     // };
    232 //     Sd[".math"] = function(E) {return Math;};
    233 //     Sd[".date"] = function(E) {return new Date();}; // TODO split new and Date
    234 //     Sd[".window"] = function(E) {return window;};
    235 //     // Sd[".callback"] = function() { // TODO event arg?
    236 //     //     var X = Os.pop();
    237 //     //     Os.push(function() {
    238 //     //                 Ps.run(X, true);
    239 //     //                 while(0 < Es.length)
    240 //     //                     Ps.step();
    241 //     //             });
    242 //     // };
    243 
    244 
    245 //     Sd["list2array"] = function list2array(E) {
    246 //         var Z = [];
    247 //         while(!isNil(E)) {
    248 //             Z.push(E.car);
    249 //             E = E.cdr;
    250 //         }
    251 //         return Z;
    252 //     };
    253 //     // Sd["array2list"] = function array2list(A) {
    254 //     //     var Z = NIL;
    255 //     //     for(var I = A.length - 1; 0 <= I; I--)
    256 //     //         Z = cons(A[I], Z);
    257 //     //     return Z;
    258 //     // };
    259 //     // Sd["object2list"] = function object2list(O) {
    260 //     //     var Z = NIL;
    261 //     //     for(var I in O)
    262 //     //         Z = cons(cons(I, O[I]), Z);
    263 //     //     return Z;
    264 //     // };
    265 
    266 //     function parse() {
    267 //         var Z;
    268 //         var A = arguments;
    269 //         if(A.length)
    270 //             for(var I = 0; I < A.length; I++)
    271 //                 Z = Rd.parse(A[I]);
    272 //         else Z = Rd.parse(A);
    273 //         return Z;
    274 //     }
    275 //     wl.prototype.parse = parse;
    276 //     return this;
    277 // }
    278 
    279 // /// lisp
    280 
    281 // // function format(N, S) {
    282 // //     var X = "" + N;
    283 // //     var L = X.length;
    284 // //     return X.slice(0, L - S) + "." + X.slice(L - S, L);
    285 // // }
    286 
    287 // // function real(N, S) {
    288 // //     return N / Math.pow(10, S);
    289 // // }
    290 
    291 // var Syms = {};
    292 
    293 // function mkSym(Nm, Val, Prop) {
    294 //     var X = new Sym(Nm, Val, Prop);
    295 //     Syms[Nm] = X;
    296 //     return X;
    297 // }
    298 
    299 // function xget(Sym) {
    300 //     return isSym(Sym) ? Sym._val : Sym;
    301 // }
    302 
    303 // function xset(Sym, Val) {
    304 //     if(!isSym(Sym)) throw "Sym expected";
    305 //     Sym._val = Val;
    306 //     return Sym._val;
    307 // }
    308 
    309 // //var NIL = mkSym("NIL");
    310 // var T = mkSym("T");
    311 
    312 // //xset(NIL, NIL);
    313 // xset(T, T);
    314 // // TODO set props for NIL and T
    315 
    316 // function intern(Sym) {
    317 //     //if(!(Sym in Syms)) Syms[Sym] = mkSym(Sym, NIL, NIL);
    318 //     return Syms[Sym] || (Syms[Sym] = mkSym(Sym, NIL, NIL));
    319 // }
    320 
    321 
    322 // function isT(X) {
    323 //     return X === T;
    324 // }
    325 
    326 
    327 
    328 
    329 
    330 
    331 
    332 
    333 // function eq(X, Y) {
    334 //     if(X === Y) return T;
    335 //     //if(X == Y) return T;
    336 //     return NIL;
    337 // }
    338 
    339 // function xdelete(A, L) {
    340 //     var X = NIL;
    341 //     while(!isNil(L)) {
    342 //         if(isNil(eq(A, L.car))) X = cons(L.car, X);
    343 //         L = L.cdr;
    344 //     }
    345 //     return reverse(X);
    346 // }
    347 
    348 // function lsApply(Fn, Args) {
    349 // }
    350 
    351 // function jsFn(Fn) {
    352 //     var F = function() {
    353 //         return lsApply(Fn, list2array(arguments));
    354 //     };
    355 //     return F;
    356 // }
    357 
    358 // function jsApply() {
    359 //     var Fn = arguments.shift();
    360 //     var Args = arguments.shift();
    361 //     var Rest = arguments;
    362 //     return Fn.apply(list2array(Args).unshift.apply(list2array(Rest)));
    363 // }
    364 
    365 // var Xeval = {};
    366 
    367 // function xdef(Nm, Fn) {
    368 //     if(!(Nm in Syms)) intern(Nm);
    369 //     Xeval[Nm] = Fn;
    370 // }
    371 
    372 // xdef("quote", function(E) {
    373 //         return cdr(E); // or cdr?
    374 //     });
    375 // xdef("if", function(E) {
    376 //         if(!isNil(xeval(cadr(E)))) return xeval(caddr(E));
    377 //         else return xeval(cadddr(E));
    378 //     });
    379 // xdef("prog", function(E) {
    380 //         var L = cdr(E);
    381 //         var X = NIL;
    382 //         while(!isNil(L)) {
    383 //             X = xeval(L.car);
    384 //             L = L.cdr;
    385 //         }
    386 //         return X;
    387 //     });
    388 
    389 // function xeval(E) {
    390 //     if(isSym(E)) return xget(E);
    391 //     else if(!isCons(E)) return E;
    392 //     else if(car(E)._nm in Xeval) return Xeval[car(E)._nm](E);
    393 //     else return xapply(xeval(car(E)), map(xeval, cdr(E)));
    394 // }
    395 
    396 // function initLisp() {
    397 //     //xalert(xeval(NIL), xeval(T), xeval(12), xeval(12.3), xeval({x: "hi"}), xeval([1, 2]));
    398 //     //xalert(xeval(cons(intern("quote"), cons("whoa", NIL))));
    399 //     //xalert(xeval(cons(intern("quote"), cons("whoa", cons("b", NIL)))));
    400 //     //xalert(intern("if"));
    401 //     //xalert(object2list(Syms));
    402 //     //xalert(object2list(Xeval));
    403 //     //xalert(xeval(cons(intern("if"), cons(T, cons("yes", cons("no", NIL))))));
    404 //     //xalert(xeval(cons(intern("if"), cons(NIL, cons("yes", cons("no", NIL))))));
    405 //     //xalert(xeval(cons(intern("quote"), intern("whoa"))));
    406 // }
    407 
    408 // // parser
    409 
    410 // function isArray(A) {
    411 //     return A && A.constructor == Array;
    412 // }
    413 
    414 // function flatten(A) {
    415 //     var X = [];
    416 //     function rec(B) {
    417 //         var N = B.length;
    418 //         var I;
    419 //         for(I = 0; I < N; I++) {
    420 //             if(isArray(B[I])) rec(B[I]);
    421 //             else X.push(B[I]);
    422 //         }
    423 //     }
    424 //     rec(A);
    425 //     return X;
    426 // }
    427 
    428 // function lisp2string(Any) {
    429 //     return flatten(unparse(Any)).join("");
    430 // }
    431 
    432 // function xalert() {
    433 //     var X = [];
    434 //     var N = arguments.length;
    435 //     var I;
    436 //     for(I = 0; I < N; I++) {
    437 //         X.push(flatten(unparse(arguments[I])).join(""));
    438 //     }
    439 //     alert(X.join(" "));
    440 // }
    441 
    442 // function xmsg(A) {
    443 //     var B = parse(A);
    444 //     var X = flatten(unparse(B)).join("");
    445 //     mk(w("test"), "pre", {}, {}, "'" + A + "' => " + X);
    446 // }