public Value this[string key] { get { return Get(key); } set { mValues = new List(new List(new Word(key), new List(value, List.Nil)), mValues); } }
public void Add(string key, Value val) { if (ContainsKey(key)) throw new Exception("'" + key + "' already defined."); mValues = new List(new List(new Word(key), new List(val, List.Nil)), mValues); }
static void AddBuiltinFunctions(Environment top) { //Missing: cond, atom top.Add("+", new BuiltinFunction((env, args) => { int accum = 0; while (args != List.Nil) { accum += ((Int)args.Val.Eval(env)).Val; args = args.Next; } return new Int(accum); })); top.Add("list", new BuiltinFunction((env, args) => { return args.Map(v => v.Eval(env)); })); top.Add("cons", new BuiltinFunction((env, args) => { return new List(args.Val.Eval(env), (List)args.Next.Val.Eval(env)); })); top.Add("quote", new BuiltinFunction((env, args) => { return args.Val; })); top.Add("car", new BuiltinFunction((env, args) => { var l = args.Val.Eval(env) as List; return l.Val; })); top.Add("cdr", new BuiltinFunction((env, args) => { var l = args.Val.Eval(env) as List; return l.Next; })); top.Add("print", new BuiltinFunction((env, args) => { Value v = args.Val.Eval(env); string str; if (v is String) str = ((String)v).Val; else str = v.ToString(); Console.WriteLine(str); return List.Nil; })); top.Add("if", new BuiltinFunction((env, args) => { if (args.Val.Eval(env).IsTrue()) return args.Next.Val.Eval(env); else return args.Next.Next.Val.Eval(env); })); top.Add("listp", new BuiltinFunction((env, args) => { if (args.Val.Eval(env) is List) return True.T; else return List.Nil; })); top.Add("lambda", new BuiltinFunction((env, args) => { var formalArgs = ((List)args.Val); var body = args.Next.Map(v => v.Eval(env)); var newFun = new UserFunction(formalArgs, body); return newFun; })); top.Add("defmacro", new BuiltinFunction((env, args) => { var name = ((Word)args.Val).Val; var formalArgs = ((List)args.Next.Val); var body = (List)args.Next.Next.Val; var newFun = new UserMacro(formalArgs, body); top[name] = newFun; return newFun; })); top.Add("exit", new BuiltinFunction((env, args) => { var exitArg = args.Val.Eval(env) as Int; int exitCode = 0; if (exitArg != null) exitCode = exitArg.Val; System.Environment.Exit(exitCode); return List.Nil; })); top.Add("eq", new BuiltinFunction((env, args) => { var v1 = args.Val.Eval(env); var v2 = args.Next.Val.Eval(env); if (v1.Equals(v2)) return True.T; else return List.Nil; })); top.Add("code", new BuiltinFunction((env, args) => { var val = args.Val.Eval(env); if (val is UserFunction) { var fun = args.Val.Eval(env) as UserFunction; return new List(fun.mArgNames, new List(fun.mFun, List.Nil)); } else if (val is UserMacro) { var fun = args.Val.Eval(env) as UserMacro; return new List(fun.mArgNames, new List(fun.mFun, List.Nil)); } else throw new Exception("Could not find user function."); })); top.Add("read", new BuiltinFunction((env, args) => { var fileName = ((String)args.Val.Eval(env)).Val; var values = new Stack<Value>(); using (var file = new StreamReader(fileName)) { var scan = new Scanner(file); while (scan.Peek().Item1 != TokenType.EOF) { values.Push(Parse(scan)); } } var ret = List.Nil; foreach (var v in values) { ret = new List(v, ret); } return ret; })); top.Add("eval", new BuiltinFunction((env, args) => { return args.Val.Eval(env).Eval(env); })); top.Add("env", new BuiltinFunction((env, args) => { return env.AsList(); })); top.Add("let", new BuiltinFunction((env, args) => { var name = (Word)args.Val; var val = args.Next.Val.Eval(env); top[name.Val] = val; return val; })); top.Add("save", new BuiltinFunction((env, args) => { var fileName = ((String)args.Val.Eval(env)).Val; var stuff = args.Next.Val.Eval(env); File.WriteAllText(fileName, stuff.ToString()); return stuff; })); top.Add("new", new BuiltinFunction((env, args) => { string className; var nameValue = args.Val.Eval(env); if (nameValue is String) className = ((String)nameValue).Val; else if (nameValue is Word) className = ((Word)nameValue).Val; else throw new Exception(nameValue.ToDotNetValue() + " is not a valid class name."); Type type = Type.GetType(className); if (type == null) { foreach (var a in SearchAssemblies) { type = a.GetType(className); if (type != null) break; } } if (type == null) throw new Exception("Could not find type '" + className + "'."); return new DotNetValue(Activator.CreateInstance(type)); })); }
static Value Parse(Scanner scan) { var tk = scan.Next(); if (tk.Item1 == TokenType.Word) return new Word(tk.Item2); else if (tk.Item1 == TokenType.Nil) return List.Nil; else if (tk.Item1 == TokenType.True) return True.T; else if (tk.Item1 == TokenType.Number) return new Int(int.Parse(tk.Item2)); else if (tk.Item1 == TokenType.String) return new String(tk.Item2); else if (tk.Item1 == TokenType.LParen) { var cons = new Stack<Value>(); while ((tk = scan.Peek()).Item1 != TokenType.RParen && tk.Item1 != TokenType.EOF) { cons.Push(Parse(scan)); } if (tk.Item1 != TokenType.RParen) throw new Exception("Missing RParen."); scan.Next(); List ret = List.Nil; while (cons.Count != 0) { ret = new List(cons.Pop(), ret); } return ret; } else if (tk.Item1 == TokenType.Quote) return new Quote(Parse(scan)); else if (tk.Item1 == TokenType.RParen) throw new Exception("Unexpected RParen."); else throw new Exception("Unknown token type."); }
public Value Execute(Environment env, List args) { var oldEnv = env; env = new Environment(env); var argNames = mArgNames; while (argNames != List.Nil && args != List.Nil) { var name = ((Word)argNames.Val).Val; env[name] = args.Val; args = args.Next; argNames = argNames.Next; } if (argNames != List.Nil || args != List.Nil) throw new Exception("Wrong number of arguments."); return mFun.Eval(env).Eval(env); }
public Value Execute(Environment env, List args) { var methodName = ((Word)args.Val.Eval(env)).Val; var arguments = new List<object>(); while ((args = args.Next) != List.Nil) { arguments.Add(args.Val.Eval(env).ToDotNetValue()); } var argTypes = arguments.Select(o => o.GetType()).ToArray(); var meth = mObj.GetType().GetMethod(methodName, argTypes); var ret = meth.Invoke(mObj, arguments.ToArray()); if (ret == null) return List.Nil; if (ret is string) return new String(ret.ToString()); else if (ret is int) return new Int((int)ret); else return new DotNetValue(ret); }
public UserFunction(List args, List fun) { this.mFun = fun; this.mArgNames = args; }
public UserMacro(List args, List fun) { this.mFun = fun; this.mArgNames = args; }
public Value Execute(Environment env, List args) { return Fun(env, args); }
private static void ToStringInner(List l, StringBuilder sb) { if (l == Nil) return; l.Val.ToString(sb); if (l.Next != Nil) sb.Append(' '); ToStringInner(l.Next, sb); }
private static List Map(List l, Func<Value, Value> f) { if (l == Nil) return Nil; return new List(f(l.Val), Map(l.Next, f)); }
private List() { this.Next = this; this.Val = this; }
public List(Value v, List n) { if (v == null || n == null) throw new ArgumentNullException(); this.Val = v; this.Next = n; }