<script>
Array.prototype.toString = function(){ return "["+this.join(",")+"]"}
function eval(s,env){
	function getEnv(env,a) {
		if (env[a] != null) return env[a];
		if (env.parent == null) throw "error";
		return getEnv(env.parent, a);
	}
	function setEnv(env, a, v) {
		if (env[a] != null) return env[a] = v;
		if (env.parent == null) throw "error";
		return setEnv(env.parent, a, v);
	}
	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 "set": return setEnv(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);
		case "lambda": return s;
		}
		var data = null;
		if(s[0] instanceof Array && s[0][0] == "lambda") data = s[0];
		else data = getEnv(env, s[0]);
		if (data == null) return "error";
		if (data instanceof Array) {
			if (data[0] == "lambda") {
				var argv = data[1];// 引数リスト
				var newenv = {parent:env};
				for (var i = 0; i < argv.length; i++) newenv[argv[i]] = eval(s[i+1],env);
				return eval(data[2],newenv);
			} else return "error";
		}
	}
	if (typeof(s) == "string") return getEnv(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"]]));
alert(eval(["begin",["define","c",["lambda",["a","b"],["add","a","b"]]],["c",1,2]]));
alert(eval([["lambda",["a","b"],["add","a","b"]],1,2]));
</script>

書きかけ