diff --git a/ok/LICENSE.txt b/ok/LICENSE.txt new file mode 100644 index 0000000..ca0c380 --- /dev/null +++ b/ok/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015, John Earnest + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/ok/appendoK.js b/ok/appendoK.js new file mode 100644 index 0000000..2553fb1 --- /dev/null +++ b/ok/appendoK.js @@ -0,0 +1,56 @@ +// stolen from iKe +var katan2 = function(x, y) { return k(0, Math.atan2(n(x).v, n(y).v)); } +var kpow = function(x, y) { return k(0, Math.pow (n(x).v, n(y).v)); } +verbs["atan2"] = [null, null, ad(katan2), ad(katan2), ad(katan2), ad(katan2), null, null]; +verbs["pow" ] = [null, null, ad(kpow) , ad(kpow) , ad(kpow) , ad(kpow) , null, null]; +// stolen from convert.js +function trampoline(env, name, args, body) { + // construct a function-wrapper trampoline for a pseudonative. + // this permits dyadic/triadic extension functions to be properly curryable. + var arguse = []; for(var z=0; z k + "dictionary", // 4 : values, k(keys) + "function" , // 5 : body, args, curry, env + "view" , // 6 : value, r, cache, depends->val + "nameref" , // 7 : name, l(index?), r(assignment), global? + "verb" , // 8 : name, l(?), r, curry? + "adverb" , // 9 : name, l(?), verb, r + "return" , // 10 : return (deprecated) + "nil" , // 11 : + "cond" , // 12 : body (list of expressions) + "quote" , // 13 : value (for quoting verbs/etc as a value) +]; + +var NIL = ks(""); +var k0 = k(0, 0); +var k1 = k(0, 1); +var EC = [["\\","\\\\"],["\"","\\\""],["\n","\\n"],["\t","\\t"]]; +var kt = [-9, -10, -11, 0, 99, 102, NaN, NaN, 107, 105, NaN, NaN, NaN]; +var SP = k(1, " ".charCodeAt(0)); +var NA = k(0, NaN); + +function k (t, v) { return { 't':t, 'v':v }; } +function md (x, y) { return { t:4, k:sl(x,y), v:y }; } +function ks (x) { return k(2, x); } +function asVerb(x, y, z) { return { t:8, v:x, l:y, r:z }; } +function kl (x) { return x.length==1 ? x[0] : k(3,x); } +function kf (x) { return match(k(3,[]), x).v || match(k0, x).v; } +function kb (x) { return x ? k1 : k0; } +function s (x) { return x.t == 3 && x.v.every(function(c) { return c.t == 1; }); } +function kmod (x, y) { return x-y*Math.floor(x/y); } +function len (x) { return l(x).v.length; } +function krange(x, f) { var r=[]; for(var z=0;z=len(x)) { throw new Error("length error."); } return x.v[y]; } +function dget (x, y) { var i=find(x.k, y); return (i.v==len(x.k)) ? NA : atx(x.v, i); } +function lset (x, y, z) { if (len(x) <= p(y)) { throw new Error("index error."); } x.v[y.v]=z; } +function dset (x, y, z) { var i=find(x.k, y).v; if(i==len(x.k)) { x.k.v.push(y); } x.v.v[i]=z; } +function lower (x) { return k(1, String.fromCharCode(x.v).toLowerCase().charCodeAt(0)); } +function kmap (x, f) { return k(3, l(x).v.map(f)); } +function kzip (x, y, f) { return kmap(sl(x,y), function(z, i) { return f(z, y.v[i]); }); } +function sl (x, y) { if (len(x) != len(y)) { throw new Error("length error."); } return x; } +function n (x) { return (x.t==0||x.t==1) ? x : ct(x, 0); } +function l (x) { return ct(x, 3); } +function d (x) { return ct(x, 4); } +function a (x) { if (x.t > 2) { throw new Error("domain error."); } return x; } +function na (x) { return x.t === 0 && isNaN(x.v); } + +function stok(x) { return kl(krange(x.length, function(z) { return k(1,x.charCodeAt(z)); }).v); } +function c(x) { return (x.t==3) ? k(x.t, x.v.slice(0)) : (x.t==4) ? md(c(x.k), c(x.v)) : x; } +function ct(n,t) { if (n.t!=t) throw new Error(TN[t]+" expected, found "+TN[n.t]+"."); return n; } +function p(x) { if (n(x).v<0||x.v%1!=0) { throw new Error("positive int expected."); } return x.v; } +function ktos(x, esc) { + if (x.t != 3) { x = enlist(x); } + var h = x.v.some(function(v){ return (v.v<32||v.v>127)&v.v!=9&v.v!=10; }); + if (h) { return "0x"+x.v.map(h2).join(""); } + var r = x.v.map(function(k) { return String.fromCharCode(k.v); }).join(""); + return esc ? '"'+EC.reduce(function(r,p) { return r.split(p[0]).join(p[1]); }, r)+'"' : r; +} + +//////////////////////////////////// +// +// Primitive Verbs +// +//////////////////////////////////// + +function plus (x, y) { return k(0, n(x).v + n(y).v); } +function minus (x, y) { return k(0, n(x).v - n(y).v); } +function times (x, y) { return k(0, n(x).v * n(y).v); } +function divide(x, y) { return k(0, n(x).v / n(y).v); } +function mod (x, y) { return k(0, n(x).v>0 ? kmod(n(y).v, x.v) : Math.floor(n(y).v / -x.v)); } +function max (x, y) { return na(x)?y:na(y)?x:k(0, Math.max(n(x).v, n(y).v)); } +function min (x, y) { return k(0, Math.min(n(x).v, n(y).v)); } +function less (x, y) { return kb(a(x).v < a(y).v); } +function more (x, y) { return kb(a(x).v > a(y).v); } +function equal (x, y) { return kb((x.v == y.v) || (na(x) && na(y))); } +function join (x, y) { return l(y).v.reduce(function(z, y) { return cat(z, cat(x, y)); }); } +function ident (x) { return x; } +function negate (x) { return k(0, -n(x).v); } +function first (x) { return (x.t == 4) ? first(x.v) : (x.t != 3) ? x : len(x) ? x.v[0]:k(3,[]); } +function sqrt (x) { return k(0, Math.sqrt(n(x).v)); } +function keys (x) { return c(d(x).k); } +function rev (x) { return x.t==4?md(rev(x.k),rev(x.v)):x.t==3?k(3,c(l(x)).v.reverse()):x; } +function asc (x) { return grade(-1, x); } +function desc (x) { return grade(1, x); } +function not (x) { return equal(n(x), k0); } +function enlist (x) { return k(3, [x]); } +function isnull (x) { return max(match(x, NIL),match(x,k(11))); } +function count (x) { return k(0, x.t == 4 ? len(x.v) : x.t == 3 ? len(x) : 1); } +function floor (x) { return x.t == 1 ? lower(x) : k(0, Math.floor(n(x).v)); } +function type (x) { return k(0, kt[x.t]); } +function kfmt (x) { var r=stok(format(x, 0, 1)); return r.t == 3 ? r : enlist(r); } +function real (x) { return krange(n(x).v, function() { return k(0, Math.random()); }); } + +function iota(x) { + if (x.t == 4) { return keys(x); } + var i = krange(Math.abs(n(x).v), k.bind(null, 0)); return x.v>=0 ? i : ar(plus)(x, i); +} + +function cat(x, y) { + if (x.t==4&&y.t==4) { x=c(x); kmap(y.k, function(v) { dset(x,v,dget(y,v)); }); return x; }; + return k(3, (x.t==3?x.v:[x]).concat(y.t==3?y.v:[y])); +} + +function keval(x, env) { + if (x.t == 5) { return x.env.d; } + return x.t == 4 ? c(x.v) : x.t == 2 ? env.lookup(x, true) : run(parse(ktos(x)), env); +} + +function dfmt(x, y) { + if ( x.t == 3 && y.t == 3) { return kzip(x, y, dfmt); } + if ( x.t == 3 && y.t != 3) { return kmap(x, function(z) { return dfmt(z, y); }); } + if ((x.t == 2 || !s(y)) && y.t == 3) { return kmap(y, function(z) { return dfmt(x, z); }); } + if (x.t == 2) { return {b: k(0,y.v&1), i: k(0,y.v|0), f: k(0,y.v), c: k(1,y.v)}[x.v]; } + if (y.t == 1) { return y; } var r=c(y); var d=Math.abs(x.v); + while(len(r) < d) { x.v>0 ? r.v.push(SP) : r.v.unshift(SP); } + while(len(r) > d) { x.v>0 ? r.v.pop() : r.v.shift(); } + return r; +} + +function except(x, y) { + y = y.t == 3 ? y : enlist(y); + return k(3, (x.t == 3 ? x : iota(x)).v.filter(function(z) { return na(pfind(y, z)); })); +} + +function ddrop(x, y) { var k = except(d(y).k, x); return md(k, atx(y, k)); } +function drop(x, y) { + if (y.t == 4) { return md(drop(x, y.k), drop(x, y.v)); } + return (y.t != 3 || len(y) < 1) ? y : k(3, n(x).v<0 ? y.v.slice(0,x.v) : y.v.slice(x.v)); +} + +function take(x, y, env) { + if (x.t == 5 || x.t == 8 || x.t == 9) { + var k = where(each(x, y, env), env); var v = atx(y, k); + return y.t == 4 ? md(k, v) : v; + } + if (y.t == 4) { return md(take(x, y.k, env), take(x, y.v, env)); } + if (y.t != 3 || len(y) == 0) { y = enlist(y); } + var s=n(x).v<0?kmod(x.v, len(y)):0; + return krange(Math.abs(x.v), function(x) { return y.v[kmod(x+s, len(y))]; }); +} + +function reshape(x, y) { + if (y.t == 4) { return md(x, atx(y, x)); } + if (y.t != 3) { y = enlist(y); } + var a = first(x); var b = x.v[len(x)-1]; var c = 0; + function rshr(x, y, i) { + return krange(x.v[i].v, function(z) { + return i==len(x)-1 ? y.v[kmod(c++, len(y))] : rshr(x, y, i+1); + }); + } + return na(a) ? (!len(y) ? y : cut(krange(len(y)/b.v, function(z) { return k(0, z*b.v); }), y)) : + na(b) ? cut(krange(a.v, function(z) { return k(0, Math.floor(z*len(y)/a.v)); }), y) : + rshr(l(x), len(y) ? y : enlist(y), 0); +} + +function match(x, y) { + if (x.t != y.t) { return k0; } + if (x.t == 4) { return min(match(x.k, y.k), match(x.v, y.v)); } + if (x.t != 3) { return equal(x, y); } + if (len(x) != len(y)) { return k0; } + return kb(x.v.every(function(x,i) { return match(x, y.v[i]).v; })); +} + +function find(x, y) { y=x.v.findIndex(function(z){return match(z,y).v}); return k(0,y>=0?y:len(x)) } +function pfind(x, y) { y=x.v.findIndex(function(z){return equal(z,y).v}); return y>=0?k(0,y):NA } +function pisnull(x) { return kb(match(x, NIL).v || match(x, k(11)).v || na(x)); } + +function cut(x, y) { + return kzip(x, cat(drop(k1,x),count(y)), function(a, b) { // {x{x@y+!z-y}[y]'1_x,#y} ? + var r=[]; for(var z=p(a);zy.v) throw new Error("length error.");return take(x,asc(real(y)),env); } + return kmap(iota(x), function(x){ return k(0,Math.floor(Math.random()*y.v)); }); +} + +function flip(x, env) { + x=eachright(k(8,"#"), over(k(8,"|"), each(k(8,"#"), x, env), env), x, env); + return krange(len(first(x)), function(z){ + return krange(len(x), function(t){ return x.v[t].v[z]; }); + }); +} + +function grade(dir, x) { + return x.t == 4 ? atx(x.k, grade(dir, x.v)) : k(3, iota(count(x)).v.sort(function(a, b) { + var f = function(i) { var v = x.v[i.v]; return s(v) ? ks(ktos(v)) : v; } + var av = f(a), bv = f(b); return less(av,bv).v ? dir : more(av,bv).v ? -dir : a.v - b.v; + })); +} + +function where(x, env) { + if (x.t == 4) { return atx(x.k, where(x.v, env)); } // {,/(0|x)#'!#x}... + var s = kmap(x.t==3 ?x:enlist(x), function(v,i) { return take(k(0,p(v)), k(0,i), env); }); + return over(asVerb(","), s, env); +} + +function group(x) { + var r={t:4, k:unique(x)}; r.v=kmap(r.k, function(){ return k(3,[]); }); + for(var z=0;z 1) { var i=a+Math.floor((b-a)/2); if (more(x.v[i], y).v) { b=i; } else { a=i; } } + return k(0, a); +} + +function split (x, y) { return (x.t != 1) ? unpack(x, y) : call(splitimpl, k(3, [x,y])); } +function unpack (x, y) { return call(unpackimpl, k(3, [x,y])); } +function pack (x, y) { return (x.t == 1) ? join(x, y) : call(packimpl, k(3, [x,y])); } +function kwindow(x, y) { return call(winimpl, k(3, [x,y])); } +function splice(xyz) { return call(spliceimpl, k(3, xyz)); } +function imat(x) { var i = iota(x); return kmap(i, function(z) { return ar(equal)(z, i); }); } +function odometer(x) { return call(odoimpl, enlist(x)); } + +//////////////////////////////////// +// +// Primitive Adverbs +// +//////////////////////////////////// + +function each(monad, x, env) { + if (x.t == 4) { return md(x.k, each(monad, x.v, env)); } + return kmap(x, function(x) { return applym(monad, x, env); }); +} + +function eachd(dyad, left, right, env) { + if (!env) { return kmap(left, function(x) { return applyd(dyad, x, null, right); }); } + if (left.t==4&&right.t==4) { return md(left.k,eachd(dyad,left.v,atx(right,left.k),env)); } + if (left.t!=3) { return eachright(dyad, left, right, env); } + if (right.t!=3) { return eachleft(dyad, left, right, env); } + return kzip(left, right, function(x, y) { return applyd(dyad, x, y, env); }); +} + +function eachright(dyad, left, list, env) { + return kmap(list, function(x) { return applyd(dyad, left, x, env); }); +} + +function eachleft(dyad, list, right, env) { + return kmap(list, function(x) { return applyd(dyad, x, right, env); }); +} + +function eachprior(dyad, x, env) { + var specials = {"+":k0, "*":k1, "-":k0, "&":first(x), ",":k(3,[]), "%":k1}; + return eachpc(dyad, (dyad.v in specials) ? specials[dyad.v] : NA, x, env); +} + +function eachpc(dyad, x, y, env) { + return kmap(y, function(v) { var t=x; x=v; return applyd(dyad, v, t, env); }); +} + +function over(dyad, x, env) { + var specials = {"+":k0, "*":k1, "|":k(0,-1/0), "&":k(0,1/0)}; + if (x.t == 3 && len(x) < 1 && dyad.v in specials) { return specials[dyad.v]; } + if (x.t == 3 && len(x) == 1 && dyad.v == ",") { return first(x).t != 3 ? x : first(x); } + if (x.t != 3 || len(x) < 1) { return x; } + return overd(dyad, first(x), drop(k1,x), env); +} + +function overd(dyad, x, y, env) { + return y.v.reduce(function(x, y) { return applyd(dyad, x, y, env); }, x); +} + +function eacha(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + if (x.t != 3) { return kmap(y, function(y) { return call(func, cat(x, y), env); }); } + return kzip(x, y, function(x, y) { return call(func, cat(x, y), env); }); +} +function overa(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + return y.v.reduce(function(x, y) { return call(func, cat(enlist(x), y), env); }, x); +} +function scana(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + return cat(x, kmap(y, function(y) { return x = call(func, cat(enlist(x), y), env); })); +} + +function fixed(monad, x, env) { + var r=x, p=x; + do { r=applym(monad, p=r, env); } while(!match(p, r).v && !match(r, x).v); return p; +} + +function fixedwhile(monad, x, y, env) { + if (x.t == 0) { for(var z=0;z" : [desc, desc, ad(more), ad(more), ad(more), ad(more), null, null ], + "=" : [imat, group, ad(equal), ad(equal), ad(equal), ad(equal), null, null ], + "~" : [am(not), am(not), match, match, match, match, null, null ], + "," : [enlist, enlist, cat, cat, cat, cat, null, null ], + "^" : [pisnull, am(pisnull),except, except, except, except, null, null ], + "#" : [count, count, take, reshape, take, reshape, null, null ], + "_" : [am(floor), am(floor), drop, ddrop, drop, cut, null, null ], + "$" : [kfmt, am(kfmt), dfmt, dfmt, dfmt, dfmt, null, null ], + "?" : [real, unique, rnd, pfind, rnd, ar(pfind), splice, null ], + "@" : [type, type, atx, atx, atx, atx, amend4, amend4], + "." : [keval, keval, call, call, call, call, dmend4, dmend4], + "'" : [null, null, null, bin, null, ar(bin), null, null ], + "/" : [null, null, null, null, pack, pack, null, null ], + "\\": [null, null, null, unpack, split, null, null, null ], + "':": [null, null, null, null, kwindow, null, null, null ], +}; + +function applyverb(node, args, env) { + if (node.curry) { + var a=[]; var i=0; for(var z=0;z 2) ? r(args, env) : left ? r(left, right, env) : r(right, env) +} + +function valence(node, env) { + if (node.t == 5) { + return (node.curry||[]).reduce(function(x,v) { return x-!isnull(v).v; }, node.args.length); + } + if (node.t == 7) { return valence(env.lookup(ks(node.v))); } + if (node.t == 9 && node.v == "'") { return valence(node.verb, env); } + if (node.t == 9) { return 1; } + if (node.t != 8) { return 0; } + if (node.forcemonad) { return 1; } + if (node.v in natives) { return 1; } + return (node.sticky && (node.sticky.t==9 || node.sticky.forcemonad || node.sticky.l)) ? 1 : 2; +} + +var adverbs = { + // mv/nv dv l-mv l-dv 3+v + "':" : [null, eachprior, null, eachpc, null ], + "'" : [each, eachd, eachd, eachd, eacha], + "/:" : [null, null, eachright, eachright, null ], + "\\:" : [null, null, eachleft, eachleft, null ], + "/" : [fixed, over, fixedwhile, overd, overa], + "\\" : [scanfixed, scan, scanwhile, scand, scana], +}; + +function applyadverb(node, verb, args, env) { + if (verb.t == 7) { verb = run(verb, env); } + var r = null; var v = valence(verb, env); + if (v > 2) { return adverbs[node.v][4](verb, args, env); } + if (v == 0 && verb.t != 5) { return applyverb(k(8,node.v), [verb, args[1]], env); } + if (v == 0 && verb.t == 5) { v = 1; } + if (v == 2 && !args[1]) { args = [null, args[0]]; } + if (v == 1 && !args[0]) { r = adverbs[node.v][0]; } + if (v == 2 && !args[0]) { r = adverbs[node.v][1]; } + if (v == 1 && args[0]) { r = adverbs[node.v][2]; } + if (v == 2 && args[0]) { r = adverbs[node.v][3]; } + if (!r) { throw new Error("invalid arguments to "+node.v+" ["+ + (args[0]?format(args[0])+" ":"")+" "+format(verb)+" (valence "+v+"), "+format(args[1])+"]"); + } + return args[0] ? r(verb, args[0], args[1], env) : r(verb, args[1], env); +} + +function Environment(pred) { + this.p = pred; this.d = md(k(3,[]), k(3,[])); + this.put = function(n, g, v) { + if (typeof n == "string") { n = ks(n); } + if (g && this.p) { this.p.put(n, g, v); } else { dset(this.d, n, v); } + }; + this.contains = function(x) { return find(this.d.k, x).v != len(this.d.k); } + this.lookup = function(n, g) { + if (g && this.p) { return this.p.lookup(n, g); } + if (!this.contains(n)) { + if (!this.p) { throw new Error("the name '"+n.v+"' has not been defined."); } + return this.p.lookup(n); + } + var view = dget(this.d, n); + if (view.t == 6) { + var dirty = view.cache == 0, env = this; + Object.keys(view.depends).forEach(function(z) { + var n = (z == view.v) ? view.cache : env.lookup(ks(z)), o = view.depends[z]; + if (!o || !match(n,o).v) { dirty=1; view.depends[z]=n; } + }) + if (dirty) { view.cache = run(view.r, this); } return view.cache; + } + return view; + }; +} + +function atx(x, y, env) { + return x.t == 2 ? atx(env.lookup(x), y, env) : y.t == 11 ? x : + x.t == 3 && y.t == 4 ? md(y.k, atx(x, y.v, env)) : + x.t == 8 || x.t == 9 ? applym(x, y, env) : + (x.t == 3 || x.t == 4) && y.t == 3 ? kmap(y, function(z) { return atx(x, z); }) : + x.t == 3 ? (y.t > 1 || y.v < 0 || y.v >= len(x) || y.v%1 != 0) ? NA : x.v[y.v] : + x.t == 4 ? dget(x, y) : call(x, enlist(y), env) +} + +function atdepth(x, y, i, env) { + if (i >= len(y)) { return x; }; var c = y.v[i]; var k = atx(x, c, env); + return (c.t != 11 && c.t != 3) ? atdepth(k, y, i+1, env) : + kmap(k, function(t) { return atdepth(t, y, i+1, env) }) +} + +function call(x, y, env) { + if (x.sticky) { return (valence(x.sticky, env)==1?applym:applyd)(x, y.v[0], y.v[1], env); } + if (x.t == 2) { return call(env.lookup(x), y, env); } + if (x.t == 3 || x.t == 4) { return y.t == 3 ? atdepth(x, y, 0, env) : atx(x, y, env); } + if (x.t == 8) { return applyverb(x, y.t == 3 ? y.v : [y], env); } + if (x.t == 9) { return applyadverb(x, run(x.verb, env), y.v, env); } + if (x.t != 5) { throw new Error("function or list expected, found " + TN[x.t]+'.'); } + if (y.t == 4) { var e=new Environment(null); e.d=y; x.env=e; return x; } + if (y.t != 3) { y = enlist(y); } + var environment = new Environment(x.env); var curry = x.curry?x.curry.concat([]):[]; + if (x.args.length != 0 || len(y) != 1 || !isnull(y.v[0]).v) { + var all=true; var i=0; for(var z=0;z= len(y)) { all=false; break; } + if (y.v[i] == null || isnull(y.v[i]).v) { all=false; } + curry[z]=y.v[i++]; + } + if (!all) { return { t:5, v:x.v, args:x.args, env:x.env, curry:curry }; } + if (i < len(y) && x.args.length != 0) { throw new Error("valence error."); } + for(var z=0;z=~,^#_$?@.]/; +var ASSIGN = /^[+\-*%!&|<>=~,^#_$?@.]:/; +var IOVERB = /^\d:/; +var ADVERB = /^['\\\/]:?/; +var SEMI = /^;/; +var COLON = /^:/; +var VIEW = /^::/; +var COND = /^\$\[/; +var DICT = /^\[[a-z]+:/i; +var OPEN_B = /^\[/; +var OPEN_P = /^\(/; +var OPEN_C = /^{/; +var CLOSE_B = /^\]/; +var CLOSE_P = /^\)/; +var CLOSE_C = /^}/; + +var des = {}; +des[NUMBER ]="number";des[NAME ]="name" ;des[SYMBOL ]="symbol";des[STRING]="string"; +des[VERB ]="verb" ;des[IOVERB ]="IO verb";des[ADVERB ]="adverb";des[SEMI ]="';'"; +des[COLON ]="':'" ;des[VIEW ]="view" ;des[COND ]="'$['" ; +des[OPEN_B ]="'['" ;des[OPEN_P ]="'('" ;des[OPEN_C ]="'{'" ;des[ASSIGN]="assignment"; +des[CLOSE_B]="']'" ;des[CLOSE_P]="')'" ;des[CLOSE_C]="'}'"; + +var text = ""; +var funcdepth = 0; +function begin(str) { + str = str.replace(/("(?:[^"\\\n]|\\.)*")|(\s\/.*)|([a-z\d\]\)]-\.?\d)/gi, function(_, x, y, z) { + // preserve a string (x), remove a comment (y), disambiguate a minus sign (z) + return x ? x : y ? "" : z.replace('-', '- ') + }) + text = str.trim().replace(/\n/g, ";"); funcdepth = 0; +} +function done() { return text.length < 1; } +function at(regex) { return regex.test(text); } +function matches(regex) { return at(regex) ? expect(regex) : false; } +function expect(regex) { + var found = regex.exec(text); + if (regex == OPEN_C) { funcdepth++; } if (regex == CLOSE_C) { funcdepth--; } + if (found == null) { throw new Error("parse error. "+des[regex]+" expected."); } + text = text.substring(found[0].length).trim(); return found[0]; +} + +//////////////////////////////////// +// +// Parser +// +//////////////////////////////////// + +function findNames(node, names) { + if (node == null) { return names; } + if (node instanceof Array) { node.forEach(function(v) { findNames(v, names); }); return names; } + if (node.t == 7) { names[node.v] = 0; } + if (node.t != 5) { findNames(node.v, names); } + return findNames([node.l, node.r, node.verb, node.curry], names); +} + +function atNoun() { + return !done()&&at(NUMBER)||at(NAME)||at(SYMBOL)||at(STRING)||at(COND)||at(OPEN_P)||at(OPEN_C); +} + +function indexedassign(node, indexer) { + var op = { t:5, args:["x","y"], v:[{ t:7, v:"y" }] }; // {y} + var gl = matches(COLON); + var ex = parseEx(parseNoun()); + //t[x]::z -> ..[`t;x;{y};z] t[x]:z -> t:.[t;x;{y};z] + if (!gl) { node.r = { t:8, v:".", curry:[ k(7,node.v), kl(indexer), op, ex] }; return node; } + return { t:8, v:".", r:{ t:8, v:".", curry:[ks(node.v), kl(indexer), op, ex] }}; +} + +function compoundassign(node, indexer) { + if (!at(ASSIGN)) { return node; } + var op = expect(ASSIGN).slice(0,1); var gl = matches(COLON); var ex = parseEx(parseNoun()); + if (!indexer) { + // t+::z -> t::(.`t)+z + var v = gl ? asVerb(".", null, ks(node.v)) : node; + return { t:node.t, v:node.v, global:gl, r:asVerb(op, v, ex) }; + } + // t[x]+::z -> ..[`t;x;+:;z] t[x]+:z -> t:.[t;x;{y};z] + if (!gl) { node.r={ t:8, v:".", curry:[ k(7,node.v),kl(indexer),asVerb(op),ex] }; return node; } + return asVerb(".", null, { t:8, v:".", curry:[ks(node.v), indexer, asVerb(op), ex] }); +} + +function applycallright(node) { + while (matches(OPEN_B)) { + var args = parseList(CLOSE_B); node = asVerb(".", node, k(3, args.length ? args : [NIL])); + } return node; +} + +function applyindexright(node) { + if (node.sticky && at(VERB)) { + var x = parseNoun(); x.l = node; x.r = parseEx(parseNoun()); return x; + } + while (matches(OPEN_B)) { node = asVerb(".", node, k(3, parseList(CLOSE_B))); } + return node; +} + +function findSticky(root) { + var n = root; if (n == null || (n.t == 9 && n.r == null)) { return; } + while(n.t == 8 && !n.curry || n.t == 9) { + if (n.r == null) { root.sticky = n; return; } n = n.r; + } +} + +function parseList(terminal, cull) { + var r=[]; do { + if (terminal && at(terminal)) { break; } + while(matches(SEMI)) { if (!cull) { r.push(k(11)); } } + var e = parseEx(parseNoun()); findSticky(e); + if (e != null) { r.push(e); } + else if (!cull) { r.push(k(11)); } + } while(matches(SEMI)); if (terminal) { expect(terminal); } return r; +} + +function parseNoun() { + if (matches(COLON)) { return { t:5, args:["x","y"], v:[{ t:7, v:"y" }] }; } // {y} + if (at(IOVERB)) { return k(8, expect(IOVERB)); } + if (at(BOOL)) { + var n = expect(BOOL); var r=[]; + for(var z=0;z@x;!x;x]}"), env); + run(parse("in:{~^y?x}"), env); + return env; +} + +var packimpl = parse("{+/y*|*\\1,|1_(#y)#x}")[0]; +var unpackimpl = parse("{(1_r,,y)-x*r:|y(_%)\\|x}")[0]; +var spliceimpl = parse("{,/(*x;$[99<@z;z x 1;z];*|x:(0,y)_x)}")[0]; +var winimpl = parse("{$[0>x;3':0,y,0;y(!0|1+(#y)-x)+\\:!x]}")[0]; +var odoimpl = parse("{+x\\'!*/x}")[0]; +var splitimpl = parse("{1_'(&x=y)_y:x,y}")[0]; + +// export the public interface: +function setIO(symbol, slot, func) { + if (!(symbol in verbs)) { verbs[symbol]=[null,null,null,null,null,null]; } + verbs[symbol][slot] = func; +} + +this.version = "0.1"; +this.parse = parse; +this.format = format; +this.run = run; +this.Environment = Environment; +this.baseEnv = baseEnv; +this.setIO = setIO; +// stolen from iKe +var katan2 = function(x, y) { return k(0, Math.atan2(n(x).v, n(y).v)); } +var kpow = function(x, y) { return k(0, Math.pow (n(x).v, n(y).v)); } +verbs["atan2"] = [null, null, ad(katan2), ad(katan2), ad(katan2), ad(katan2), null, null]; +verbs["pow" ] = [null, null, ad(kpow) , ad(kpow) , ad(kpow) , ad(kpow) , null, null]; +// stolen from convert.js +function trampoline(env, name, args, body) { + // construct a function-wrapper trampoline for a pseudonative. + // this permits dyadic/triadic extension functions to be properly curryable. + var arguse = []; for(var z=0; z k + "dictionary", // 4 : values, k(keys) + "function" , // 5 : body, args, curry, env + "view" , // 6 : value, r, cache, depends->val + "nameref" , // 7 : name, l(index?), r(assignment), global? + "verb" , // 8 : name, l(?), r, curry? + "adverb" , // 9 : name, l(?), verb, r + "return" , // 10 : return (deprecated) + "nil" , // 11 : + "cond" , // 12 : body (list of expressions) + "quote" , // 13 : value (for quoting verbs/etc as a value) +]; + +var NIL = ks(""); +var k0 = k(0, 0); +var k1 = k(0, 1); +var EC = [["\\","\\\\"],["\"","\\\""],["\n","\\n"],["\t","\\t"]]; +var kt = [-9, -10, -11, 0, 99, 102, NaN, NaN, 107, 105, NaN, NaN, NaN]; +var SP = k(1, " ".charCodeAt(0)); +var NA = k(0, NaN); + +function k (t, v) { return { 't':t, 'v':v }; } +function md (x, y) { return { t:4, k:sl(x,y), v:y }; } +function ks (x) { return k(2, x); } +function asVerb(x, y, z) { return { t:8, v:x, l:y, r:z }; } +function kl (x) { return x.length==1 ? x[0] : k(3,x); } +function kf (x) { return match(k(3,[]), x).v || match(k0, x).v; } +function kb (x) { return x ? k1 : k0; } +function s (x) { return x.t == 3 && x.v.every(function(c) { return c.t == 1; }); } +function kmod (x, y) { return x-y*Math.floor(x/y); } +function len (x) { return l(x).v.length; } +function krange(x, f) { var r=[]; for(var z=0;z=len(x)) { throw new Error("length error."); } return x.v[y]; } +function dget (x, y) { var i=find(x.k, y); return (i.v==len(x.k)) ? NA : atx(x.v, i); } +function lset (x, y, z) { if (len(x) <= p(y)) { throw new Error("index error."); } x.v[y.v]=z; } +function dset (x, y, z) { var i=find(x.k, y).v; if(i==len(x.k)) { x.k.v.push(y); } x.v.v[i]=z; } +function lower (x) { return k(1, String.fromCharCode(x.v).toLowerCase().charCodeAt(0)); } +function kmap (x, f) { return k(3, l(x).v.map(f)); } +function kzip (x, y, f) { return kmap(sl(x,y), function(z, i) { return f(z, y.v[i]); }); } +function sl (x, y) { if (len(x) != len(y)) { throw new Error("length error."); } return x; } +function n (x) { return (x.t==0||x.t==1) ? x : ct(x, 0); } +function l (x) { return ct(x, 3); } +function d (x) { return ct(x, 4); } +function a (x) { if (x.t > 2) { throw new Error("domain error."); } return x; } +function na (x) { return x.t === 0 && isNaN(x.v); } + +function stok(x) { return kl(krange(x.length, function(z) { return k(1,x.charCodeAt(z)); }).v); } +function c(x) { return (x.t==3) ? k(x.t, x.v.slice(0)) : (x.t==4) ? md(c(x.k), c(x.v)) : x; } +function ct(n,t) { if (n.t!=t) throw new Error(TN[t]+" expected, found "+TN[n.t]+"."); return n; } +function p(x) { if (n(x).v<0||x.v%1!=0) { throw new Error("positive int expected."); } return x.v; } +function ktos(x, esc) { + if (x.t != 3) { x = enlist(x); } + var h = x.v.some(function(v){ return (v.v<32||v.v>127)&v.v!=9&v.v!=10; }); + if (h) { return "0x"+x.v.map(h2).join(""); } + var r = x.v.map(function(k) { return String.fromCharCode(k.v); }).join(""); + return esc ? '"'+EC.reduce(function(r,p) { return r.split(p[0]).join(p[1]); }, r)+'"' : r; +} + +//////////////////////////////////// +// +// Primitive Verbs +// +//////////////////////////////////// + +function plus (x, y) { return k(0, n(x).v + n(y).v); } +function minus (x, y) { return k(0, n(x).v - n(y).v); } +function times (x, y) { return k(0, n(x).v * n(y).v); } +function divide(x, y) { return k(0, n(x).v / n(y).v); } +function mod (x, y) { return k(0, n(x).v>0 ? kmod(n(y).v, x.v) : Math.floor(n(y).v / -x.v)); } +function max (x, y) { return na(x)?y:na(y)?x:k(0, Math.max(n(x).v, n(y).v)); } +function min (x, y) { return k(0, Math.min(n(x).v, n(y).v)); } +function less (x, y) { return kb(a(x).v < a(y).v); } +function more (x, y) { return kb(a(x).v > a(y).v); } +function equal (x, y) { return kb((x.v == y.v) || (na(x) && na(y))); } +function join (x, y) { return l(y).v.reduce(function(z, y) { return cat(z, cat(x, y)); }); } +function ident (x) { return x; } +function negate (x) { return k(0, -n(x).v); } +function first (x) { return (x.t == 4) ? first(x.v) : (x.t != 3) ? x : len(x) ? x.v[0]:k(3,[]); } +function sqrt (x) { return k(0, Math.sqrt(n(x).v)); } +function keys (x) { return c(d(x).k); } +function rev (x) { return x.t==4?md(rev(x.k),rev(x.v)):x.t==3?k(3,c(l(x)).v.reverse()):x; } +function asc (x) { return grade(-1, x); } +function desc (x) { return grade(1, x); } +function not (x) { return equal(n(x), k0); } +function enlist (x) { return k(3, [x]); } +function isnull (x) { return max(match(x, NIL),match(x,k(11))); } +function count (x) { return k(0, x.t == 4 ? len(x.v) : x.t == 3 ? len(x) : 1); } +function floor (x) { return x.t == 1 ? lower(x) : k(0, Math.floor(n(x).v)); } +function type (x) { return k(0, kt[x.t]); } +function kfmt (x) { var r=stok(format(x, 0, 1)); return r.t == 3 ? r : enlist(r); } +function real (x) { return krange(n(x).v, function() { return k(0, Math.random()); }); } + +function iota(x) { + if (x.t == 4) { return keys(x); } + var i = krange(Math.abs(n(x).v), k.bind(null, 0)); return x.v>=0 ? i : ar(plus)(x, i); +} + +function cat(x, y) { + if (x.t==4&&y.t==4) { x=c(x); kmap(y.k, function(v) { dset(x,v,dget(y,v)); }); return x; }; + return k(3, (x.t==3?x.v:[x]).concat(y.t==3?y.v:[y])); +} + +function keval(x, env) { + if (x.t == 5) { return x.env.d; } + return x.t == 4 ? c(x.v) : x.t == 2 ? env.lookup(x, true) : run(parse(ktos(x)), env); +} + +function dfmt(x, y) { + if ( x.t == 3 && y.t == 3) { return kzip(x, y, dfmt); } + if ( x.t == 3 && y.t != 3) { return kmap(x, function(z) { return dfmt(z, y); }); } + if ((x.t == 2 || !s(y)) && y.t == 3) { return kmap(y, function(z) { return dfmt(x, z); }); } + if (x.t == 2) { return {b: k(0,y.v&1), i: k(0,y.v|0), f: k(0,y.v), c: k(1,y.v)}[x.v]; } + if (y.t == 1) { return y; } var r=c(y); var d=Math.abs(x.v); + while(len(r) < d) { x.v>0 ? r.v.push(SP) : r.v.unshift(SP); } + while(len(r) > d) { x.v>0 ? r.v.pop() : r.v.shift(); } + return r; +} + +function except(x, y) { + y = y.t == 3 ? y : enlist(y); + return k(3, (x.t == 3 ? x : iota(x)).v.filter(function(z) { return na(pfind(y, z)); })); +} + +function ddrop(x, y) { var k = except(d(y).k, x); return md(k, atx(y, k)); } +function drop(x, y) { + if (y.t == 4) { return md(drop(x, y.k), drop(x, y.v)); } + return (y.t != 3 || len(y) < 1) ? y : k(3, n(x).v<0 ? y.v.slice(0,x.v) : y.v.slice(x.v)); +} + +function take(x, y, env) { + if (x.t == 5 || x.t == 8 || x.t == 9) { + var k = where(each(x, y, env), env); var v = atx(y, k); + return y.t == 4 ? md(k, v) : v; + } + if (y.t == 4) { return md(take(x, y.k, env), take(x, y.v, env)); } + if (y.t != 3 || len(y) == 0) { y = enlist(y); } + var s=n(x).v<0?kmod(x.v, len(y)):0; + return krange(Math.abs(x.v), function(x) { return y.v[kmod(x+s, len(y))]; }); +} + +function reshape(x, y) { + if (y.t == 4) { return md(x, atx(y, x)); } + if (y.t != 3) { y = enlist(y); } + var a = first(x); var b = x.v[len(x)-1]; var c = 0; + function rshr(x, y, i) { + return krange(x.v[i].v, function(z) { + return i==len(x)-1 ? y.v[kmod(c++, len(y))] : rshr(x, y, i+1); + }); + } + return na(a) ? (!len(y) ? y : cut(krange(len(y)/b.v, function(z) { return k(0, z*b.v); }), y)) : + na(b) ? cut(krange(a.v, function(z) { return k(0, Math.floor(z*len(y)/a.v)); }), y) : + rshr(l(x), len(y) ? y : enlist(y), 0); +} + +function match(x, y) { + if (x.t != y.t) { return k0; } + if (x.t == 4) { return min(match(x.k, y.k), match(x.v, y.v)); } + if (x.t != 3) { return equal(x, y); } + if (len(x) != len(y)) { return k0; } + return kb(x.v.every(function(x,i) { return match(x, y.v[i]).v; })); +} + +function find(x, y) { y=x.v.findIndex(function(z){return match(z,y).v}); return k(0,y>=0?y:len(x)) } +function pfind(x, y) { y=x.v.findIndex(function(z){return equal(z,y).v}); return y>=0?k(0,y):NA } +function pisnull(x) { return kb(match(x, NIL).v || match(x, k(11)).v || na(x)); } + +function cut(x, y) { + return kzip(x, cat(drop(k1,x),count(y)), function(a, b) { // {x{x@y+!z-y}[y]'1_x,#y} ? + var r=[]; for(var z=p(a);zy.v) throw new Error("length error.");return take(x,asc(real(y)),env); } + return kmap(iota(x), function(x){ return k(0,Math.floor(Math.random()*y.v)); }); +} + +function flip(x, env) { + x=eachright(k(8,"#"), over(k(8,"|"), each(k(8,"#"), x, env), env), x, env); + return krange(len(first(x)), function(z){ + return krange(len(x), function(t){ return x.v[t].v[z]; }); + }); +} + +function grade(dir, x) { + return x.t == 4 ? atx(x.k, grade(dir, x.v)) : k(3, iota(count(x)).v.sort(function(a, b) { + var f = function(i) { var v = x.v[i.v]; return s(v) ? ks(ktos(v)) : v; } + var av = f(a), bv = f(b); return less(av,bv).v ? dir : more(av,bv).v ? -dir : a.v - b.v; + })); +} + +function where(x, env) { + if (x.t == 4) { return atx(x.k, where(x.v, env)); } // {,/(0|x)#'!#x}... + var s = kmap(x.t==3 ?x:enlist(x), function(v,i) { return take(k(0,p(v)), k(0,i), env); }); + return over(asVerb(","), s, env); +} + +function group(x) { + var r={t:4, k:unique(x)}; r.v=kmap(r.k, function(){ return k(3,[]); }); + for(var z=0;z 1) { var i=a+Math.floor((b-a)/2); if (more(x.v[i], y).v) { b=i; } else { a=i; } } + return k(0, a); +} + +function split (x, y) { return (x.t != 1) ? unpack(x, y) : call(splitimpl, k(3, [x,y])); } +function unpack (x, y) { return call(unpackimpl, k(3, [x,y])); } +function pack (x, y) { return (x.t == 1) ? join(x, y) : call(packimpl, k(3, [x,y])); } +function kwindow(x, y) { return call(winimpl, k(3, [x,y])); } +function splice(xyz) { return call(spliceimpl, k(3, xyz)); } +function imat(x) { var i = iota(x); return kmap(i, function(z) { return ar(equal)(z, i); }); } +function odometer(x) { return call(odoimpl, enlist(x)); } + +//////////////////////////////////// +// +// Primitive Adverbs +// +//////////////////////////////////// + +function each(monad, x, env) { + if (x.t == 4) { return md(x.k, each(monad, x.v, env)); } + return kmap(x, function(x) { return applym(monad, x, env); }); +} + +function eachd(dyad, left, right, env) { + if (!env) { return kmap(left, function(x) { return applyd(dyad, x, null, right); }); } + if (left.t==4&&right.t==4) { return md(left.k,eachd(dyad,left.v,atx(right,left.k),env)); } + if (left.t!=3) { return eachright(dyad, left, right, env); } + if (right.t!=3) { return eachleft(dyad, left, right, env); } + return kzip(left, right, function(x, y) { return applyd(dyad, x, y, env); }); +} + +function eachright(dyad, left, list, env) { + return kmap(list, function(x) { return applyd(dyad, left, x, env); }); +} + +function eachleft(dyad, list, right, env) { + return kmap(list, function(x) { return applyd(dyad, x, right, env); }); +} + +function eachprior(dyad, x, env) { + var specials = {"+":k0, "*":k1, "-":k0, "&":first(x), ",":k(3,[]), "%":k1}; + return eachpc(dyad, (dyad.v in specials) ? specials[dyad.v] : NA, x, env); +} + +function eachpc(dyad, x, y, env) { + return kmap(y, function(v) { var t=x; x=v; return applyd(dyad, v, t, env); }); +} + +function over(dyad, x, env) { + var specials = {"+":k0, "*":k1, "|":k(0,-1/0), "&":k(0,1/0)}; + if (x.t == 3 && len(x) < 1 && dyad.v in specials) { return specials[dyad.v]; } + if (x.t == 3 && len(x) == 1 && dyad.v == ",") { return first(x).t != 3 ? x : first(x); } + if (x.t != 3 || len(x) < 1) { return x; } + return overd(dyad, first(x), drop(k1,x), env); +} + +function overd(dyad, x, y, env) { + return y.v.reduce(function(x, y) { return applyd(dyad, x, y, env); }, x); +} + +function eacha(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + if (x.t != 3) { return kmap(y, function(y) { return call(func, cat(x, y), env); }); } + return kzip(x, y, function(x, y) { return call(func, cat(x, y), env); }); +} +function overa(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + return y.v.reduce(function(x, y) { return call(func, cat(enlist(x), y), env); }, x); +} +function scana(func, args, env) { + var x = args[0]; var y = flip(k(3, args.slice(1)), env); + return cat(x, kmap(y, function(y) { return x = call(func, cat(enlist(x), y), env); })); +} + +function fixed(monad, x, env) { + var r=x, p=x; + do { r=applym(monad, p=r, env); } while(!match(p, r).v && !match(r, x).v); return p; +} + +function fixedwhile(monad, x, y, env) { + if (x.t == 0) { for(var z=0;z" : [desc, desc, ad(more), ad(more), ad(more), ad(more), null, null ], + "=" : [imat, group, ad(equal), ad(equal), ad(equal), ad(equal), null, null ], + "~" : [am(not), am(not), match, match, match, match, null, null ], + "," : [enlist, enlist, cat, cat, cat, cat, null, null ], + "^" : [pisnull, am(pisnull),except, except, except, except, null, null ], + "#" : [count, count, take, reshape, take, reshape, null, null ], + "_" : [am(floor), am(floor), drop, ddrop, drop, cut, null, null ], + "$" : [kfmt, am(kfmt), dfmt, dfmt, dfmt, dfmt, null, null ], + "?" : [real, unique, rnd, pfind, rnd, ar(pfind), splice, null ], + "@" : [type, type, atx, atx, atx, atx, amend4, amend4], + "." : [keval, keval, call, call, call, call, dmend4, dmend4], + "'" : [null, null, null, bin, null, ar(bin), null, null ], + "/" : [null, null, null, null, pack, pack, null, null ], + "\\": [null, null, null, unpack, split, null, null, null ], + "':": [null, null, null, null, kwindow, null, null, null ], +}; + +function applyverb(node, args, env) { + if (node.curry) { + var a=[]; var i=0; for(var z=0;z 2) ? r(args, env) : left ? r(left, right, env) : r(right, env) +} + +function valence(node, env) { + if (node.t == 5) { + return (node.curry||[]).reduce(function(x,v) { return x-!isnull(v).v; }, node.args.length); + } + if (node.t == 7) { return valence(env.lookup(ks(node.v))); } + if (node.t == 9 && node.v == "'") { return valence(node.verb, env); } + if (node.t == 9) { return 1; } + if (node.t != 8) { return 0; } + if (node.forcemonad) { return 1; } + if (node.v in natives) { return 1; } + return (node.sticky && (node.sticky.t==9 || node.sticky.forcemonad || node.sticky.l)) ? 1 : 2; +} + +var adverbs = { + // mv/nv dv l-mv l-dv 3+v + "':" : [null, eachprior, null, eachpc, null ], + "'" : [each, eachd, eachd, eachd, eacha], + "/:" : [null, null, eachright, eachright, null ], + "\\:" : [null, null, eachleft, eachleft, null ], + "/" : [fixed, over, fixedwhile, overd, overa], + "\\" : [scanfixed, scan, scanwhile, scand, scana], +}; + +function applyadverb(node, verb, args, env) { + if (verb.t == 7) { verb = run(verb, env); } + var r = null; var v = valence(verb, env); + if (v > 2) { return adverbs[node.v][4](verb, args, env); } + if (v == 0 && verb.t != 5) { return applyverb(k(8,node.v), [verb, args[1]], env); } + if (v == 0 && verb.t == 5) { v = 1; } + if (v == 2 && !args[1]) { args = [null, args[0]]; } + if (v == 1 && !args[0]) { r = adverbs[node.v][0]; } + if (v == 2 && !args[0]) { r = adverbs[node.v][1]; } + if (v == 1 && args[0]) { r = adverbs[node.v][2]; } + if (v == 2 && args[0]) { r = adverbs[node.v][3]; } + if (!r) { throw new Error("invalid arguments to "+node.v+" ["+ + (args[0]?format(args[0])+" ":"")+" "+format(verb)+" (valence "+v+"), "+format(args[1])+"]"); + } + return args[0] ? r(verb, args[0], args[1], env) : r(verb, args[1], env); +} + +function Environment(pred) { + this.p = pred; this.d = md(k(3,[]), k(3,[])); + this.put = function(n, g, v) { + if (typeof n == "string") { n = ks(n); } + if (g && this.p) { this.p.put(n, g, v); } else { dset(this.d, n, v); } + }; + this.contains = function(x) { return find(this.d.k, x).v != len(this.d.k); } + this.lookup = function(n, g) { + if (g && this.p) { return this.p.lookup(n, g); } + if (!this.contains(n)) { + if (!this.p) { throw new Error("the name '"+n.v+"' has not been defined."); } + return this.p.lookup(n); + } + var view = dget(this.d, n); + if (view.t == 6) { + var dirty = view.cache == 0, env = this; + Object.keys(view.depends).forEach(function(z) { + var n = (z == view.v) ? view.cache : env.lookup(ks(z)), o = view.depends[z]; + if (!o || !match(n,o).v) { dirty=1; view.depends[z]=n; } + }) + if (dirty) { view.cache = run(view.r, this); } return view.cache; + } + return view; + }; +} + +function atx(x, y, env) { + return x.t == 2 ? atx(env.lookup(x), y, env) : y.t == 11 ? x : + x.t == 3 && y.t == 4 ? md(y.k, atx(x, y.v, env)) : + x.t == 8 || x.t == 9 ? applym(x, y, env) : + (x.t == 3 || x.t == 4) && y.t == 3 ? kmap(y, function(z) { return atx(x, z); }) : + x.t == 3 ? (y.t > 1 || y.v < 0 || y.v >= len(x) || y.v%1 != 0) ? NA : x.v[y.v] : + x.t == 4 ? dget(x, y) : call(x, enlist(y), env) +} + +function atdepth(x, y, i, env) { + if (i >= len(y)) { return x; }; var c = y.v[i]; var k = atx(x, c, env); + return (c.t != 11 && c.t != 3) ? atdepth(k, y, i+1, env) : + kmap(k, function(t) { return atdepth(t, y, i+1, env) }) +} + +function call(x, y, env) { + if (x.sticky) { return (valence(x.sticky, env)==1?applym:applyd)(x, y.v[0], y.v[1], env); } + if (x.t == 2) { return call(env.lookup(x), y, env); } + if (x.t == 3 || x.t == 4) { return y.t == 3 ? atdepth(x, y, 0, env) : atx(x, y, env); } + if (x.t == 8) { return applyverb(x, y.t == 3 ? y.v : [y], env); } + if (x.t == 9) { return applyadverb(x, run(x.verb, env), y.v, env); } + if (x.t != 5) { throw new Error("function or list expected, found " + TN[x.t]+'.'); } + if (y.t == 4) { var e=new Environment(null); e.d=y; x.env=e; return x; } + if (y.t != 3) { y = enlist(y); } + var environment = new Environment(x.env); var curry = x.curry?x.curry.concat([]):[]; + if (x.args.length != 0 || len(y) != 1 || !isnull(y.v[0]).v) { + var all=true; var i=0; for(var z=0;z= len(y)) { all=false; break; } + if (y.v[i] == null || isnull(y.v[i]).v) { all=false; } + curry[z]=y.v[i++]; + } + if (!all) { return { t:5, v:x.v, args:x.args, env:x.env, curry:curry }; } + if (i < len(y) && x.args.length != 0) { throw new Error("valence error."); } + for(var z=0;z=~,^#_$?@.]/; +var ASSIGN = /^[+\-*%!&|<>=~,^#_$?@.]:/; +var IOVERB = /^\d:/; +var ADVERB = /^['\\\/]:?/; +var SEMI = /^;/; +var COLON = /^:/; +var VIEW = /^::/; +var COND = /^\$\[/; +var DICT = /^\[[a-z]+:/i; +var OPEN_B = /^\[/; +var OPEN_P = /^\(/; +var OPEN_C = /^{/; +var CLOSE_B = /^\]/; +var CLOSE_P = /^\)/; +var CLOSE_C = /^}/; + +var des = {}; +des[NUMBER ]="number";des[NAME ]="name" ;des[SYMBOL ]="symbol";des[STRING]="string"; +des[VERB ]="verb" ;des[IOVERB ]="IO verb";des[ADVERB ]="adverb";des[SEMI ]="';'"; +des[COLON ]="':'" ;des[VIEW ]="view" ;des[COND ]="'$['" ; +des[OPEN_B ]="'['" ;des[OPEN_P ]="'('" ;des[OPEN_C ]="'{'" ;des[ASSIGN]="assignment"; +des[CLOSE_B]="']'" ;des[CLOSE_P]="')'" ;des[CLOSE_C]="'}'"; + +var text = ""; +var funcdepth = 0; +function begin(str) { + str = str.replace(/("(?:[^"\\\n]|\\.)*")|(\s\/.*)|([a-z\d\]\)]-\.?\d)/gi, function(_, x, y, z) { + // preserve a string (x), remove a comment (y), disambiguate a minus sign (z) + return x ? x : y ? "" : z.replace('-', '- ') + }) + text = str.trim().replace(/\n/g, ";"); funcdepth = 0; +} +function done() { return text.length < 1; } +function at(regex) { return regex.test(text); } +function matches(regex) { return at(regex) ? expect(regex) : false; } +function expect(regex) { + var found = regex.exec(text); + if (regex == OPEN_C) { funcdepth++; } if (regex == CLOSE_C) { funcdepth--; } + if (found == null) { throw new Error("parse error. "+des[regex]+" expected."); } + text = text.substring(found[0].length).trim(); return found[0]; +} + +//////////////////////////////////// +// +// Parser +// +//////////////////////////////////// + +function findNames(node, names) { + if (node == null) { return names; } + if (node instanceof Array) { node.forEach(function(v) { findNames(v, names); }); return names; } + if (node.t == 7) { names[node.v] = 0; } + if (node.t != 5) { findNames(node.v, names); } + return findNames([node.l, node.r, node.verb, node.curry], names); +} + +function atNoun() { + return !done()&&at(NUMBER)||at(NAME)||at(SYMBOL)||at(STRING)||at(COND)||at(OPEN_P)||at(OPEN_C); +} + +function indexedassign(node, indexer) { + var op = { t:5, args:["x","y"], v:[{ t:7, v:"y" }] }; // {y} + var gl = matches(COLON); + var ex = parseEx(parseNoun()); + //t[x]::z -> ..[`t;x;{y};z] t[x]:z -> t:.[t;x;{y};z] + if (!gl) { node.r = { t:8, v:".", curry:[ k(7,node.v), kl(indexer), op, ex] }; return node; } + return { t:8, v:".", r:{ t:8, v:".", curry:[ks(node.v), kl(indexer), op, ex] }}; +} + +function compoundassign(node, indexer) { + if (!at(ASSIGN)) { return node; } + var op = expect(ASSIGN).slice(0,1); var gl = matches(COLON); var ex = parseEx(parseNoun()); + if (!indexer) { + // t+::z -> t::(.`t)+z + var v = gl ? asVerb(".", null, ks(node.v)) : node; + return { t:node.t, v:node.v, global:gl, r:asVerb(op, v, ex) }; + } + // t[x]+::z -> ..[`t;x;+:;z] t[x]+:z -> t:.[t;x;{y};z] + if (!gl) { node.r={ t:8, v:".", curry:[ k(7,node.v),kl(indexer),asVerb(op),ex] }; return node; } + return asVerb(".", null, { t:8, v:".", curry:[ks(node.v), indexer, asVerb(op), ex] }); +} + +function applycallright(node) { + while (matches(OPEN_B)) { + var args = parseList(CLOSE_B); node = asVerb(".", node, k(3, args.length ? args : [NIL])); + } return node; +} + +function applyindexright(node) { + if (node.sticky && at(VERB)) { + var x = parseNoun(); x.l = node; x.r = parseEx(parseNoun()); return x; + } + while (matches(OPEN_B)) { node = asVerb(".", node, k(3, parseList(CLOSE_B))); } + return node; +} + +function findSticky(root) { + var n = root; if (n == null || (n.t == 9 && n.r == null)) { return; } + while(n.t == 8 && !n.curry || n.t == 9) { + if (n.r == null) { root.sticky = n; return; } n = n.r; + } +} + +function parseList(terminal, cull) { + var r=[]; do { + if (terminal && at(terminal)) { break; } + while(matches(SEMI)) { if (!cull) { r.push(k(11)); } } + var e = parseEx(parseNoun()); findSticky(e); + if (e != null) { r.push(e); } + else if (!cull) { r.push(k(11)); } + } while(matches(SEMI)); if (terminal) { expect(terminal); } return r; +} + +function parseNoun() { + if (matches(COLON)) { return { t:5, args:["x","y"], v:[{ t:7, v:"y" }] }; } // {y} + if (at(IOVERB)) { return k(8, expect(IOVERB)); } + if (at(BOOL)) { + var n = expect(BOOL); var r=[]; + for(var z=0;z@x;!x;x]}"), env); + run(parse("in:{~^y?x}"), env); + return env; +} + +var packimpl = parse("{+/y*|*\\1,|1_(#y)#x}")[0]; +var unpackimpl = parse("{(1_r,,y)-x*r:|y(_%)\\|x}")[0]; +var spliceimpl = parse("{,/(*x;$[99<@z;z x 1;z];*|x:(0,y)_x)}")[0]; +var winimpl = parse("{$[0>x;3':0,y,0;y(!0|1+(#y)-x)+\\:!x]}")[0]; +var odoimpl = parse("{+x\\'!*/x}")[0]; +var splitimpl = parse("{1_'(&x=y)_y:x,y}")[0]; + +// export the public interface: +function setIO(symbol, slot, func) { + if (!(symbol in verbs)) { verbs[symbol]=[null,null,null,null,null,null]; } + verbs[symbol][slot] = func; +} + +this.version = "0.1"; +this.parse = parse; +this.format = format; +this.run = run; +this.Environment = Environment; +this.baseEnv = baseEnv; +this.setIO = setIO; diff --git a/ok/readme.txt b/ok/readme.txt new file mode 100644 index 0000000..d195ef0 --- /dev/null +++ b/ok/readme.txt @@ -0,0 +1 @@ +This is just https://github.com/johnearnest/ok but with some extra files made by me. diff --git a/ok/repl.js b/ok/repl.js new file mode 100755 index 0000000..984af65 --- /dev/null +++ b/ok/repl.js @@ -0,0 +1,108 @@ +#!/usr/bin/env node +var ok = require('./oK'); +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var readline = require('readline'); +var conv = require('./convert'); + +// register I/O hooks +function str(x) { // convert a k string or symbol to a js string + var s = conv.tojs(x); + if (typeof s !== 'string') { throw Error('ERROR: type'); } + return s; +} +function read(x) { + var f = str(x); + if (f) { + f = path.resolve(process.cwd(), f); + return conv.tok(fs.statSync(f).isDirectory() ? fs.readdirSync(f) : fs.readFileSync(f, 'utf8').replace(/\r?\n$/, '').split(/\r?\n/)); + } else if (rl) { + throw Error('ERROR: cannot read from stdin while in REPL'); + } else { + var b = Buffer(128), b0, n = 0; + while (fs.readSync(process.stdin.fd, b, n, 1) && b[n] !== 10) { + n++; + if (n === b.length) { b0 = b; b = Buffer(2 * n); b0.copy(b, 0, 0, n); b0 = null; } // resize buffer when full + } + return conv.tok(b.toString('utf8', 0, n)); + } +} +function write(x, y) { + var s = conv.tojs(y); + if (Array.isArray(s)) { s = s.join('\n') + '\n'; } + if (typeof s !== 'string') { throw Error('ERROR: type'); } + var f = str(x); + if (f) { + fs.writeFileSync(path.resolve(process.cwd(), f), s); + } else { + fs.writeSync(process.stdout.fd, s); + } + return y; +} +for (var i = 0; i < 2; i++) { ok.setIO('0:', i, read ); } +for (var i = 2; i < 6; i++) { ok.setIO('0:', i, write); } +for (var i = 0; i < 2; i++) { ok.setIO('5:', i, function(x) { return conv.tok(ok.format(x)); }); } + +var env = ok.baseEnv(); + +// run user prelude file if exists +try { + var preludeFile = os.homedir() + "/.config/okrc.k" + var program = fs.readFileSync(preludeFile, 'utf8'); + ok.run(ok.parse(program), env) +} catch (err) { + if (err.code != 'ENOENT') throw err +} + +// process filename.k as a command-line arg +if (process.argv.length > 2) { + var program = fs.readFileSync(process.argv[2], 'utf8'); + env.put('x', true, conv.tok(process.argv.slice(3))) + process.stdout.write(ok.format(ok.run(ok.parse(program), env)) + '\n'); + process.exit(0); +} + +// actual REPL +process.stdout.write('oK v' + ok.version + '\n'); +var rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + completer: function (line) { + var m = /[a-z][a-z\d]*$/i.exec(line); + var prefix = m ? m[0] : ''; + var names = []; + for (var e = env; e; e = e.p) { // iterate over ancestor environments + for (var name in e.d) { + if (name.slice(0, prefix.length) === prefix && names.indexOf(name) < 0) { + names.push(name); + } + } + } + return [names, prefix]; + } +}); +rl.on('line', function (line) { + if (line === '\\\\') { process.exit(0); } + var showtime = false; + if (line.lastIndexOf("\\t") == 0) { + line = line.slice(2); + showtime = true; + } + try { + if (line.trim()) { + var starttime = new Date().getTime(); + var output = ok.format(ok.run(ok.parse(line), env)) + '\n'; + if (showtime) { + var endtime = new Date().getTime(); + output += "completed in "+(endtime-starttime)+"ms.\n"; + } + process.stdout.write(output); + } + } catch (err) { + process.stdout.write(err.message + '\n'); + } + rl.prompt(); +}); +rl.on('close', function () { process.stdout.write('\n'); process.exit(0); }); +rl.setPrompt(' '); rl.prompt(); diff --git a/okrc.k b/okrc.k new file mode 100644 index 0000000..ea29194 --- /dev/null +++ b/okrc.k @@ -0,0 +1,25 @@ +/extra built-ins: abs, tan, acos, asin, atan, sinh, cosh, tanh, atan2, pow + +font:(0 0 0 0 0 0 0 0 0 0 0 0;0 0 8 8 8 8 8 0 8 8 0 0;0 20 20 20 0 0 0 0 0 0 0 0;0 0 20 20 62 20 20 62 20 20 0 0;0 0 8 28 42 40 28 10 42 28 8 0;0 0 18 42 20 4 8 10 21 18 0 0;0 0 8 20 20 8 26 36 36 26 0 0;0 8 8 8 0 0 0 0 0 0 0 0;0 0 4 8 16 16 16 16 8 4 0 0;0 0 16 8 4 4 4 4 8 16 0 0;0 0 0 0 20 8 62 8 20 0 0 0;0 0 0 0 8 8 62 8 8 0 0 0;0 0 0 0 0 0 0 0 8 8 16 0;0 0 0 0 0 0 62 0 0 0 0 0;0 0 0 0 0 0 0 0 8 8 0 0;0 0 2 2 4 4 8 8 16 16 0 0;0 0 28 34 38 42 50 34 34 28 0 0;0 0 8 24 8 8 8 8 8 28 0 0;0 0 28 34 34 2 4 8 16 62 0 0;0 0 28 34 2 12 2 2 34 28 0 0;0 0 2 6 10 18 34 62 2 2 0 0;0 0 62 32 32 60 2 2 34 28 0 0;0 0 28 32 32 60 34 34 34 28 0 0;0 0 62 2 2 4 4 8 8 8 0 0;0 0 28 34 34 28 34 34 34 28 0 0;0 0 28 34 34 34 30 2 2 28 0 0;0 0 0 0 8 8 0 0 8 8 0 0;0 0 0 0 8 8 0 0 8 8 16 0;0 0 0 2 4 8 16 8 4 2 0 0;0 0 0 0 62 0 0 62 0 0 0 0;0 0 0 16 8 4 2 4 8 16 0 0;0 0 28 34 34 4 8 0 8 8 0 0;0 0 28 34 38 42 42 38 32 30 0 0;0 0 28 34 34 34 62 34 34 34 0 0;0 0 60 34 34 60 34 34 34 60 0 0;0 0 28 34 32 32 32 32 34 28 0 0;0 0 56 36 34 34 34 34 36 56 0 0;0 0 62 32 32 60 32 32 32 62 0 0;0 0 62 32 32 60 32 32 32 32 0 0;0 0 28 34 32 32 46 34 34 28 0 0;0 0 34 34 34 62 34 34 34 34 0 0;0 0 28 8 8 8 8 8 8 28 0 0;0 0 14 4 4 4 4 36 36 24 0 0;0 0 34 36 40 48 48 40 36 34 0 0;0 0 32 32 32 32 32 32 32 62 0 0;0 0 34 54 42 42 34 34 34 34 0 0;0 0 34 34 50 42 38 34 34 34 0 0;0 0 28 34 34 34 34 34 34 28 0 0;0 0 60 34 34 34 60 32 32 32 0 0;0 0 28 34 34 34 34 34 42 28 2 0;0 0 60 34 34 34 60 40 36 34 0 0;0 0 28 34 32 28 2 2 34 28 0 0;0 0 62 8 8 8 8 8 8 8 0 0;0 0 34 34 34 34 34 34 34 28 0 0;0 0 34 34 34 20 20 20 8 8 0 0;0 0 34 34 34 34 42 42 54 34 0 0;0 0 34 34 20 8 8 20 34 34 0 0;0 0 34 34 20 20 8 8 8 8 0 0;0 0 62 2 4 8 16 32 32 62 0 0;0 0 28 16 16 16 16 16 16 28 0 0;0 0 16 16 8 8 4 4 2 2 0 0;0 0 28 4 4 4 4 4 4 28 0 0;0 8 20 34 0 0 0 0 0 0 0 0;0 0 0 0 0 0 0 0 0 0 62 0;16 8 0 0 0 0 0 0 0 0 0 0;0 0 0 0 28 2 30 34 34 30 0 0;0 0 32 32 60 34 34 34 34 60 0 0;0 0 0 0 28 34 32 32 34 28 0 0;0 0 2 2 30 34 34 34 34 30 0 0;0 0 0 0 28 34 62 32 32 30 0 0;0 0 6 8 28 8 8 8 8 8 0 0;0 0 0 0 30 34 34 34 34 30 2 28;0 0 32 32 60 34 34 34 34 34 0 0;0 8 8 0 24 8 8 8 8 28 0 0;0 2 2 0 6 2 2 2 2 2 18 12;0 0 16 16 18 20 24 24 20 18 0 0;0 0 24 8 8 8 8 8 8 28 0 0;0 0 0 0 60 42 42 42 42 42 0 0;0 0 0 0 60 34 34 34 34 34 0 0;0 0 0 0 28 34 34 34 34 28 0 0;0 0 0 0 60 34 34 34 34 60 32 32;0 0 0 0 30 34 34 34 34 30 2 2;0 0 0 0 46 48 32 32 32 32 0 0;0 0 0 0 30 32 28 2 2 60 0 0;0 0 8 8 28 8 8 8 8 6 0 0;0 0 0 0 34 34 34 34 34 30 0 0;0 0 0 0 34 34 20 20 8 8 0 0;0 0 0 0 34 34 42 42 42 28 0 0;0 0 0 0 34 20 8 8 20 34 0 0;0 0 0 0 34 34 34 34 34 30 2 28;0 0 0 0 62 4 8 16 32 62 0 0;0 0 6 8 8 16 8 8 8 6 0 0;0 0 8 8 8 8 8 8 8 8 0 0;0 0 24 4 4 2 4 4 4 24 0 0;0 18 42 36 0 0 0 0 0 0 0 0) + +/view a binary matrix using braille characters +binview:{`0:`c$10240+{2/0|x./:8 2#4\3700758592}''+0N 4#/:+0N 2#/:x,(4!#x)#,0;x} + +/plots given ydata, with implicit xdata:!#ydata. +plotn:{binview@+(|=x*4)@_.5+(-1+x*4)*w%|/w:y-&/y;y} +plot:plotn[3] /plotn with height of 3 lines + +/uses font to turn text into a binary matrix +bintext:{(,')/((6#2)\')'font{x*x<#font}0|x-32} + +randomdigit:{(,/("left ";"right "),\:/:((" "\"big second third fourth little"),\:" toe"),((,"thumb"),(" "\"index middle ring little"),\:" finger"))@x?20} + +horizon:{%:x*x+12742.016} /distance to horizon, standing x km high on earth + +apaper:{_.2+1000%2 pow .25*-1+2*x}'1 0+ /width and height of Ax paper (A4, etc) + +pi:3.14159265358979323846264338327950288419716939937510 +tau:2*pi +e:2.71828182845904523536028747135266249775724709369995 +phi:(1+%5)%2 +shikhin:1 diff --git a/timezone.py b/timezone.py new file mode 100644 index 0000000..4177057 --- /dev/null +++ b/timezone.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +import re +from subprocess import Popen, PIPE +import pickle +import pytz +from datetime import datetime +from sys import argv + +def cmd(*args): + proc = Popen(args, stdout=PIPE) + while True: + line = proc.stdout.readline() + if line: + try: + yield str(line[:-1], 'utf-8', 'ignore') + except: + pass + else: + break + +data_file = '/home/zgrep/offtopiabday/timezone-offtopia.pickle' + +def get_data(): + global data_file + with open(data_file, 'rb') as fh: + return pickle.load(fh) + +def save_data(data): + global data_file + with open(data_file, 'wb') as fh: + return pickle.dump(data, fh) + +def get_time(n): + nl = n.lower() + data = get_data() + if nl in data: + tz = data[nl] + return 'time(' + n + ') = ' + tz.fromutc(datetime.now()).strftime('%a, %Y-%m-%d %H:%M:%S %Z.') + return n + '.tz = undefined' + +def set_tz(n, s): + data = get_data() + nl = n.lower() + try: + tz = pytz.timezone(s) + except pytz.exceptions.UnknownTimeZoneError: + if s.lower() in ('none', 'false', 'delete', '', 'undefined'): + if nl in data: + del data[nl] + save_data(data) + return n + '.tz = undefined' + return n + '.tz = undefined' + return 'tz(' + s + ') = InvalidTimezone' + except: + return 'ERR: NaN IS A NUMBER.' + data[nl] = tz + save_data(data) + return n + '.tz = ' + s + '; ' + get_time(n) + +def main(): + if len(argv) == 3: + print(get_time(argv[2])) + exit() + + if len(argv) != 2: + print('Usage:', argv[0], '#channel') + exit(1) + + chan = '/home/zgrep/offtopiabday/irc.freenode.net/' + argv[1] + + for line in cmd('tail', '-n', '0', '-f', chan + '/out'): + date, time, nick, line = line.split(' ', 3) + nick = nick[1:-1] + if nick in ('happybot', 'hatebot', '!', '-!-'): + continue + m = re.match(r'(?:@?(?:happybot|hatebot)[:,]? )?tz ?= ?(.+)$', line) + if m: + reply = set_tz(nick, m.group(1)) + with open(chan + '/in', 'w') as fh: + fh.write(reply + '\n') + continue + for i, (r, o) in enumerate(( + (r'time\((\S+)\);?', True), + (r'\(time (\S+)\)', True), + (r'time\[(\S+)\];?', True), + (r'(\S+)\.time', True), + (r'time (\S+)', False)), + ): + m = r'@?(?:happy|hate)(bot)[:,]? ' + if o: m = r'(?:' + m + r')?' + m = re.match(m + r + r'$', line) + if m: break + if m: + reply = get_time(m.group(2)) + with open(chan + '/in', 'w') as fh: + fh.write(nick + ': ' + reply + '\n') + continue + +if __name__ == '__main__': + main()