summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-09-25 20:05:19 -0400
committerLLLL Colonq <llll@colonq>2025-09-25 20:05:19 -0400
commit811f11463851a0f35835ac72ef09b65b1072de20 (patch)
tree225cee11b86af7662e6319c9864788b92be3dfb1
parent8e79c8ac42d3fa248174120266ae0988361df212 (diff)
Add runtime freezing, add defun and defmacro
-rw-r--r--Makefile2
-rw-r--r--flake.nix2
-rw-r--r--src/lexer.c16
-rw-r--r--src/library.c44
-rw-r--r--src/main.c26
-rw-r--r--src/parser.c12
-rw-r--r--src/parser.h2
-rw-r--r--src/runtime.c86
-rw-r--r--src/runtime.h15
9 files changed, 143 insertions, 62 deletions
diff --git a/Makefile b/Makefile
index 55266b0..6eab26f 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ EXE := pit
CC := musl-gcc
CHK_SOURCES ?= $(SRCS)
CPPFLAGS ?= -MMD -MP
-CFLAGS ?= -Ideps/ -Isrc/ -Wall -Wextra -Wpedantic -ftrapv --std=c23 -O0 -g
+CFLAGS ?= -Ideps/ -Isrc/ -Wall -Wextra -Wpedantic -ftrapv --std=c23 -g
LDFLAGS ?= -g -static
.PHONY: all clean check-syntax
diff --git a/flake.nix b/flake.nix
index eff6434..3f3d960 100644
--- a/flake.nix
+++ b/flake.nix
@@ -9,8 +9,10 @@
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.x86_64-linux.default = pkgs.mkShell {
+ hardeningDisable = [ "all" ];
buildInputs = [
pkgs.musl
+ pkgs.valgrind
];
};
};
diff --git a/src/lexer.c b/src/lexer.c
index 159f73b..16f8aee 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -49,12 +49,16 @@ static bool match(pit_lexer *st, int (*f)(int)) {
pit_lexer *pit_lex_file(char *path) {
pit_lexer *ret = malloc(sizeof(*ret));
FILE *f = fopen(path, "r");
- if (!f) pit_panic("failed to open file for lexing: %s", path);
+ if (f == NULL) {
+ pit_panic("failed to open file for lexing: %s", path);
+ return NULL;
+ }
fseek(f, 0, SEEK_END);
ret->len = ftell(f);
fseek(f, 0, SEEK_SET);
ret->input = calloc(ret->len, sizeof(char));
fread(ret->input, sizeof(char), ret->len, f);
+ fclose(f);
ret->start = 0;
ret->end = 0;
return ret;
@@ -80,7 +84,13 @@ restart:
return PIT_LEX_TOKEN_STRING_LITERAL;
default:
if (isspace(c)) goto restart;
- if (isdigit(c)) { while (match(st, isdigit)); return PIT_LEX_TOKEN_INTEGER_LITERAL; }
- else { while (match(st, is_symchar)); return PIT_LEX_TOKEN_SYMBOL; }
+ if (isdigit(c)) {
+ while (match(st, isdigit)) {}
+ return PIT_LEX_TOKEN_INTEGER_LITERAL;
+ }
+ else {
+ while (match(st, is_symchar)) {}
+ return PIT_LEX_TOKEN_SYMBOL;
+ }
}
}
diff --git a/src/library.c b/src/library.c
index fed601e..3ca716f 100644
--- a/src/library.c
+++ b/src/library.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
#include "runtime.h"
static pit_value impl_sf_quote(pit_runtime *rt, pit_value args) {
@@ -42,6 +44,26 @@ static pit_value impl_sf_lambda(pit_runtime *rt, pit_value args) {
return PIT_NIL;
}
+static pit_value impl_m_defun(pit_runtime *rt, pit_value args) {
+ pit_value nm = pit_car(rt, args);
+ pit_value as = pit_car(rt, pit_cdr(rt, args));
+ pit_value body = pit_cdr(rt, pit_cdr(rt, args));
+ return pit_list(rt, 3,
+ pit_intern_cstr(rt, "fset"),
+ pit_list(rt, 2, pit_intern_cstr(rt, "quote"), nm),
+ pit_cons(rt, pit_intern_cstr(rt, "lambda"), pit_cons(rt, as, body))
+ );
+}
+
+static pit_value impl_m_defmacro(pit_runtime *rt, pit_value args) {
+ pit_value nm = pit_car(rt, args);
+ return pit_list(rt, 3,
+ pit_intern_cstr(rt, "progn"),
+ pit_cons(rt, pit_intern_cstr(rt, "defun"), args),
+ pit_list(rt, 2, pit_intern_cstr(rt, "set-symbol-macro"), nm)
+ );
+}
+
static pit_value impl_m_let(pit_runtime *rt, pit_value args) {
pit_value lparams = PIT_NIL;
pit_value largs = PIT_NIL;
@@ -88,9 +110,23 @@ static pit_value impl_fset(pit_runtime *rt, pit_value args) {
return v;
}
+static pit_value impl_symbol_is_macro(pit_runtime *rt, pit_value args) {
+ pit_value sym = pit_car(rt, args);
+ pit_symbol_is_macro(rt, sym);
+ return PIT_NIL;
+}
+
+static pit_value impl_eval(pit_runtime *rt, pit_value args) {
+ pit_value x = pit_car(rt, args);
+ return pit_eval(rt, x);
+}
+
static pit_value impl_print(pit_runtime *rt, pit_value args) {
pit_value x = pit_car(rt, args);
- pit_trace(rt, x);
+ char buf[1024] = {0};
+ pit_dump(rt, buf, sizeof(buf), x);
+ buf[1023] = 0;
+ puts(buf);
return x;
}
@@ -112,12 +148,16 @@ void pit_install_library_essential(pit_runtime *rt) {
pit_sfset(rt, pit_intern_cstr(rt, "progn"), pit_nativefunc_new(rt, impl_sf_progn));
pit_sfset(rt, pit_intern_cstr(rt, "lambda"), pit_nativefunc_new(rt, impl_sf_lambda));
+ pit_mset(rt, pit_intern_cstr(rt, "defun"), pit_nativefunc_new(rt, impl_m_defun));
+ pit_mset(rt, pit_intern_cstr(rt, "defmacro"), pit_nativefunc_new(rt, impl_m_defmacro));
pit_mset(rt, pit_intern_cstr(rt, "let"), pit_nativefunc_new(rt, impl_m_let));
pit_mset(rt, pit_intern_cstr(rt, "and"), pit_nativefunc_new(rt, impl_m_and));
- pit_fset(rt, pit_intern_cstr(rt, "print"), pit_nativefunc_new(rt, impl_print));
pit_fset(rt, pit_intern_cstr(rt, "set"), pit_nativefunc_new(rt, impl_set));
pit_fset(rt, pit_intern_cstr(rt, "fset"), pit_nativefunc_new(rt, impl_fset));
+ pit_fset(rt, pit_intern_cstr(rt, "symbol-is-macro"), pit_nativefunc_new(rt, impl_symbol_is_macro));
+ pit_fset(rt, pit_intern_cstr(rt, "eval"), pit_nativefunc_new(rt, impl_eval));
+ pit_fset(rt, pit_intern_cstr(rt, "print"), pit_nativefunc_new(rt, impl_print));
pit_fset(rt, pit_intern_cstr(rt, "+"), pit_nativefunc_new(rt, impl_add));
pit_fset(rt, pit_intern_cstr(rt, "-"), pit_nativefunc_new(rt, impl_sub));
}
diff --git a/src/main.c b/src/main.c
index c056270..071cf7e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,25 +12,13 @@ int main(int argc, char **argv) {
pit_check_error_maybe_panic(rt);
pit_lexer *lex = pit_lex_file(argv[1]);
-
- printf("checking parse...\n");
pit_parser *parse = pit_parser_from_lexer(lex);
- pit_value program = pit_parse(rt, parse);
- pit_check_error_maybe_panic(rt);
- pit_trace(rt, program);
-
- printf("checking macro expansion...\n");
- pit_value expanded = pit_expand_macros(rt, program);
- pit_check_error_maybe_panic(rt);
- pit_trace(rt, expanded);
- printf("checking free variables...\n");
- pit_value freevars = pit_free_vars(rt, PIT_NIL, expanded);
- pit_check_error_maybe_panic(rt);
- pit_trace(rt, freevars);
-
- printf("checking eval...\n");
- pit_value ret = pit_eval(rt, program);
- pit_check_error_maybe_panic(rt);
- pit_trace(rt, ret);
+ bool eof = false;
+ while (!eof) {
+ pit_value program = pit_parse(rt, parse, &eof);
+ pit_check_error_maybe_panic(rt);
+ pit_eval(rt, program);
+ pit_check_error_maybe_panic(rt);
+ }
}
diff --git a/src/parser.c b/src/parser.c
index cb75817..0c9714a 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -46,7 +46,7 @@ pit_parser *pit_parser_from_lexer(pit_lexer *lex) {
}
// parse a single expression
-pit_value pit_parse(pit_runtime *rt, pit_parser *st) {
+pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
char buf[256] = {0};
pit_lex_token t = advance(st);
switch (t) {
@@ -54,7 +54,11 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st) {
pit_error(rt, "encountered an error token while parsing");
return PIT_NIL;
case PIT_LEX_TOKEN_EOF:
- pit_error(rt, "end-of-file while parsing");
+ if (eof != NULL) {
+ *eof = true;
+ } else {
+ pit_error(rt, "end-of-file while parsing");
+ }
return PIT_NIL;
case PIT_LEX_TOKEN_LPAREN: {
// to construct a cons-list, we need the arguments "backwards"
@@ -64,7 +68,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st) {
i64 scratch_reset = rt->scratch->next;
while (!match(st, PIT_LEX_TOKEN_RPAREN)) {
pit_value *cell = pit_arena_alloc_bulk(rt->scratch, sizeof(pit_value));
- *cell = pit_parse(rt, st);
+ *cell = pit_parse(rt, st, eof);
if (rt->error != PIT_NIL) return PIT_NIL; // if we hit an error, stop!
}
pit_value ret = PIT_NIL;
@@ -76,7 +80,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st) {
return ret;
}
case PIT_LEX_TOKEN_QUOTE:
- return pit_list(rt, 2, pit_intern_cstr(rt, "quote"), pit_parse(rt, st));
+ return pit_list(rt, 2, pit_intern_cstr(rt, "quote"), pit_parse(rt, st, eof));
case PIT_LEX_TOKEN_INTEGER_LITERAL:
get_token_string(st, buf, sizeof(buf));
return pit_integer_new(rt, atoi(buf));
diff --git a/src/parser.h b/src/parser.h
index 73c489a..f99a891 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -15,6 +15,6 @@ typedef struct {
} pit_parser;
pit_parser *pit_parser_from_lexer(pit_lexer *lex);
-pit_value pit_parse(pit_runtime *rt, pit_parser *st);
+pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof);
#endif
diff --git a/src/runtime.c b/src/runtime.c
index 230b595..3bfd1d4 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -16,32 +16,31 @@ pit_arena *pit_arena_new(i64 capacity, i64 elem_size) {
a->next = 0;
return a;
}
-
-i32 pit_arena_alloc_idx(pit_arena *a) {
+i32 pit_arena_next_idx(pit_arena *a) {
i32 byte_idx; pit_mul(&byte_idx, a->elem_size, a->next);
+ return byte_idx;
+}
+i32 pit_arena_alloc_idx(pit_arena *a) {
+ i32 byte_idx = pit_arena_next_idx(a);
if (byte_idx >= a->capacity) { return -1; }
a->next += 1;
return byte_idx;
}
-
i32 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num) {
- i32 byte_idx; pit_mul(&byte_idx, a->elem_size, a->next);
+ i32 byte_idx = pit_arena_next_idx(a);
i32 byte_len; pit_mul(&byte_len, a->elem_size, num);
if (byte_idx + byte_len > a->capacity) { return -1; }
a->next += num;
return byte_idx;
}
-
void *pit_arena_idx(pit_arena *a, i32 idx) {
if (idx < 0 || idx >= a->capacity) return NULL;
return &a->data[idx];
}
-
void *pit_arena_alloc(pit_arena *a) {
i32 byte_idx = pit_arena_alloc_idx(a);
return pit_arena_idx(a, byte_idx);
}
-
void *pit_arena_alloc_bulk(pit_arena *a, i64 num) {
i32 byte_idx = pit_arena_alloc_bulk_idx(a, num);
return pit_arena_idx(a, byte_idx);
@@ -73,14 +72,30 @@ pit_runtime *pit_runtime_new() {
ret->result_stack = pit_values_new(1024);
ret->program = pit_runtime_eval_program_new(64 * 1024);
ret->saved_bindings = pit_values_new(1024);
+ ret->frozen_values = 0;
+ ret->frozen_bytes = 0;
+ ret->frozen_symtab = 0;
ret->error = PIT_NIL;
- pit_intern_cstr(ret, "nil"); // nil must be the 0th symbol for PIT_NIL to work
+ pit_value nil = pit_intern_cstr(ret, "nil"); // nil must be the 0th symbol for PIT_NIL to work
+ 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_runtime_freeze(ret);
return ret;
}
+void pit_runtime_freeze(pit_runtime *rt) {
+ rt->frozen_values = pit_arena_next_idx(rt->values);
+ rt->frozen_bytes = pit_arena_next_idx(rt->bytes);
+ rt->frozen_symtab = pit_arena_next_idx(rt->symtab);
+}
+void pit_runtime_reset(pit_runtime *rt) {
+ rt->values->next = rt->frozen_values;
+ rt->bytes->next = rt->frozen_bytes;
+ rt->symtab->next = rt->frozen_symtab;
+}
+
i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
pit_value_heavy *h = NULL;
if (len <= 0) return 0;
@@ -416,6 +431,8 @@ pit_value pit_get(pit_runtime *rt, pit_value sym) {
return pit_cell_get(rt, pit_get_value_cell(rt, sym));
}
void pit_set(pit_runtime *rt, pit_value sym, pit_value v) {
+ pit_symbol idx = pit_as_symbol(rt, sym);
+ if (idx < rt->frozen_symtab) { pit_error(rt, "attempted to modify frozen symbol"); return; }
pit_symtab_entry *ent = pit_symtab_lookup(rt, sym);
if (!ent) { pit_error(rt, "bad symbol"); return; }
if (pit_value_sort(ent->value) != PIT_VALUE_SORT_REF) {
@@ -427,6 +444,8 @@ pit_value pit_fget(pit_runtime *rt, pit_value sym) {
return pit_cell_get(rt, pit_get_function_cell(rt, sym));
}
void pit_fset(pit_runtime *rt, pit_value sym, pit_value v) {
+ pit_symbol idx = pit_as_symbol(rt, sym);
+ if (idx < rt->frozen_symtab) { pit_error(rt, "attempted to modify frozen symbol"); return; }
pit_symtab_entry *ent = pit_symtab_lookup(rt, sym);
if (!ent) { pit_error(rt, "bad symbol"); return; }
if (pit_value_sort(ent->function) != PIT_VALUE_SORT_REF) {
@@ -463,6 +482,7 @@ void pit_sfset(pit_runtime *rt, pit_value sym, pit_value v) {
pit_symbol_is_special_form(rt, sym);
}
void pit_bind(pit_runtime *rt, pit_value sym, pit_value cell) {
+ // although we cannot set frozen symbols, we can still bind them temporarily - no need to check
pit_symtab_entry *ent = pit_symtab_lookup(rt, sym);
if (!ent) { pit_error(rt, "bad symbol"); return; }
pit_values_push(rt, rt->saved_bindings, ent->value);
@@ -502,7 +522,9 @@ void pit_cell_set(pit_runtime *rt, pit_value cell, pit_value v) {
pit_error(rt, "cell value is not ref");
return;
}
- pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, cell));
+ pit_ref idx = pit_as_ref(rt, cell);
+ if (idx < rt->frozen_values) { pit_error(rt, "attempt to modify frozen cell"); return; }
+ pit_value_heavy *h = pit_deref(rt, idx);
if (!h) { pit_error(rt, "bad ref"); return; }
if (h->hsort != PIT_VALUE_HEAVY_SORT_CELL) {
pit_error(rt, "cell value ref does not point to cell");
@@ -520,7 +542,6 @@ pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr) {
h->cons.cdr = cdr;
return ret;
}
-
pit_value pit_list(pit_runtime *rt, i64 num, ...) {
pit_value temp[64];
if (num > 64) { pit_error(rt, "failed to create list of size %d\n", num); return PIT_NIL; }
@@ -536,7 +557,6 @@ pit_value pit_list(pit_runtime *rt, i64 num, ...) {
}
return ret;
}
-
pit_value pit_car(pit_runtime *rt, pit_value v) {
if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return PIT_NIL;
pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v));
@@ -553,14 +573,18 @@ pit_value pit_cdr(pit_runtime *rt, pit_value v) {
}
void pit_setcar(pit_runtime *rt, pit_value v, pit_value x) {
if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return; }
- pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v));
+ pit_ref idx = pit_as_ref(rt, v);
+ if (idx < rt->frozen_values) { pit_error(rt, "attempted to modify frozen cons"); return; }
+ pit_value_heavy *h = pit_deref(rt, idx);
if (!h) { pit_error(rt, "bad ref"); return; }
if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) { pit_error(rt, "not a cons"); return; }
h->cons.car = x;
}
void pit_setcdr(pit_runtime *rt, pit_value v, pit_value x) {
if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return; }
- pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v));
+ pit_ref idx = pit_as_ref(rt, v);
+ if (idx < rt->frozen_values) { pit_error(rt, "attempted to modify frozen cons"); return; }
+ pit_value_heavy *h = pit_deref(rt, idx);
if (!h) { pit_error(rt, "bad ref"); return; }
if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) { pit_error(rt, "not a cons"); return; }
h->cons.cdr = x;
@@ -604,6 +628,8 @@ pit_value pit_free_vars(pit_runtime *rt, pit_value args, pit_value body) {
if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "lambda")) {
bound = pit_append(rt, pit_car(rt, args), bound);
} else if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "quote")) {
+ // don't look inside quote!
+ // if we add other special forms, make sure to consider them here if necessary!
} else {
while (args != PIT_NIL) {
pit_values_push(rt, rt->expr_stack, pit_car(rt, args));
@@ -622,7 +648,6 @@ pit_value pit_free_vars(pit_runtime *rt, pit_value args, pit_value body) {
rt->expr_stack->top = expr_stack_reset;
return ret;
}
-
pit_value pit_lambda(pit_runtime *rt, pit_value args, pit_value body) {
pit_value ret = pit_heavy_new(rt);
pit_value_heavy *h = pit_deref(rt, ret);
@@ -637,12 +662,19 @@ pit_value pit_lambda(pit_runtime *rt, pit_value args, pit_value body) {
freevars = pit_cdr(rt, freevars);
}
h->hsort = PIT_VALUE_HEAVY_SORT_FUNC;
- h->func.args = args;
+ pit_value arg_cells = PIT_NIL;
+ 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);
+ }
+ arg_cells = pit_reverse(rt, arg_cells);
+ h->func.args = arg_cells;
h->func.env = env;
h->func.body = expanded;
return ret;
}
-
pit_value pit_nativefunc_new(pit_runtime *rt, pit_nativefunc f) {
pit_value ret = pit_heavy_new(rt);
pit_value_heavy *h = pit_deref(rt, ret);
@@ -651,7 +683,6 @@ pit_value pit_nativefunc_new(pit_runtime *rt, pit_nativefunc f) {
h->nativefunc = f;
return ret;
}
-
pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args) {
switch (pit_value_sort(f)) {
case PIT_VALUE_SORT_REF:
@@ -669,22 +700,15 @@ pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args) {
}
pit_value anames = h->func.args;
while (anames != PIT_NIL) {
- pit_value nm = pit_car(rt, anames);
- pit_value c = pit_cell_new(rt, pit_car(rt, args));
- pit_bind(rt, nm, c);
+ 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);
bound = pit_cons(rt, nm, bound);
args = pit_cdr(rt, args);
anames = pit_cdr(rt, anames);
}
- // update the closure's environment with new values
- env = h->func.env;
- while (env != PIT_NIL) {
- pit_value b = pit_car(rt, env);
- pit_value nm = pit_car(rt, b);
- pit_value v = pit_get(rt, nm);
- pit_cell_set(rt, pit_cdr(rt, b), v);
- env = pit_cdr(rt, env);
- }
pit_value ret = pit_eval(rt, h->func.body);
while (bound != PIT_NIL) {
pit_unbind(rt, pit_car(rt, bound));
@@ -739,6 +763,7 @@ pit_value pit_expand_macros(pit_runtime *rt, pit_value top) {
i64 program_reset = rt->program->top;
pit_values_push(rt, rt->expr_stack, top);
while (rt->expr_stack->top > 0) {
+ if (rt->error != PIT_NIL) goto end;
pit_value cur = pit_values_pop(rt, rt->expr_stack);
if (pit_is_cons(rt, cur)) {
pit_value fsym = pit_car(rt, cur);
@@ -810,6 +835,7 @@ pit_value pit_expand_macros(pit_runtime *rt, pit_value top) {
}
}
for (i64 idx = rt->program->top - 1; idx >= program_reset; --idx) {
+ if (rt->error != PIT_NIL) goto end;
pit_runtime_eval_program_entry *ent = &rt->program->data[idx];
switch (ent->sort) {
case EVAL_PROGRAM_ENTRY_LITERAL:
@@ -843,6 +869,7 @@ pit_value pit_eval(pit_runtime *rt, pit_value top) {
pit_values_push(rt, rt->expr_stack, top);
// first, convert the expression tree into "polish notation" in program
while (rt->expr_stack->top > 0) {
+ if (rt->error != PIT_NIL) goto end;
pit_value cur = pit_values_pop(rt, rt->expr_stack);
if (pit_is_cons(rt, cur)) { // compound expressions: function/macro application special forms
pit_value fsym = pit_car(rt, cur);
@@ -896,6 +923,7 @@ pit_value pit_eval(pit_runtime *rt, pit_value top) {
// then, execute the polish notation program from right to left
// this has the nice consequence of putting the arguments in the right order
for (i64 idx = rt->program->top - 1; idx >= program_reset; --idx) {
+ if (rt->error != PIT_NIL) goto end;
pit_runtime_eval_program_entry *ent = &rt->program->data[idx];
switch (ent->sort) {
case EVAL_PROGRAM_ENTRY_LITERAL:
diff --git a/src/runtime.h b/src/runtime.h
index c5040f1..f9995d1 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -12,6 +12,7 @@ typedef struct {
u8 data[];
} pit_arena;
pit_arena *pit_arena_new(i64 capacity, i64 elem_size);
+i32 pit_arena_next_idx(pit_arena *a);
i32 pit_arena_alloc_idx(pit_arena *a);
i32 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num);
void *pit_arena_idx(pit_arena *a, i32 idx);
@@ -86,18 +87,26 @@ pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity);
void pit_runtime_eval_program_push(struct pit_runtime *rt, pit_runtime_eval_program *s, pit_runtime_eval_program_entry x);
typedef struct pit_runtime {
- pit_arena *values; // all heavy values - effectively an array of pit_value_heavy
- pit_arena *bytes; // all bytestrings (including symbol names)
- pit_arena *symtab; i64 symtab_len; // all symbols - effectively an array of pit_symtab_entry
+ // interpreter state
+ pit_arena *values; // all heavy values - effectively an array of pit_value_heavy - MUTABLE!
+ pit_arena *bytes; // all bytestrings (including symbol names) - immutable
+ pit_arena *symtab; i64 symtab_len; // all symbols - effectively an array of pit_symtab_entry - MUTABLE!
+ // temporary/"scratch" memory
pit_arena *scratch; // temporary arena used during parsing and evaluation
pit_values *saved_bindings; // stack used to save old values of bindings to be restored ("shallow binding")
pit_values *expr_stack; // stack of subexpressions to evaluate during evaluation
pit_values *result_stack; // stack of intermediate values during evaluation
pit_runtime_eval_program *program; // intermediate stack-based program constructed during evaluation
+ // bookkeeping
+ // "frozen" values offsets: values before these offsets are immutable, and we can reset here later
+ i64 frozen_values, frozen_bytes, frozen_symtab;
pit_value error; // error value - if this is non-nil, an error has occured! only tracks the first error
} pit_runtime;
pit_runtime *pit_runtime_new();
+void pit_runtime_freeze(pit_runtime *rt); // freeze the runtime at the current point - everything currently defined becomes immutable
+void pit_runtime_reset(pit_runtime *rt); // restore the runtime to the frozen point, resetting everything that has happened since
+
i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v);
#define pit_trace(rt, v) pit_trace_(rt, "Trace [" __FILE__ ":" PIT_STR(__LINE__) "] %s\n", v)
void pit_trace_(pit_runtime *rt, const char *format, pit_value v);