Example #1
0
        internal override Value Copy()
        {
            var res = new LambdaFuncValue(Formals.Copy() as QExprValue, Body.Copy())
            {
                Environment = Environment.Copy()
            };

            return(res);
        }
Example #2
0
        internal static Value Call(Env environment, FuncValue function, SExprValue arguments)
        {
            BuiltinFuncValue builtin = function.As <BuiltinFuncValue>();
            LambdaFuncValue  lambda  = function.As <LambdaFuncValue>();

            // If Builtin then simply call that
            if (builtin != null)
            {
                return(builtin.BuiltinFunction(environment, arguments));
            }

            // Record Argument Counts
            int given = arguments.Cell.Count;
            int total = lambda.Formals.Cell.Count;

            // While arguments still remain to be processed
            while (arguments.Cell.Count > 0)
            {
                // If we've ran out of formal arguments to bind
                if (lambda.Formals.Cell.Count == 0)
                {
                    return(new ErrorValue($"Function passed too many arguments. Got {given}, Expected {total}."));
                }

                // Pop the first symbol from the formals
                SymbolValue symbol = lambda.Formals.Cell[0].As <SymbolValue>();
                lambda.Formals.Cell.RemoveAt(0);

                // Special Case to deal with '&'
                if (symbol.Value == "&")
                {
                    // Ensure '&' is followed by another symbol
                    if (lambda.Formals.Cell.Count != 1)
                    {
                        return(new ErrorValue("Function format invalid.  Symbol '&' not followed by single symbol."));
                    }

                    // Next formal should be bound to remaining arguments.
                    SymbolValue nsym = lambda.Formals.Cell[0].As <SymbolValue>();
                    lambda.Formals.Cell.RemoveAt(0);
                    lambda.Environment.Put(nsym.Value, Builtins.List(environment, arguments));
                    break;
                }

                // Pop the next argument from the list
                Value val = arguments.Cell[0];
                arguments.Cell.RemoveAt(0);

                // Bind a copy into the function's environment
                lambda.Environment.Put(symbol.Value, val);
            }

            // Argument list is now bound.

            // if '&' remains in formal list after we've bound arguments then bind to empty list
            if (lambda.Formals.Cell.Count > 0 &&
                lambda.Formals.Cell[0].As <SymbolValue>().Value == "&")
            {
                // check to ensure that & is not passed invalidly.
                if (lambda.Formals.Cell.Count != 2)
                {
                    return(new ErrorValue("Function format invalid.  Symbol '&' not followed by single symbol."));
                }

                // Pop and throw away '&' symbol
                lambda.Formals.Cell.RemoveAt(0);

                // Pop next symbol and create empty list
                SymbolValue symbolValue = lambda.Formals.Cell[0].As <SymbolValue>();
                lambda.Formals.Cell.RemoveAt(0);

                QExprValue val = new QExprValue();

                // Bind to environment and delete
                lambda.Environment.Put(symbolValue.Value, val);
            }

            // If all formals have been bound evaluate
            if (lambda.Formals.Cell.Count == 0)
            {
                // Set environment parent to evaluation environment
                lambda.Environment.Parent = environment;

                // Evaluate and return
                var sexpr = new SExprValue();
                sexpr.Cell.Add(lambda.Body.Copy());
                return(Builtins.Eval(lambda.Environment, sexpr));
            }
            else
            {
                // Otherwise return partially evaluated function
                return(lambda.Copy());
            }
        }