diff options
| author | LLLL Colonq <llll@colonq> | 2025-09-27 04:21:06 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2025-09-27 04:21:06 -0400 |
| commit | ab57bc2a6d6ea9c24aa119df6efbd8a38b54c312 (patch) | |
| tree | bfc7fe32f40804e7808016038a3f2f15ef9e643e /src | |
| parent | 811f11463851a0f35835ac72ef09b65b1072de20 (diff) | |
Source location tracking
Diffstat (limited to 'src')
| -rw-r--r-- | src/lexer.c | 53 | ||||
| -rw-r--r-- | src/lexer.h | 9 | ||||
| -rw-r--r-- | src/library.c | 57 | ||||
| -rw-r--r-- | src/main.c | 54 | ||||
| -rw-r--r-- | src/parser.c | 12 | ||||
| -rw-r--r-- | src/parser.h | 3 | ||||
| -rw-r--r-- | src/runtime.c | 103 | ||||
| -rw-r--r-- | src/runtime.h | 11 |
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)); } @@ -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); |
