summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-12-19 16:24:15 -0500
committerLLLL Colonq <llll@colonq>2025-12-19 16:24:15 -0500
commit219c94c7eb7448bfc86602579de3765216888297 (patch)
tree04d45285bec04fe0e4e025e90f50dc262384b390 /include
parent09435bffe025a96e0d9c3b44ee9c505973b383bd (diff)
Update
Diffstat (limited to 'include')
-rw-r--r--include/lcq/pit/lexer.h34
-rw-r--r--include/lcq/pit/library.h10
-rw-r--r--include/lcq/pit/parser.h21
-rw-r--r--include/lcq/pit/runtime.h214
-rw-r--r--include/lcq/pit/types.h17
-rw-r--r--include/lcq/pit/utils.h12
6 files changed, 308 insertions, 0 deletions
diff --git a/include/lcq/pit/lexer.h b/include/lcq/pit/lexer.h
new file mode 100644
index 0000000..d6e4611
--- /dev/null
+++ b/include/lcq/pit/lexer.h
@@ -0,0 +1,34 @@
+#ifndef LCOLONQ_PIT_LEXER_H
+#define LCOLONQ_PIT_LEXER_H
+
+#include <lcq/pit/types.h>
+
+typedef enum {
+ PIT_LEX_TOKEN_ERROR=-1,
+ PIT_LEX_TOKEN_EOF=0,
+ PIT_LEX_TOKEN_LPAREN,
+ PIT_LEX_TOKEN_RPAREN,
+ PIT_LEX_TOKEN_DOT,
+ PIT_LEX_TOKEN_QUOTE,
+ PIT_LEX_TOKEN_INTEGER_LITERAL,
+ PIT_LEX_TOKEN_STRING_LITERAL,
+ PIT_LEX_TOKEN_SYMBOL,
+ PIT_LEX_TOKEN__SENTINEL
+} pit_lex_token;
+
+typedef struct {
+ char *input;
+ 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;
+
+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);
+pit_lex_token pit_lex_next(pit_lexer *st);
+const char *pit_lex_token_name(pit_lex_token t);
+
+#endif
diff --git a/include/lcq/pit/library.h b/include/lcq/pit/library.h
new file mode 100644
index 0000000..ff325dc
--- /dev/null
+++ b/include/lcq/pit/library.h
@@ -0,0 +1,10 @@
+#ifndef LCOLONQ_PIT_LIBRARY_H
+#define LCOLONQ_PIT_LIBRARY_H
+
+#include <lcq/pit/runtime.h>
+
+void pit_install_library_essential(pit_runtime *rt);
+void pit_install_library_io(pit_runtime *rt);
+void pit_install_library_bytestring(pit_runtime *rt);
+
+#endif
diff --git a/include/lcq/pit/parser.h b/include/lcq/pit/parser.h
new file mode 100644
index 0000000..c2f1597
--- /dev/null
+++ b/include/lcq/pit/parser.h
@@ -0,0 +1,21 @@
+#ifndef LCOLONQ_PIT_PARSER_H
+#define LCOLONQ_PIT_PARSER_H
+
+#include <lcq/pit/lexer.h>
+#include <lcq/pit/runtime.h>
+
+typedef struct {
+ pit_lex_token token;
+ i64 start, end;
+ i64 line, column; /* for error reporting */
+} pit_parser_token_info;
+
+typedef struct {
+ pit_lexer *lexer;
+ pit_parser_token_info cur, next;
+} pit_parser;
+
+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/include/lcq/pit/runtime.h b/include/lcq/pit/runtime.h
new file mode 100644
index 0000000..a8b6593
--- /dev/null
+++ b/include/lcq/pit/runtime.h
@@ -0,0 +1,214 @@
+#ifndef LCOLONQ_PIT_RUNTIME_H
+#define LCOLONQ_PIT_RUNTIME_H
+
+#include <lcq/pit/types.h>
+#include <lcq/pit/utils.h>
+#include <lcq/pit/lexer.h>
+
+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);
+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);
+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 0xfff4000000000001 /* 0b1111111111110100000000000000000000000000000000000000000000000001 */
+
+enum pit_value_sort {
+ PIT_VALUE_SORT_DOUBLE = 0, /* 0b00 - double */
+ PIT_VALUE_SORT_INTEGER = 1, /* 0b01 - NaN-boxed 49-bit integer */
+ PIT_VALUE_SORT_SYMBOL = 2, /* 0b10 - NaN-boxed index into symbol table */
+ PIT_VALUE_SORT_REF = 3 /* 0b11 - NaN-boxed index into "heavy object" arena */
+};
+typedef i32 pit_symbol; /* a symbol at runtime is an index into the runtime's symbol table */
+typedef i32 pit_ref; /* a reference is an index into the runtime's arena */
+typedef u64 pit_value;
+enum pit_value_sort pit_value_sort(pit_value v);
+u64 pit_value_data(pit_value v);
+
+typedef struct {
+ i64 top, cap;
+ pit_value data[];
+} pit_values;
+pit_values *pit_values_new(i64 capacity);
+void pit_values_push(struct pit_runtime *rt, pit_values *s, pit_value x);
+pit_value pit_values_pop(struct pit_runtime *rt, pit_values *s);
+
+typedef pit_value (*pit_nativefunc)(struct pit_runtime *rt, pit_value args);
+typedef struct { /* "heavy" values, the targets of refs */
+ enum pit_value_heavy_sort {
+ PIT_VALUE_HEAVY_SORT_CELL=0, /* value cell - basically, a "location" referred to by a variable binding */
+ PIT_VALUE_HEAVY_SORT_CONS, /* cons cell - a pair of two values */
+ PIT_VALUE_HEAVY_SORT_ARRAY, /* fixed-size array of values */
+ PIT_VALUE_HEAVY_SORT_BYTES, /* bytestring */
+ PIT_VALUE_HEAVY_SORT_FUNC, /* Lisp closure */
+ PIT_VALUE_HEAVY_SORT_NATIVEFUNC, /* native function */
+ PIT_VALUE_HEAVY_SORT_NATIVEDATA /* native data (C pointer) */
+ } hsort;
+ union {
+ pit_value cell;
+ struct { pit_value car, cdr; } cons;
+ struct { pit_value *data; i64 len; } array;
+ struct { u8 *data; i64 len; } bytes;
+ struct { pit_value env; pit_value args; pit_value body; } func;
+ pit_nativefunc nativefunc;
+ struct { pit_value tag; void *data; } nativedata;
+ } in;
+} pit_value_heavy;
+
+typedef struct {
+ pit_value name; /* ref to bytestring */
+ pit_value value; /* ref to cell */
+ pit_value function; /* ref to cell */
+ bool is_macro, is_special_form;
+} pit_symtab_entry;
+
+/* "programs"; vectors of "instructions" for a very simple VM used by the evaluator */
+typedef struct {
+ enum {
+ EVAL_PROGRAM_ENTRY_LITERAL,
+ EVAL_PROGRAM_ENTRY_APPLY
+ } sort;
+ union {
+ pit_value literal;
+ i64 apply; /* arity of application */
+ } in;
+} pit_runtime_eval_program_entry;
+typedef struct {
+ i64 top, cap;
+ pit_runtime_eval_program_entry data[];
+} pit_runtime_eval_program;
+pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity);
+void pit_runtime_eval_program_push_literal(struct pit_runtime *rt, pit_runtime_eval_program *s, pit_value x);
+void pit_runtime_eval_program_push_apply(struct pit_runtime *rt, pit_runtime_eval_program *s, i64 arity);
+
+typedef struct pit_runtime {
+ /* 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 */
+ 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);
+
+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, 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, ...);
+
+/* working with small values */
+pit_value pit_value_new(pit_runtime *rt, enum pit_value_sort s, u64 data);
+double pit_as_double(pit_runtime *rt, pit_value v);
+pit_value pit_double_new(pit_runtime *rt, double d);
+i64 pit_as_integer(pit_runtime *rt, pit_value v);
+pit_value pit_integer_new(pit_runtime *rt, i64 i);
+pit_symbol pit_as_symbol(pit_runtime *rt, pit_value v);
+pit_value pit_symbol_new(pit_runtime *rt, pit_symbol s);
+pit_ref pit_as_ref(pit_runtime *rt, pit_value v);
+pit_value pit_ref_new(pit_runtime *rt, pit_ref r);
+
+/* working with heavy values and refs */
+pit_value pit_heavy_new(pit_runtime *rt);
+pit_value_heavy *pit_deref(pit_runtime *rt, pit_ref p);
+
+/* convenient predicates */
+bool pit_is_integer(pit_runtime *rt, pit_value a);
+bool pit_is_double(pit_runtime *rt, pit_value a);
+bool pit_is_symbol(pit_runtime *rt, pit_value a);
+bool pit_is_value_heavy_sort(pit_runtime *rt, pit_value a, enum pit_value_heavy_sort e);
+bool pit_is_cell(pit_runtime *rt, pit_value a);
+bool pit_is_cons(pit_runtime *rt, pit_value a);
+bool pit_is_array(pit_runtime *rt, pit_value a);
+bool pit_is_bytes(pit_runtime *rt, pit_value a);
+bool pit_is_func(pit_runtime *rt, pit_value a);
+bool pit_is_nativefunc(pit_runtime *rt, pit_value a);
+bool pit_is_nativedata(pit_runtime *rt, pit_value a);
+bool pit_eq(pit_value a, pit_value b);
+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);
+pit_value pit_intern_cstr(pit_runtime *rt, char *nm);
+bool pit_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len);
+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_value pit_get_value_cell(pit_runtime *rt, pit_value sym);
+pit_value pit_get_function_cell(pit_runtime *rt, pit_value sym);
+pit_value pit_get(pit_runtime *rt, pit_value sym);
+void pit_set(pit_runtime *rt, pit_value sym, pit_value v);
+pit_value pit_fget(pit_runtime *rt, pit_value sym);
+void pit_fset(pit_runtime *rt, pit_value sym, pit_value v);
+bool pit_is_symbol_macro(pit_runtime *rt, pit_value sym);
+void pit_symbol_is_macro(pit_runtime *rt, pit_value sym);
+void pit_mset(pit_runtime *rt, pit_value sym, pit_value v);
+bool pit_is_symbol_special_form(pit_runtime *rt, pit_value sym);
+void pit_symbol_is_special_form(pit_runtime *rt, pit_value sym);
+void pit_sfset(pit_runtime *rt, pit_value sym, pit_value v);
+void pit_bind(pit_runtime *rt, pit_value sym, pit_value v);
+pit_value pit_unbind(pit_runtime *rt, pit_value sym);
+
+/* working with cells */
+pit_value pit_cell_new(pit_runtime *rt, pit_value v);
+pit_value pit_cell_get(pit_runtime *rt, pit_value cell);
+void pit_cell_set(pit_runtime *rt, pit_value cell, pit_value v);
+
+/* working with cons cells */
+pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr);
+pit_value pit_list(pit_runtime *rt, i64 num, ...);
+pit_value pit_car(pit_runtime *rt, pit_value v);
+pit_value pit_cdr(pit_runtime *rt, pit_value v);
+void pit_setcar(pit_runtime *rt, pit_value v, pit_value x);
+void pit_setcdr(pit_runtime *rt, pit_value v, pit_value x);
+pit_value pit_append(pit_runtime *rt, pit_value xs, pit_value ys);
+pit_value pit_reverse(pit_runtime *rt, pit_value xs);
+pit_value pit_contains_eq(pit_runtime *rt, pit_value needle, pit_value haystack);
+
+/* working with functions */
+pit_value pit_free_vars(pit_runtime *rt, pit_value args, pit_value body);
+pit_value pit_lambda(pit_runtime *rt, pit_value args, pit_value body);
+pit_value pit_nativefunc_new(pit_runtime *rt, pit_nativefunc f);
+pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args);
+
+/* working with native data */
+pit_value pit_nativedata_new(pit_runtime *rt, pit_value tag, void *d);
+
+
+/* evaluation! */
+pit_value pit_expand_macros(pit_runtime *rt, pit_value top);
+pit_value pit_eval(pit_runtime *rt, pit_value e);
+
+#endif
diff --git a/include/lcq/pit/types.h b/include/lcq/pit/types.h
new file mode 100644
index 0000000..384dc77
--- /dev/null
+++ b/include/lcq/pit/types.h
@@ -0,0 +1,17 @@
+#ifndef LCOLONQ_PIT_TYPES_H
+#define LCOLONQ_PIT_TYPES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+#endif
diff --git a/include/lcq/pit/utils.h b/include/lcq/pit/utils.h
new file mode 100644
index 0000000..36c74c1
--- /dev/null
+++ b/include/lcq/pit/utils.h
@@ -0,0 +1,12 @@
+#ifndef LCOLONQ_PIT_UTILS_H
+#define LCOLONQ_PIT_UTILS_H
+
+#include <stdckdint.h>
+
+#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","");
+
+#endif