僕が作った僕 Lispです
JavaScript 1.8 (Firefox 3) でしか動かないので注意してね><
var tokenize = function(source) source.match(/\"(?:[^"])*\"|\|[^\|]*\||(\)|\(|\s+|[^\(\)\s]+)/gm).filter(/^[^\s]/);
var parse = function(tokens) {
var list = [], token;
while ((token = tokens.shift()) && token != ')')
list.push((token == '(') ? parse(tokens) :
(token[0] == '"') ? token.substring(1, token.length - 1) :
(token.match(/^-?\d/)) ? eval(token) :
new Symbol(token));
return list;
};
var scope = function(proto) ({ __proto__: proto });
var Symbol = function(name) { this.name = name.match(/^\|/) ? name.substring(1, name.length - 1) : name };
Symbol.prototype.toString = function() this.name;
var SpecialForm = function(fn) { fn.special = true; return fn };
var ev = function(o, _) {
if (o instanceof Array) {
var [fn, args] = [ev(o[0], _), o.slice(1)]
return fn.apply(_, fn.special ? args : args.map(function(a) ev(a, _)));
}
else if (o instanceof Symbol) return _[o];
else return o
};
var define = new SpecialForm(function() {
var islambda = arguments[0] instanceof Array;
var symbol = islambda ? arguments[0][0] : arguments[0];
var value = islambda ?
lambda.apply(null, [arguments[0].slice(1)].concat(Array.slice(arguments, 1))) : arguments[1];
return this[symbol] = ev(value, this);
});
var jsspform = function(___source) new SpecialForm(function() {
with(this)
return (eval('(' + ___source + ')')).apply(this, arguments)
});
(define jslambda (jsspform "function(___source) {
var ___scope = this;
var ___fn = function() {
with(___scope)
return eval('(' + ___source + ')')
.apply(null, Array.map(arguments, function(a) ev(a, ___scope)));
};
return ___fn;
}"))
(define -> (jsspform "function(self, prop) {
var self = ev(self, this), prop = self[prop];
return (typeof prop == 'function') ?
function() { return prop.apply(self, arguments) } :
prop
}"))
(define if (jsspform "function(cond, t, f) ev(cond, this) ? ev(t, this) : ev(f, this)"))
(define set! (jsspform "function(symbol, value) {
var scp = this;
do {
// just hack
if (scp instanceof Window && scp.location === window.location) scp = window;
if (scp.hasOwnProperty(symbol.name)) {
scp[symbol] = ev(value, this);
return 0;
}
} while (scp = scp.__proto__);
}"))
(define lambda (jsspform "function() {
var args = Array.shift(arguments);
var exprs = arguments;
var pscope = this;
return function() {
var _ = scope(pscope);
for (var i = 0; i < args.length; i ++) _[args[i]] = arguments[i];
for (var i = 0; i < exprs.length; i++) var r = ev(exprs[i], _);
return r;
};
}"))
(define let (jsspform "function() {
var pairs = Array.shift(arguments), ps = [], vs = [];
pairs.forEach(function([p, v]) { ps.push(p); vs.push(v) });
Array.unshift(arguments, ps);
var list = [this.lambda.apply(null, arguments)].concat(vs);
return ev(list, this);
}"))
(define begin (jslambda "function() { return arguments[arguments.length - 1] }"))
(define + (jslambda "function() {
var result = arguments[0];
for (var i = 1; i < arguments.length; i ++) result += arguments[i];
return result
}"))
(define - (jslambda "function() {
var result = arguments[0];
for (var i = 1; i < arguments.length; i ++) result -= arguments[i];
return result
}"))
(define / (jslambda "function() {
var result = arguments[0];
for (var i = 1; i < arguments.length; i ++) result /= arguments[i];
return result
}"))
(define * (jslambda "function() {
var result = arguments[0];
for (var i = 1; i < arguments.length; i ++) result *= arguments[i];
return result
}"))
(define = (jslambda "function(a, b) a == b ? 1 : 0"))
(define < (jslambda "function(a, b) a < b ? 1 : 0"))
(define > (jslambda "function(a, b) a > b ? 1 : 0"))
(define expt (jslambda "function(a, b) Math.pow(a, b)"))
(define or (jslambda "function(a, b) a || b ? 1 : 0"))
(define and (jslambda "function(a, b) a && b ? 1 : 0"))
(define display (jslambda "function(a) {
document.getElementById('log').appendChild(document.createTextNode(a + '\n'));
return a;
}"))