summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-09-27 04:21:06 -0400
committerLLLL Colonq <llll@colonq>2025-09-27 04:21:06 -0400
commitab57bc2a6d6ea9c24aa119df6efbd8a38b54c312 (patch)
treebfc7fe32f40804e7808016038a3f2f15ef9e643e /src
parent811f11463851a0f35835ac72ef09b65b1072de20 (diff)
Source location tracking
Diffstat (limited to 'src')
-rw-r--r--src/lexer.c53
-rw-r--r--src/lexer.h9
-rw-r--r--src/library.c57
-rw-r--r--src/main.c54
-rw-r--r--src/parser.c12
-rw-r--r--src/parser.h3
-rw-r--r--src/runtime.c103
-rw-r--r--src/runtime.h11
8 files changed, 247 insertions, 55 deletions
diff --git a/src/lexer.c b/src/lexer.c
index 16f8aee..f7cc05e 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <ctype.h>
#include "utils.h"
@@ -35,38 +36,65 @@ static char peek(pit_lexer *st) {
}
static char advance(pit_lexer *st) {
- if (is_more_input(st)) return st->input[st->end++];
+ if (is_more_input(st)) {
+ char ret = st->input[st->end++];
+ if (ret == '\n') {
+ st->line += 1;
+ st->column = 0;
+ } else {
+ st->column += 1;
+ }
+ return ret;
+ }
else return 0;
}
static bool match(pit_lexer *st, int (*f)(int)) {
if (f(peek(st))) {
- st->end += 1;
+ advance(st);
return true;
} else return false;
}
-pit_lexer *pit_lex_file(char *path) {
- pit_lexer *ret = malloc(sizeof(*ret));
+void pit_lex_cstr(pit_lexer *ret, char *buf) {
+ ret->input = buf;
+ ret->len = strlen(buf);
+ ret->start = 0;
+ ret->end = 0;
+ ret->line = ret->start_line = 1;
+ ret->column = ret->start_column = 0;
+ ret->error = NULL;
+}
+
+void pit_lex_bytes(pit_lexer *ret, char *buf, i64 len) {
+ ret->len = len;
+ ret->input = buf;
+ ret->start = 0;
+ ret->end = 0;
+ ret->line = ret->start_line = 1;
+ ret->column = ret->start_column = 0;
+ ret->error = NULL;
+}
+void 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 NULL;
+ return;
}
fseek(f, 0, SEEK_END);
- ret->len = ftell(f);
+ i64 len = ftell(f);
fseek(f, 0, SEEK_SET);
- ret->input = calloc(ret->len, sizeof(char));
+ char *buf = calloc(ret->len, sizeof(char));
fread(ret->input, sizeof(char), ret->len, f);
fclose(f);
- ret->start = 0;
- ret->end = 0;
- return ret;
+ pit_lex_bytes(ret, buf, len);
}
pit_lex_token pit_lex_next(pit_lexer *st) {
restart:
st->start = st->end;
+ st->start_line = st->line;
+ st->start_column = st->column;
char c = advance(st);
switch (c) {
case 0: return PIT_LEX_TOKEN_EOF;
@@ -78,7 +106,10 @@ restart:
case '"':
while (peek(st) != '"') {
if (peek(st) == '\\') advance(st); // skip escaped characters
- if (!advance(st)) pit_panic("unterminated string starting at: %d", st->start);
+ if (!advance(st)) {
+ st->error = "unterminated string";
+ return PIT_LEX_TOKEN_ERROR;
+ }
}
advance(st);
return PIT_LEX_TOKEN_STRING_LITERAL;
diff --git a/src/lexer.h b/src/lexer.h
index dabe534..6f48d8f 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -18,10 +18,15 @@ typedef enum {
typedef struct {
char *input;
- i64 start, end, len;
+ i64 len; // length of input
+ i64 start, end; // bounds of the current token
+ i64 line, column; // for error reporting only; current line and column
+ i64 start_line, start_column; // for error reporting only; line and column of token start
+ char *error;
} pit_lexer;
-pit_lexer *pit_lex_file(char *path);
+void pit_lex_bytes(pit_lexer *ret, char *buf, i64 len);
+void 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/src/library.c b/src/library.c
index 3ca716f..be38292 100644
--- a/src/library.c
+++ b/src/library.c
@@ -1,5 +1,7 @@
#include <stdio.h>
+#include "lexer.h"
+#include "parser.h"
#include "runtime.h"
static pit_value impl_sf_quote(pit_runtime *rt, pit_value args) {
@@ -96,6 +98,16 @@ static pit_value impl_m_and(pit_runtime *rt, pit_value args) {
return ret;
}
+static pit_value impl_m_setq(pit_runtime *rt, pit_value args) {
+ pit_value sym = pit_car(rt, args);
+ pit_value v = pit_car(rt, pit_cdr(rt, args));
+ return pit_list(rt, 3,
+ pit_intern_cstr(rt, "set"),
+ pit_list(rt, 2, pit_intern_cstr(rt, "quote"), sym),
+ v
+ );
+}
+
static pit_value impl_set(pit_runtime *rt, pit_value args) {
pit_value sym = pit_car(rt, args);
pit_value v = pit_car(rt, pit_cdr(rt, args));
@@ -116,15 +128,54 @@ static pit_value impl_symbol_is_macro(pit_runtime *rt, pit_value args) {
return PIT_NIL;
}
+static pit_value impl_funcall(pit_runtime *rt, pit_value args) {
+ pit_value fsym = pit_car(rt, args);
+ pit_value f = pit_fget(rt, fsym);
+ pit_value as = pit_cdr(rt, args);
+ return pit_apply(rt, f, as);
+}
+
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_load(pit_runtime *rt, pit_value args) {
+ pit_value path = pit_car(rt, args);
+ char pathbuf[1024] = {0};
+ 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;
+ if (!pit_lexer_from_bytes(rt, &lex, bs)) {
+ pit_error(rt, "failed to initialize lexer");
+ return PIT_NIL;
+ }
+ pit_parser parse;
+ 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;
+}
+
static pit_value impl_print(pit_runtime *rt, pit_value args) {
pit_value x = pit_car(rt, args);
char buf[1024] = {0};
- pit_dump(rt, buf, sizeof(buf), x);
+ pit_dump(rt, buf, sizeof(buf), x, true);
+ buf[1023] = 0;
+ puts(buf);
+ return x;
+}
+
+static pit_value impl_princ(pit_runtime *rt, pit_value args) {
+ pit_value x = pit_car(rt, args);
+ char buf[1024] = {0};
+ pit_dump(rt, buf, sizeof(buf), x, false);
buf[1023] = 0;
puts(buf);
return x;
@@ -152,12 +203,16 @@ void pit_install_library_essential(pit_runtime *rt) {
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_mset(rt, pit_intern_cstr(rt, "setq"), pit_nativefunc_new(rt, impl_m_setq));
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, "funcall"), pit_nativefunc_new(rt, impl_funcall));
pit_fset(rt, pit_intern_cstr(rt, "eval"), pit_nativefunc_new(rt, impl_eval));
+ pit_fset(rt, pit_intern_cstr(rt, "load"), pit_nativefunc_new(rt, impl_load));
pit_fset(rt, pit_intern_cstr(rt, "print"), pit_nativefunc_new(rt, impl_print));
+ pit_fset(rt, pit_intern_cstr(rt, "princ"), pit_nativefunc_new(rt, impl_princ));
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 071cf7e..ef57b81 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <stdio.h>
#include "utils.h"
@@ -6,19 +7,46 @@
#include "runtime.h"
int main(int argc, char **argv) {
- if (argc < 2) pit_panic("usage: %s FILE", argv[0]);
-
pit_runtime *rt = pit_runtime_new();
- pit_check_error_maybe_panic(rt);
-
- pit_lexer *lex = pit_lex_file(argv[1]);
- pit_parser *parse = pit_parser_from_lexer(lex);
-
- 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);
+ if (argc < 2) { // run repl
+ pit_runtime_freeze(rt);
+ setbuf(stdout, NULL);
+ printf("> ");
+ char buf[1024] = {0};
+ i64 len = 0;
+ while (len < (i64) sizeof(buf) && (buf[len++] = getchar()) != EOF) {
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = 0;
+ pit_value bs = pit_bytes_new_cstr(rt, buf);
+ pit_value prog = pit_read_bytes(rt, bs);
+ pit_value res = pit_eval(rt, prog);
+ if (pit_runtime_print_error(rt)) {
+ rt->error = PIT_NIL;
+ printf("> ");
+ } else {
+ char dumpbuf[1024] = {0};
+ pit_dump(rt, dumpbuf, sizeof(dumpbuf) - 1, res, true);
+ printf("%s\n> ", dumpbuf);
+ }
+ len = 0;
+ }
+ }
+ } else { // run file
+ pit_value bs = pit_bytes_new_file(rt, argv[1]);
+ pit_lexer lex;
+ if (!pit_lexer_from_bytes(rt, &lex, bs)) {
+ pit_error(rt, "failed to initialize lexer");
+ }
+ pit_parser parse;
+ pit_parser_from_lexer(&parse, &lex);
+ bool eof = false;
+ pit_value p = PIT_NIL;
+ while (p = pit_parse(rt, &parse, &eof), !eof) {
+ pit_eval(rt, p);
+ if (pit_runtime_print_error(rt)) {
+ exit(1);
+ }
+ }
}
+
}
diff --git a/src/parser.c b/src/parser.c
index 0c9714a..30e38e6 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -18,6 +18,8 @@ static pit_lex_token advance(pit_parser *st) {
st->next.token = pit_lex_next(st->lexer);
st->next.start = st->lexer->start;
st->next.end = st->lexer->end;
+ st->next.line = st->lexer->start_line;
+ st->next.column = st->lexer->start_column;
return st->cur.token;
}
@@ -35,23 +37,25 @@ static void get_token_string(pit_parser *st, char *buf, i64 len) {
buf[tlen] = 0;
}
-pit_parser *pit_parser_from_lexer(pit_lexer *lex) {
- pit_parser *ret = malloc(sizeof(*ret));
+void pit_parser_from_lexer(pit_parser *ret, pit_lexer *lex) {
ret->lexer = lex;
ret->cur.token = ret->next.token = PIT_LEX_TOKEN_ERROR;
ret->cur.start = ret->next.start = 0;
ret->cur.end = ret->next.end = 0;
+ ret->cur.line = ret->next.line = -1;
+ ret->cur.column = ret->next.column = -1;
advance(ret);
- return ret;
}
// parse a single expression
pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
char buf[256] = {0};
pit_lex_token t = advance(st);
+ rt->source_line = st->cur.line;
+ rt->source_column = st->cur.column;
switch (t) {
case PIT_LEX_TOKEN_ERROR:
- pit_error(rt, "encountered an error token while parsing");
+ pit_error(rt, "encountered an error while lexing: %s", st->lexer->error);
return PIT_NIL;
case PIT_LEX_TOKEN_EOF:
if (eof != NULL) {
diff --git a/src/parser.h b/src/parser.h
index f99a891..bcd5458 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -7,6 +7,7 @@
typedef struct {
pit_lex_token token;
i64 start, end;
+ i64 line, column; // for error reporting
} pit_parser_token_info;
typedef struct {
@@ -14,7 +15,7 @@ typedef struct {
pit_parser_token_info cur, next;
} pit_parser;
-pit_parser *pit_parser_from_lexer(pit_lexer *lex);
+void pit_parser_from_lexer(pit_parser *ret, pit_lexer *lex);
pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof);
#endif
diff --git a/src/runtime.c b/src/runtime.c
index 3bfd1d4..6825bbe 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -6,6 +6,8 @@
#include <math.h>
#include "utils.h"
+#include "lexer.h"
+#include "parser.h"
#include "runtime.h"
#include "library.h"
@@ -76,6 +78,8 @@ pit_runtime *pit_runtime_new() {
ret->frozen_bytes = 0;
ret->frozen_symtab = 0;
ret->error = PIT_NIL;
+ ret->source_line = ret->source_column = -1;
+ ret->error_line = ret->error_column = -1;
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");
@@ -95,8 +99,17 @@ void pit_runtime_reset(pit_runtime *rt) {
rt->bytes->next = rt->frozen_bytes;
rt->symtab->next = rt->frozen_symtab;
}
+bool pit_runtime_print_error(pit_runtime *rt) {
+ if (!pit_eq(rt->error, PIT_NIL)) {
+ char buf[1024] = {0};
+ pit_dump(rt, buf, sizeof(buf), rt->error, false);
+ fprintf(stderr, "error at line %ld, column %ld: %s\n", rt->error_line, rt->error_column, buf);
+ return true;
+ }
+ return false;
+}
-i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
+i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
pit_value_heavy *h = NULL;
if (len <= 0) return 0;
switch (pit_value_sort(v)) {
@@ -128,7 +141,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
char *end = buf + len;
char *start = buf;
*(buf++) = '{';
- buf += pit_dump(rt, buf, end - buf, pit_car(rt, h->cell));
+ buf += pit_dump(rt, buf, end - buf, pit_car(rt, h->cell), readable);
*(buf++) = '}';
return buf - start;
}
@@ -139,12 +152,12 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
do {
if (pit_is_cons(rt, cur)) {
*(buf++) = ' '; if (buf >= end) return end - buf;
- buf += pit_dump(rt, buf, end - buf, pit_car(rt, cur));
+ buf += pit_dump(rt, buf, end - buf, pit_car(rt, cur), readable);
if (buf >= end) return end - buf;
} else {
buf += snprintf(buf, end - buf, " . ");
if (buf >= end) return end - buf;
- buf += pit_dump(rt, buf, end - buf, cur);
+ buf += pit_dump(rt, buf, end - buf, cur, readable);
if (buf >= end) return end - buf;
}
} while (!pit_eq((cur = pit_cdr(rt, cur)), PIT_NIL));
@@ -153,14 +166,15 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
return buf - start;
}
case PIT_VALUE_HEAVY_SORT_BYTES:
- buf[0] = '"';
- i64 i = 1;
- for (i64 j = 0; i < len - 1 && j < h->bytes.len;) {
+ i64 i = 0;
+ if (readable) buf[i++] = '"';
+ i64 maxlen = len - i;
+ for (i64 j = 0; i < maxlen && j < h->bytes.len;) {
if (buf[i - 1] != '\\' && (h->bytes.data[j] == '\\' || h->bytes.data[j] == '"'))
buf[i++] = '\\';
else buf[i++] = h->bytes.data[j++];
}
- if (i < len - 1) buf[i++] = '"';
+ if (readable && i < len - 1) buf[i++] = '"';
return i;
default:
return snprintf(buf, len, "<ref %d>", r);
@@ -173,7 +187,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v) {
void pit_trace_(pit_runtime *rt, const char *format, pit_value v) {
char buf[1024] = {0};
- pit_dump(rt, buf, sizeof(buf), v);
+ pit_dump(rt, buf, sizeof(buf), v, true);
fprintf(stderr, format, buf);
}
@@ -185,14 +199,8 @@ void pit_error(pit_runtime *rt, const char *format, ...) {
vsnprintf(buf, sizeof(buf), format, vargs);
va_end(vargs);
rt->error = pit_bytes_new_cstr(rt, buf);
- }
-}
-
-void pit_check_error_maybe_panic(pit_runtime *rt) {
- if (!pit_eq(rt->error, PIT_NIL)) {
- char buf[1024] = {0};
- pit_dump(rt, buf, sizeof(buf), rt->error);
- pit_panic("runtime error: %s", buf);
+ rt->error_line = rt->source_line;
+ rt->error_column = rt->source_column;
}
}
@@ -349,12 +357,10 @@ 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);
if (!dest) { pit_error(rt, "failed to allocate bytes"); return PIT_NIL; }
memcpy(dest, buf, len);
- if (!dest) return PIT_NIL;
pit_value ret = pit_heavy_new(rt);
pit_value_heavy *h = pit_deref(rt, ret);
if (!h) { pit_error(rt, "failed to create new heavy value for bytes"); return PIT_NIL; }
@@ -363,11 +369,30 @@ pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len) {
h->bytes.len = len;
return ret;
}
-
pit_value pit_bytes_new_cstr(pit_runtime *rt, char *s) {
return pit_bytes_new(rt, (u8 *) s, strlen(s));
}
-
+pit_value pit_bytes_new_file(pit_runtime *rt, char *path) {
+ FILE *f = fopen(path, "r");
+ if (f == NULL) {
+ pit_error(rt, "failed to open file: %s", path);
+ return PIT_NIL;
+ }
+ fseek(f, 0, SEEK_END);
+ i64 len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ u8 *dest = pit_arena_alloc_bulk(rt->bytes, len);
+ if (!dest) { pit_error(rt, "failed to allocate bytes"); fclose(f); return PIT_NIL; }
+ fread(dest, sizeof(char), len, f);
+ fclose(f);
+ pit_value ret = pit_heavy_new(rt);
+ pit_value_heavy *h = pit_deref(rt, ret);
+ if (!h) { pit_error(rt, "failed to create new heavy value for bytes"); return PIT_NIL; }
+ h->hsort = PIT_VALUE_HEAVY_SORT_BYTES;
+ h->bytes.data = dest;
+ h->bytes.len = len;
+ return ret;
+}
// return true if v is a reference to bytes that are the same as those in buf
bool pit_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len) {
if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return false;
@@ -381,6 +406,42 @@ bool pit_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len) {
}
return true;
}
+i64 pit_as_bytes(pit_runtime *rt, pit_value v, u8 *buf, i64 maxlen) {
+ if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return -1;
+ pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v));
+ if (!h) { pit_error(rt, "bad ref"); return -1; }
+ if (h->hsort != PIT_VALUE_HEAVY_SORT_BYTES) {
+ pit_error(rt, "invalid use of value as bytes");
+ return -1;
+ }
+ i64 len = maxlen < h->bytes.len ? maxlen : h->bytes.len;
+ for (i64 i = 0; i < len; ++i) {
+ buf[i] = h->bytes.data[i];
+ }
+ 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->bytes.data, h->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;
+ if (!pit_lexer_from_bytes(rt, &lex, v)) {
+ pit_error(rt, "failed to initialize lexer");
+ return PIT_NIL;
+ }
+ pit_parser parse;
+ pit_parser_from_lexer(&parse, &lex);
+ pit_value program = pit_parse(rt, &parse, NULL);
+ return pit_eval(rt, program);
+}
pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len) {
for (i64 i = 0; i < rt->symtab_len; ++i) {
diff --git a/src/runtime.h b/src/runtime.h
index f9995d1..101b677 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -3,6 +3,7 @@
#include "types.h"
#include "utils.h"
+#include "lexer.h"
struct pit_runtime;
@@ -101,17 +102,19 @@ typedef struct pit_runtime {
// "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
+ 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
} 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
+bool pit_runtime_print_error(pit_runtime *rt); // return true if an error has occured, and print to stderr
-i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v);
+i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable); // if readable is true, try to produce output that can be machine-read (quotes on strings, etc)
#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);
void pit_error(pit_runtime *rt, const char *format, ...);
-void pit_check_error_maybe_panic(pit_runtime *rt);
// working with small values
pit_value pit_value_new(pit_runtime *rt, enum pit_value_sort s, u64 data);
@@ -145,7 +148,11 @@ bool pit_equal(pit_runtime *rt, pit_value a, pit_value b);
// working with binary data
pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len);
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);