Closed bobbicodes closed 11 months ago
The place where this was previously handled was in the function type:
function hasLoop(ast) {
let loops = []
postwalk(x => {
if (x.value == _symbol("loop")) {
loops.push(true)
return true
} else {
return x
}
return x
}, ast)
if (loops.length > 0) {
return true
} else {
return false
}
}
export function _function(Eval, Env, ast, env, params) {
var fn = function () {
return Eval(ast, new Env(env, params, arguments))
}
let swapRecur = postwalk(x => {
if (x.value == _symbol("recur")) {
return fn
} else {
return x
}
return x
}, ast)
if (!hasLoop(ast)) {
ast = swapRecur
fn = function () {
return Eval(ast, new Env(env, params, arguments))
}
}
fn.__meta__ = null;
fn.__ast__ = ast;
fn.__gen_env__ = function (args) { return new Env(env, params, args); };
fn._ismacro_ = false;
return fn;
}
Fixed by #22
Currently,
recur
may only be used withloop
. It took me an entire month to properly implementloop
, so I got a bit burnt out. But in some ways, using a function as a recur point is actually easier, because we already have implicit tail recursion optimization unlike Clojure. Because of this fact, any use ofrecur
without aloop
I believe can be done by simply replacing therecur
with the actual function! In fact, I had this working in a previous version. We have a postwalk function which I implemented specifically for this, which is currently not being used. How sad. So I know it works, at least for all the test cases I tried. All I needed to do was check if the function being defined has aloop
, and if not, walk the AST and replace any occurrence ofrecur
with the function itself (the function object, not its name, otherwise it wouldn't work with lambdas).