diff options
| author | LLLL Colonq <llll@colonq> | 2025-09-25 20:05:19 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2025-09-25 20:05:19 -0400 |
| commit | 811f11463851a0f35835ac72ef09b65b1072de20 (patch) | |
| tree | 225cee11b86af7662e6319c9864788b92be3dfb1 | |
| parent | 8e79c8ac42d3fa248174120266ae0988361df212 (diff) | |
Add runtime freezing, add defun and defmacro
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | flake.nix | 2 | ||||
| -rw-r--r-- | src/lexer.c | 16 | ||||
| -rw-r--r-- | src/library.c | 44 | ||||
| -rw-r--r-- | src/main.c | 26 | ||||
| -rw-r--r-- | src/parser.c | 12 | ||||
| -rw-r--r-- | src/parser.h | 2 | ||||
| -rw-r--r-- | src/runtime.c | 86 | ||||
| -rw-r--r-- | src/runtime.h | 15 |
9 files changed, 143 insertions, 62 deletions
@@ -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 @@ -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)); } @@ -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); |
