// eval static MalVal EVAL(MalVal orig_ast, Dictionary <string, MalVal> env) { MalVal a0; // Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true)); if (orig_ast is MalSymbol) { MalSymbol sym = (MalSymbol)orig_ast; return((MalVal)env[sym.getName()]); } else if (orig_ast is MalVector) { MalVector old_lst = (MalVector)orig_ast; MalVector new_lst = new MalVector(); foreach (MalVal mv in old_lst.getValue()) { new_lst.conj_BANG(EVAL(mv, env)); } return(new_lst); } else if (orig_ast is MalHashMap) { var new_dict = new Dictionary <string, MalVal>(); foreach (var entry in ((MalHashMap)orig_ast).getValue()) { new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env)); } return(new MalHashMap(new_dict)); } else if (!(orig_ast is MalList)) { return(orig_ast); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return(ast); } a0 = ast[0]; if (!(a0 is MalSymbol)) { throw new Mal.types.MalError("attempt to apply on non-symbol '" + Mal.printer._pr_str(a0, true) + "'"); } MalFunc f = (MalFunc)EVAL(ast[0], env); MalList arguments = new MalList(); foreach (MalVal mv in ast.rest().getValue()) { arguments.conj_BANG(EVAL(mv, env)); } return(f.apply(arguments)); }
public static MalVal macroexpand(MalVal ast, Env env) { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast)[0]; MalFunc mac = (MalFunc)env.get(a0); ast = mac.apply(((MalList)ast).rest()); } return(ast); }
static MalVal EVAL(MalVal orig_ast, Env env) { MalVal a0, a1, a2, res; while (true) { MalVal dbgeval = env.get("DEBUG-EVAL"); if (dbgeval != null && dbgeval != Mal.types.Nil && dbgeval != Mal.types.False) { Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true)); } if (orig_ast is MalSymbol) { string key = ((MalSymbol)orig_ast).getName(); res = env.get(key); if (res == null) { throw new Mal.types.MalException("'" + key + "' not found"); } return(res); } else if (orig_ast is MalVector) { MalVector old_lst = (MalVector)orig_ast; MalVector new_lst = new MalVector(); foreach (MalVal mv in old_lst.getValue()) { new_lst.conj_BANG(EVAL(mv, env)); } return(new_lst); } else if (orig_ast is MalHashMap) { var new_dict = new Dictionary <string, MalVal>(); foreach (var entry in ((MalHashMap)orig_ast).getValue()) { new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env)); } return(new MalHashMap(new_dict)); } else if (!(orig_ast is MalList)) { return(orig_ast); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return(ast); } a0 = ast[0]; String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { case "def!": a1 = ast[1]; a2 = ast[2]; res = EVAL(a2, env); env.set((MalSymbol)a1, res); return(res); case "let*": a1 = ast[1]; a2 = ast[2]; MalSymbol key; MalVal val; Env let_env = new Env(env); for (int i = 0; i < ((MalList)a1).size(); i += 2) { key = (MalSymbol)((MalList)a1)[i]; val = ((MalList)a1)[i + 1]; let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; break; case "quote": return(ast[1]); case "quasiquote": orig_ast = quasiquote(ast[1]); break; case "do": foreach (MalVal mv in ast.slice(1, ast.size() - 1).getValue()) { EVAL(mv, env); } orig_ast = ast[ast.size() - 1]; break; case "if": a1 = ast[1]; MalVal cond = EVAL(a1, env); if (cond == Mal.types.Nil || cond == Mal.types.False) { // eval false slot form if (ast.size() > 3) { orig_ast = ast[3]; } else { return(Mal.types.Nil); } } else { // eval true slot form orig_ast = ast[2]; } break; case "fn*": MalList a1f = (MalList)ast[1]; MalVal a2f = ast[2]; Env cur_env = env; return(new MalFunc(a2f, env, a1f, args => EVAL(a2f, new Env(cur_env, a1f, args)))); default: MalFunc f = (MalFunc)EVAL(ast[0], env); MalList arguments = new MalList(); foreach (MalVal mv in ast.rest().getValue()) { arguments.conj_BANG(EVAL(mv, env)); } MalVal fnast = f.getAst(); if (fnast != null) { orig_ast = fnast; env = f.genEnv(arguments); } else { return(f.apply(arguments)); } break; } } }
// eval static MalVal EVAL(MalVal orig_ast, Env env) { MalVal a0, a1, a2, res; MalVal dbgeval = env.get("DEBUG-EVAL"); if (dbgeval != null && dbgeval != Mal.types.Nil && dbgeval != Mal.types.False) { Console.WriteLine("EVAL: " + printer._pr_str(orig_ast, true)); } if (orig_ast is MalSymbol) { string key = ((MalSymbol)orig_ast).getName(); res = env.get(key); if (res == null) { throw new Mal.types.MalException("'" + key + "' not found"); } return(res); } else if (orig_ast is MalVector) { MalVector old_lst = (MalVector)orig_ast; MalVector new_lst = new MalVector(); foreach (MalVal mv in old_lst.getValue()) { new_lst.conj_BANG(EVAL(mv, env)); } return(new_lst); } else if (orig_ast is MalHashMap) { var new_dict = new Dictionary <string, MalVal>(); foreach (var entry in ((MalHashMap)orig_ast).getValue()) { new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env)); } return(new MalHashMap(new_dict)); } else if (!(orig_ast is MalList)) { return(orig_ast); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return(ast); } a0 = ast[0]; if (!(a0 is MalSymbol)) { throw new Mal.types.MalError("attempt to apply on non-symbol '" + Mal.printer._pr_str(a0, true) + "'"); } switch (((MalSymbol)a0).getName()) { case "def!": a1 = ast[1]; a2 = ast[2]; res = EVAL(a2, env); env.set((MalSymbol)a1, res); return(res); case "let*": a1 = ast[1]; a2 = ast[2]; MalSymbol key; MalVal val; Env let_env = new Env(env); for (int i = 0; i < ((MalList)a1).size(); i += 2) { key = (MalSymbol)((MalList)a1)[i]; val = ((MalList)a1)[i + 1]; let_env.set(key, EVAL(val, let_env)); } return(EVAL(a2, let_env)); default: MalFunc f = (MalFunc)EVAL(ast[0], env); MalList arguments = new MalList(); foreach (MalVal mv in ast.rest().getValue()) { arguments.conj_BANG(EVAL(mv, env)); } return(f.apply(arguments)); } }