summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2026-03-03 14:20:26 -0500
committerLLLL Colonq <llll@colonq>2026-03-03 14:20:26 -0500
commit3707dfaa64715c8fb1ba8a23f9762fef174538d8 (patch)
tree539ae38f4cde9d6f8ffa5eb5f9a8a32c203a0942
parentfae5921bfcbf9f0c8c138dd13aa9c8822a75a316 (diff)
Collect more garbage!
-rw-r--r--flake.nix1
-rw-r--r--include/lcq/pit/lexer.h2
-rw-r--r--include/lcq/pit/runtime.h32
-rw-r--r--include/lcq/pit/utils.h16
-rw-r--r--src/lexer.c16
-rw-r--r--src/library.c20
-rw-r--r--src/main.c3
-rw-r--r--src/parser.c12
-rw-r--r--src/runtime.c233
-rw-r--r--src/utils.c63
10 files changed, 201 insertions, 197 deletions
diff --git a/flake.nix b/flake.nix
index 60c1dde..fe3e803 100644
--- a/flake.nix
+++ b/flake.nix
@@ -25,6 +25,7 @@
};
devShells.default = pkgs.mkShell {
hardeningDisable = ["all"];
+ NIX_ENFORCE_NO_NATIVE = "0";
buildInputs = [
pkgs.musl
pkgs.valgrind
diff --git a/include/lcq/pit/lexer.h b/include/lcq/pit/lexer.h
index 7664e87..db452e7 100644
--- a/include/lcq/pit/lexer.h
+++ b/include/lcq/pit/lexer.h
@@ -29,7 +29,7 @@ typedef struct {
void pit_lex_cstr(pit_lexer *ret, char *buf);
void pit_lex_bytes(pit_lexer *ret, char *buf, i64 len);
-void pit_lex_file(pit_lexer *ret, char *path);
+i64 pit_lex_file(pit_lexer *ret, char *path);
pit_lex_token pit_lex_next(pit_lexer *st);
const char *pit_lex_token_name(pit_lex_token t);
diff --git a/include/lcq/pit/runtime.h b/include/lcq/pit/runtime.h
index 3ff8c90..4132231 100644
--- a/include/lcq/pit/runtime.h
+++ b/include/lcq/pit/runtime.h
@@ -7,18 +7,6 @@
struct pit_runtime;
-/* arenas */
-typedef struct {
- i64 elem_size, capacity, next;
- u8 data[];
-} pit_arena;
-pit_arena *pit_arena_new(i64 capacity, i64 elem_size);
-i64 pit_arena_alloc_idx(pit_arena *a);
-i64 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num);
-void *pit_arena_idx(pit_arena *a, i64 idx);
-void *pit_arena_alloc(pit_arena *a);
-void *pit_arena_alloc_bulk(pit_arena *a, i64 num);
-
/* nil is always the symbol with index 0 */
#define PIT_NIL 0xfff4000000000000 /* 0b1111111111110100000000000000000000000000000000000000000000000000 */
#define PIT_T (PIT_NIL+sizeof(pit_symtab_entry))
@@ -36,7 +24,7 @@ enum pit_value_sort pit_value_sort(pit_value v);
u64 pit_value_data(pit_value v);
typedef struct {
- i64 top, cap;
+ i64 capacity, next;
pit_value data[];
} pit_values;
pit_values *pit_values_new(i64 capacity);
@@ -86,7 +74,7 @@ typedef struct {
} in;
} pit_runtime_eval_program_entry;
typedef struct {
- i64 top, cap;
+ i64 capacity, next;
pit_runtime_eval_program_entry data[];
} pit_runtime_eval_program;
pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity);
@@ -95,11 +83,11 @@ void pit_runtime_eval_program_push_apply(struct pit_runtime *rt, pit_runtime_eva
typedef struct pit_runtime {
/* interpreter state */
- pit_arena *values; /* all heavy values - effectively an array of pit_value_heavy - MUTABLE! */
- pit_arena *values_backbuffer; /* other values buffer (used by GC) */
- pit_arena *arrays; /* all arrays - 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! */
+ pit_arena *heap; /* all heavy values, bytestrings, and arrays. */
+ /* bytestrings and arrays are allocated at the end (descending), heavy values are allocated at the front */
+ /* this allows us to iterate over only heavy values at the front (useful in Cheney's algorithm for GC */
+ pit_arena *backbuffer; /* additional allocation, the same size as the heap (used by GC) */
+ pit_arena *symtab; i64 symtab_len; /* all symbols - effectively an array of pit_symtab_entry */
/* 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") */
@@ -108,7 +96,7 @@ typedef struct pit_runtime {
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_arrays, frozen_bytes, frozen_symtab;
+ i64 frozen_values, frozen_symtab;
pit_value error; /* error value - if this is non-nil, an error has occured! only tracks the first error */
i64 source_line, source_column; /* for error reporting only; line and column of token start */
i64 error_line, error_column; /* line and column of token start at time of error */
@@ -162,8 +150,6 @@ pit_value pit_bytes_new_cstr(pit_runtime *rt, char *s);
pit_value pit_bytes_new_file(pit_runtime *rt, char *path);
bool pit_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len);
i64 pit_as_bytes(pit_runtime *rt, pit_value v, u8 *buf, i64 maxlen);
-bool pit_lexer_from_bytes(pit_runtime *rt, pit_lexer *ret, pit_value v);
-pit_value pit_read_bytes(pit_runtime *rt, pit_value v);
/* working with the symbol table */
pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len);
@@ -231,7 +217,7 @@ pit_value pit_eval(pit_runtime *rt, pit_value e);
void pit_collect_garbage(pit_runtime *rt);
/* repl / file loading */
-void pit_run_file(pit_runtime *rt, char *path);
+pit_value pit_load_file(pit_runtime *rt, char *path);
void pit_repl(pit_runtime *rt);
#endif
diff --git a/include/lcq/pit/utils.h b/include/lcq/pit/utils.h
index 36c74c1..6c297ea 100644
--- a/include/lcq/pit/utils.h
+++ b/include/lcq/pit/utils.h
@@ -2,11 +2,27 @@
#define LCOLONQ_PIT_UTILS_H
#include <stdckdint.h>
+#include <lcq/pit/types.h>
+/* assorted utilities and debugging tools */
#define PIT_STRSTR(x) #x
#define PIT_STR(x) PIT_STRSTR(x)
void pit_panic(const char *format, ...);
void pit_debug(const char *format, ...);
#define pit_mul(result, a, b) if (ckd_mul(result, a, b)) pit_panic("integer overflow during multiplication%s","");
+/* arenas */
+typedef struct {
+ i64 elem_size, capacity, next, back;
+ u8 data[];
+} pit_arena;
+pit_arena *pit_arena_new(i64 len, i64 elem_size);
+void pit_arena_reset(pit_arena *a);
+i64 pit_arena_alloc_idx(pit_arena *a);
+i64 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num);
+void *pit_arena_get(pit_arena *a, i64 idx);
+void *pit_arena_alloc(pit_arena *a);
+void *pit_arena_alloc_bulk(pit_arena *a, i64 num);
+void *pit_arena_alloc_back(pit_arena *a, i64 sz);
+
#endif
diff --git a/src/lexer.c b/src/lexer.c
index 623dd39..3a741b4 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -82,22 +82,20 @@ void pit_lex_bytes(pit_lexer *ret, char *buf, i64 len) {
ret->column = ret->start_column = 0;
ret->error = NULL;
}
-void pit_lex_file(pit_lexer *ret, char *path) {
+i64 pit_lex_file(pit_lexer *ret, char *path) {
FILE *f = fopen(path, "r");
- if (f == NULL) {
- pit_panic("failed to open file for lexing: %s", path);
- return;
- }
+ if (f == NULL) { return -1; }
fseek(f, 0, SEEK_END);
i64 len = ftell(f);
fseek(f, 0, SEEK_SET);
- char *buf = calloc((size_t) ret->len, sizeof(char));
- if ((size_t) ret->len != fread(ret->input, sizeof(char), (size_t) ret->len, f)) {
- pit_panic("failed to read file for lexing: %s", path);
- return;
+ char *buf = calloc((size_t) len, sizeof(char));
+ if ((size_t) len != fread(buf, sizeof(char), (size_t) len, f)) {
+ fclose(f);
+ return -1;
}
fclose(f);
pit_lex_bytes(ret, buf, len);
+ return 0;
}
pit_lex_token pit_lex_next(pit_lexer *st) {
diff --git a/src/library.c b/src/library.c
index 5176874..7966bc4 100644
--- a/src/library.c
+++ b/src/library.c
@@ -523,7 +523,7 @@ static pit_value impl_array(pit_runtime *rt, pit_value args) {
args = pit_cdr(rt, args);
}
rt->scratch->next = scratch_reset;
- return pit_array_from_buf(rt, pit_arena_idx(rt->scratch, (i32) scratch_reset), len);
+ return pit_array_from_buf(rt, pit_arena_get(rt->scratch, (i32) scratch_reset), len);
}
static pit_value impl_array_to_list(pit_runtime *rt, pit_value args) {
pit_value arr = pit_car(rt, args);
@@ -807,7 +807,7 @@ void pit_install_library_essential(pit_runtime *rt) {
static pit_value impl_diagnostics(pit_runtime *rt, pit_value args) {
(void) args;
- fprintf(stderr, "value allocs: %ld\n", rt->values->next);
+ fprintf(stderr, "value allocs: %ld\n", rt->heap->next);
return PIT_NIL;
}
static pit_value impl_print(pit_runtime *rt, pit_value args) {
@@ -832,21 +832,7 @@ static pit_value impl_load(pit_runtime *rt, pit_value args) {
i64 len = pit_as_bytes(rt, path, (u8 *) pathbuf, sizeof(pathbuf) - 1);
if (len < 0) { pit_error(rt, "path was not a string"); return PIT_NIL; }
pathbuf[len] = 0;
- pit_value bs = pit_bytes_new_file(rt, pathbuf);
- pit_lexer lex = {0};
- if (!pit_lexer_from_bytes(rt, &lex, bs)) {
- pit_error(rt, "failed to initialize lexer");
- return PIT_NIL;
- }
- pit_parser parse = {0};
- pit_parser_from_lexer(&parse, &lex);
- pit_value ret = PIT_NIL;
- bool eof = false;
- pit_value p = PIT_NIL;
- while (p = pit_parse(rt, &parse, &eof), !eof) {
- ret = pit_eval(rt, p);
- }
- return ret;
+ return pit_load_file(rt, pathbuf);
}
void pit_install_library_io(pit_runtime *rt) {
/* diagnostics */
diff --git a/src/main.c b/src/main.c
index b6b2a2c..d2ba8aa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,6 +17,7 @@ int main(int argc, char **argv) {
if (argc < 2) {
pit_repl(rt);
} else {
- pit_run_file(rt, argv[1]);
+ pit_load_file(rt, argv[1]);
+ if (pit_runtime_print_error(rt)) return -1;
}
}
diff --git a/src/parser.c b/src/parser.c
index 1f540d6..7d66061 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -2,10 +2,10 @@
#include <stdio.h>
#include <string.h>
-#include "lcq/pit/types.h"
-#include "lcq/pit/lexer.h"
-#include "lcq/pit/parser.h"
-#include "lcq/pit/runtime.h"
+#include <lcq/pit/types.h>
+#include <lcq/pit/lexer.h>
+#include <lcq/pit/parser.h>
+#include <lcq/pit/runtime.h>
static pit_lex_token peek(pit_parser *st) {
if (!st) return PIT_LEX_TOKEN_ERROR;
@@ -106,7 +106,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
i >= scratch_reset;
i -= (i64) sizeof(pit_value)
) {
- pit_value *v = pit_arena_idx(rt->scratch, (i32) i);
+ pit_value *v = pit_arena_get(rt->scratch, (i32) i);
ret = pit_cons(rt, *v, ret);
}
rt->scratch->next = scratch_reset;
@@ -125,7 +125,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
}
}
rt->scratch->next = scratch_reset;
- return pit_array_from_buf(rt, pit_arena_idx(rt->scratch, (i32) scratch_reset), len);
+ return pit_array_from_buf(rt, pit_arena_get(rt->scratch, (i32) scratch_reset), len);
}
case PIT_LEX_TOKEN_QUOTE:
return pit_list(rt, 2, pit_intern_cstr(rt, "quote"), pit_parse(rt, st, eof));
diff --git a/src/runtime.c b/src/runtime.c
index fea53dd..a77fbf4 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -11,50 +11,6 @@
#include <lcq/pit/runtime.h>
#include <lcq/pit/library.h>
-pit_arena *pit_arena_new(i64 capacity, i64 elem_size) {
- pit_arena *a = malloc(sizeof(pit_arena) + (size_t) capacity * (size_t) elem_size);
- a->elem_size = elem_size;
- a->capacity = capacity;
- a->next = 0;
- return a;
-}
-static i64 pit_arena_byte_idx(pit_arena *a, i64 idx) {
- i64 byte_idx = 0; pit_mul(&byte_idx, a->elem_size, idx);
- return byte_idx;
-}
-i64 pit_arena_alloc_idx(pit_arena *a) {
- i64 ret = a->next;
- i64 byte_idx = pit_arena_byte_idx(a, ret);
- if (byte_idx >= a->capacity) {
- return -1;
- }
- a->next += 1;
- return ret;
-}
-i64 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num) {
- i64 ret = a->next;
- i64 byte_idx = pit_arena_byte_idx(a, ret);
- i64 byte_len = 0; pit_mul(&byte_len, a->elem_size, num);
- if (byte_idx + byte_len > a->capacity) { return -1; }
- a->next += num;
- return ret;
-}
-void *pit_arena_idx(pit_arena *a, i64 idx) {
- i64 byte_idx = pit_arena_byte_idx(a, idx);
- if (byte_idx < 0 || byte_idx >= a->capacity) {
- return NULL;
- }
- return &a->data[byte_idx];
-}
-void *pit_arena_alloc(pit_arena *a) {
- i64 idx = pit_arena_alloc_idx(a);
- return pit_arena_idx(a, idx);
-}
-void *pit_arena_alloc_bulk(pit_arena *a, i64 num) {
- i64 idx = pit_arena_alloc_bulk_idx(a, num);
- return pit_arena_idx(a, idx);
-}
-
enum pit_value_sort pit_value_sort(pit_value v) {
/* if this isn't a NaN, or it's a quiet NaN, this is a real double */
/* if (((v >> 52) & 0b011111111111) != 0b011111111111 || ((v >> 51) & 0b1) == 1) return PIT_VALUE_SORT_DOUBLE; */
@@ -75,10 +31,8 @@ u64 pit_value_data(pit_value v) {
pit_runtime *pit_runtime_new() {
pit_runtime *ret = malloc(sizeof(*ret));
- ret->values = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
- ret->values_backbuffer = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
- ret->arrays = pit_arena_new(1024 * 1024, sizeof(pit_value));
- ret->bytes = pit_arena_new(1024 * 1024, sizeof(u8));
+ ret->heap = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
+ ret->backbuffer = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
ret->symtab = pit_arena_new(1024 * 1024, sizeof(pit_symtab_entry));
ret->symtab_len = 0;
ret->scratch = pit_arena_new(1024 * 1024, sizeof(u8));
@@ -87,8 +41,6 @@ pit_runtime *pit_runtime_new() {
ret->program = pit_runtime_eval_program_new(64 * 1024);
ret->saved_bindings = pit_values_new(64 * 1024);
ret->frozen_values = 0;
- ret->frozen_arrays = 0;
- ret->frozen_bytes = 0;
ret->frozen_symtab = 0;
ret->error = PIT_NIL;
ret->source_line = ret->source_column = -1;
@@ -102,15 +54,11 @@ pit_runtime *pit_runtime_new() {
}
void pit_runtime_freeze(pit_runtime *rt) {
- rt->frozen_values = rt->values->next;
- rt->frozen_arrays = rt->arrays->next;
- rt->frozen_bytes = rt->bytes->next;
+ rt->frozen_values = rt->heap->next;
rt->frozen_symtab = rt->symtab->next;
}
void pit_runtime_reset(pit_runtime *rt) {
- rt->values->next = rt->frozen_values;
- rt->arrays->next = rt->frozen_arrays;
- rt->bytes->next = rt->frozen_bytes;
+ rt->heap->next = rt->frozen_values;
rt->symtab->next = rt->frozen_symtab;
}
bool pit_runtime_print_error(pit_runtime *rt) {
@@ -310,7 +258,7 @@ pit_value pit_ref_new(pit_runtime *rt, pit_ref r) {
}
pit_value pit_heavy_new(pit_runtime *rt) {
- i64 idx = pit_arena_alloc_idx(rt->values);
+ i64 idx = pit_arena_alloc_idx(rt->heap);
if (idx < 0) {
pit_error(rt, "failed to allocate space for heavy value");
return PIT_NIL;
@@ -319,7 +267,7 @@ pit_value pit_heavy_new(pit_runtime *rt) {
}
pit_value_heavy *pit_deref(pit_runtime *rt, pit_ref p) {
- return pit_arena_idx(rt->values, p);
+ return pit_arena_get(rt->heap, p);
}
bool pit_is_integer(pit_runtime *rt, pit_value a) {
@@ -425,7 +373,7 @@ bool pit_equal(pit_runtime *rt, pit_value a, pit_value b) {
return false;
}
pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len) {
- u8 *dest = pit_arena_alloc_bulk(rt->bytes, len);
+ u8 *dest = pit_arena_alloc_back(rt->heap, len);
if (!dest) { pit_error(rt, "failed to allocate bytes"); return PIT_NIL; }
memcpy(dest, buf, (size_t) len);
pit_value ret = pit_heavy_new(rt);
@@ -449,7 +397,7 @@ pit_value pit_bytes_new_file(pit_runtime *rt, char *path) {
fseek(f, 0, SEEK_END);
i64 len = ftell(f);
fseek(f, 0, SEEK_SET);
- u8 *dest = pit_arena_alloc_bulk(rt->bytes, len);
+ u8 *dest = pit_arena_alloc_bulk(rt->heap, len);
if (!dest) { pit_error(rt, "failed to allocate bytes"); fclose(f); return PIT_NIL; }
if ((size_t) len != fread(dest, sizeof(char), (size_t) len, f)) {
fclose(f);
@@ -492,37 +440,16 @@ i64 pit_as_bytes(pit_runtime *rt, pit_value v, u8 *buf, i64 maxlen) {
}
return len;
}
-bool pit_lexer_from_bytes(pit_runtime *rt, pit_lexer *ret, pit_value v) {
- if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return false;
- pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v));
- if (!h) { pit_error(rt, "bad ref"); return false; }
- if (h->hsort != PIT_VALUE_HEAVY_SORT_BYTES) {
- pit_error(rt, "invalid use of value as bytes");
- return -1;
- }
- pit_lex_bytes(ret, (char *) h->in.bytes.data, h->in.bytes.len);
- return true;
-}
-pit_value pit_read_bytes(pit_runtime *rt, pit_value v) { /* read a single lisp form from a bytestring */
- pit_lexer lex = {0};
- pit_parser parse = {0};
- if (!pit_lexer_from_bytes(rt, &lex, v)) {
- pit_error(rt, "failed to initialize lexer");
- return PIT_NIL;
- }
- pit_parser_from_lexer(&parse, &lex);
- return pit_parse(rt, &parse, NULL);
-}
pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len) {
if (rt->error != PIT_NIL) return PIT_NIL;
for (i64 sidx = 0; sidx < rt->symtab_len; ++sidx) {
- pit_symtab_entry *sent = pit_arena_idx(rt->symtab, sidx);
+ pit_symtab_entry *sent = pit_arena_get(rt->symtab, sidx);
if (!sent) { pit_error(rt, "corrupted symbol table"); return PIT_NIL; }
if (pit_bytes_match(rt, sent->name, nm, len)) return pit_symbol_new(rt, sidx);
}
i64 idx = pit_arena_alloc_idx(rt->symtab);
- pit_symtab_entry *ent = pit_arena_idx(rt->symtab, idx);
+ pit_symtab_entry *ent = pit_arena_get(rt->symtab, idx);
if (!ent) { pit_error(rt, "failed to allocate symtab entry"); return PIT_NIL; }
ent->name = pit_bytes_new(rt, nm, len);
ent->value = PIT_NIL;
@@ -551,7 +478,7 @@ bool pit_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s) {
}
pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym) {
pit_symbol s = pit_as_symbol(rt, sym);
- return pit_arena_idx(rt->symtab, s);
+ return pit_arena_get(rt->symtab, s);
}
pit_value pit_get_value_cell(pit_runtime *rt, pit_value sym) {
pit_symtab_entry *ent = pit_symtab_lookup(rt, sym);
@@ -677,10 +604,10 @@ void pit_cell_set(pit_runtime *rt, pit_value cell, pit_value v, pit_value sym) {
pit_value pit_array_new(pit_runtime *rt, i64 len) {
if (len < 0) { pit_error(rt, "failed to create array of negative size"); return PIT_NIL; }
- int i = 0;
- pit_value *dest = pit_arena_alloc_bulk(rt->arrays, len);
+ i64 byte_len = 0; pit_mul(&byte_len, sizeof(pit_value), len);
+ pit_value *dest = pit_arena_alloc_bulk(rt->heap, byte_len);
if (!dest) { pit_error(rt, "failed to allocate array"); return PIT_NIL; }
- for (; i < len; ++i) dest[i] = PIT_NIL;
+ for (i64 i = 0; i < len; ++i) dest[i] = PIT_NIL;
pit_value ret = pit_heavy_new(rt);
pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret));
if (!h) { pit_error(rt, "failed to create new heavy value for array"); return PIT_NIL; }
@@ -833,10 +760,10 @@ pit_value pit_plist_get(pit_runtime *rt, pit_value k, pit_value vs) {
}
pit_value pit_free_vars(pit_runtime *rt, pit_value initial_bound, pit_value body) {
- i64 expr_stack_reset = rt->expr_stack->top;
+ i64 expr_stack_reset = rt->expr_stack->next;
pit_value ret = PIT_NIL;
pit_values_push(rt, rt->expr_stack, pit_cons(rt, initial_bound, body));
- while (rt->expr_stack->top > expr_stack_reset) {
+ while (rt->expr_stack->next > expr_stack_reset) {
pit_value boundscur = pit_values_pop(rt, rt->expr_stack);
pit_value bound = pit_car(rt, boundscur);
pit_value cur = pit_cdr(rt, boundscur);
@@ -869,7 +796,7 @@ pit_value pit_free_vars(pit_runtime *rt, pit_value initial_bound, pit_value body
}
}
}
- rt->expr_stack->top = expr_stack_reset;
+ rt->expr_stack->next = expr_stack_reset;
return ret;
}
pit_value pit_lambda(pit_runtime *rt, pit_value args, pit_value body) {
@@ -1016,48 +943,48 @@ void *pit_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v) {
pit_values *pit_values_new(i64 capacity) {
i64 cap = capacity / (i64) sizeof(pit_value);
pit_values *ret = malloc(sizeof(*ret) + (size_t) cap * sizeof(pit_value));
- ret->top = 0;
- ret->cap = cap;
+ ret->next = 0;
+ ret->capacity = cap;
return ret;
}
void pit_values_push(pit_runtime *rt, pit_values *s, pit_value x) {
(void) rt;
- s->data[s->top++] = x;
- if (s->top >= s->cap) { pit_error(rt, "evaluation stack overflow"); }
+ s->data[s->next++] = x;
+ if (s->next >= s->capacity) { pit_error(rt, "evaluation stack overflow"); }
}
pit_value pit_values_pop(pit_runtime *rt, pit_values *s) {
- if (s->top == 0) { pit_error(rt, "evaluation stack underflow"); return PIT_NIL; }
- return s->data[--s->top];
+ if (s->next == 0) { pit_error(rt, "evaluation stack underflow"); return PIT_NIL; }
+ return s->data[--s->next];
}
pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity) {
i64 cap = capacity / (i64) sizeof(pit_runtime_eval_program_entry);
pit_runtime_eval_program *ret = malloc(sizeof(*ret) + (size_t) cap * sizeof(pit_runtime_eval_program_entry));
- ret->top = 0;
- ret->cap = cap;
+ ret->next = 0;
+ ret->capacity = cap;
return ret;
}
void pit_runtime_eval_program_push_literal(pit_runtime *rt, pit_runtime_eval_program *s, pit_value x) {
- pit_runtime_eval_program_entry *ent = &s->data[s->top++];
+ pit_runtime_eval_program_entry *ent = &s->data[s->next++];
ent->sort = EVAL_PROGRAM_ENTRY_LITERAL;
ent->in.literal = x;
- if (s->top >= s->cap) { pit_error(rt, "evaluation program overflow"); }
+ if (s->next >= s->capacity) { pit_error(rt, "evaluation program overflow"); }
(void) rt;
}
void pit_runtime_eval_program_push_apply(pit_runtime *rt, pit_runtime_eval_program *s, i64 arity) {
- pit_runtime_eval_program_entry *ent = &s->data[s->top++];
+ pit_runtime_eval_program_entry *ent = &s->data[s->next++];
ent->sort = EVAL_PROGRAM_ENTRY_APPLY;
ent->in.apply = arity;
- if (s->top >= s->cap) { pit_error(rt, "evaluation program overflow"); }
+ if (s->next >= s->capacity) { pit_error(rt, "evaluation program overflow"); }
(void) rt;
}
pit_value pit_expand_macros(pit_runtime *rt, pit_value top) {
- i64 expr_stack_reset = rt->expr_stack->top;
- i64 result_stack_reset = rt->result_stack->top;
- i64 program_reset = rt->program->top;
+ i64 expr_stack_reset = rt->expr_stack->next;
+ i64 result_stack_reset = rt->result_stack->next;
+ i64 program_reset = rt->program->next;
pit_values_push(rt, rt->expr_stack, top);
- while (rt->expr_stack->top > expr_stack_reset) {
+ while (rt->expr_stack->next > expr_stack_reset) {
pit_value cur;
if (rt->error != PIT_NIL) goto end;
cur = pit_values_pop(rt, rt->expr_stack);
@@ -1109,7 +1036,7 @@ pit_value pit_expand_macros(pit_runtime *rt, pit_value top) {
pit_runtime_eval_program_push_literal(rt, rt->program, cur);
}
}
- for (i64 idx = rt->program->top - 1; idx >= program_reset; --idx) {
+ for (i64 idx = rt->program->next - 1; idx >= program_reset; --idx) {
pit_runtime_eval_program_entry *ent;
if (rt->error != PIT_NIL) goto end;
ent = &rt->program->data[idx];
@@ -1133,20 +1060,20 @@ pit_value pit_expand_macros(pit_runtime *rt, pit_value top) {
}
end: {
pit_value ret = pit_values_pop(rt, rt->result_stack);
- rt->expr_stack->top = expr_stack_reset;
- rt->result_stack->top = result_stack_reset;
- rt->program->top = program_reset;
+ rt->expr_stack->next = expr_stack_reset;
+ rt->result_stack->next = result_stack_reset;
+ rt->program->next = program_reset;
return ret;
}
}
pit_value pit_eval(pit_runtime *rt, pit_value top) {
- i64 expr_stack_reset = rt->expr_stack->top;
- i64 result_stack_reset = rt->result_stack->top;
- i64 program_reset = rt->program->top;
+ i64 expr_stack_reset = rt->expr_stack->next;
+ i64 result_stack_reset = rt->result_stack->next;
+ i64 program_reset = rt->program->next;
pit_values_push(rt, rt->expr_stack, top);
/* first, convert the expression tree into "polish notation" in program */
- while (rt->expr_stack->top > expr_stack_reset) {
+ while (rt->expr_stack->next > expr_stack_reset) {
pit_value cur;
if (rt->error != PIT_NIL) goto end;
cur = pit_values_pop(rt, rt->expr_stack);
@@ -1194,7 +1121,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) {
+ for (i64 idx = rt->program->next - 1; idx >= program_reset; --idx) {
pit_runtime_eval_program_entry *ent;
if (rt->error != PIT_NIL) goto end;
ent = &rt->program->data[idx];
@@ -1218,9 +1145,9 @@ pit_value pit_eval(pit_runtime *rt, pit_value top) {
}
end: {
pit_value ret = pit_values_pop(rt, rt->result_stack);
- rt->expr_stack->top = expr_stack_reset;
- rt->result_stack->top = result_stack_reset;
- rt->program->top = program_reset;
+ rt->expr_stack->next = expr_stack_reset;
+ rt->result_stack->next = result_stack_reset;
+ rt->program->next = program_reset;
return ret;
}
}
@@ -1247,22 +1174,24 @@ static pit_value gc_copy_value(pit_runtime *rt, pit_arena *tospace, pit_value v)
}
}
void pit_collect_garbage(pit_runtime *rt) {
- pit_arena *fromspace = rt->values;
- pit_arena *tospace = rt->values_backbuffer;
- tospace->next = 0;
+ rt->frozen_values = 0;
+ rt->frozen_symtab = 0;
+ pit_arena *fromspace = rt->heap;
+ pit_arena *tospace = rt->backbuffer;
+ pit_arena_reset(tospace);
/* populate tospace with immediately reachable values */
for (i64 i = 0; i < rt->symtab_len; ++i) {
- pit_symtab_entry *ent = pit_arena_idx(rt->symtab, i);
+ pit_symtab_entry *ent = pit_arena_get(rt->symtab, i);
ent->name = gc_copy_value(rt, tospace, ent->name);
ent->value = gc_copy_value(rt, tospace, ent->value);
ent->function = gc_copy_value(rt, tospace, ent->function);
}
- for (i64 i = 0; i < rt->saved_bindings->top; ++i) {
+ for (i64 i = 0; i < rt->saved_bindings->next; ++i) {
pit_value *v = &rt->saved_bindings->data[i];
*v = gc_copy_value(rt, tospace, *v);
}
for (i64 scan = 0; scan < tospace->next; ++scan) {
- pit_value_heavy *h = pit_arena_idx(tospace, scan);
+ pit_value_heavy *h = pit_arena_get(tospace, scan);
switch (h->hsort) {
case PIT_VALUE_HEAVY_SORT_CELL:
h->in.cell = gc_copy_value(rt, tospace, h->in.cell);
@@ -1271,12 +1200,23 @@ void pit_collect_garbage(pit_runtime *rt) {
h->in.cons.car = gc_copy_value(rt, tospace, h->in.cons.car);
h->in.cons.cdr = gc_copy_value(rt, tospace, h->in.cons.cdr);
break;
- case PIT_VALUE_HEAVY_SORT_ARRAY:
+ case PIT_VALUE_HEAVY_SORT_ARRAY: {
+ i64 byte_len = 0; pit_mul(&byte_len, sizeof(pit_value), h->in.array.len);
+ pit_value *data = pit_arena_alloc_back(tospace, byte_len);
for (i64 i = 0; i < h->in.array.len; ++i) {
- h->in.array.data[i] = gc_copy_value(rt, tospace, h->in.array.data[i]);
+ data[i] = gc_copy_value(rt, tospace, h->in.array.data[i]);
}
+ h->in.array.data = data;
break;
- case PIT_VALUE_HEAVY_SORT_BYTES: break;
+ }
+ case PIT_VALUE_HEAVY_SORT_BYTES: {
+ u8 *data = pit_arena_alloc_back(tospace, h->in.bytes.len);
+ for (i64 i = 0; i < h->in.bytes.len; ++i) {
+ data[i] = h->in.bytes.data[i];
+ }
+ h->in.bytes.data = data;
+ break;
+ }
case PIT_VALUE_HEAVY_SORT_FUNC:
h->in.func.env = gc_copy_value(rt, tospace, h->in.func.env);
h->in.func.args = gc_copy_value(rt, tospace, h->in.func.args);
@@ -1292,29 +1232,40 @@ void pit_collect_garbage(pit_runtime *rt) {
break;
}
}
- rt->values = tospace;
- rt->values_backbuffer = fromspace;
+ rt->heap = tospace;
+ rt->backbuffer = fromspace;
}
-void pit_run_file(pit_runtime *rt, char *path) {
- pit_value bs = pit_bytes_new_file(rt, path);
+static void check_invariants(pit_runtime *rt) {
+ if (rt->scratch->next != 0) {
+ pit_error(rt, "leaked scratch memory! %ld", rt->scratch->next);
+ }
+ if (rt->scratch->next != 0) {
+ pit_error(rt, "leaked scratch memory! %ld", rt->scratch->next);
+ }
+}
+
+pit_value pit_load_file(pit_runtime *rt, char *path) {
pit_lexer lex;
pit_parser parse;
bool eof = false;
pit_value p = PIT_NIL;
- if (!pit_lexer_from_bytes(rt, &lex, bs)) {
- pit_error(rt, "failed to initialize lexer");
+ pit_value ret = PIT_NIL;
+ if (pit_lex_file(&lex, path) < 0) {
+ pit_error(rt, "failed to lex file: %s", path);
+ return PIT_NIL;
}
pit_parser_from_lexer(&parse, &lex);
while (p = pit_parse(rt, &parse, &eof), !eof) {
- if (pit_runtime_print_error(rt)) exit(1);
- pit_eval(rt, p);
- if (pit_runtime_print_error(rt)) exit(1);
+ check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
+ ret = pit_eval(rt, p);
+ check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
pit_collect_garbage(rt);
- if (pit_runtime_print_error(rt)) exit(1);
+ check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
}
- if (pit_runtime_print_error(rt)) exit(1);
- fprintf(stderr, "value allocs at exit: %ld\n", rt->values->next);
+ check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
+ fprintf(stderr, "value allocs at exit: %ld\n", rt->heap->next);
+ return ret;
}
void pit_repl(pit_runtime *rt) {
@@ -1322,7 +1273,7 @@ void pit_repl(pit_runtime *rt) {
char *buf = malloc(bufcap);
i64 len = 0;
pit_runtime_freeze(rt);
- if (pit_runtime_print_error(rt)) { exit(1); }
+ check_invariants(rt); if (pit_runtime_print_error(rt)) exit(1);
setbuf(stdout, NULL);
printf("> ");
while ((buf[len++] = (char) getchar()) != EOF) {
@@ -1353,7 +1304,9 @@ void pit_repl(pit_runtime *rt) {
pit_lex_bytes(&lex, buf, len);
pit_parser_from_lexer(&parse, &lex);
while (p = pit_parse(rt, &parse, &eof), !eof) {
+ check_invariants(rt);
res = pit_eval(rt, p);
+ check_invariants(rt);
}
if (pit_runtime_print_error(rt)) {
rt->error = PIT_NIL;
diff --git a/src/utils.c b/src/utils.c
index ebff4a7..5f9d49e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -18,3 +18,66 @@ void pit_debug(const char *format, ...) {
vfprintf(stderr, format, vargs);
va_end(vargs);
}
+
+static uintptr_t pit_align_down(uintptr_t addr, uintptr_t align) {
+ return addr & ~(align - 1); /* easy! just zero the low bits */
+}
+static uintptr_t pit_align_up(uintptr_t addr, uintptr_t align) {
+ return (addr + align - 1) /* increment past the next aligned address... */
+ & ~(align - 1); /* ...and then zero the low bits */
+}
+
+pit_arena *pit_arena_new(i64 capacity, i64 elem_size) {
+ i64 byte_len = 0;
+ pit_mul(&byte_len, elem_size, capacity);
+ pit_arena *a = (pit_arena *) malloc(sizeof(pit_arena) + (size_t) byte_len);
+ if (!a || byte_len <= 0) return NULL;
+ a->elem_size = elem_size;
+ a->capacity = byte_len / elem_size;
+ a->next = 0;
+ a->back = byte_len;
+ return a;
+}
+void pit_arena_reset(pit_arena *a) {
+ a->next = 0;
+ pit_mul(&a->back, a->elem_size, a->capacity);
+}
+static i64 pit_arena_byte_idx(pit_arena *a, i64 idx) {
+ i64 byte_idx = 0; pit_mul(&byte_idx, a->elem_size, idx);
+ return byte_idx;
+}
+i64 pit_arena_alloc_idx(pit_arena *a) {
+ i64 ret = a->next;
+ i64 byte_idx = pit_arena_byte_idx(a, ret);
+ if (byte_idx + a->elem_size >= a->back) { return -1; }
+ a->next += 1;
+ return ret;
+}
+i64 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num) {
+ i64 ret = a->next;
+ i64 byte_idx = pit_arena_byte_idx(a, ret);
+ i64 byte_len = 0; pit_mul(&byte_len, a->elem_size, num);
+ if (byte_idx + byte_len > a->back) { return -1; }
+ a->next += num;
+ return ret;
+}
+void *pit_arena_get(pit_arena *a, i64 idx) {
+ i64 byte_idx = pit_arena_byte_idx(a, idx);
+ if (byte_idx < 0 || byte_idx + a->elem_size >= a->back) { return NULL; }
+ return &a->data[byte_idx];
+}
+void *pit_arena_alloc(pit_arena *a) {
+ i64 idx = pit_arena_alloc_idx(a);
+ return pit_arena_get(a, idx);
+}
+void *pit_arena_alloc_bulk(pit_arena *a, i64 num) {
+ i64 idx = pit_arena_alloc_bulk_idx(a, num);
+ return pit_arena_get(a, idx);
+}
+void *pit_arena_alloc_back(pit_arena *a, i64 sz) {
+ i64 next_byte = pit_arena_byte_idx(a, a->next);
+ i64 back_byte = (i64) pit_align_down((uintptr_t) (a->back - sz), sizeof(void *));
+ if (back_byte < next_byte) return NULL;
+ a->back = back_byte;
+ return &a->data[a->back];
+}