using System.Reflection.Metadata.Ecma335; namespace KumiScript.Interpreter { public class MathPrimitives { public static NumberExpression Plus(ListExpression args, Environment env) { List 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 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 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 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 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 GreaterThan(ListExpression args, Environment env) { List 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 arg0.GetValueAsFloat() > arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance(); } public static Expression LessThan(ListExpression args, Environment env) { List 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 arg0.GetValueAsFloat() < arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance(); } public static Expression LessThanEquals(ListExpression args, Environment env) { List 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 arg0.GetValueAsFloat() <= arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance(); } public static Expression GreaterThanEquals(ListExpression args, Environment env) { List 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 arg0.GetValueAsFloat() >= arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance(); } public static Expression PlusPlus(ListExpression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); SymbolExpression? binding = argl[0] as SymbolExpression; if (binding is null) throw new InterpreterTypingException(); Symbol name = binding.GetSymbol(); Expression val = env.Lookup(name); NumberExpression? num = val as NumberExpression; if (num is null) throw new InterpreterTypingException(); NumberExpression nump = NumberFactory.NormalizeFloat(num.GetValueAsFloat() + 1); env.RedefineSymbol(name, nump); return nump; } public static Expression MinusMinus(ListExpression args, Environment env) { List argl = args.GetMembers(); if (argl.Count != 1) throw new InterpreterInvalidApplicationException(); SymbolExpression? binding = argl[0] as SymbolExpression; if (binding is null) throw new InterpreterTypingException(); Symbol name = binding.GetSymbol(); Expression val = env.Lookup(name); NumberExpression? num = val as NumberExpression; if (num is null) throw new InterpreterTypingException(); NumberExpression nump = NumberFactory.NormalizeFloat(num.GetValueAsFloat() - 1); env.RedefineSymbol(name, nump); return nump; } public static Environment RegisterPrimitives(Environment outer) { Environment result = new Environment(outer); 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(">"), new ProcedureExpression(new PrimitiveProcedure(GreaterThan))); result.AddSymbol(new Symbol("<"), new ProcedureExpression(new PrimitiveProcedure(LessThan))); result.AddSymbol(new Symbol("<="), new ProcedureExpression(new PrimitiveProcedure(LessThanEquals))); result.AddSymbol(new Symbol(">="), new ProcedureExpression(new PrimitiveProcedure(GreaterThanEquals))); result.AddSymbol(new Symbol("++!"), new ProcedureExpression(new PrimitiveProcedure(PlusPlus))); result.AddSymbol(new Symbol("--!"), new ProcedureExpression(new PrimitiveProcedure(MinusMinus))); return result; } } }