// Name changed from the guide to highlight that the outcome is complicated. static JKLVal Quasiquote(JKLVal 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. JKLList qList = new JKLList(); qList.Add(new JKLSym("quote")); qList.Add(ast); //qList.Conj(new JKLSym("quote"), ast); return(qList); } else { JKLSequence astSeq = (JKLSequence)ast; JKLVal 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 JKLSym a0Sym && a0Sym.getName() == "unquote") { // (qq (uq form)) -> form return(astSeq[1]); }
public JKLFunc(JKLVal ast, Env e, JKLSequence fparams, Func <JKLList, JKLVal> fn) { this.ast = ast; this.env = e; this.fparams = fparams; this.fn = fn; IsCore = false; }
// 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, JKLSequence binds, JKLSequence exprs) { // A key-JKLVal dictionary. data = new Dictionary <string, JKLVal>(); // 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] == jklVarArgsChar) { // E.g. (fn* f (a1 a2 & restArgs) (list a1 a2 restargs )) called with (f 1 2 3 4) if (bindsProcessed == binds.Count() - 1) { // jklVarArgsChar isn't followed by the name of the varargs parameter. throw new JKLEvalError("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 JKLSym 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 JKLEvalError("Expected symbol after & but got '" + binds[bindsProcessed + 1].ToString(true)); } // } else if (binds[bindsProcessed] is JKLSym symbol) { // Bind an expression to a binding symbol. if (bindsProcessed >= exprs.Count()) { throw new JKLEvalError("Incorrect number of arguments " + exprs.Count()); } Set(symbol, exprs[bindsProcessed]); } else { throw new JKLEvalError("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 JKLEvalError(exprs.ToString(true) + " - more expressions (" + exprs.Count() + ") than bindings: " + bindsProcessed); } }
public JKLFunc(JKLVal ast, Env e, JKLSequence fparams, Func <JKLList, JKLVal> fn, bool isMacro, JKLVal meta) { this.ast = ast; this.env = e; this.fparams = fparams; this.fn = fn; this.isMacro = isMacro; this.meta = meta; IsCore = false; }