using KumiScript.Reader; namespace KumiScript.Interpreter { public class LispPrimitives { public static Expression Lambda(Expression args, Environment env) { Expression car = args.Car(); Expression rest = args.Cdr(); List headl = car.GetMembers(); List arg_names = new List(); for (int i = 0; i < headl.Count; i++) { arg_names.Add(headl[i].GetSymbol()); } Expression body = rest.Car(); return new ProcedureExpression(new LispProcedure(arg_names, body, env)); } public static Expression Quote(Expression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); return argl[0]; } public static Expression Define(Expression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); Expression? binding = argl[0]; Symbol name = binding.GetSymbol(); Expression definition = argl[1].Eval(env); env.AddSymbol(name, definition); return definition; } public static Expression Car(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); return argl[0].Car(); } public static Expression Cdr(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); return argl[0].Cdr(); } public static ProperListExpression Cons(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); Expression car = argl[0]; Expression cdr = argl[1]; return cdr.Cons(car); } public static Expression Quit(Expression args, Environment env) { System.Environment.Exit(0); return new SymbolExpression(new Symbol("bye")); } public static Expression Cond(Expression args, Environment env) { List argl = args.GetMembers(); for (int i = 0; i < argl.Count; i ++) { Expression conditional = argl[i]; Expression antecedent = conditional.Car(); Expression consequent = conditional.Cdr().Car(); if (antecedent.Eval(env) != NilExpression.GetInstance()) return consequent.Eval(env); } return NilExpression.GetInstance(); } public static Expression Eq(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); if (argl[0].Equals(argl[1])) return TrueExpression.GetInstance(); return NilExpression.GetInstance(); } public static Expression Set(Expression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); Symbol name = argl[0].GetSymbol(); Expression definition = argl[1].Eval(env); env.RedefineSymbol(name, definition); return definition; } public static Expression For(Expression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 4) throw new InterpreterInvalidApplicationException(); Expression init = argl[0]; Expression cond = argl[1]; Expression step = argl[2]; Expression body = argl[3]; Expression result = NilExpression.GetInstance(); Environment inner = new Environment(env); for (init.Eval(inner); cond.Eval(inner) != NilExpression.GetInstance(); step.Eval(inner)) result = body.Eval(inner); return result; } public static Expression Progn(Expression args, Environment env) { List argl = args.GetMembers(); Expression result = NilExpression.GetInstance(); foreach (Expression expr in argl) result = expr.Eval(env); return result; } public static Expression Prog1(Expression args, Environment env) { List argl = args.GetMembers(); Expression result = argl.Count > 0 ? argl[0] : NilExpression.GetInstance(); foreach (Expression expr in argl) expr.Eval(env); return result; } public static Expression Not(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); return argl[0] != NilExpression.GetInstance() ? NilExpression.GetInstance() : TrueExpression.GetInstance(); } public static Expression Nth(Expression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); int n = (int) argl[0].GetValueAsFloat(); List arg1l = argl[1].GetMembers(); return n >= 0 && n < arg1l.Count ? arg1l[n] : NilExpression.GetInstance(); } public static Expression While(Expression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); Expression cond = argl[0]; Expression body = argl[1]; Expression result = NilExpression.GetInstance(); Environment inner = new Environment(env); while (cond.Eval(inner) != NilExpression.GetInstance()) result = body.Eval(inner); return result; } public static Environment RegisterPrimitives() { Environment result = new Environment(); result.AddSymbol(SymbolTable.GetInstance().FromString("lambda"), new ProcedureExpression(new PrimitiveProcedure(Lambda))); result.AddSymbol(SymbolTable.GetInstance().FromString("quote"), new ProcedureExpression(new PrimitiveProcedure(Quote))); result.AddSymbol(SymbolTable.GetInstance().FromString("define"), new ProcedureExpression(new PrimitiveProcedure(Define))); result.AddSymbol(SymbolTable.GetInstance().FromString("car"), new ProcedureExpression(new PrimitiveProcedure(Car))); result.AddSymbol(SymbolTable.GetInstance().FromString("cdr"), new ProcedureExpression(new PrimitiveProcedure(Cdr))); result.AddSymbol(SymbolTable.GetInstance().FromString("cons"), new ProcedureExpression(new PrimitiveProcedure(Cons))); result.AddSymbol(SymbolTable.GetInstance().FromString("quit"), new ProcedureExpression(new PrimitiveProcedure(Quit))); result.AddSymbol(SymbolTable.GetInstance().FromString("cond"), new ProcedureExpression(new PrimitiveProcedure(Cond))); result.AddSymbol(SymbolTable.GetInstance().FromString("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq))); result.AddSymbol(SymbolTable.GetInstance().FromString("set!"), new ProcedureExpression(new PrimitiveProcedure(Set))); result.AddSymbol(SymbolTable.GetInstance().FromString("for"), new ProcedureExpression(new PrimitiveProcedure(For))); result.AddSymbol(SymbolTable.GetInstance().FromString("progn"), new ProcedureExpression(new PrimitiveProcedure(Progn))); result.AddSymbol(SymbolTable.GetInstance().FromString("not"), new ProcedureExpression(new PrimitiveProcedure(Not))); result.AddSymbol(SymbolTable.GetInstance().FromString("prog1"), new ProcedureExpression(new PrimitiveProcedure(Prog1))); result.AddSymbol(SymbolTable.GetInstance().FromString("nth"), new ProcedureExpression(new PrimitiveProcedure(Nth))); result.AddSymbol(SymbolTable.GetInstance().FromString("while"), new ProcedureExpression(new PrimitiveProcedure(While))); return result; } } }