From ec5910bea4db98b40db374a2484380fe1892c563 Mon Sep 17 00:00:00 2001 From: Mistivia Date: Tue, 24 Jun 2025 16:47:52 +0800 Subject: tailcalll on let block --- src/interp.c | 8 ++++++++ src/primitives.c | 5 +++++ tests/let-binding.lisp | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/src/interp.c b/src/interp.c index 80ddfed..65eeaff 100644 --- a/src/interp.c +++ b/src/interp.c @@ -478,6 +478,13 @@ SExpRef lisp_macroexpand1(Interp *interp, SExpRef macro, SExpRef args) { PUSH_REG(fn); SExpRef ret = lisp_apply(interp, fn, args, false); POP_REG(); + 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(); + } return ret; error: return new_error(interp, "macroexpand: syntax error.\n"); @@ -734,6 +741,7 @@ end: return ret; } + SExpRef lisp_eval(Interp *interp, SExpRef sexp, bool istail) { if (interp->recursion_depth > 2048) { return new_error(interp, "eval: stack overflow.\n"); diff --git a/src/primitives.c b/src/primitives.c index 5f70f09..8e56bf9 100644 --- a/src/primitives.c +++ b/src/primitives.c @@ -198,6 +198,11 @@ SExpRef primitive_let(Interp *interp, SExpRef args, bool istail) { } body = CDR(args); + if (istail) { + SExpRef closure = new_lambda(interp, NIL, body, env); + ret = new_tailcall(interp, closure, NIL); + goto end; + } iter = body; while (!NILP(iter)) { exp = CAR(iter); diff --git a/tests/let-binding.lisp b/tests/let-binding.lisp index eead06a..c132db8 100644 --- a/tests/let-binding.lisp +++ b/tests/let-binding.lisp @@ -22,3 +22,9 @@ (assert (not (funcall my-evenp 9))) (assert (not (funcall my-oddp 10)))) +(assert + (= 2 + (funcall + (lambda () + (let () (return 2)) + (return 1))))) -- cgit v1.0