namespace KumiScript.Interpreter { public class LispPrimitives { public static Expression Lambda(ListExpression args, Environment env) { Expression car = args.Car(); ListExpression rest = args.Cdr(); ListExpression? head = car as ListExpression; if (head is null) throw new InterpreterInvalidDefinitionException(); List headl = head.GetMembers(); List arg_names = new List(); for (int i = 0; i < headl.Count; i++) { SymbolExpression? argi = headl[i] as SymbolExpression; if (argi is null) throw new InterpreterInvalidDefinitionException(); arg_names.Add(argi.GetSymbol()); } Expression body = rest.Car(); return new ProcedureExpression(new LispProcedure(arg_names, body, env)); } public static Expression Quote(ListExpression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); return argl[0]; } public static Expression Define(ListExpression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); SymbolExpression? binding = argl[0] as SymbolExpression; if (binding is null) throw new InterpreterTypingException(); Symbol name = binding.GetSymbol(); Expression definition = argl[1].Eval(env); env.AddSymbol(name, definition); return definition; } public static Expression Car(ListExpression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); ListExpression? list = argl[0] as ListExpression; if (list is null) throw new InterpreterTypingException(); return list.Car(); } public static ListExpression Cdr(ListExpression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); ListExpression? list = argl[0] as ListExpression; if (list is null) throw new InterpreterTypingException(); return list.Cdr(); } public static ProperListExpression Cons(ListExpression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); Expression car = argl[0]; ListExpression? cdr = argl[1] as ListExpression; if (cdr is null) throw new InterpreterTypingException(); return cdr.Cons(car); } public static Expression Quit(ListExpression args, Environment env) { System.Environment.Exit(0); return new SymbolExpression(new Symbol("bye")); } public static Expression Cond(ListExpression args, Environment env) { List argl = args.GetMembers(); for (int i = 0; i < argl.Count; i ++) { ProperListExpression? conditional = argl[i] as ProperListExpression; if (conditional is null) throw new InterpreterTypingException(); 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(ListExpression 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(ListExpression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); SymbolExpression? binding = argl[0] as SymbolExpression; if (binding is null) throw new InterpreterTypingException(); Symbol name = binding.GetSymbol(); Expression definition = argl[1].Eval(env); env.RedefineSymbol(name, definition); return definition; } public static Expression For(ListExpression 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(ListExpression 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(ListExpression 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(ListExpression 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(ListExpression args, Environment env) { List argl = args.EvalMembers(env); if (argl.Count != 2) throw new InterpreterInvalidApplicationException(); IntegerExpression? arg0 = argl[0] as IntegerExpression; if (arg0 is null) throw new InterpreterTypingException(); ListExpression? arg1 = argl[1] as ListExpression; if (arg1 is null) throw new InterpreterTypingException(); int n = arg0.GetValueAsInt(); List arg1l = arg1.GetMembers(); return n >= 0 && n < arg1l.Count ? arg1l[n] : NilExpression.GetInstance(); } public static Expression While(ListExpression 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(new Symbol("lambda"), new ProcedureExpression(new PrimitiveProcedure(Lambda))); result.AddSymbol(new Symbol("quote"), new ProcedureExpression(new PrimitiveProcedure(Quote))); result.AddSymbol(new Symbol("define"), new ProcedureExpression(new PrimitiveProcedure(Define))); result.AddSymbol(new Symbol("car"), new ProcedureExpression(new PrimitiveProcedure(Car))); result.AddSymbol(new Symbol("cdr"), new ProcedureExpression(new PrimitiveProcedure(Cdr))); result.AddSymbol(new Symbol("cons"), new ProcedureExpression(new PrimitiveProcedure(Cons))); result.AddSymbol(new Symbol("quit"), new ProcedureExpression(new PrimitiveProcedure(Quit))); result.AddSymbol(new Symbol("cond"), new ProcedureExpression(new PrimitiveProcedure(Cond))); result.AddSymbol(new Symbol("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq))); result.AddSymbol(new Symbol("set!"), new ProcedureExpression(new PrimitiveProcedure(Set))); result.AddSymbol(new Symbol("for"), new ProcedureExpression(new PrimitiveProcedure(For))); result.AddSymbol(new Symbol("progn"), new ProcedureExpression(new PrimitiveProcedure(Progn))); result.AddSymbol(new Symbol("not"), new ProcedureExpression(new PrimitiveProcedure(Not))); result.AddSymbol(new Symbol("prog1"), new ProcedureExpression(new PrimitiveProcedure(Prog1))); result.AddSymbol(new Symbol("nth"), new ProcedureExpression(new PrimitiveProcedure(Nth))); result.AddSymbol(new Symbol("while"), new ProcedureExpression(new PrimitiveProcedure(While))); return result; } } }