継続インタプリタ

やっぱり、継続をまちがえてたので修正した。
まだ間違えているかもしれない。

<html>
<script>
Array.prototype.toString = function(){ return "["+this.join(",")+"]"}
Object.prototype.toString = function(){ var a = []; for(var i in this) a.push(i+":"+this[i]); return "{"+a.join(",")+"}"}
function jeval(s, env, k) {
	if (k == null) k = function(u){return u;}
	if (env == null) env = {};
	function getEnv(env, a) {
		if (env[a] != null) return env[a];
		if (env.parent == null) throw "error not get value " + a;
		return getEnv(env.parent, a);
	}
	function setEnv(env, a, v) {
		if (env[a] != null) return env[a] = v;
		if (env.parent == null) throw "error not set value " + a;
		return setEnv(env.parent, a, v);
	}
	function begin(n,env){
		return jeval(s[n], env, function(u){
			if (n >= s.length-1) return k(u)
			return begin(n+1,env)
		})
	}
	function apply(lambda, newenv, s, i) {
		if (i == lambda[1].length) return jeval(lambda[2],newenv,k)
		else                       return jeval(s[i+1], env, function(v){ newenv[lambda[1][i]]=v; return apply(lambda,newenv,s,i+1)})
	}
	if (s instanceof Array) {
		switch (s[0]) {
		case "add":    return jeval(s[1],env,function(u){return jeval(s[2],env,function(v){return k(u+v)})})
		case "mul":    return jeval(s[1],env,function(u){return jeval(s[2],env,function(v){return k(u*v)})})
		case "cont":   return ["#cont",s[1], env,k]
		case "list":   return k(s[1])
		case "callCC": var cont = ["#cont",null,env,function(v){return k(cont[4])},null];
			           return jeval([s[1], ["list",cont]], env, k)
		case "#cont":  return jeval(s[1],s[2],s[3])
		case "define": return jeval(s[2],env,function(u){return k(env[s[1]] = u)})
		case "set!":   return jeval(s[2],env,function(u){return k(setEnv(env, s[1], u))})
		case "begin":  return begin(1,env)
		case "lambda": return k(["#closure", s, {parent:env}])
		case "alert":  return jeval(s[1], env, function(v){alert(v); return k(v)})
		case "display": return jeval(s[1], env, function(v){log(v); return k(v)})
		}
		return jeval(s[0], env, function(data){
			if (data instanceof Array && data[0] == "#closure") return apply(data[1], data[2], s, 0)
			if (data instanceof Array && data[0] == "#cont")    { data[4]=s[1];return jeval(data,env,k)}
			return k(data)
		})
	}
	if (typeof(s) == "string") return k(getEnv(env, s))
	return k(s)
}
var env = {};
function log(s){ document.getElementById("output").value = (s+"\n")+document.getElementById("output").value; return s }
function run() {
	try{
		log(jeval(eval(document.getElementById("input").value),env))
	}catch(e){log(e)}
}
</script>
<body>
<h3>継続つきJSON Lisp</h3>
<form>
<textarea id="input" cols=80 rows=5>
["begin",
	["define","s",0],
	["add",100,["callCC",["lambda",["cc"],["begin",["set!","s","cc"],3]]]]
	]
</textarea><input type="button" value="実行" onclick="run()"><br>
<textarea id="output" cols=80 rows=25></textarea>
</form>
</body>
</html>