継続付きインタプリタ(2)

今日は変数を定義して読み込んだり出来るように拡張します。
そのために、環境を導入します。

function eval(s){
	if (s instanceof Array) {
		switch(s[0]){
		case "add": return eval(s[1]) + eval(s[2]);
		case "mul": return eval(s[1]) * eval(s[2]);
		}
	}
	return s;
}

これに、変数の保存、読み込み、処理の列挙ができる機能をつけます。

<script>
Array.prototype.toString = function(){ return "{"+this.join(",")+"}"}
function eval(s,env){
	if (env == null) env = {};
	if (s instanceof Array) {
		switch(s[0]){
		case "add": return eval(s[1],env) + eval(s[2],env);
		case "mul": return eval(s[1],env) * eval(s[2],env);
		case "define": return env[s[1]] = eval(s[2],env);
		case "begin":
			var a = s.reverse();a.pop();
			var rc = eval(a.pop(),env);
			if (a.length == 0) return rc;
			a.push("begin");
			return eval(a.reverse(),env);
		}
	}
	if (typeof(s) == "string") return env[s];
	return s;
}
var env = {};
//alert(eval(["define","a",["add",["mul",2,3],2]],env));
//alert(eval("a",env));
alert(eval(["begin",["define","a",["add",1,2]],["define","b",["add",1,2]],["add","a","b"]]));
</script>

ってかんじです。
これを継続渡し形式にして継続の機能をつけると以下のようになります。

<script>
Array.prototype.toString = function(){return "["+this.join(",")+"]"}
function log(s){document.write(s+"<br>");}
function eval(s,env,k){
	log(s);
	if (k == null) k = function(u){return u}
	if (env == null) env = {}
	if (s instanceof Array) {
		switch(s[0]){
		case "add": return eval(s[1],env,function(u){return eval(s[2],env,function(v){return k(u+v)})})
		case "mul": return eval(s[1],env,function(u){return eval(s[2],env,function(v){return k(u*v)})})
		case "cont": return ["#cont",s[1], env,k]
		case "#cont": return eval(s[1],s[2],s[3])
		case "define": return eval(s[2],env,function(u){return k(env[s[1]] = u);});
		case "begin":
			var a = s.reverse();a.pop();
			return eval(a.pop(),env,function(u) {
				if (a.length == 0) return k(u);
				return eval(a.concat("begin").reverse(),env,function(v){return k(v)});
			});
		}
	}
	if (typeof(s) == "string") return k(env[s]);
	return k(s);
}
var env = {};
alert(eval(["add",1,2],env));
alert(eval(["define","a",555],env));
alert(env["a"]);
alert(eval(["begin",["define","a",["add",1,2]],["define","b",2],["mul","a","b"]]));
c = eval(["begin",["define","a",["add",1,2]],["cont"],["define","b",2],["cont"],["mul","a","b"]]);
alert(c);
alert(c2=eval(c));
alert(eval(c2));
alert(c2=eval(c));
alert(eval(c2));
alert(c2=eval(c));
alert(eval(c2));
</script>

これで、より継続っぽくなってきました。