すきJSとよみます
throwとかうんこすぎるのでやめたい
var ScheJS = { }; with (ScheJS) { new function() { ScheJS.eval = function(string) { ScheJS.buffer = string; var context = { }; initContext.call(context); try { while (1) var value = evalExpression.call(context, read()); } catch (e) { return value; } } ScheJS.evalExpression = function(expr) { if (expr instanceof Array) { var evalee = evalExpression.call(this, expr[0]); var args = expr.slice(1); if (!evalee.isSpecialForm) args = args.map(evalExpression, this); return evalee.apply(this, args); } else { switch (true) { case expr in this: return this[expr]; case !isNaN(Number(expr)): return Number(expr); } } } ScheJS.initContext = function() { for (var n in SPECIAL_FORMS) { this[n] = SPECIAL_FORMS[n]; this[n].isSpecialForm = true; } for (var n in DEFINITIONS){ this[n] = DEFINITIONS[n]; } } ScheJS.SPECIAL_FORMS = { 'lambda': function(args) { var body = Array.slice(arguments, 1); return function() { var context = { }; for (var i = 0; i < args.length; i++) context[args[i]] = arguments[i]; context.__proto__ = this; return body.map(evalExpression, context)[body.length - 1]; } }, 'define': function(name, expr) { this[name] = evalExpression.call(this, expr); }, 'define-macro': function(name, expr) { this[name] = evalExpression.call(this, expr); this[name].isSpecialForm = true; } } ScheJS.DEFINITIONS = { cons: function(car, cdr) { return { car: car, cdr: cdr, toString: function() { return '(' + this.car + ' . ' + this.cdr + ')' } }; }, car: function(val) { if (val instanceof Array) return val[0]; else return val.car; }, cdr: function(val) { if (val instanceof Array) return val.slice(1); else return val.cdr; }, alert: function(val) { alert(val); } } ScheJS.read = function(string) { if (string) ScheJS.buffer = string; return readExpression(); } ScheJS.readExpression = function() { eat(); switch (true) { case eat('('): var expr = []; try { while (1) expr.push(readExpression()); } catch (e) { } return expr; case eat('[^()\\s]+'): return RegExp.$1; case eat(')'): default: throw 'End of S-Expression'; } } function eat(pattern) { var regexp = new RegExp('^(' + (pattern || '').replace(/[()]/g, '\\$&') + ')\\s*'); if (buffer.match(regexp)) { buffer = RegExp.rightContext; return true; } else { return false; } } } }