267 lines
10 KiB
C#
267 lines
10 KiB
C#
|
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 NumberExpression Plus(ListExpression args, Environment env)
|
||
|
{
|
||
|
List<Expression> argl = args.EvalMembers(env);
|
||
|
decimal acc = 0;
|
||
|
for (int i = 0; i < argl.Count; i++)
|
||
|
{
|
||
|
NumberExpression? argin = argl[i] as NumberExpression;
|
||
|
if (argin is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
acc += argin.GetValueAsFloat();
|
||
|
}
|
||
|
|
||
|
return NumberFactory.NormalizeFloat(acc);
|
||
|
}
|
||
|
|
||
|
public static NumberExpression Minus(ListExpression args, Environment env)
|
||
|
{
|
||
|
List<Expression> argl = args.EvalMembers(env);
|
||
|
if (argl.Count == 0)
|
||
|
throw new InterpreterInvalidApplicationException();
|
||
|
|
||
|
NumberExpression? argn0 = argl[0] as NumberExpression;
|
||
|
if (argn0 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
decimal acc = argn0.GetValueAsFloat();
|
||
|
if (argl.Count == 1)
|
||
|
return NumberFactory.NormalizeFloat(1 - acc);
|
||
|
|
||
|
for (int i = 1; i < argl.Count; i++)
|
||
|
{
|
||
|
NumberExpression? argin = argl[i] as NumberExpression;
|
||
|
if (argin is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
acc -= argin.GetValueAsFloat();
|
||
|
}
|
||
|
return NumberFactory.NormalizeFloat(acc);
|
||
|
}
|
||
|
|
||
|
public static NumberExpression Times(ListExpression args, Environment env)
|
||
|
{
|
||
|
List<Expression> argl = args.EvalMembers(env);
|
||
|
if (argl.Count < 2)
|
||
|
throw new InterpreterInvalidInvocationException();
|
||
|
|
||
|
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||
|
if (arg0 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
decimal f = arg0.GetValueAsFloat();
|
||
|
for (int i = 1; i < argl.Count; i++)
|
||
|
{
|
||
|
NumberExpression? argn = argl[i] as NumberExpression;
|
||
|
if (argn is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
f *= argn.GetValueAsFloat();
|
||
|
}
|
||
|
return NumberFactory.NormalizeFloat(f);
|
||
|
}
|
||
|
|
||
|
public static NumberExpression DividedBy(ListExpression args, Environment env)
|
||
|
{
|
||
|
List<Expression> argl = args.EvalMembers(env);
|
||
|
if (argl.Count != 2)
|
||
|
throw new InterpreterInvalidApplicationException();
|
||
|
|
||
|
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||
|
if (arg0 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
NumberExpression? arg1 = argl[1] as NumberExpression;
|
||
|
if (arg1 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
return NumberFactory.NormalizeFloat(arg0.GetValueAsFloat() / arg1.GetValueAsFloat());
|
||
|
}
|
||
|
|
||
|
public static NumberExpression Modulus(ListExpression args, Environment env)
|
||
|
{
|
||
|
List<Expression> argl = args.EvalMembers(env);
|
||
|
if (argl.Count != 2)
|
||
|
throw new InterpreterInvalidApplicationException();
|
||
|
|
||
|
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||
|
if (arg0 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
NumberExpression? arg1 = argl[1] as NumberExpression;
|
||
|
if (arg1 is null)
|
||
|
throw new InterpreterTypingException();
|
||
|
|
||
|
return NumberFactory.NormalizeFloat(arg0.GetValueAsFloat() % arg1.GetValueAsFloat());
|
||
|
}
|
||
|
|
||
|
|
||
|
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();
|
||
|
if (!(antecedent.Eval(env) is NilExpression))
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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("+"), new ProcedureExpression(new PrimitiveProcedure(Plus)));
|
||
|
result.AddSymbol(new Symbol("-"), new ProcedureExpression(new PrimitiveProcedure(Minus)));
|
||
|
result.AddSymbol(new Symbol("*"), new ProcedureExpression(new PrimitiveProcedure(Times)));
|
||
|
result.AddSymbol(new Symbol("/"), new ProcedureExpression(new PrimitiveProcedure(DividedBy)));
|
||
|
result.AddSymbol(new Symbol("%"), new ProcedureExpression(new PrimitiveProcedure(Modulus)));
|
||
|
result.AddSymbol(new Symbol("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq)));
|
||
|
result.AddSymbol(new Symbol("set!"), new ProcedureExpression(new PrimitiveProcedure(Set)));
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|