Example #1
0
        // Name changed from the guide to highlight that the outcome is complicated.
        static MalVal Quasiquote(MalVal ast)
        {
            if (!is_pair(ast))
            {
                // Case 1.
                // If is_pair of ast is false: return a new list containing: a symbol named "quote" and ast.
                MalList qList = new MalList();

                qList.Add(new MalSym("quote"));
                qList.Add(ast);

                //qList.Conj(new MalSym("quote"), ast);
                return(qList);
            }
            else
            {
                MalSequence astSeq = (MalSequence)ast;
                MalVal      a0     = astSeq[0];

                // Case 2:  if the first element of ast is a symbol named "unquote": return the second element of ast.
                if (a0 is MalSym a0Sym && a0Sym.getName() == "unquote")
                {
                    // (qq (uq form)) -> form
                    return(astSeq[1]);
                }
Example #2
0
 public MalFunc(MalVal ast, Env e, MalSequence fparams, Func <MalList, MalVal> fn)
 {
     this.ast     = ast;
     this.env     = e;
     this.fparams = fparams;
     this.fn      = fn;
     IsCore       = false;
 }
Example #3
0
        // Given a sequence of symbols (binds) and a list of expressions, work through the
        // sequences, setting each bind in turn to the value of its corresponding expression.
        // The primary application is setting function arguments (binds) to their values (expressions).
        // If one of the binds is the Var args character ('&') the next bind is associated with
        // all of the remaining exprs. Trapped errors include non-symbols being used as binds
        // or cases where the binds and expr sequences are of incompatible lengths.
        public Env(Env outer, MalSequence binds, MalSequence exprs)
        {
            // A key-MalVal dictionary.
            data = new Dictionary <string, MalVal>();

            // The scope we are created in. Null is taken to mean the outermost REPL's env.
            this.outer = outer;
            int bindsProcessed = 0;

            //  (def f (fn (a & b) (list a b))) -- okay
            // Bind (set) each element (symbol) to the respective elements of the exprs list.
            for (bindsProcessed = 0; bindsProcessed < binds.Count(); bindsProcessed++)
            {
                if (binds[bindsProcessed] == malVarArgsChar)
                {
                    // E.g. (fn f (a1 a2 & restArgs) (list a1 a2 restargs )) called with (f 1 2 3 4)
                    if (bindsProcessed == binds.Count() - 1)
                    {
                        // malVarArgsChar isn't followed by the name of the varargs parameter.
                        throw new MalEvalError("Expected symbol after & in arg list");
                        // If there are multiple symbols after '&' all but the first will be trapped as
                        // unbound symbols later on.
                    }
                    if (binds[bindsProcessed + 1] is MalSym symbol)
                    {
                        // Bind the rest of the expressions to the symbol following the varargs char.
                        Set(symbol, exprs.GetRange(bindsProcessed, exprs.Count()));
                        return;
                    }
                    else
                    {
                        // Not sure if this can heppen but just in case.
                        throw new MalEvalError("Expected symbol after & but got '" + binds[bindsProcessed + 1].ToString(true));
                    }
                    //
                }
                else if (binds[bindsProcessed] is MalSym symbol)
                {
                    // Bind an expression to a binding symbol.
                    if (bindsProcessed >= exprs.Count())
                    {
                        throw new MalEvalError("Incorrect number of arguments " + exprs.Count());
                    }
                    Set(symbol, exprs[bindsProcessed]);
                }
                else
                {
                    throw new MalEvalError("expected symbol to bind but got '" + binds[bindsProcessed].ToString(true) + '"');
                }
            }
            if (bindsProcessed < exprs.Count())
            {
                // We ran out of bindings although there are expressions remaining.
                throw new MalEvalError(exprs.ToString(true) + " - more expressions (" + exprs.Count() + ") than bindings: " + bindsProcessed);
            }
        }