summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-12-19 21:01:18 -0500
committerLLLL Colonq <llll@colonq>2025-12-19 21:01:18 -0500
commit2dfa52e475fbc5614f92cfbc42d5b25fc5b8eff2 (patch)
tree01109ae3e8748aeb784bdd97925af3e942fde316
parent8612ca228aacb3e770c485d851c809ddc4a5a7b2 (diff)
Add support for keywords and variadic arguments
-rw-r--r--.gitignore2
-rw-r--r--include/lcq/pit/library.h1
-rw-r--r--include/lcq/pit/runtime.h5
-rw-r--r--src/library.c23
-rw-r--r--src/main.c5
-rw-r--r--src/runtime.c41
6 files changed, 61 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index f1cfca4..53f2c26 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-/build/
+/build_gcc/
/.direnv/
/pit
/*.a
diff --git a/include/lcq/pit/library.h b/include/lcq/pit/library.h
index ff325dc..6bca3a6 100644
--- a/include/lcq/pit/library.h
+++ b/include/lcq/pit/library.h
@@ -5,6 +5,7 @@
void pit_install_library_essential(pit_runtime *rt);
void pit_install_library_io(pit_runtime *rt);
+void pit_install_library_plist(pit_runtime *rt);
void pit_install_library_bytestring(pit_runtime *rt);
#endif
diff --git a/include/lcq/pit/runtime.h b/include/lcq/pit/runtime.h
index a8b6593..32bf198 100644
--- a/include/lcq/pit/runtime.h
+++ b/include/lcq/pit/runtime.h
@@ -60,7 +60,7 @@ typedef struct { /* "heavy" values, the targets of refs */
struct { pit_value car, cdr; } cons;
struct { pit_value *data; i64 len; } array;
struct { u8 *data; i64 len; } bytes;
- struct { pit_value env; pit_value args; pit_value body; } func;
+ struct { pit_value env; pit_value args; pit_value arg_rest_nm; pit_value body; } func;
pit_nativefunc nativefunc;
struct { pit_value tag; void *data; } nativedata;
} in;
@@ -70,7 +70,7 @@ typedef struct {
pit_value name; /* ref to bytestring */
pit_value value; /* ref to cell */
pit_value function; /* ref to cell */
- bool is_macro, is_special_form;
+ bool is_macro, is_special_form, is_keyword;
} pit_symtab_entry;
/* "programs"; vectors of "instructions" for a very simple VM used by the evaluator */
@@ -206,7 +206,6 @@ pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args);
/* working with native data */
pit_value pit_nativedata_new(pit_runtime *rt, pit_value tag, void *d);
-
/* evaluation! */
pit_value pit_expand_macros(pit_runtime *rt, pit_value top);
pit_value pit_eval(pit_runtime *rt, pit_value e);
diff --git a/src/library.c b/src/library.c
index 3175e27..9a40646 100644
--- a/src/library.c
+++ b/src/library.c
@@ -322,6 +322,22 @@ void pit_install_library_io(pit_runtime *rt) {
pit_fset(rt, pit_intern_cstr(rt, "load!"), pit_nativefunc_new(rt, impl_load));
}
+static pit_value impl_plist_get(pit_runtime *rt, pit_value args) {
+ pit_value k = pit_car(rt, args);
+ pit_value vs = pit_car(rt, pit_cdr(rt, args));
+ while (vs != PIT_NIL) {
+ if (pit_eq(k, pit_car(rt, vs))) {
+ return pit_car(rt, pit_cdr(rt, vs));
+ }
+ vs = pit_cdr(rt, vs);
+ }
+ return PIT_NIL;
+}
+void pit_install_library_plist(pit_runtime *rt) {
+ /* property lists / keyword arguments */
+ pit_fset(rt, pit_intern_cstr(rt, "plist/get"), pit_nativefunc_new(rt, impl_plist_get));
+}
+
struct bytestring {
i64 len, cap;
u8 *data;
@@ -373,8 +389,10 @@ static pit_value impl_bs_delete(pit_runtime *rt, pit_value args) {
return PIT_NIL;
}
struct bytestring *bs = h->in.nativedata.data;
- if (bs->data) free(bs->data); bs->data = NULL;
- free(bs); h->in.nativedata.data = NULL;
+ if (bs->data) free(bs->data);
+ bs->data = NULL;
+ free(bs);
+ h->in.nativedata.data = NULL;
return PIT_T;
}
static pit_value impl_bs_grow(pit_runtime *rt, pit_value args) {
@@ -390,6 +408,7 @@ static pit_value impl_bs_grow(pit_runtime *rt, pit_value args) {
}
bs->len = sz;
}
+ return v;
}
static pit_value impl_bs_spit(pit_runtime *rt, pit_value args) {
pit_value path = pit_car(rt, args);
diff --git a/src/main.c b/src/main.c
index 2ea5ef8..bc697de 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,9 +5,14 @@
#include <lcq/pit/lexer.h>
#include <lcq/pit/parser.h>
#include <lcq/pit/runtime.h>
+#include <lcq/pit/library.h>
int main(int argc, char **argv) {
pit_runtime *rt = pit_runtime_new();
+ pit_install_library_essential(rt);
+ pit_install_library_io(rt);
+ pit_install_library_plist(rt);
+ pit_install_library_bytestring(rt);
if (argc < 2) { /* run repl */
char buf[1024] = {0};
i64 len = 0;
diff --git a/src/runtime.c b/src/runtime.c
index d0386ef..fcfe81a 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -87,9 +87,6 @@ pit_runtime *pit_runtime_new() {
pit_set(ret, nil, PIT_NIL);
pit_value truth = pit_intern_cstr(ret, "t");
pit_set(ret, truth, truth);
- pit_install_library_essential(ret);
- pit_install_library_io(ret);
- pit_install_library_bytestring(ret);
pit_runtime_freeze(ret);
return ret;
}
@@ -489,6 +486,7 @@ pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len) {
ent->function = PIT_NIL;
ent->is_macro = false;
ent->is_special_form = false;
+ ent->is_keyword = len >= 1 && nm[0] == ':';
rt->symtab_len += 1;
return pit_symbol_new(rt, idx);
}
@@ -708,7 +706,7 @@ pit_value pit_free_vars(pit_runtime *rt, pit_value bound, pit_value body) {
i64 expr_stack_reset = rt->expr_stack->top;
pit_value ret = PIT_NIL;
pit_values_push(rt, rt->expr_stack, body);
- while (rt->expr_stack->top > 0) {
+ while (rt->expr_stack->top > expr_stack_reset) {
pit_value cur = pit_values_pop(rt, rt->expr_stack);
if (pit_is_cons(rt, cur)) {
pit_value fsym = pit_car(rt, cur);
@@ -752,14 +750,26 @@ pit_value pit_lambda(pit_runtime *rt, pit_value args, pit_value body) {
}
h->hsort = PIT_VALUE_HEAVY_SORT_FUNC;
pit_value arg_cells = PIT_NIL;
+ pit_value arg_rest_nm = PIT_NIL;
+ pit_value separator = pit_intern_cstr(rt, "&");
while (args != PIT_NIL) {
pit_value nm = pit_car(rt, args);
- pit_value ent = pit_cons(rt, nm, pit_cell_new(rt, PIT_NIL));
- arg_cells = pit_cons(rt, ent, arg_cells);
- args = pit_cdr(rt, args);
+ if (pit_eq(nm, separator)) {
+ pit_value next_nm = pit_car(rt, pit_cdr(rt, args));
+ if (next_nm == PIT_NIL) { pit_error(rt, "invalid & in lambda list"); return PIT_NIL; }
+ arg_rest_nm = next_nm;
+ pit_value ent = pit_cons(rt, next_nm, pit_cell_new(rt, PIT_NIL));
+ arg_cells = pit_cons(rt, ent, arg_cells);
+ break;
+ } else {
+ pit_value ent = pit_cons(rt, nm, pit_cell_new(rt, PIT_NIL));
+ arg_cells = pit_cons(rt, ent, arg_cells);
+ args = pit_cdr(rt, args);
+ }
}
arg_cells = pit_reverse(rt, arg_cells);
h->in.func.args = arg_cells;
+ h->in.func.arg_rest_nm = arg_rest_nm;
h->in.func.env = env;
h->in.func.body = expanded;
return ret;
@@ -793,8 +803,14 @@ pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args) {
pit_value aform = pit_car(rt, anames);
pit_value nm = pit_car(rt, aform);
pit_value cell = pit_cdr(rt, aform);
- pit_cell_set(rt, cell, pit_car(rt, args));
- pit_bind(rt, nm, cell);
+ if (h->in.func.arg_rest_nm != PIT_NIL && pit_eq(nm, h->in.func.arg_rest_nm)) {
+ pit_cell_set(rt, cell, args);
+ pit_bind(rt, nm, cell);
+ break;
+ } else {
+ pit_cell_set(rt, cell, pit_car(rt, args));
+ pit_bind(rt, nm, cell);
+ }
bound = pit_cons(rt, nm, bound);
args = pit_cdr(rt, args);
anames = pit_cdr(rt, anames);
@@ -998,7 +1014,12 @@ pit_value pit_eval(pit_runtime *rt, pit_value top) {
}
}
} else if (pit_is_symbol(rt, cur)) { /* unquoted symbols: variable lookup */
- pit_runtime_eval_program_push_literal(rt, rt->program, pit_get(rt, cur));
+ pit_symtab_entry *ent = pit_symtab_lookup(rt, cur);
+ if (ent->is_keyword) {
+ pit_runtime_eval_program_push_literal(rt, rt->program, cur);
+ } else {
+ pit_runtime_eval_program_push_literal(rt, rt->program, pit_get(rt, cur));
+ }
} else { /* other expressions evaluate to themselves! */
pit_runtime_eval_program_push_literal(rt, rt->program, cur);
}