diff options
| author | Mistivia <i@mistivia.com> | 2025-06-24 20:05:41 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-06-24 20:05:41 +0800 |
| commit | 7b50a2a3c6213d58f9e6a824e8d33c43f2dd9f60 (patch) | |
| tree | 2cce2d023aeafff685368f78809f8640a11a73b1 /src/interp.c | |
| parent | a19d0c8bc99948af39b43cc8291abfa89e5a57f8 (diff) | |
fix tailcall bug
Diffstat (limited to 'src/interp.c')
| -rw-r--r-- | src/interp.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/src/interp.c b/src/interp.c index 3d7b318..44800c8 100644 --- a/src/interp.c +++ b/src/interp.c @@ -481,7 +481,7 @@ const char* lisp_to_string(Interp *interp, SExpRef val) { SExpRef lisp_macroexpand1(Interp *interp, SExpRef macro, SExpRef args) { SExpRef fn = new_lambda(interp, REF(macro)->macro.args, REF(macro)->macro.body, interp->top_level); PUSH_REG(fn); - SExpRef ret = lisp_apply(interp, fn, args, false); + SExpRef ret = lisp_call(interp, fn, args); POP_REG(); return ret; error: @@ -691,6 +691,19 @@ static SExpRef build_function_env(Interp *interp, SExpRef func, SExpRef args) { return env; } +SExpRef lisp_call(Interp *interp, SExpRef fn, SExpRef args) { + SExpRef ret = lisp_apply(interp, fn, args, false); + while (VALTYPE(ret) == kTailcallSExp) { + fn = REF(ret)->tailcall.fn; + args = REF(ret)->tailcall.args; + PUSH_REG(ret); + ret = lisp_apply(interp, fn, args, false); + POP_REG(); + if (CTL_FL(ret)) break; + } + return ret; +} + SExpRef lisp_apply(Interp *interp, SExpRef fn, SExpRef args, bool istail) { if (interp->recursion_depth > 2048) return new_error(interp, "apply: stack overflow.\n"); @@ -734,14 +747,6 @@ end: if (VALTYPE(ret) == kReturnSignal) { ret = REF(ret)->ret; } - if (VALTYPE(ret) == kTailcallSExp && !istail) { - fn = REF(ret)->tailcall.fn; - args = REF(ret)->tailcall.args; - PUSH_REG(ret); - ret = lisp_apply(interp, fn, args, false); - POP_REG(); - goto end; - } interp->stack = CDR(interp->stack); interp->recursion_depth--; return ret; |
