static int Main(string[] args) { Env env = CreateTopLevelEnv(); List <Value> malArgs = new List <Value>(); for (int i = 1; i < args.Length; i++) { malArgs.Add(new Str(args[i])); } env.Set(Reader.AddSymbol("*ARGV*") as Symbol, new List(malArgs)); Rep("(try* (load-file \".malrc\"))", env); if (args.Length == 0) { return(Repl(env)); } #if NATIVE_LOAD_FILE FileInfo fi = new FileInfo(args[0]); if (fi.Exists) { using (Stream stream = fi.OpenRead()) LoadStream(stream, env); } else { Console.Error.WriteLine("ERROR: unable open file '{0}'", args[0]); return(1); } #else List loaderArgs = new List(new List <Value>() { new Str(args[0]) }); try { var val = env.Get(Reader.Load_file); if (val is Closure cls) { EVAL(cls.Body, cls.CreateEnv(loaderArgs)); } else if (val is Func_Native fn) { fn.Apply(loaderArgs); } else { throw new MalException("unknown function to evaluate file"); } } catch (MalException ex) { Console.Error.WriteLine("ERROR: {0}", ex.Message); return(1); } catch (MalQuitExc) { } #endif return(0); }
// A helper function for EVAL that handles symbols (it looks them up) and // sequences (it EVAL's their elements by mutual recursion with EVAL). static MalVal eval_ast(MalVal ast, Env env) { // Switch on the type of the ast. switch ((Object)ast) { case MalSym malSym: // Simplest case - look up and return a symbol's value. return(env.Get(malSym)); case MalList malList: // Build and return a new list that contains the result of calling EVAL // on each member of the original list. MalList derivedList = new MalList(); for (int i = 0; i < malList.Count(); i++) { derivedList.Add(EVAL(malList.Get(i), env)); } return(derivedList); case MalVector malVec: // Build and return a new vector. MalVector derivedVec = new MalVector(); for (int i = 0; i < malVec.Count(); i++) { derivedVec.Add(EVAL(malVec.Get(i), env)); } return(derivedVec); case MalHashMap malHashMap: // Return a new hash-map which consists of key-value pairs where the key is a key from the hash-map // and the value is the result of calling EVAL on the corresponding value. if (malHashMap.Count() % 2 != 0) { throw new MalEvalError("Hashmap requires an even number of elements forming key value pairs '" + malHashMap.ToString(true) + "'"); } MalHashMap derivedHashMap = new MalHashMap(); // Build and return a new HashMap. it checks that keys are in fact keys and // evaluates the values before storing them. // Work through successive key value pairs. // Note - C#-Mal creates a dictionary, loads it and then passes the result to a Hashmap c'tor that takes a Dict. for (int i = 0; i < malHashMap.Count(); i += 2) { MalVal key = malHashMap.Get(i); if (key is MalString || key is MalKeyword) { derivedHashMap.Add(key); derivedHashMap.Add(EVAL(malHashMap.Get(i + 1), env)); } else { throw new MalEvalError("Expecting a keyword or string as a HashMap key but got '" + key.ToString(true) + "'"); } } return(derivedHashMap); default: // It's not a symbol or a list. return(ast); } }
static Value Eval_ast(Value arg, Env env) { if (env == null) { return(arg); } if (arg == null) { return(arg); } if (arg is Symbol sym) { Value val = env.Get(sym); if (val == null) { throw new MalException(string.Format("'{0}' not found", sym.Name)); } return(val); } else if (arg is List lst) { if (lst.Elements == null) { return(arg); } List <Value> elms = new List <Value>(); for (List.Node elm = lst.Elements; elm != null; elm = elm.cdr) { elms.Add(EVAL(elm.car, env)); } return(new List(elms)); } else if (arg is Vector vec) { List <Value> elms = new List <Value>(); foreach (Value v in vec.Elements) { elms.Add(EVAL(v, env)); } return(new Vector(elms)); } else if (arg is HashMap map) { HashMap hm = new HashMap(); Dictionary <Value, Value> elms = hm.Elements; foreach (var kv in map.Elements) { elms[kv.Key] = EVAL(kv.Value, env); } return(hm); } return(arg); }