From d6c89d0e6df4320d885f384ee5c5f09e032b3521 Mon Sep 17 00:00:00 2001 From: "Javier B. Torres" Date: Thu, 15 Jan 2026 12:17:43 -0300 Subject: [PATCH] add `load` primitive and (minimal) stdlib --- README.md | 5 ++++- include/wolflisp.h | 2 ++ src/core/interp.c | 1 + src/core/prim.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/core/prim.h | 1 + src/main.c | 1 - src/std.scm | 24 ++++++++++++++++++++++++ 7 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/std.scm diff --git a/README.md b/README.md index c39c5d4..e75b204 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # wolflisp -a lisp but wolfy. right now it's very minimal... :^) + +A toy Lisp started as a learning project. +I might work on making it less toy-ish and more useful-ish, but for now expect +bites and nibbles from it if you do things wrong. :^) diff --git a/include/wolflisp.h b/include/wolflisp.h index 14eb097..5d97188 100644 --- a/include/wolflisp.h +++ b/include/wolflisp.h @@ -290,6 +290,8 @@ O list_assoc(In *in, O key, O alist); O list_reverse(In *in, O list); O list_next(In *in, O *list); +int read_expr(In *in, Lx *lex, O *result); + V compile(Cm *co, O expr, I toplevel); V disassemble(Cm *co); O vm_run(Cm *c); diff --git a/src/core/interp.c b/src/core/interp.c index d3f2c46..076c5ad 100644 --- a/src/core/interp.c +++ b/src/core/interp.c @@ -42,6 +42,7 @@ V interp_init(In *in) { PRIM(">", prim_gt, 2, 2); PRIM("=", prim_equal, 0, -1); // variadic PRIM("gc", prim_gc, 0, 0); + PRIM("load", prim_load, 1, 1); #undef PRIM } diff --git a/src/core/prim.c b/src/core/prim.c index 8e75dcb..425278f 100644 --- a/src/core/prim.c +++ b/src/core/prim.c @@ -1,5 +1,6 @@ #include #include +#include #include #define BOOL(x) ((x) ? in->t : NIL) @@ -207,3 +208,45 @@ O prim_gc(In *in, O *args, int argc, O env) { gc_collect(&in->gc); return NIL; } + +O prim_load(In *in, O *args, int argc, O env) { + (void)env; + if (argc != 1) + error_throw(in, "load: expected 1 argument, got %d", argc); + if (type(args[0]) != TYPE_STR) + error_throw(in, "load: expected string argument, got %s", + typename(type(args[0]))); + Ss *s = (Ss *)(UNBOX(args[0]) + 1); + FILE *fp = fopen(s->data, "r"); + if (!fp) + error_throw(in, "load: could not open file '%s'", s->data); + Lx lex = {0, 0, fp, {0}}; + nexttoken(&lex); + O result = NIL; + I mark = gc_rootmark(&in->gc); + gc_addroot(&in->gc, &result); + while (lex.kind != TOK_EOF) { + O expr = NIL; + if (read_expr(in, &lex, &expr) == -1) + break; + + Cm compiler; + memset(&compiler, 0, sizeof(Cm)); + compiler.in = in; + + compile(&compiler, expr, 1); + result = vm_run(&compiler); + + free(compiler.code); + if (compiler.locals.data) + free(compiler.locals.data); + if (compiler.constants.data) + free(compiler.constants.data); + + nexttoken(&lex); + } + + gc_rootreset(&in->gc, mark); + fclose(fp); + return result; +} diff --git a/src/core/prim.h b/src/core/prim.h index 5d419aa..a930b16 100644 --- a/src/core/prim.h +++ b/src/core/prim.h @@ -18,3 +18,4 @@ O prim_gt(In *in, O *args, int argc, O env); O prim_nil_p(In *in, O *args, int argc, O env); O prim_env(In *in, O *args, int argc, O env); O prim_gc(In *in, O *args, int argc, O env); +O prim_load(In *in, O *args, int argc, O env); diff --git a/src/main.c b/src/main.c index 5b9040f..a53b8b6 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,6 @@ void repl(void) { if (setjmp(in.err.handler) == 0) { in.err.active = 1; compile(&compiler, expr, 1); - disassemble(&compiler); result = vm_run(&compiler); println(result); } else { diff --git a/src/std.scm b/src/std.scm new file mode 100644 index 0000000..158c78b --- /dev/null +++ b/src/std.scm @@ -0,0 +1,24 @@ +(def defmacro + (mac (name args . body) + (list 'def name (cons 'mac (cons args body))))) + +(defmacro defn (name args . body) + (list 'def name (cons 'fn (cons args body)))) + +(defn map-aux (f acc l) + (if (nil? l) + (acc f '()) + (map-aux + f + (fn (f ys) + (acc f (cons (f (head l)) ys))) + (tail l)))) +(defn map (f l) + (map-aux f (fn (f x) x) l)) + +(defmacro let (bindings . body) + (cons + (cons 'fn (cons (map head bindings) body)) + (map (fn (x) (head (tail x))) bindings))) + +'()