KumiScript/interpreter/LispPrimitives.cs

256 lines
10 KiB
C#
Raw Normal View History

2024-01-26 05:37:51 +00:00
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<Expression> headl = head.GetMembers();
List<Symbol> arg_names = new List<Symbol>();
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<Expression> argl = args.GetMembers();
if (argl.Count != 1)
throw new InterpreterInvalidApplicationException();
return argl[0];
}
public static Expression Define(ListExpression args, Environment env)
{
List<Expression> 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<Expression> 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<Expression> 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<Expression> 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<Expression> 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();
2024-02-14 06:20:53 +00:00
if (antecedent.Eval(env) != NilExpression.GetInstance())
2024-01-26 05:37:51 +00:00
return consequent.Eval(env);
}
return NilExpression.GetInstance();
}
public static Expression Eq(ListExpression args, Environment env)
{
List<Expression> 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<Expression> 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;
}
2024-02-14 06:20:53 +00:00
public static Expression For(ListExpression args, Environment env)
{
List<Expression> 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<Expression> 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<Expression> 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<Expression> 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<Expression> 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<Expression> arg1l = arg1.GetMembers();
return n >= 0 && n < arg1l.Count ? arg1l[n] : NilExpression.GetInstance();
}
public static Expression While(ListExpression args, Environment env)
{
List<Expression> 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;
}
2024-01-26 05:37:51 +00:00
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)));
2024-02-14 06:20:53 +00:00
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)));
2024-01-26 05:37:51 +00:00
return result;
}
}
}