lispeval = require './eval' {cons, nil, nilp, car, cdr, listToVector} = require './lists' module.exports = create_vm_expression_evaluator: (defining_scope, params, body) -> (cells, scope) -> args = (amap = (cells, accum) -> return accum if nilp cells amap((cdr cells), accum.concat(lispeval (car cells), scope)))(cells, []) body.apply null, args create_lisp_expression_evaluator: (defining_scope, params, body) -> (cells, scope) -> # Takes the current scope, which has been passed in during the # execution phase, and evaluate the contents of the parameters # in the context in which this call is made (i.e. when the # function is *called*, rather than defined. new_scope = (cmap = (cells, params, nscope) -> return nscope if (nilp cells) or (nilp params) nscope[(car params)] = lispeval (car cells), scope cmap((cdr cells), (cdr params), nscope))(cells, params, {}) # Execute and evaluate the body, creating an inner scope that # consists of: (1) the bound variables (the parameters) # evaluated in the context of the function call, because that's # where they were encountered (2) the free variables evaluated # in the context of the defining scope, because that's where # *they* were encountered. # # While this inspiration comes from Coglan, the clearest # explanation is from Lisperator's 'make_lambda' paragraph at # http://lisperator.net/pltut/eval1/ inner_scope = cons(new_scope, defining_scope) (nval = (body, memo) -> return memo if nilp body nval((cdr body), lispeval((car body), inner_scope)))(body) create_special_form_evaluator: (defining_scope, params, body) -> (cells, scope) -> body(cells, scope)