aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interp.c8
-rw-r--r--src/primitives.c5
-rw-r--r--tests/let-binding.lisp6
3 files changed, 19 insertions, 0 deletions
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)))))