/// <summary> /// Process the arguments passed to a closure, and add them to the given enviroment. /// </summary> /// <param name="argumentNameList">The list of names and kewords the closure was created with.</param> /// <param name="argumentList">The arguments passed to the closure.</param> /// <param name="localEnvironment">The closure's local variables.</param> /// <returns>Nothing.</returns> public static void ProcessArguments(Cons argumentNameList, Cons argumentList, Environment localEnvironment) { while (argumentNameList != null) { // Get the name for the closure's parameter. Then check to see if it's a keyword, if it is then // process the keyword. Otherwise set up that parameter in the closure's enviroment with the // caller specified value. Symbol argumentName = (Symbol)argumentNameList.Car(); switch (argumentName.ToString()) { case "&rest": argumentName = (Symbol)argumentNameList.Cadr(); localEnvironment.AssignLocal(argumentName, argumentList); argumentNameList = null; argumentList = null; break; case "&optional": ProcessOptionalArguments((Cons)argumentNameList.Cdr(), argumentList, localEnvironment); argumentNameList = null; argumentList = null; break; case "&key": ProcessKeyArguments((Cons)argumentNameList.Cdr(), argumentList, localEnvironment); argumentNameList = null; argumentList = null; break; default: if (argumentList == null) { throw new LSharpException("Not enough parameters given."); } localEnvironment.AssignLocal(argumentName, argumentList.Car()); argumentList = (Cons)argumentList.Cdr(); argumentNameList = (Cons)argumentNameList.Cdr(); break; } } // Looks like the caller has supplied more parameters than the closure can use. if (argumentList != null) { throw new LSharpException("Too many parameters given."); } }
/// <summary> /// Starts the toploop running using specified input, output and error streams /// /// </summary> /// <param name="reader"></param> /// <param name="writer"></param> /// <param name="error"></param> public void Run(TextReader reader, TextWriter writer, TextWriter error) { Symbol LAST = Symbol.FromName("?"); while (true) { try { Object o = trace ? Runtime.EvalString("(eval (prl (read (in Console))))", environment) : Runtime.EvalString("(eval (read (in Console)))", environment); if (o == Reader.EOFVALUE) { return; } if (tracereturn) { writer.Write(prompt); writer.WriteLine(Printer.WriteToString(o)); } environment.AssignLocal(LAST, o); } catch (LSharpException e) { error.WriteLine(e.Message); } catch (Exception e) { error.WriteLine(e.GetBaseException()); } } }
public static Object Try(Cons args, Environment environment) { try { return(Runtime.Eval(args.First(), environment)); } catch (Exception e) { environment.AssignLocal(Symbol.IT, e); // If a catch form is specified then evaluate it if (args.Second() as Symbol == Symbol.NULL) { throw; } return(Runtime.Eval(args.Second(), environment)); } finally { // If a finally form was specified then evaluate it if (args.Length() > 2) { Runtime.Eval(args.Third(), environment); } } }
public static Object To(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); localEnvironment.AssignLocal((Symbol)args.First(), 0); int endStop = int.Parse(Runtime.Eval(args.Second(), localEnvironment).ToString()); while ((int)localEnvironment.GetValue((Symbol)args.First()) < endStop) { foreach (object item in (Cons)args.Cddr()) { Runtime.Eval(item, localEnvironment); } localEnvironment.AssignLocal((Symbol)args.First(), ((int)Runtime.Eval(args.First(), localEnvironment)) + 1); } return(null); }
/// <summary> /// Sets a variable with given symbol to a given value /// </summary> /// <param name="symbol"></param> /// <param name="value"></param> /// <returns></returns> public object Assign(Symbol symbol, object value) { Environment environment = GetEnvironment(symbol); if (environment == null) { environment = this; } return(environment.AssignLocal(symbol, value)); }
private static void ProcessOptionalArguments(Cons argumentNameList, Cons argumentList, Environment localEnvironment) { // We need to add all the arguments to the closure's environment. while (argumentNameList != null) { Symbol argumentName = null; object argumentValue = null; // We need to get the name of the argument, it can either be just the name or, it can be // it's own Cons with the name and an expression for the default value. if (argumentNameList.Car() is Cons) { // It is a Cons, so extract the name and the default value. argumentName = (Symbol)argumentNameList.Caar(); argumentValue = argumentNameList.Cadar(); } else { argumentName = (Symbol)argumentNameList.Car(); } // Now, if the caller has specified a value for this argument, get it now. if (argumentList != null) { argumentValue = argumentList.Car(); argumentList = (Cons)argumentList.Cdr(); } // Finally add the parameter to the closure's list and then move onto the next argument. // Because the default can be any expression, we need to evaluate the value every time the // function is called. localEnvironment.AssignLocal(argumentName, Runtime.Eval(argumentValue, localEnvironment)); argumentNameList = (Cons)argumentNameList.Cdr(); } // Looks like the caller has supplied more parameters than the closure can use. if (argumentList != null) { throw new LSharpException("Too many parameters given."); } }
public static Object Let(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); localEnvironment.AssignLocal((Symbol)args.First(), Runtime.Eval(args.Second(), environment)); object result = null; foreach (object item in (Cons)args.Cddr()) { result = Runtime.Eval(item, localEnvironment); } //return Runtime.Eval(args.Third(),localEnvironment); return(result); }
public static Object ForEach(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); Symbol variable = (Symbol)args.First(); Object list = Runtime.Eval(args.Second(), localEnvironment); foreach (object o in (System.Collections.IEnumerable)list) { localEnvironment.AssignLocal(variable, o); //Runtime.Eval(args.Third(),localEnvironment); foreach (object item in (Cons)args.Cddr()) { Runtime.Eval(item, localEnvironment); } } return(null); }
public static Object With(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); Cons bindings = (Cons)args.First(); while ((bindings != null) && (bindings.Length() > 1)) { localEnvironment.AssignLocal((Symbol)bindings.First(), Runtime.Eval(bindings.Second(), environment)); bindings = (Cons)bindings.Cddr(); } object result = null; foreach (object item in (Cons)args.Cdr()) { result = Runtime.Eval(item, localEnvironment); } return(result); }
/// <summary> /// (with ((symbol value)* ) expression*) /// Binds new local variables symbols to values in a new local /// lexical environment, before evaluating expressions. Similar to /// let, but allows multiple local variables to be bound. /// </summary> /// <param name="args"></param> /// <param name="environment"></param> /// <returns></returns> public static Object With(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); Cons bindings = (Cons)args.First(); while ((bindings != null) && (bindings.Length() > 1)) { localEnvironment.AssignLocal((Symbol)bindings.First(), Runtime.Eval(bindings.Second(), localEnvironment)); bindings = (Cons)bindings.Cddr(); } object result = null; foreach (object item in (Cons)args.Cdr()) { result = Runtime.Eval(item, localEnvironment); } return result; }
/// <summary> /// (try expression catch [finally]) /// The try special form corresponds to the try-catch-finally construct found /// in C#. If catch is null then there is deemed to be no catch block /// at all. If an exception occurs, the variable "it" is bound to the Exception /// object in the local environment. /// </summary> /// <param name="args"></param> /// <param name="environment"></param> /// <returns></returns> public static Object Try(Cons args, Environment environment) { try { return Runtime.Eval(args.First(),environment); } catch (Exception e) { environment.AssignLocal(Symbol.IT,e); // If a catch form is specified then evaluate it if (args.Second() == Symbol.NULL) throw; return Runtime.Eval(args.Second(),environment); } finally { // If a finally form was specified then evaluate it if (args.Length() > 2) Runtime.Eval(args.Third(),environment); } }
/// <summary> /// (to variable limit expression) /// Starting at 0, assigns variable to succesive integers upto and /// including limit. Executes expression on each iteration. /// </summary> /// <param name="args"></param> /// <param name="environment"></param> /// <returns></returns> public static Object To(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); localEnvironment.AssignLocal((Symbol) args.First(), 0); int endStop = int.Parse(Runtime.Eval(args.Second(),localEnvironment).ToString()); while ((int)localEnvironment.GetValue((Symbol) args.First()) < endStop) { foreach (object item in (Cons)args.Cddr()) { Runtime.Eval(item, localEnvironment); } localEnvironment.AssignLocal((Symbol) args.First(), ((int)Runtime.Eval(args.First(), localEnvironment)) + 1); } return null; }
/// <summary> /// (let symbol value expression*) /// Binds a new local variable symbol to value in a new local lexical environment, /// before evaluating expressions. Similar to with, but often more convenient for /// decalring a single local variable. /// </summary> /// <param name="args"></param> /// <param name="environment"></param> /// <returns></returns> public static Object Let(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); localEnvironment.AssignLocal((Symbol) args.First(), Runtime.Eval(args.Second(),environment)); object result = null; foreach (object item in (Cons)args.Cddr()) { result = Runtime.Eval(item, localEnvironment); } //return Runtime.Eval(args.Third(),localEnvironment); return result; }
/// <summary> /// (each symbol IEnumerable expression) /// Iterates over any object which impelements IEnumerablewith succesive /// elements being assigned to a variable named symbol; exceutes expression /// on each iteration. Cons (LSharp lists), as well as many .NET collections /// are IEnumerable. Foreach is a synonym for each. /// </summary> /// <param name="args"></param> /// <param name="environment"></param> /// <returns></returns> public static Object ForEach(Cons args, Environment environment) { Environment localEnvironment = new Environment(environment); Symbol variable = (Symbol) args.First(); Object list = Runtime.Eval(args.Second(),localEnvironment); foreach (object o in (System.Collections.IEnumerable)list) { localEnvironment.AssignLocal(variable, o); //Runtime.Eval(args.Third(),localEnvironment); foreach (object item in (Cons)args.Cddr()) { Runtime.Eval(item, localEnvironment); } } return null; }
/// <summary> /// (defmethod name "arg1 arg2" "(expression1)" "(expression 2)" [...]) /// Created methods used for DefClass <br /> /// </summary> /// <param name="args"></param> /// <param name="e"></param> /// <returns></returns> public static object DefMethod(Cons args, Environment e) { string name; string[] _args; string commands = ""; name = args.First().ToString(); _args = args.Second().ToString().Split(new string[] {" "}, StringSplitOptions.None);; for (int i = 2; i < args.Length(); i++) commands += args.Nth(i) + " "; commands = commands.Replace("\\", "\\\\"); commands = commands.Replace("\"", "\\\""); //FIXME: //code = code.Replace("\n", "\\n"); DefinedMethod ret = new DefinedMethod(commands, name, _args); e.AssignLocal(Symbol.FromName(name), ret); Console.WriteLine("Assigned '" + ret.Name + "' as a DefinedMethod"); return ret; }
/// <summary> /// Creates a new runtime /// </summary> public Runtime(TextReader textReader, TextWriter writer, TextWriter errorWriter) { // Initialise the input, output and error streams this.stdin = textReader; this.stdout = writer; this.stderr = errorWriter; // Install a new global environemt globalEnvironment = new LSharp.Environment(); // Set up a default definition for the language .. // LISP true and false globalEnvironment.AssignLocal(T, true); globalEnvironment.AssignLocal(NIL, null); // .NET true and false are booleans globalEnvironment.AssignLocal(Symbol.FromName("true"), true); globalEnvironment.AssignLocal(Symbol.FromName("false"), false); // Null globalEnvironment.AssignLocal(Symbol.FromName("null"), null); // Wire up the functions that are defined in C# .. globalEnvironment.AssignLocal(Symbol.FromName("+"), new Function(new Func<IEnumerable, object>(Runtime.Add), "& xs", "If the first x is a number, returns the sum of xs, otherwise the concatenation of all xs. (+) returns 0.", true)); globalEnvironment.AssignLocal(Symbol.FromName("-"), new Function(new Func<IEnumerable, object>(Runtime.Subtract), "& xs", "Subtraction.", true)); globalEnvironment.AssignLocal(Symbol.FromName("/"), new Function(new Func<object[], object>(Runtime.Divide), "& xs", "Division.", true)); globalEnvironment.AssignLocal(Symbol.FromName("*"), new Function(new Func<object[], object>(Runtime.Multiply), "& xs", "Returns the product of the xs. (*) returns 1.", true)); globalEnvironment.AssignLocal(Symbol.FromName(">"), new Function(new Func<object[], object>(Runtime.GreaterThan), "& xs", "Greater than.", true)); globalEnvironment.AssignLocal(Symbol.FromName("<"), new Function(new Func<object[], object>(Runtime.LessThan), "& xs", "Less than.", true)); globalEnvironment.AssignLocal(Symbol.FromName("atom?"), new Function(new Func<object, bool>(Runtime.IsAtom), "x", "Returns true if x is an atom.", false)); globalEnvironment.AssignLocal(Symbol.FromName("car"), new Function(new Func<object, object>(Runtime.Car), "seq", "Returns the first item in a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("caar"), new Function(new Func<object, object>(Runtime.Caar), "seq", "Returns the first item of the first item in a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("cadr"), new Function(new Func<object, object>(Runtime.Cadr), "seq", "Returns the second item in a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("cddr"), new Function(new Func<object, object>(Runtime.Cddr), "seq", "Returns the rest of the rest of a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("cdr"), new Function(new Func<object, object>(Runtime.Cdr), "seq", "Returns the rest of a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("coerce"), new Function(new Func<object, object, object>(Runtime.Coerce), "x t", "Converts objext x to type t.", false)); globalEnvironment.AssignLocal(Symbol.FromName("compile"), new Function(new Func<object, object>(Compile), "expr", "Compiles the expression and returns executable code.", false)); globalEnvironment.AssignLocal(Symbol.FromName("cons"), new Function(new Func<object, object, object>(Runtime.Cons), "x seq", "Creates a new sequence whose head is x and tail is seq.", false)); globalEnvironment.AssignLocal(Symbol.FromName("do"), new Function(new Func<object[], object>(Runtime.Progn), "& body", "Executes body forms in order, returns the result of the last body.", true)); globalEnvironment.AssignLocal(Symbol.FromName("do1"), new Function(new Func<object[], object>(Runtime.Do1), "& body", "Executes body forms in order, returns the result of the first body.", true)); globalEnvironment.AssignLocal(Symbol.FromName("empty?"), new Function(new Func<object, bool>(Runtime.IsEmpty), "x", "Returns true if x is an empty sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("err"), new Function(new Func<object, object>(Runtime.Err), "exception", "Raises an exception", false)); globalEnvironment.AssignLocal(Symbol.FromName("eval"), new Function(new Func<object, object>(Eval), "expr", "Evaluates an expression.", false)); //globalEnvironment.AssignLocal(Symbol.FromName("help"), // new Function(new Func<object, object>(Runtime.Help), // "x", // "Displays help text for x.", false)); globalEnvironment.AssignLocal(Symbol.FromName("idfn"), new Function(new Func<object, object>(Runtime.IdFn), "x", "The identity function, returns x.", false)); globalEnvironment.AssignLocal(Symbol.FromName("is"), new Function(new Func<object, object, bool>(Runtime.Is), "a b", "Returns true if a and b are the same.", false)); globalEnvironment.AssignLocal(Symbol.FromName("last"), new Function(new Func<object, object>(Runtime.Last), "seq", "Returns the last item in a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("length"), new Function(new Func<object, int>(Runtime.Len), "seq", "Returns the length of the sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("list"), new Function(new Func<object[], Pair>(Runtime.List), "& xs", "Creates a list of xs.", true)); globalEnvironment.AssignLocal(Symbol.FromName("load"), new Function(new Func<string, object>(Load), "filename", "Loads the lsharp expressions from filename.", false)); globalEnvironment.AssignLocal(Symbol.FromName("member?"), new Function(new Func<object, object, bool>(Runtime.Member), "item seq", "Returns true is item is a member of seq.", false)); globalEnvironment.AssignLocal(Symbol.FromName("mod"), new Function(new Func<object[], object>(Runtime.Mod), "& xs", "Returns the remainder when dividing the args.", true)); // TODO: Should new be a special form that compiles the constructor call? globalEnvironment.AssignLocal(Symbol.FromName("new"), new Function(new Func<object[], object>(Runtime.New), "t & xs ", "Constructs a new object of type t with constructir arguments xs.", true)); globalEnvironment.AssignLocal(Symbol.FromName("not"), new Function(new Func<object, bool>(Runtime.Not), "n", "Returns true if n is false, false otherwise.", false)); globalEnvironment.AssignLocal(Symbol.FromName("nth"), new Function(new Func<object, int, object>(Runtime.Nth), "n seq", "Returns the nth element in sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("progn"), new Function(new Func<object[], object>(Runtime.Progn), "& xs", "progn xs", true)); globalEnvironment.AssignLocal(Symbol.FromName("reference"), new Function(new Func<object[], object>(Runtime.Reference), "& xs", "Loads the given list of assemblies.", true)); globalEnvironment.AssignLocal(Symbol.FromName("reverse"), new Function(new Func<object, object>(Runtime.Reverse), "seq", "Reverses the sequence.", false)); //globalEnvironment.AssignLocal(Symbol.FromName("sleep"), // new Function(new Func<double, double>(Runtime.Sleep), // "n", // "Sleeps for n seconds.", false)); globalEnvironment.AssignLocal(Symbol.FromName("seq"), new Function(new Func<object, ISequence>(Runtime.Seq), "x", "Returns x if x is a sequence, otherwise returns a Sequence represenation of x.", false)); globalEnvironment.AssignLocal(Symbol.FromName("seq?"), new Function(new Func<object, bool>(Runtime.IsSeq), "x", "Return true if x is a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("stdin"), new Function(new Func<TextReader>(StdIn), "", "Returns the standard input stream.", false)); globalEnvironment.AssignLocal(Symbol.FromName("stdout"), new Function(new Func<TextWriter>(StdOut), "", "Returns the standard output stream.", false)); globalEnvironment.AssignLocal(Symbol.FromName("stderr"), new Function(new Func<TextWriter>(StdErr), "", "Returns the standard error stream.", false)); globalEnvironment.AssignLocal(Symbol.FromName("str"), new Function(new Func<object[], string>(Runtime.Str), "& xs", "xxx", true)); globalEnvironment.AssignLocal(Symbol.FromName("toarray"), new Function(new Func<IEnumerable, object>(Runtime.AsArray), "seq", "Returns an object[] containing all the members of a sequence.", false)); globalEnvironment.AssignLocal(Symbol.FromName("tolist"), new Function(new Func<IEnumerable, Pair>(Runtime.ToList), "seq", "Returns a list containing all the members of a sequence..", false)); globalEnvironment.AssignLocal(Symbol.FromName("type"), new Function(new Func<object, Type>(Runtime.Type), "x", "Returns the Type of x.", false)); globalEnvironment.AssignLocal(Symbol.FromName("typeof"), new Function(new Func<object, Type>(Runtime.TypeOf), "t", "Returns the Type object named t.", false)); globalEnvironment.AssignLocal(Symbol.FromName("uniq"), new Function(new Func<Symbol>(Runtime.Uniq), "", "", false)); globalEnvironment.AssignLocal(Symbol.FromName("using"), new Function(new Func<object[], object>(Runtime.Using), "xs", "XXX", true)); // Bootstrap L# .. EvalString("(LSharp.Runtime.VarSet (quote set) (LSharp.Runtime.MakeMacro '(x y) (quote `(LSharp.Runtime.VarSet (quote ,x) ,y environment)) \"Set a variable\" environment) environment)"); EvalString("(set map (fn (f s) \"Maps a function f over a sequence.\" (LSharp.Runtime.map f s environment)))"); EvalString("(set bound (fn (sym) \"Returns true if sym is bound in the current environment.\" (LSharp.Runtime.Bound sym environment)))"); EvalString("(set safeset (macro (var val) `(do (if (bound ',var) (prn \"*** redefining \" ',var)) (set ,var ,val))))"); EvalString("(set mac (macro (name parms & body) \"Creates a new macro.\" `(safeset ,name (macro ,parms ,@body))))"); EvalString("(mac def (name parms & body) \"Defines a new function.\" `(safeset ,name (fn ,parms ,@body)))"); // Some synonyms EvalString("(set first car)"); EvalString("(set rest cdr)"); EvalString("(set len length)"); EvalString("(set no not)"); EvalString("(set throw err)"); EvalString("(set = set)"); // Define the rest of the language .. EvalString("(def apply (f x) (LSharp.Runtime.Apply f x environment))"); EvalString("(def even (n) \"Returns true if n is even\" (is (mod n 2) 0))"); //EvalString("(LSharp.Runtime.VarSet (quote if) (LSharp.Runtime.MakeMacro '(& xs) (quote `(LSharp.Runtime.If (map compile (quote ,xs)) environment)) \"if\" environment) environment)"); EvalString("(def inspect (x) \"Inspects the object x for debugging purposes.\" (LSharp.Runtime.Inspect x (stdout)))"); EvalString("(def msec () \"Returns the current time in milliseconds.\" (/ (.ticks (DateTime.Now)) 10000))"); EvalString("(def sleep (n) \"Sleeps for n seconds\" (System.Threading.Thread.Sleep (coerce (* n 1000) \"Int32\")))"); EvalString("(def macex (x) (LSharp.Runtime.MacroExpand x false environment))"); EvalString("(def macex1 (x) (LSharp.Runtime.MacroExpand x true environment))"); EvalString("(def range (a b (c 1)) (LSharp.Runtime.Range a b c))"); EvalString("(def pr (& xs) (LSharp.Runtime.Pr xs (stdout)))"); EvalString("(def prn (& xs) (LSharp.Runtime.Prn xs (stdout)))"); EvalString("(def help (f) \"Prints help documentation for f\" (LSharp.Runtime.Help f (stdout)))"); EvalString("(def sqrt (n) (Math.Sqrt (coerce n \"Double\")))"); EvalString("(def expt (x y) (Math.Pow x y))"); EvalString("(def odd (n) \"Returns true if n is odd\" (no (even n)))"); EvalString("(def isa (x t) \"Returns true if x is of type t.\" (is (type x) t))"); EvalString("(def pair (xs (f list))(if (no xs) nil (no (cdr xs))(list (list (car xs)))(cons (f (car xs) (cadr xs))(pair (cddr xs) f))))"); EvalString("(def reduce (f s) (LSharp.Runtime.reduce f s environment))"); EvalString("(mac and (& xs) `(LSharp.Runtime.And (map compile (quote ,xs)) environment))"); EvalString("(mac with (parms & body) `((fn ,(map car (pair parms)) ,@body) ,@(map cadr (pair parms))))"); EvalString("(mac let (var val & body) `(with (,var ,val) ,@body))"); EvalString("(mac or (& xs) `(LSharp.Runtime.Or (map compile (quote ,xs)) environment))"); EvalString("(mac each (x xs & body) `(LSharp.Runtime.EachLoop ,xs (fn (,x) ,@body) environment))"); EvalString("(mac while (test & body) `(LSharp.Runtime.WhileLoop (fn () ,test) (fn () ,@body) environment))"); EvalString("(mac for (x start finish & body) `(LSharp.Runtime.ForLoop ,start ,finish (fn (,x) ,@body) environment))"); EvalString("(mac nor args `(no (or ,@args)))"); EvalString("(mac when (test & body) `(if ,test (do ,@body)))"); EvalString("(mac unless (test & body) `(if (no ,test) (do ,@body)))"); EvalString("(mac time (expr) \"Times how long it takes to run the expression.\" `(LSharp.Runtime.Time (quote ,expr) (stdout) environment))"); EvalString("(def iso (x y) \"Isomorphic comparison of x and y.\"(or (is x y)(and (seq? x)(seq? y)(iso (car x) (car y))(iso (cdr x) (cdr y)))))"); EvalString("(def testify (x) (if (is x (typeof \"LSharp.Function\")) x (fn (a) (is a x))))"); EvalString("(def some? (f xs) (apply or (map (testify f) xs)))"); EvalString("(def every? (f xs) (apply and (map (testify f) xs)))"); }
private static void ProcessKeyArguments(Cons argumentNameList, Cons argumentList, Environment localEnvironment) { // Make sure that all of the defined key arguments are inserted to the local enviroment with their // defaults. while (argumentNameList != null) { Symbol argumentName = null; object argumentValue = null; // We need to get the name of the argument, it can either be just the name or, it can be // it's own Cons with the name and an expression for the default value. if (argumentNameList.Car() is Cons) { // It is a Cons, so extract the name and the default value. Because the default can be // any expression, we need to evaluate the value every time the function is called. argumentName = (Symbol)argumentNameList.Caar(); argumentValue = Runtime.Eval(argumentNameList.Cadar(), localEnvironment); } else { argumentName = (Symbol)argumentNameList.Car(); } // Add this variable to the closure's environment, then advance to the next parameter. localEnvironment.AssignLocal(argumentName, argumentValue); argumentNameList = (Cons)argumentNameList.Cdr(); } // Now that the parameters and their defaults have been added to the environment we can now // process the supplied arguments. while (argumentList != null) { // Because these are keyed parameters, the caller needs to specify the name of each // parameter. if (argumentList.Car().GetType() != typeof(Symbol)) { throw new LSharpException("Key parameters must be specified by name."); } // Grab the current parameter and the value associated with it. Then make sure that this // is a keyword. Symbol keywordName = (Symbol)argumentList.Car(); object argumentValue = argumentList.Cadr(); if (keywordName.Name[0] != ':') { throw new LSharpException(keywordName + " is not a valid keyword."); } // Now that we know they supplied a keyword, create a symbol out of it and make sure that // it exists. //keywordName = new Symbol(keywordName.Name.Substring(1)); keywordName = Symbol.FromName(keywordName.Name.Substring(1)); if (localEnvironment.Contains(keywordName) == false) { throw new LSharpException(keywordName + " is not a recognised keyword."); } // Update the parameter with the value that the user specified and then move onto the next // argument in the list. localEnvironment.AssignLocal(keywordName, argumentValue); argumentList = (Cons)argumentList.Cddr(); } }
private static void ProcessOptionalArguments(Cons argumentNameList, Cons argumentList, Environment localEnvironment) { // We need to add all the arguments to the closure's environment. while (argumentNameList != null) { Symbol argumentName = null; object argumentValue = null; // We need to get the name of the argument, it can either be just the name or, it can be // it's own Cons with the name and an expression for the default value. if (argumentNameList.Car().GetType() == typeof(Cons)) { // It is a Cons, so extract the name and the default value. argumentName = (Symbol)argumentNameList.Caar(); argumentValue = argumentNameList.Cadar(); } else { argumentName = (Symbol)argumentNameList.Car(); } // Now, if the caller has specified a value for this argument, get it now. if (argumentList != null) { argumentValue = argumentList.Car(); argumentList = (Cons)argumentList.Cdr(); } // Finally add the parameter to the closure's list and then move onto the next argument. // Because the default can be any expression, we need to evaluate the value every time the // function is called. localEnvironment.AssignLocal(argumentName, Runtime.Eval(argumentValue, localEnvironment)); argumentNameList = (Cons)argumentNameList.Cdr(); } // Looks like the caller has supplied more parameters than the closure can use. if (argumentList != null) { throw new LSharpException("Too many parameters given."); } }
private static void ProcessKeyArguments(Cons argumentNameList, Cons argumentList, Environment localEnvironment) { // Make sure that all of the defined key arguments are inserted to the local enviroment with their // defaults. while (argumentNameList != null) { Symbol argumentName = null; object argumentValue = null; // We need to get the name of the argument, it can either be just the name or, it can be // it's own Cons with the name and an expression for the default value. if (argumentNameList.Car().GetType() == typeof(Cons)) { // It is a Cons, so extract the name and the default value. Because the default can be // any expression, we need to evaluate the value every time the function is called. argumentName = (Symbol)argumentNameList.Caar(); argumentValue = Runtime.Eval(argumentNameList.Cadar(), localEnvironment); } else { argumentName = (Symbol)argumentNameList.Car(); } // Add this variable to the closure's environment, then advance to the next parameter. localEnvironment.AssignLocal(argumentName, argumentValue); argumentNameList = (Cons)argumentNameList.Cdr(); } // Now that the parameters and their defaults have been added to the environment we can now // process the supplied arguments. while (argumentList != null) { // Because these are keyed parameters, the caller needs to specify the name of each // parameter. if (argumentList.Car().GetType() != typeof(Symbol)) { throw new LSharpException("Key parameters must be specified by name."); } // Grab the current parameter and the value associated with it. Then make sure that this // is a keyword. Symbol keywordName = (Symbol)argumentList.Car(); object argumentValue = argumentList.Cadr(); if (keywordName.Name[0] != ':') { throw new LSharpException(keywordName + " is not a valid keyword."); } // Now that we know they supplied a keyword, create a symbol out of it and make sure that // it exists. //keywordName = new Symbol(keywordName.Name.Substring(1)); keywordName = Symbol.FromName(keywordName.Name.Substring(1)); if (localEnvironment.Contains(keywordName) == false) { throw new LSharpException(keywordName + " is not a recognised keyword."); } // Update the parameter with the value that the user specified and then move onto the next // argument in the list. localEnvironment.AssignLocal(keywordName, argumentValue); argumentList = (Cons)argumentList.Cddr(); } }
/// <summary> /// (each symbol IEnumerable expression) /// </summary> public static Object ForEach(Cons args, LSharp.Environment environment) { //string v = "//(each " + Printer.ConsToString(args) + ")" + NewLine; string v = ""; LSharp.Environment localEnvironment = new LSharp.Environment(environment); Symbol variable = (Symbol) args.First(); string vn = localEnvironment.AssignLocal(variable, MakeUnique(variable.Name)) as string; v += Generate(args.Second(),environment) + string.Format(@" foreach (object {0} in (System.Collections.IEnumerable)retval) {{", vn); foreach (object item in (Cons)args.Cddr()) { v += Generate(item, localEnvironment); } v += "}" + NewLine; return v; }