A Clojure inspired Lisp-0 with automatic tail-call optimization (TCO), JavaScript interop, first class functions, lexical scope, let blocks, function closures, variadic functions, and JSON syntax.
for(_='n(|inz["q","K",qII`K@ z _val^"==5rea4,A$[i#t=RstrzgQJSON.Pt[GfunctionF=F(Eif(Dvar C){BCa=|tZ[0]Y.sliceX5tY)WW{ZX(1V.^ueUfacIelse.map,aX(1))("\\n").apply(]]r(ArrayaY[a[1return En,rB"]nu.as(F(nB);foCi.lengthG2],e)]\\nqtexta4 ,tY.onkeyup.is(}$qD"G1]=Object.c4te(< rows=9 cols=60>V),f=;F |n,t{DeBtt=0;n>i;i++B&5n#]BGn#+1=.prototypeX.call(e,i);b4k}Gn#=e#]}t}n)?nn,t)}):"Q5typeof n?n_t?Gn]:null[n]:n}F t{fo;;BD!t))|t;defWe[]=;letW{ee_)i%2&&(e[#-1=#]);R}{`W;.-2_a?=a[2]:f}.faY,aX(2))}doV,t-1);RGt-1]} ifWR?:G3];{fnW{CuEB,|,e,arguments))};R[,e,],u}Z,u=aY;D!t)uu;RtY,e=|,}}}}Athis)$.js=e^$.e^EnBn$)====r<"]r>n++r--r**r//r}$r(n)},b.znerHTML=\'qletIm@mzi",q+Km@MAL"defKfnIn"],qifKnI*KnI-Kn",1],1mapK`",[7,8,9.KMath@random"</ ></ >\',Rb.childrenEBU=tYU.splitn?PQify(Pparse(n)$)):""}).joz}()';g=/[-U-ZB-GP-R#$45^_@IKqz|]/.exec(_);)with(_.split(g))_=join(shift());eval(_)
Zm9yKF89J24ofGluelsicSIsIksiLHFJSWBLQCB6IF92YWxeIj09NXJlYTQsQSRbaSN0PVJzdHJ6Z1FKU09OLlB0W0dmdW5jdGlvbkY9RihFaWYoRHZhciBDKXtCQ2E9fHRaWzBdWS5zbGljZVg1dFkpV1d7WlgoMVYuXnVlVWZhY0kfZWxzZR4ubWFwHSxhWCgxKSkcKCJcXG4iKRsuYXBwbHkoGl1dGXIoGEFycmF5F2FZW2FbMRkWcmV0dXJuIBVFbixyQhUUIl0UbhN1LmFzEh0oRihuQhURKTtmbxhDaRAubGVuZ3RoD0cyXQ4sZSkMGV1cXG5xC3RleHRhNAksdFkub25rZXl1cAgXLmlzFygHfSRxBkQiBUcxXQQ9T2JqZWN0LmM0dGUoAzwJIHJvd3M9OSBjb2xzPTYwPgJWKQwsZj0WOxUBRiB8bix0DHtEZUJ0A3QQPTA7bg8+aTtpKytCBSY1biNdQkduIysxGT0XLnByb3RvdHlwZVguY2FsbChlLGkpO2I0a31HbiMZPWUjXX0VdH0VB24pP24RGG4sdCl9KToiUTV0eXBlb2Ygbj9uX3Q/R25dOm51bGxbbl06bn1GIBh0DHtmbxg7O0JEIQd0KSkVfHQMOwVkZWZXFWVbBF09GA4MOwVsZXRXe2UDZRBfBClpJTImJihlWwQjLTEZPRgEI10MKTtSDn0eewVgVxUEOwUuLQEyX2E/Fj1hWzJdOmZ9BS4BZhphWSxhWCgyKSl9BWRvVix0Dy0xKQw7Ukd0Dy0xXX0eIAVpZldSGAQMPw46RzNdOx57BWZuV3tDdUVCFRgOLHwELGUsYXJndW1lbnRzKSl9OxUSUlsOLGUsBF0sdX1aDCx1PWFZO0QhEnQpFXUadRw7UhJ0WSxlPXwSDiwSBBx9fX19QQN0aGlzKSQuanM9ZV4kLmVeRW5CFRhuJCkGPRM9PT1yBjwiXRRyPm4GKxMrcgYtEy1yBioTKnIGLxMvcn0kHRRyHShuKX0sYi56bmVySFRNTD1cJwJxbGV0SW1AbXppIhkscStLbUBNQUwiC2RlZksfZm5JbiJdLHFpZktuSSpLbkkfLUtuIiwxGV0sMQttYXBLH2AiLFs3LDgsOQsuS01hdGhAcmFuZG9tIhk8Lwk+AjwvCT5cJyxSYi5jaGlsZHJlbghFQgRVPXRZVS5zcGxpdBsRbj9QUWlmeSgYUHBhcnNlKG4pJCkpOiIifSkuam96G30IKCknO2c9L1sBLR9VLVpCLUdQLVIjJDQ1Xl9ASUtxenxdLy5leGVjKF8pOyl3aXRoKF8uc3BsaXQoZykpXz1qb2luKHNoaWZ0KCkpO2V2YWwoXykK
// miniMAL
// Copyright (C) 2014 Joel Martin
// Licensed under MPL 2.0
// 2 args: eval_ast, 3 args: env_bind
function eval_ast_or_bind(ast, env, exprs) {
if (exprs) {
// Return new Env with symbols in ast bound to
// corresponding values in exprs
env = Object.create(env);
for (var i=0; i<ast.length; i++) {
if (ast[i] == "&") {
// variable length arguments
env[ast[i+1]] = Array.prototype.slice.call(exprs, i);
break;
} else {
env[ast[i]] = exprs[i];
}
}
return env;
}
// Evaluate the form/ast
return Array.isArray(ast) // list?
? ast.map(function(e){return EVAL(e, env);}) // list
: (typeof ast == "string") // symbol?
? ast in env // symbol in env?
? env[ast] // lookup symbol
: null[ast] // undefined symbol
: ast; // ast unchanged
}
function EVAL(ast, env) {
while (true) {
//console.log("EVAL:", ast);
if (!Array.isArray(ast)) return eval_ast_or_bind(ast, env);
// apply
if (ast[0] == "def") { // update current environment
return env[ast[1]] = EVAL(ast[2], env);
} else if (ast[0] == "let") { // new environment with bindings
env = Object.create(env);
for (var i in ast[1]) {
if (i%2) {
env[ast[1][i-1]] = EVAL(ast[1][i], env);
}
}
ast = ast[2]; // TCO
} else if (ast[0] == "`") { // quote (unevaluated)
return ast[1];
} else if (ast[0] == ".-") { // get or set attribute
var el = eval_ast_or_bind(ast.slice(1), env);
var x = el[0][el[1]];
return 2 in el ? el[0][el[1]] = el[2] : x;
} else if (ast[0] == ".") { // call object method
var el = eval_ast_or_bind(ast.slice(1), env);
var x = el[0][el[1]];
return x.apply(el[0], el.slice(2));
} else if (ast[0] == "do") { // multiple forms (for side-effects)
var el = eval_ast_or_bind(ast.slice(1,ast.length-1), env);
ast = ast[ast.length-1]; // TCO
} else if (ast[0] == "if") { // branching conditional
ast = EVAL(ast[1], env) ? ast[2] : ast[3]; // TCO
} else if (ast[0] == "fn") { // define new function (lambda)
var f = function() {
return EVAL(ast[2], eval_ast_or_bind(ast[1], env, arguments));
}
f.ast = [ast[2], env, ast[1]]; // f.ast compresses more than f.data
return f;
} else { // invoke list form
var el = eval_ast_or_bind(ast, env);
var f = el[0];
if (f.ast) {
ast = f.ast[0];
env = eval_ast_or_bind(f.ast[2], f.ast[1], el.slice(1)); // TCO
} else {
return f.apply(f, el.slice(1))
}
}
}
}
E = Object.create(this);
E["js"] = eval;
E["eval"] = function(a) { return EVAL(a, E); }
// These could all also be interop
E["="] = function(a,b) { return a===b; }
E["<"] = function(a,b) { return a<b; }
E["+"] = function(a,b) { return a+b; }
E["-"] = function(a,b) { return a-b; }
E["*"] = function(a,b) { return a*b; }
E["/"] = function(a,b) { return a/b; }
///E["isa"] = function(a,b) { return a instanceof b; }
///E["type"] = function(a) { return typeof a; }
///E["new"] = function(a) { return new (a.bind.apply(a, arguments)); }
///E["list"] = function(a,b) { return Array.prototype.slice.call(arguments); }
E["map"] = function(a,b) { return b.map(a); }
///E["throw"] = function(a) { throw(a); }
///E["del"] = function(a,b) { return delete a[b]; }
///E["read-string"] = function(a) { return JSON.parse(a); }
///E["slurp"] = function(a) { return require('fs').readFileSync(a,'utf-8'); }
///E["load-file"] = function(a) { return EVAL(JSON.parse(E["slurp"](a)),E); }
// Web specific
b.innerHTML = '<textarea rows=9 cols=60>["let",["m",["`","mini"]],["+","m",["`","MAL"]]]\n["def","fac",["fn",["n"],["if","n",["*","n",["fac",["-","n",1]]],1]]]\n["map","fac",["`",[7,8,9]]]\n[".","Math",["`","random"]]</textarea><textarea rows=9 cols=60></textarea>';
//b.innerHTML = '<textarea rows=9 cols=60>["let",["m",["`","mini"]],["+","m",["`","MAL"]]]\n["def","fac",["fn",["n"],["if","n",["*","n",["fac",["-","n",1]]],1]]]\n["map","fac",["`",[7,8,9]]]\n[".-", [".-",[".-","t",1],["`","style"]],["`","color"],["`","red"]]</textarea><textarea rows=9 cols=60></textarea>';
t = b.children;
t[0].onkeyup = function(){
t[1].value = t[0].value.split('\n').map(function(a) {
return a ? JSON.stringify(EVAL(JSON.parse(a),E)):'';
}).join('\n');
};
t[0].onkeyup();