How the batchinterpreter works To evaluate an expression, we put it on a stack (the "call stack"). If the expression is atomic, we evaluate it and return the value. If it's a compound expression (like a special form or a function call), we go over its elements, evaluating them one by one. This is done by putting them on the call stack. The next "round" of the interpreter then looks at the top of the call stack, and does an evaluation step. Special forms have special evaluation rules (see special.d). Not every part is evaluated, depending on the form, and in some cases the form we end up with must be evaluated further. Some of the tail-call optimization happens here. User-defined functions are evaluated by creating a new environment (with as parent, the environment that the function was defined in), binding the arguments to that function in that environment, and then pushing the function's body on the call stack, associated with the new environment. Keyword arguments are passed to frame.processed[]; the keywords themselves are passed as-is, any values associated with them are evaluated and then added. When we finally call the function, we extract the keyword arguments from frame.processed and put them in funargs. (Regular and rest args were already stored in funargs.)