aboutsummaryrefslogtreecommitdiff
path: root/src/primitives.c
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-06-28 19:54:37 +0800
committerMistivia <i@mistivia.com>2025-06-28 19:54:37 +0800
commit9a4f460d6dd476767ea211c879f115e127ee2410 (patch)
tree8a7ad58e670065af74c261f51f5f21e9bfec3615 /src/primitives.c
parent0633c6c2797bc9182b2c1888385eac6cb6caed10 (diff)
exception & try-catch
Diffstat (limited to 'src/primitives.c')
-rw-r--r--src/primitives.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/src/primitives.c b/src/primitives.c
index 9f3e670..0eadbb7 100644
--- a/src/primitives.c
+++ b/src/primitives.c
@@ -3,6 +3,16 @@
#include "sexp.h"
#include "parser.h"
+SExpRef primitive_assert_exception(Interp *interp, SExpRef args, bool istail) {
+ SExpRef eargs = lisp_eval_args(interp, args);
+ if (VALTYPE(eargs) == kExceptionSignal) return interp->t;
+
+ const char *expstr = lisp_to_string(interp, CAR(args));
+ SExpRef ret = new_error(interp, "assert-exception failed, no exception: %s.\n", expstr);
+ free((void*)expstr);
+ return ret;
+}
+
SExpRef primitive_assert_error(Interp *interp, SExpRef args, bool istail) {
SExpRef eargs = lisp_eval_args(interp, args);
if (VALTYPE(eargs) == kErrSignal) return interp->t;
@@ -13,6 +23,27 @@ SExpRef primitive_assert_error(Interp *interp, SExpRef args, bool istail) {
return ret;
}
+SExpRef primitive_try(Interp *interp, SExpRef args, bool istail) {
+ if (LENGTH(args) != 2) {
+ return new_error(interp, "try: syntax error.\n");
+ }
+ SExpRef exp = CAR(args), ctch = CADR(args);
+ SExpRef ret = EVAL(exp);
+ PUSH_REG(ret);
+ SExpRef catch_func = EVAL(ctch);
+ POP_REG();
+ if (VALTYPE(catch_func) != kUserFuncSExp
+ && VALTYPE(catch_func) != kFuncSExp) {
+ return new_error(interp, "try: syntax error, catch is not a function.\n");
+ }
+ if (VALTYPE(ret) == kExceptionSignal) {
+ PUSH_REG(catch_func);
+ ret = lisp_apply(interp, catch_func, CONS(REF(ret)->ret, NIL), istail);
+ POP_REG();
+ }
+ return ret;
+}
+
SExpRef primitive_load(Interp *interp, SExpRef args, bool istail) {
if (CAR(interp->stack).idx != interp->top_level.idx) {
return new_error(interp, "load: load can only be in top level.\n");
@@ -84,9 +115,11 @@ SExpRef primitive_unwind_protect(Interp *interp, SExpRef args, bool istail) {
return new_error(interp, "unwind-protect: syntax error.\n");
}
SExpRef ret = EVAL(CAR(args));
+ PUSH_REG(ret);
for (SExpRef i = CDR(args); !NILP(i); i = CDR(i)) {
EVAL(CAR(i));
}
+ POP_REG();
return ret;
}
@@ -245,7 +278,7 @@ SExpRef primitive_while(Interp *interp, SExpRef args, bool istail) {
nextloop:
cond = EVAL(pred);
if (CTL_FL(cond)) {
- if (VALTYPE(cond) != kErrSignal) {
+ if (VALTYPE(cond) != kErrSignal && VALTYPE(cond) != kExceptionSignal) {
return new_error(interp, "while: unexpected control flow.\n");
}
return cond;
@@ -255,7 +288,9 @@ nextloop:
while (!NILP(iter)) {
x = CAR(iter);
ret = EVAL(x);
- if (VALTYPE(ret) == kErrSignal || VALTYPE(ret) == kReturnSignal) {
+ if (VALTYPE(ret) == kErrSignal
+ || VALTYPE(ret) == kReturnSignal
+ || VALTYPE(ret) == kExceptionSignal) {
return ret;
}
if (VALTYPE(ret) == kBreakSignal) {