private static Shelisp.Vector ReadVector(StreamReader s) { Debug.Print ("ReadVector>"); // consume the [ s.Read(); List<Shelisp.Object> objs = new List<Shelisp.Object>(); Shelisp.Object obj; while ((obj = Read (s, ']')) != null) { Debug.Print ("+ {0}", obj); objs.Add (obj); } var rv = new Vector (objs.ToArray()); Debug.Print ("ReadList returning {0}", rv); return rv; }
public static Shelisp.Object ApplyLambda(L l, Shelisp.Object fun, Shelisp.Object args, [LispOptional] Shelisp.Object env, bool eval_args = true) { try { if (l.eval_depth ++ >= L.max_lisp_eval_depth) throw new Exception ("max eval depth exceeded"); // Console.WriteLine ("in ApplyLambda, fun = {0}, args = {1}, eval_args = {2}", fun, args, eval_args); // Console.WriteLine (Environment.StackTrace); if (env == null) env = l.Environment; if (!L.CONSP(fun)) Console.WriteLine ("{0} is not a cons cell! we're about to die!", fun); if (L.CAR(fun).LispEq (L.Qclosure)) { // this sets fun = ( environment args rest... ) where args rest... came from the original lambda. // so the cdr below meant to skip the lambda actually skips the environment. fun = L.CDR(fun); env = L.CAR(fun); } Shelisp.Object rest = L.CDR (fun); // get rid of the lambda Shelisp.Object arg_names = L.CAR(rest); Shelisp.Object body = L.CDR (rest); /* evaluate each of the arguments in the current environment, then add them to the environment and evaluate the body of the lambda */ Shelisp.Object lexenv = env; if (L.CONSP (arg_names)) { IEnumerator<Shelisp.Object> argname_enumerator = ((List)arg_names).GetEnumerator(); IEnumerator<Shelisp.Object> arg_enumerator = L.NILP (args) ? (new List<Shelisp.Object>()).GetEnumerator() : ((List)args).GetEnumerator(); bool optional_seen = false; bool rest_seen = false; while (argname_enumerator.MoveNext()) { if (((Symbol)argname_enumerator.Current).name == "&optional") { optional_seen = true; continue; } if (((Symbol)argname_enumerator.Current).name == "&rest") { rest_seen = true; continue; } if (rest_seen) { // gather up the rest of the args into a single list, add it to the lexenv using the current argname, // and break out of the loop List<Shelisp.Object> list = new List<Shelisp.Object>(); while (arg_enumerator.MoveNext()) list.Add (eval_args ? arg_enumerator.Current.Eval (l, env) : arg_enumerator.Current); Shelisp.Object rest_args = list.Count == 0 ? L.Qnil : new List(list.ToArray()); lexenv = new List (new List (argname_enumerator.Current, rest_args), lexenv); break; } else if (optional_seen) { // if there is nothing else in arg_enumerator, set parameters to nil if (!arg_enumerator.MoveNext()) { lexenv = new List (new List (argname_enumerator.Current, L.Qnil), lexenv); continue; } } else { if (!arg_enumerator.MoveNext()) throw new Exception ("not enough args"); } lexenv = new List (new List (argname_enumerator.Current, eval_args ? arg_enumerator.Current.Eval (l, env) : arg_enumerator.Current), lexenv); } } var old_env = l.Environment; l.Environment = lexenv; try { Shelisp.Object rv = L.Qnil; foreach (var form in (List)body) { L.EvalIndent(); rv = form.Eval (l, lexenv); L.EvalOutdent(); } return rv; } catch (Exception) { Debug.Print ("at lisp {0}", body); throw; } finally { l.Environment = old_env; } } finally { l.eval_depth --; } }
private static Shelisp.Object ReadList(StreamReader s) { Debug.Print ("ReadList>"); // consume the ( s.Read(); List<Shelisp.Object> objs = new List<Shelisp.Object>(); Shelisp.Object obj; bool dot_seen = false; bool el_after_dot = false; while ((obj = Read (s, ')')) != null) { if (obj.LispEq (L.intern("."))) { if (dot_seen) throw new LispInvalidReadSyntaxException (". in wrong context"); dot_seen = true; continue; } else if (dot_seen) { if (el_after_dot) throw new LispInvalidReadSyntaxException (". in wrong context"); el_after_dot = true; } Debug.Print ("+ {0}", obj); objs.Add (obj); } Shelisp.Object rv; if (dot_seen) rv = L.make_list_atom_tail (objs.ToArray()); else rv = L.make_list (objs.ToArray()); Debug.Print ("ReadList returning {0}", rv); return rv; }