From 1c028e3a2250a56eface56ebbb1835d77e4e2579 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Tue, 30 Jun 2026 14:30:19 -0400 Subject: Big refactor --- Makefile | 11 +- include/lcq/pit/runtime.h | 202 +---- include/lcq/pit/runtime/dump.h | 10 + include/lcq/pit/runtime/eval.h | 8 + include/lcq/pit/runtime/gc.h | 8 + include/lcq/pit/runtime/macroexpand.h | 8 + include/lcq/pit/runtime/symtab.h | 27 + include/lcq/pit/runtime/value.h | 59 ++ include/lcq/pit/runtime/value/array.h | 15 + include/lcq/pit/runtime/value/bytes.h | 16 + include/lcq/pit/runtime/value/cell.h | 14 + include/lcq/pit/runtime/value/cons.h | 23 + include/lcq/pit/runtime/value/func.h | 15 + include/lcq/pit/runtime/value/nativedata.h | 12 + include/lcq/pit/runtime/value/small.h | 31 + include/lcq/pit/vec.h | 4 + src/lexer.c | 2 +- src/library.c | 796 +++++++++--------- src/main.c | 1 - src/native.c | 95 ++- src/parser.c | 53 +- src/runtime.c | 1217 +--------------------------- src/runtime/dump.c | 100 +++ src/runtime/eval.c | 107 +++ src/runtime/gc.c | 100 +++ src/runtime/macroexpand.c | 111 +++ src/runtime/symtab.c | 118 +++ src/runtime/value.c | 76 ++ src/runtime/value/array.c | 57 ++ src/runtime/value/bytes.c | 47 ++ src/runtime/value/cell.c | 47 ++ src/runtime/value/cons.c | 110 +++ src/runtime/value/func.c | 177 ++++ src/runtime/value/nativedata.c | 36 + src/runtime/value/small.c | 96 +++ 35 files changed, 1965 insertions(+), 1844 deletions(-) create mode 100644 include/lcq/pit/runtime/dump.h create mode 100644 include/lcq/pit/runtime/eval.h create mode 100644 include/lcq/pit/runtime/gc.h create mode 100644 include/lcq/pit/runtime/macroexpand.h create mode 100644 include/lcq/pit/runtime/symtab.h create mode 100644 include/lcq/pit/runtime/value.h create mode 100644 include/lcq/pit/runtime/value/array.h create mode 100644 include/lcq/pit/runtime/value/bytes.h create mode 100644 include/lcq/pit/runtime/value/cell.h create mode 100644 include/lcq/pit/runtime/value/cons.h create mode 100644 include/lcq/pit/runtime/value/func.h create mode 100644 include/lcq/pit/runtime/value/nativedata.h create mode 100644 include/lcq/pit/runtime/value/small.h create mode 100644 src/runtime/dump.c create mode 100644 src/runtime/eval.c create mode 100644 src/runtime/gc.c create mode 100644 src/runtime/macroexpand.c create mode 100644 src/runtime/symtab.c create mode 100644 src/runtime/value.c create mode 100644 src/runtime/value/array.c create mode 100644 src/runtime/value/bytes.c create mode 100644 src/runtime/value/cell.c create mode 100644 src/runtime/value/cons.c create mode 100644 src/runtime/value/func.c create mode 100644 src/runtime/value/nativedata.c create mode 100644 src/runtime/value/small.c diff --git a/Makefile b/Makefile index 40d12dc..2802d2e 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,17 @@ EXE ?= pit CC ?= gcc AR ?= ar override CPPFLAGS += -MMD -MP -override CFLAGS += -Oz -fPIC --std=c99 -g -Ideps/ -Isrc/ -Iinclude/ -Wall -Wextra -Wpedantic -Wconversion -Wformat-security -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wfloat-equal -Wundef -Wpointer-arith -Wbad-function-cast -Wlogical-op -Wmissing-braces -Wcast-align -Wstrict-overflow=5 -fwrapv # -ftrapv +override CFLAGS += -fPIC --std=c99 -g -Ideps/ -Isrc/ -Iinclude/ -Wall -Wextra -Wpedantic -Wconversion -Wformat-security -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wfloat-equal -Wundef -Wpointer-arith -Wbad-function-cast -Wlogical-op -Wmissing-braces -Wcast-align -Wstrict-overflow=5 -fwrapv # -ftrapv override LDFLAGS += -g -static BUILD = build_$(CC) -SRCS_CORE := src/utils.c src/arena.c src/lexer.c src/parser.c src/runtime.c src/library.c +SRCS_CORE := \ + src/utils.c src/arena.c src/lexer.c src/parser.c src/runtime.c \ + src/runtime/value.c \ + src/runtime/value/small.c src/runtime/value/cell.c src/runtime/value/cons.c src/runtime/value/array.c src/runtime/value/bytes.c src/runtime/value/func.c src/runtime/value/nativedata.c \ + src/runtime/symtab.c src/runtime/dump.c src/runtime/macroexpand.c src/runtime/eval.c src/runtime/gc.c \ + src/library.c OBJECTS_CORE := $(SRCS_CORE:src/%.c=$(BUILD)/%.o) LIB_CORE := libcolonq-pit.a SRCS_NATIVE := src/native.c @@ -39,6 +44,8 @@ $(LIB_NATIVE): $(OBJECTS_NATIVE) $(BUILD): mkdir $(BUILD)/ + mkdir $(BUILD)/runtime/ + mkdir $(BUILD)/runtime/value/ $(BUILD)/%.o: src/%.c | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< diff --git a/include/lcq/pit/runtime.h b/include/lcq/pit/runtime.h index da3cbdd..7692e03 100644 --- a/include/lcq/pit/runtime.h +++ b/include/lcq/pit/runtime.h @@ -7,56 +7,33 @@ #include #include -struct pit_runtime; - -/* nil is always the symbol with index 0 */ -#define PIT_NIL 0xfff4000000000000 /* 0b1111111111110100000000000000000000000000000000000000000000000000 */ -#define PIT_T (PIT_NIL+1) - -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 u64 pit_value; typedef i64 pit_symbol; /* a symbol at runtime is an index into the runtime's symbol table */ typedef i64 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); - PIT_DECLARE_VEC(pit_value) -typedef pit_value (*pit_nativefunc)(struct pit_runtime *rt, pit_value args, void *data); -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) */ - PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER /* forwarding pointer to to-space (during GC) */ - } 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 arg_rest_nm; pit_value body; } func; - struct { pit_nativefunc f; void *data; } nativefunc; - struct { pit_value tag; void *data; } nativedata; - i64 forwarding_pointer; - } in; -} pit_value_heavy; +struct pit_runtime; +/* symbol table entries. these are created/looked up when you intern a symbol */ 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, is_keyword; } pit_symtab_entry; +PIT_DECLARE_VEC(pit_symtab_entry) + +/* annotation attached to (some) heavy values detailing things like line numbers */ +typedef struct { + i64 line, column; +} pit_annotation; +typedef struct { + pit_ref ref; + pit_annotation annotation; +} pit_annotated_ref; +PIT_DECLARE_VEC(pit_annotated_ref) +void pit_annotation_set(struct pit_runtime *rt, pit_ref ref, pit_annotation annotation); +pit_annotated_ref *pit_annotation_get(struct pit_runtime *rt, pit_ref ref); /* "programs"; vectors of "instructions" for a very simple VM used by the evaluator */ typedef struct { @@ -66,26 +43,12 @@ typedef struct { } sort; union { pit_value literal; - i64 apply; /* arity of application */ + struct { i64 arity; pit_annotated_ref *annotation; } apply; } in; } pit_runtime_eval_ins; PIT_DECLARE_VEC(pit_runtime_eval_ins) void pit_runtime_eval_program_push_literal(struct pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, pit_value x); -void pit_runtime_eval_program_push_apply(struct pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, i64 arity); - -/* annotation attached to (some) heavy values detaiking things like line numbers */ -typedef struct { - pit_ref ref; - i64 line; - i64 column; -} pit_expr_annotation; -typedef struct { - i64 capacity, next; - pit_expr_annotation data[]; -} pit_expr_annotations; -pit_expr_annotations *pit_expr_annotations_new(u8 *buf, i64 buf_len); -void pit_expr_annotations_push(pit_expr_annotations *s, pit_ref ref, i64 line, i64 column); -pit_expr_annotation *pit_expr_annotations_lookup(pit_expr_annotations *s, pit_ref ref); +void pit_runtime_eval_program_push_apply(struct pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, i64 arity, pit_annotated_ref *annotation); typedef struct pit_runtime { /* interpreter state */ @@ -93,11 +56,10 @@ typedef struct pit_runtime { /* 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_expr_annotations *annotations; - pit_expr_annotations *annotations_backbuffer; - pit_arena *symtab; i64 symtab_len; /* all symbols - effectively an array of pit_symtab_entry */ + pit_vec(pit_annotated_ref) *annotations; + pit_vec(pit_annotated_ref) *backtrace; /* we reuse this vector for both backtraces and the GC */ + pit_vec(pit_symtab_entry) *symtab;/* all symbols */ /* temporary/"scratch" memory */ - pit_arena *scratch; /* temporary arena used during parsing and evaluation */ pit_vec(pit_value) *saved_bindings; /* stack used to save old values of bindings to be restored ("shallow binding") */ pit_vec(pit_value) *expr_stack; /* stack of subexpressions to evaluate during evaluation */ pit_vec(pit_value) *result_stack; /* stack of intermediate values during evaluation */ @@ -115,124 +77,20 @@ void pit_runtime_freeze(pit_runtime *rt); /* freeze the runtime at the current p 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, char *format, pit_value v); -pit_value pit_get_error(pit_runtime *rt); +#define pit_debug_trace(rt, v) pit_debug_trace_(rt, "Trace [" __FILE__ ":" PIT_STR(__LINE__) "] %s\n", v) +void pit_debug_trace_(pit_runtime *rt, char *format, pit_value v); +pit_value pit_error_get(pit_runtime *rt); void pit_error(pit_runtime *rt, char *format, ...); -/* working with small values */ -pit_value pit_value_new(pit_runtime *rt, enum pit_value_sort s, u64 data); -#ifndef PIT_NO_DOUBLE -double pit_as_double(pit_runtime *rt, pit_value v); -pit_value pit_double_new(pit_runtime *rt, double d); -#endif -i64 pit_as_integer(pit_runtime *rt, pit_value v); -pit_value pit_integer_new(pit_runtime *rt, i64 i); -pit_value pit_bool_new(pit_runtime *rt, bool 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_is_forwarding_pointer(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); - -/* 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); -pit_value pit_symbol_name(pit_runtime *rt, pit_value sym); -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, pit_value sym); -void pit_cell_set(pit_runtime *rt, pit_value cell, pit_value v, pit_value sym); - -/* working with arrays */ -pit_value pit_array_new(pit_runtime *rt, i64 len); -pit_value pit_array_from_buf(pit_runtime *rt, pit_value *xs, i64 len); -i64 pit_array_len(pit_runtime *rt, pit_value arr); -pit_value pit_array_get(pit_runtime *rt, pit_value arr, i64 idx); -pit_value pit_array_set(pit_runtime *rt, pit_value arr, i64 idx, 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, ...); -i64 pit_list_len(pit_runtime *rt, pit_value xs); -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); -pit_value pit_contains_equal(pit_runtime *rt, pit_value needle, pit_value haystack); -pit_value pit_plist_get(pit_runtime *rt, pit_value k, pit_value vs); - -/* 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_with_data(pit_runtime *rt, pit_nativefunc f, void *data); -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); -void *pit_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v); - -/* evaluation! */ -pit_value pit_expand_macros(pit_runtime *rt, pit_value top); -pit_value pit_eval(pit_runtime *rt, pit_value e); - -/* garbage collection */ -void pit_collect_garbage(pit_runtime *rt); - /* repl / file loading */ pit_value pit_load_file(pit_runtime *rt, char *path); void pit_repl(pit_runtime *rt); -/* test entrypoint */ -int pit_runtime_test(u8 *out, i64 out_len, u8 *buf, i64 len); +#include +#include +#include +#include +#include +#include #endif diff --git a/include/lcq/pit/runtime/dump.h b/include/lcq/pit/runtime/dump.h new file mode 100644 index 0000000..581cba0 --- /dev/null +++ b/include/lcq/pit/runtime/dump.h @@ -0,0 +1,10 @@ +#ifndef LCOLONQ_PIT_RUNTIME_DUMP_H +#define LCOLONQ_PIT_RUNTIME_DUMP_H + +#include + +/* pretty-print a pit value + if readable is true, try to produce output that can be machine-read (quotes on strings, etc) */ +i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable); + +#endif diff --git a/include/lcq/pit/runtime/eval.h b/include/lcq/pit/runtime/eval.h new file mode 100644 index 0000000..3dc9e3c --- /dev/null +++ b/include/lcq/pit/runtime/eval.h @@ -0,0 +1,8 @@ +#ifndef LCOLONQ_PIT_RUNTIME_EVAL_H +#define LCOLONQ_PIT_RUNTIME_EVAL_H + +#include + +pit_value pit_eval(pit_runtime *rt, pit_value e); + +#endif diff --git a/include/lcq/pit/runtime/gc.h b/include/lcq/pit/runtime/gc.h new file mode 100644 index 0000000..49921f0 --- /dev/null +++ b/include/lcq/pit/runtime/gc.h @@ -0,0 +1,8 @@ +#ifndef LCOLONQ_PIT_RUNTIME_GC_H +#define LCOLONQ_PIT_RUNTIME_GC_H + +#include + +void pit_gc(pit_runtime *rt); + +#endif diff --git a/include/lcq/pit/runtime/macroexpand.h b/include/lcq/pit/runtime/macroexpand.h new file mode 100644 index 0000000..bc1f756 --- /dev/null +++ b/include/lcq/pit/runtime/macroexpand.h @@ -0,0 +1,8 @@ +#ifndef LCOLONQ_PIT_RUNTIME_MACROEXPAND_H +#define LCOLONQ_PIT_RUNTIME_MACROEXPAND_H + +#include + +pit_value pit_macroexpand(pit_runtime *rt, pit_value top); + +#endif diff --git a/include/lcq/pit/runtime/symtab.h b/include/lcq/pit/runtime/symtab.h new file mode 100644 index 0000000..ac60523 --- /dev/null +++ b/include/lcq/pit/runtime/symtab.h @@ -0,0 +1,27 @@ +#ifndef LCOLONQ_PIT_RUNTIME_SYMTAB_H +#define LCOLONQ_PIT_RUNTIME_SYMTAB_H + +#include + +pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym); +pit_value pit_symtab_intern(pit_runtime *rt, u8 *nm, i64 len); +pit_value pit_symtab_intern_cstr(pit_runtime *rt, char *nm); +pit_value pit_symtab_symbol_name(pit_runtime *rt, pit_value sym); +bool pit_symtab_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len); +bool pit_symtab_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s); +pit_value pit_symtab_get_value_cell(pit_runtime *rt, pit_value sym); +pit_value pit_symtab_get_function_cell(pit_runtime *rt, pit_value sym); +pit_value pit_symtab_get(pit_runtime *rt, pit_value sym); +void pit_symtab_set(pit_runtime *rt, pit_value sym, pit_value v); +pit_value pit_symtab_fget(pit_runtime *rt, pit_value sym); +void pit_symtab_fset(pit_runtime *rt, pit_value sym, pit_value v); +bool pit_symtab_is_symbol_macro(pit_runtime *rt, pit_value sym); +void pit_symtab_symbol_mark_macro(pit_runtime *rt, pit_value sym); +void pit_symtab_mset(pit_runtime *rt, pit_value sym, pit_value v); +bool pit_symtab_is_symbol_special_form(pit_runtime *rt, pit_value sym); +void pit_symtab_symbol_mark_special_form(pit_runtime *rt, pit_value sym); +void pit_symtab_sfset(pit_runtime *rt, pit_value sym, pit_value v); +void pit_symtab_bind(pit_runtime *rt, pit_value sym, pit_value v); +pit_value pit_symtab_unbind(pit_runtime *rt, pit_value sym); + +#endif diff --git a/include/lcq/pit/runtime/value.h b/include/lcq/pit/runtime/value.h new file mode 100644 index 0000000..fa59a46 --- /dev/null +++ b/include/lcq/pit/runtime/value.h @@ -0,0 +1,59 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_H +#define LCOLONQ_PIT_RUNTIME_VALUE_H + +#include +#include + +/* the basic value type - it's just a u64 */ +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 */ +}; +enum pit_value_sort pit_value_sort(pit_value v); +u64 pit_value_data(pit_value v); + +/* nil is always the symbol with index 0 */ +#define PIT_NIL 0xfff4000000000000 /* 0b1111111111110100000000000000000000000000000000000000000000000000 */ +#define PIT_T (PIT_NIL+1) + +/* "heavy" values, the targets of refs */ +typedef pit_value (*pit_nativefunc)(struct pit_runtime *rt, pit_value args, void *data); +typedef struct { + 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) */ + PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER /* forwarding pointer to to-space (during GC) */ + } 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 arg_rest_nm; pit_value body; } func; + struct { pit_nativefunc f; void *data; } nativefunc; + struct { pit_value tag; void *data; } nativedata; + i64 forwarding_pointer; + } in; +} pit_value_heavy; + +pit_value pit_value_new(struct pit_runtime *rt, enum pit_value_sort s, u64 data); + +bool pit_value_eq(pit_value a, pit_value b); +bool pit_value_equal(pit_runtime *rt, pit_value a, pit_value b); + +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/include/lcq/pit/runtime/value/array.h b/include/lcq/pit/runtime/value/array.h new file mode 100644 index 0000000..0e5dd64 --- /dev/null +++ b/include/lcq/pit/runtime/value/array.h @@ -0,0 +1,15 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_ARRAY_H +#define LCOLONQ_PIT_RUNTIME_VALUE_ARRAY_H + +#include +#include + +/* heavy value - array */ +bool pit_value_is_array(pit_runtime *rt, pit_value a); +pit_value pit_value_array_new(pit_runtime *rt, i64 len); +pit_value pit_value_array_from_buf(pit_runtime *rt, pit_value *xs, i64 len); +i64 pit_value_array_len(pit_runtime *rt, pit_value arr); +pit_value pit_value_array_get(pit_runtime *rt, pit_value arr, i64 idx); +pit_value pit_value_array_set(pit_runtime *rt, pit_value arr, i64 idx, pit_value v); + +#endif diff --git a/include/lcq/pit/runtime/value/bytes.h b/include/lcq/pit/runtime/value/bytes.h new file mode 100644 index 0000000..cef5bed --- /dev/null +++ b/include/lcq/pit/runtime/value/bytes.h @@ -0,0 +1,16 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_BYTES_H +#define LCOLONQ_PIT_RUNTIME_VALUE_BYTES_H + +#include +#include + +/* heavy value - bytes */ + +bool pit_value_is_bytes(pit_runtime *rt, pit_value a); +pit_value pit_value_bytes_new(pit_runtime *rt, u8 *buf, i64 len); +pit_value pit_value_bytes_new_cstr(pit_runtime *rt, char *s); +pit_value pit_value_bytes_new_file(pit_runtime *rt, char *path); +bool pit_value_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len); +i64 pit_value_bytes_copy(pit_runtime *rt, pit_value v, u8 *buf, i64 maxlen); + +#endif diff --git a/include/lcq/pit/runtime/value/cell.h b/include/lcq/pit/runtime/value/cell.h new file mode 100644 index 0000000..01c503e --- /dev/null +++ b/include/lcq/pit/runtime/value/cell.h @@ -0,0 +1,14 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_CELL_H +#define LCOLONQ_PIT_RUNTIME_VALUE_CELL_H + +#include +#include + +/* heavy value - cell */ + +bool pit_value_is_cell(pit_runtime *rt, pit_value a); +pit_value pit_value_cell_new(pit_runtime *rt, pit_value v); +pit_value pit_value_cell_get(pit_runtime *rt, pit_value cell, pit_value sym); +void pit_value_cell_set(pit_runtime *rt, pit_value cell, pit_value v, pit_value sym); + +#endif diff --git a/include/lcq/pit/runtime/value/cons.h b/include/lcq/pit/runtime/value/cons.h new file mode 100644 index 0000000..e7f030a --- /dev/null +++ b/include/lcq/pit/runtime/value/cons.h @@ -0,0 +1,23 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_CONS_H +#define LCOLONQ_PIT_RUNTIME_VALUE_CONS_H + +#include +#include + +/* heavy value - cons/list */ +bool pit_value_is_cons(pit_runtime *rt, pit_value a); +pit_value pit_value_cons(pit_runtime *rt, pit_value car, pit_value cdr); +pit_value pit_value_cons_car(pit_runtime *rt, pit_value v); +pit_value pit_value_cons_cdr(pit_runtime *rt, pit_value v); +void pit_value_cons_setcar(pit_runtime *rt, pit_value v, pit_value x); +void pit_value_cons_setcdr(pit_runtime *rt, pit_value v, pit_value x); + +pit_value pit_value_list(pit_runtime *rt, i64 num, ...); +i64 pit_value_list_len(pit_runtime *rt, pit_value xs); +pit_value pit_value_list_append(pit_runtime *rt, pit_value xs, pit_value ys); +pit_value pit_value_list_reverse(pit_runtime *rt, pit_value xs); +pit_value pit_value_list_contains_eq(pit_runtime *rt, pit_value needle, pit_value haystack); +pit_value pit_value_list_contains_equal(pit_runtime *rt, pit_value needle, pit_value haystack); +pit_value pit_value_list_plist_get(pit_runtime *rt, pit_value k, pit_value vs); + +#endif diff --git a/include/lcq/pit/runtime/value/func.h b/include/lcq/pit/runtime/value/func.h new file mode 100644 index 0000000..852c90d --- /dev/null +++ b/include/lcq/pit/runtime/value/func.h @@ -0,0 +1,15 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_FUNC_H +#define LCOLONQ_PIT_RUNTIME_VALUE_FUNC_H + +#include +#include + +/* heavy value - func / nativefunc */ +bool pit_value_is_func(pit_runtime *rt, pit_value a); +bool pit_value_is_nativefunc(pit_runtime *rt, pit_value a); +pit_value pit_value_func_lambda(pit_runtime *rt, pit_value args, pit_value body); +pit_value pit_value_nativefunc_new_with_data(pit_runtime *rt, pit_nativefunc f, void *data); +pit_value pit_value_nativefunc_new(pit_runtime *rt, pit_nativefunc f); +pit_value pit_value_apply(pit_runtime *rt, pit_value f, pit_value args); + +#endif diff --git a/include/lcq/pit/runtime/value/nativedata.h b/include/lcq/pit/runtime/value/nativedata.h new file mode 100644 index 0000000..f8ffa4e --- /dev/null +++ b/include/lcq/pit/runtime/value/nativedata.h @@ -0,0 +1,12 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_NATIVEDATA_H +#define LCOLONQ_PIT_RUNTIME_VALUE_NATIVEDATA_H + +#include +#include + +/* heavy value - nativedata */ +bool pit_value_is_nativedata(pit_runtime *rt, pit_value a); +pit_value pit_value_nativedata_new(pit_runtime *rt, pit_value tag, void *d); +void *pit_value_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v); + +#endif diff --git a/include/lcq/pit/runtime/value/small.h b/include/lcq/pit/runtime/value/small.h new file mode 100644 index 0000000..957a670 --- /dev/null +++ b/include/lcq/pit/runtime/value/small.h @@ -0,0 +1,31 @@ +#ifndef LCOLONQ_PIT_RUNTIME_VALUE_SMALL_H +#define LCOLONQ_PIT_RUNTIME_VALUE_SMALL_H + +#include +#include + +/* the small values that can be NaN-boxed: doubles, integers, symbols */ + +#ifndef PIT_NO_DOUBLE +double pit_value_as_double(pit_runtime *rt, pit_value v); +bool pit_value_is_double(pit_runtime *rt, pit_value a); +pit_value pit_value_double_new(pit_runtime *rt, double d); +#endif + +i64 pit_value_as_integer(pit_runtime *rt, pit_value v); +bool pit_value_is_integer(pit_runtime *rt, pit_value a); +pit_value pit_value_integer_new(pit_runtime *rt, i64 i); +pit_value pit_value_bool_new(pit_runtime *rt, bool i); + +pit_symbol pit_value_as_symbol(pit_runtime *rt, pit_value v); +bool pit_value_is_symbol(pit_runtime *rt, pit_value a); +pit_value pit_value_symbol_new(pit_runtime *rt, pit_symbol s); + +pit_ref pit_value_as_ref(struct pit_runtime *rt, pit_value v); +bool pit_value_is_ref(pit_runtime *rt, pit_value a); +pit_value pit_value_ref_new(struct pit_runtime *rt, pit_ref r); +pit_value pit_value_ref_heavy_new(struct pit_runtime *rt); +pit_value_heavy *pit_value_ref_deref(struct pit_runtime *rt, pit_ref p); +bool pit_value_is_ref_heavy_sort(struct pit_runtime *rt, pit_value a, enum pit_value_heavy_sort e); + +#endif diff --git a/include/lcq/pit/vec.h b/include/lcq/pit/vec.h index 646f2e0..88cf804 100644 --- a/include/lcq/pit/vec.h +++ b/include/lcq/pit/vec.h @@ -6,6 +6,7 @@ #define pit_vec(ty) pit_vec__ ## ty ## __type #define pit_vec_new(ty) pit_vec__ ## ty ## __new +#define pit_vec_reset(ty) pit_vec__ ## ty ## __reset #define pit_vec_get(ty) pit_vec__ ## ty ## __get #define pit_vec_push(ty) pit_vec__ ## ty ## __push #define pit_vec_pop(ty) pit_vec__ ## ty ## __pop @@ -27,6 +28,9 @@ if ((ret->next + 1) * (i64) sizeof(ty) > ret->capacity) return NULL; \ return ret; \ } \ + static __attribute__ ((unused)) void pit_vec_reset(ty)(pit_vec(ty) *s) { \ + s->next = 0; \ + } \ static __attribute__ ((unused)) ty *pit_vec_get(ty)(pit_vec(ty) *s, i64 i) { \ i64 idx = i * (i64) sizeof(ty); \ if (idx + (i64) sizeof(ty) > s->capacity) return NULL; \ diff --git a/src/lexer.c b/src/lexer.c index 77d928e..def4084 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -24,7 +24,7 @@ static bool is_more_input(pit_lexer *st) { } static int is_symchar(int c) { - return c != '(' && c != ')' && c != '.' && c != '\'' && c != '"' + return c != '(' && c != ')' && c != '[' && c != ']' && c != '.' && c != '\'' && c != '"' && pit_libc_ctype_isprint(c) && !pit_libc_ctype_isspace(c); } diff --git a/src/library.c b/src/library.c index 1038004..b6b8b42 100644 --- a/src/library.c +++ b/src/library.c @@ -6,17 +6,17 @@ static pit_value impl_sf_quote(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_runtime_eval_program_push_literal(rt, rt->program, pit_car(rt, args)); + pit_runtime_eval_program_push_literal(rt, rt->program, pit_value_cons_car(rt, args)); return PIT_NIL; } static pit_value impl_sf_if(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value c = pit_car(rt, args); + pit_value c = pit_value_cons_car(rt, args); if (pit_eval(rt, c) != PIT_NIL) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_car(rt, pit_cdr(rt, args))) < 0) + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))) < 0) pit_error(rt, "in special form \"if\": evaluation stack overflow"); } else { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_car(rt, pit_cdr(rt, pit_cdr(rt, args)))) < 0) + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args)))) < 0) pit_error(rt, "in special form \"if\": evaluation stack overflow"); } return PIT_NIL; @@ -24,14 +24,14 @@ static pit_value impl_sf_if(pit_runtime *rt, pit_value args, void *data) { static pit_value impl_sf_cond(pit_runtime *rt, pit_value args, void *data) { (void) data; while (args != PIT_NIL) { - pit_value clause = pit_car(rt, args); - pit_value cond = pit_car(rt, clause); + pit_value clause = pit_value_cons_car(rt, args); + pit_value cond = pit_value_cons_car(rt, clause); if (pit_eval(rt, cond) != PIT_NIL) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_cons(rt, pit_intern_cstr(rt, "progn"), pit_cdr(rt, clause))) < 0) + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons(rt, pit_symtab_intern_cstr(rt, "progn"), pit_value_cons_cdr(rt, clause))) < 0) pit_error(rt, "in special form \"cond\": evaluation stack overflow"); return PIT_NIL; } - args = pit_cdr(rt, args); + args = pit_value_cons_cdr(rt, args); } if (pit_vec_push(pit_value)(rt->expr_stack, PIT_NIL) < 0) pit_error(rt, "in special form \"cond\": evaluation stack overflow"); @@ -42,8 +42,8 @@ static pit_value impl_sf_progn(pit_runtime *rt, pit_value args, void *data) { pit_value bodyforms = args; pit_value final = PIT_NIL; while (bodyforms != PIT_NIL) { - final = pit_eval(rt, pit_car(rt, bodyforms)); - bodyforms = pit_cdr(rt, bodyforms); + final = pit_eval(rt, pit_value_cons_car(rt, bodyforms)); + bodyforms = pit_value_cons_cdr(rt, bodyforms); } pit_runtime_eval_program_push_literal(rt, rt->program, final); return PIT_NIL; @@ -53,38 +53,38 @@ static pit_value impl_sf_or(pit_runtime *rt, pit_value args, void *data) { pit_value bodyforms = args; pit_value final = PIT_NIL; while (bodyforms != PIT_NIL) { - final = pit_eval(rt, pit_car(rt, bodyforms)); + final = pit_eval(rt, pit_value_cons_car(rt, bodyforms)); if (final != PIT_NIL) break; - bodyforms = pit_cdr(rt, bodyforms); + bodyforms = pit_value_cons_cdr(rt, bodyforms); } pit_runtime_eval_program_push_literal(rt, rt->program, final); return PIT_NIL; } static pit_value impl_sf_lambda(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value as = pit_car(rt, args); - pit_value body = pit_cdr(rt, args); - pit_runtime_eval_program_push_literal(rt, rt->program, pit_lambda(rt, as, body)); + pit_value as = pit_value_cons_car(rt, args); + pit_value body = pit_value_cons_cdr(rt, args); + pit_runtime_eval_program_push_literal(rt, rt->program, pit_value_func_lambda(rt, as, body)); return PIT_NIL; } static pit_value impl_m_defun(pit_runtime *rt, pit_value args, void *data) { (void) data; - 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)) + pit_value nm = pit_value_cons_car(rt, args); + pit_value as = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value body = pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args)); + return pit_value_list(rt, 3, + pit_symtab_intern_cstr(rt, "fset!"), + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "quote"), nm), + pit_value_cons(rt, pit_symtab_intern_cstr(rt, "lambda"), pit_value_cons(rt, as, body)) ); } static pit_value impl_m_defmacro(pit_runtime *rt, pit_value args, void *data) { (void) data; - 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) + pit_value nm = pit_value_cons_car(rt, args); + return pit_value_list(rt, 3, + pit_symtab_intern_cstr(rt, "progn"), + pit_value_cons(rt, pit_symtab_intern_cstr(rt, "defun!"), args), + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "set-symbol-macro!"), nm) ); } static pit_value impl_m_defstruct(pit_runtime *rt, pit_value args, void *data) { @@ -95,76 +95,76 @@ static pit_value impl_m_defstruct(pit_runtime *rt, pit_value args, void *data) { char nm_str[128]; char field_str[128]; char buf[512]; - pit_value nm = pit_car(rt, args); - pit_value fields = pit_cdr(rt, args); + pit_value nm = pit_value_cons_car(rt, args); + pit_value fields = pit_value_cons_cdr(rt, args); i64 field_idx = 0; - i64 nm_len = pit_as_bytes(rt, pit_symbol_name(rt, nm), (u8 *) nm_str, sizeof(nm_str) - 1); + i64 nm_len = pit_value_bytes_copy(rt, pit_symtab_symbol_name(rt, nm), (u8 *) nm_str, sizeof(nm_str) - 1); if (nm_len < 0) return PIT_NIL; nm_str[nm_len] = 0; /* constructor */ pit_libc_string_snprintf(buf, sizeof(buf), ":%s", nm_str); - aargs = pit_cons(rt, pit_intern_cstr(rt, buf), pit_cons(rt, pit_intern_cstr(rt, "array"), PIT_NIL)); - fields = pit_cdr(rt, args); + aargs = pit_value_cons(rt, pit_symtab_intern_cstr(rt, buf), pit_value_cons(rt, pit_symtab_intern_cstr(rt, "array"), PIT_NIL)); + fields = pit_value_cons_cdr(rt, args); while (fields != PIT_NIL) { - i64 field_len = pit_as_bytes(rt, - pit_symbol_name(rt, pit_car(rt, fields)), + i64 field_len = pit_value_bytes_copy(rt, + pit_symtab_symbol_name(rt, pit_value_cons_car(rt, fields)), (u8 *) field_str, sizeof(field_str) - 1 ); if (field_len < 0) return PIT_NIL; field_str[field_len] = 0; pit_libc_string_snprintf(buf, sizeof(buf), ":%s", field_str); - aargs = pit_cons(rt, - pit_list(rt, 3, pit_intern_cstr(rt, "plist/get"), pit_intern_cstr(rt, buf), pit_intern_cstr(rt, "kwargs")), + aargs = pit_value_cons(rt, + pit_value_list(rt, 3, pit_symtab_intern_cstr(rt, "plist/get"), pit_symtab_intern_cstr(rt, buf), pit_symtab_intern_cstr(rt, "kwargs")), aargs ); - fields = pit_cdr(rt, fields); + fields = pit_value_cons_cdr(rt, fields); } pit_libc_string_snprintf(buf, sizeof(buf), "%s/new", nm_str); - df = pit_list(rt, 4, - pit_intern_cstr(rt, "defun!"), - pit_intern_cstr(rt, buf), - pit_list(rt, 2, pit_intern_cstr(rt, "&"), pit_intern_cstr(rt, "kwargs")), - pit_reverse(rt, aargs) + df = pit_value_list(rt, 4, + pit_symtab_intern_cstr(rt, "defun!"), + pit_symtab_intern_cstr(rt, buf), + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "&"), pit_symtab_intern_cstr(rt, "kwargs")), + pit_value_list_reverse(rt, aargs) ); - ret = pit_cons(rt, df, ret); + ret = pit_value_cons(rt, df, ret); /* getters and setters */ - fields = pit_cdr(rt, args); + fields = pit_value_cons_cdr(rt, args); field_idx = 0; while (fields != PIT_NIL) { - i64 field_len = pit_as_bytes(rt, - pit_symbol_name(rt, pit_car(rt, fields)), + i64 field_len = pit_value_bytes_copy(rt, + pit_symtab_symbol_name(rt, pit_value_cons_car(rt, fields)), (u8 *) field_str, sizeof(field_str) - 1 ); if (field_len < 0) return PIT_NIL; field_str[field_len] = 0; /* getter */ pit_libc_string_snprintf(buf, sizeof(buf), "%s/get-%s", nm_str, field_str); - df = pit_list(rt, 4, - pit_intern_cstr(rt, "defun!"), - pit_intern_cstr(rt, buf), - pit_list(rt, 1, pit_intern_cstr(rt, "v")), - pit_list(rt, 3, - pit_intern_cstr(rt, "array/get"), - pit_integer_new(rt, field_idx + 1), - pit_intern_cstr(rt, "v") + df = pit_value_list(rt, 4, + pit_symtab_intern_cstr(rt, "defun!"), + pit_symtab_intern_cstr(rt, buf), + pit_value_list(rt, 1, pit_symtab_intern_cstr(rt, "v")), + pit_value_list(rt, 3, + pit_symtab_intern_cstr(rt, "array/get"), + pit_value_integer_new(rt, field_idx + 1), + pit_symtab_intern_cstr(rt, "v") ) ); - ret = pit_cons(rt, df, ret); + ret = pit_value_cons(rt, df, ret); /* setter */ pit_libc_string_snprintf(buf, sizeof(buf), "%s/set-%s!", nm_str, field_str); - df = pit_list(rt, 4, - pit_intern_cstr(rt, "defun!"), - pit_intern_cstr(rt, buf), - pit_list(rt, 2, pit_intern_cstr(rt, "v"), pit_intern_cstr(rt, "x")), - pit_list(rt, 4, - pit_intern_cstr(rt, "array/set!"), - pit_integer_new(rt, field_idx + 1), - pit_intern_cstr(rt, "x"), - pit_intern_cstr(rt, "v") + df = pit_value_list(rt, 4, + pit_symtab_intern_cstr(rt, "defun!"), + pit_symtab_intern_cstr(rt, buf), + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "v"), pit_symtab_intern_cstr(rt, "x")), + pit_value_list(rt, 4, + pit_symtab_intern_cstr(rt, "array/set!"), + pit_value_integer_new(rt, field_idx + 1), + pit_symtab_intern_cstr(rt, "x"), + pit_symtab_intern_cstr(rt, "v") ) ); - ret = pit_cons(rt, df, ret); - fields = pit_cdr(rt, fields); + ret = pit_value_cons(rt, df, ret); + fields = pit_value_cons_cdr(rt, fields); field_idx += 1; } // (defstruct foo x y z) @@ -172,48 +172,48 @@ static pit_value impl_m_defstruct(pit_runtime *rt, pit_value args, void *data) { // (defun foo/get-x (f) ...) // (defun foo/set-x! (f v) ...) // pit_trace(rt, ret); - return pit_cons(rt, pit_intern_cstr(rt, "progn"), ret); + return pit_value_cons(rt, pit_symtab_intern_cstr(rt, "progn"), ret); } static pit_value impl_m_let(pit_runtime *rt, pit_value args, void *data) { (void) data; pit_value lparams = PIT_NIL; pit_value largs = PIT_NIL; - pit_value binds = pit_car(rt, args); - pit_value bodyforms = pit_cdr(rt, args); + pit_value binds = pit_value_cons_car(rt, args); + pit_value bodyforms = pit_value_cons_cdr(rt, args); pit_value lambda, application; while (binds != PIT_NIL) { - pit_value bind = pit_car(rt, binds); - pit_value sym = pit_car(rt, bind); - pit_value expr = pit_car(rt, pit_cdr(rt, bind)); - lparams = pit_cons(rt, sym, lparams); - largs = pit_cons(rt, expr, largs); - binds = pit_cdr(rt, binds); - } - lambda = pit_cons(rt, pit_intern_cstr(rt, "lambda"), pit_cons(rt, lparams, bodyforms)); - application = pit_cons(rt, lambda, largs); + pit_value bind = pit_value_cons_car(rt, binds); + pit_value sym = pit_value_cons_car(rt, bind); + pit_value expr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, bind)); + lparams = pit_value_cons(rt, sym, lparams); + largs = pit_value_cons(rt, expr, largs); + binds = pit_value_cons_cdr(rt, binds); + } + lambda = pit_value_cons(rt, pit_symtab_intern_cstr(rt, "lambda"), pit_value_cons(rt, lparams, bodyforms)); + application = pit_value_cons(rt, lambda, largs); return application; } static pit_value impl_m_and(pit_runtime *rt, pit_value args, void *data) { (void) data; pit_value ret = PIT_NIL; - args = pit_reverse(rt, args); + args = pit_value_list_reverse(rt, args); if (args != PIT_NIL) { - ret = pit_car(rt, args); - args = pit_cdr(rt, args); + ret = pit_value_cons_car(rt, args); + args = pit_value_cons_cdr(rt, args); } while (args != PIT_NIL) { - ret = pit_list(rt, 3, pit_intern_cstr(rt, "if"), pit_car(rt, args), ret, PIT_NIL); - args = pit_cdr(rt, args); + ret = pit_value_list(rt, 3, pit_symtab_intern_cstr(rt, "if"), pit_value_cons_car(rt, args), ret, PIT_NIL); + args = pit_value_cons_cdr(rt, args); } return ret; } static pit_value impl_m_setq(pit_runtime *rt, pit_value args, void *data) { (void) data; - 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), + pit_value sym = pit_value_cons_car(rt, args); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_list(rt, 3, + pit_symtab_intern_cstr(rt, "set!"), + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "quote"), sym), v ); } @@ -222,139 +222,139 @@ static pit_value impl_m_setq(pit_runtime *rt, pit_value args, void *data) { // (cond ((eq x 'y) 'foo) ((eq x 'z) 'bar)) static pit_value impl_m_case(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value x = pit_car(rt, args); - pit_value cases = pit_cdr(rt, args); + pit_value x = pit_value_cons_car(rt, args); + pit_value cases = pit_value_cons_cdr(rt, args); pit_value clauses = PIT_NIL; - pit_value xvar = pit_intern_cstr(rt, "(internal case)"); + pit_value xvar = pit_symtab_intern_cstr(rt, "(internal case)"); while (cases != PIT_NIL) { - pit_value c = pit_car(rt, cases); - clauses = pit_cons(rt, - pit_list(rt, 2, - pit_list(rt, 3, pit_intern_cstr(rt, "equal?"), + pit_value c = pit_value_cons_car(rt, cases); + clauses = pit_value_cons(rt, + pit_value_list(rt, 2, + pit_value_list(rt, 3, pit_symtab_intern_cstr(rt, "equal?"), xvar, - pit_list(rt, 2, pit_intern_cstr(rt, "quote"), pit_car(rt, c)) + pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "quote"), pit_value_cons_car(rt, c)) ), - pit_car(rt, pit_cdr(rt, c)) + pit_value_cons_car(rt, pit_value_cons_cdr(rt, c)) ), clauses ); - cases = pit_cdr(rt, cases); + cases = pit_value_cons_cdr(rt, cases); } - return pit_list(rt, 3, - pit_intern_cstr(rt, "let"), - pit_list(rt, 1, pit_list(rt, 2, xvar, x)), - pit_cons(rt, pit_intern_cstr(rt, "cond"), pit_reverse(rt, clauses)) + return pit_value_list(rt, 3, + pit_symtab_intern_cstr(rt, "let"), + pit_value_list(rt, 1, pit_value_list(rt, 2, xvar, x)), + pit_value_cons(rt, pit_symtab_intern_cstr(rt, "cond"), pit_value_list_reverse(rt, clauses)) ); } static pit_value impl_set(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value sym = pit_car(rt, args); - pit_value v = pit_car(rt, pit_cdr(rt, args)); - pit_set(rt, sym, v); + pit_value sym = pit_value_cons_car(rt, args); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_symtab_set(rt, sym, v); return v; } static pit_value impl_fset(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value sym = pit_car(rt, args); - pit_value v = pit_car(rt, pit_cdr(rt, args)); - pit_fset(rt, sym, v); + pit_value sym = pit_value_cons_car(rt, args); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_symtab_fset(rt, sym, v); return v; } -static pit_value impl_symbol_is_macro(pit_runtime *rt, pit_value args, void *data) { +static pit_value impl_symbol_mark_macro(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value sym = pit_car(rt, args); - pit_symbol_is_macro(rt, sym); + pit_value sym = pit_value_cons_car(rt, args); + pit_symtab_symbol_mark_macro(rt, sym); return PIT_NIL; } static pit_value impl_funcall(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value f = pit_car(rt, args); - return pit_apply(rt, f, pit_cdr(rt, args)); + pit_value f = pit_value_cons_car(rt, args); + return pit_value_apply(rt, f, pit_value_cons_cdr(rt, args)); } static pit_value impl_apply(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value f = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); - return pit_apply(rt, f, xs); + pit_value f = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_apply(rt, f, xs); } static pit_value impl_error(pit_runtime *rt, pit_value args, void *data) { (void) data; rt->error = PIT_T; - rt->error = pit_car(rt, args); + rt->error = pit_value_cons_car(rt, args); rt->error_line = rt->source_line; rt->error_column = rt->source_column; return PIT_NIL; } static pit_value impl_eval(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_eval(rt, pit_car(rt, args)); + return pit_eval(rt, pit_value_cons_car(rt, args)); } static pit_value impl_eq_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value x = pit_car(rt, args); - pit_value y = pit_car(rt, pit_cdr(rt, args)); - return pit_bool_new(rt, pit_eq(x, y)); + pit_value x = pit_value_cons_car(rt, args); + pit_value y = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_bool_new(rt, pit_value_eq(x, y)); } static pit_value impl_equal_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value x = pit_car(rt, args); - pit_value y = pit_car(rt, pit_cdr(rt, args)); - return pit_bool_new(rt, pit_equal(rt, x, y)); + pit_value x = pit_value_cons_car(rt, args); + pit_value y = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_bool_new(rt, pit_value_equal(rt, x, y)); } static pit_value impl_integer_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_integer(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_integer(rt, pit_value_cons_car(rt, args))); } static pit_value impl_double_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_double(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_double(rt, pit_value_cons_car(rt, args))); } static pit_value impl_symbol_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_symbol(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_symbol(rt, pit_value_cons_car(rt, args))); } static pit_value impl_cons_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_cons(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_cons(rt, pit_value_cons_car(rt, args))); } static pit_value impl_array_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_array(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_array(rt, pit_value_cons_car(rt, args))); } static pit_value impl_bytes_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_bool_new(rt, pit_is_bytes(rt, pit_car(rt, args))); + return pit_value_bool_new(rt, pit_value_is_bytes(rt, pit_value_cons_car(rt, args))); } static pit_value impl_function_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value a = pit_car(rt, args); - bool b = (pit_is_symbol(rt, a) && pit_fget(rt, a) != PIT_NIL) - || pit_is_func(rt, a) - || pit_is_nativefunc(rt, a); - return pit_bool_new(rt, b); + pit_value a = pit_value_cons_car(rt, args); + bool b = (pit_value_is_symbol(rt, a) && pit_symtab_fget(rt, a) != PIT_NIL) + || pit_value_is_func(rt, a) + || pit_value_is_nativefunc(rt, a); + return pit_value_bool_new(rt, b); } static pit_value impl_cons(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_cons(rt, pit_car(rt, args), pit_car(rt, pit_cdr(rt, args))); + return pit_value_cons(rt, pit_value_cons_car(rt, args), pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); } static pit_value impl_car(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_car(rt, pit_car(rt, args)); + return pit_value_cons_car(rt, pit_value_cons_car(rt, args)); } static pit_value impl_cdr(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_cdr(rt, pit_car(rt, args)); + return pit_value_cons_cdr(rt, pit_value_cons_car(rt, args)); } static pit_value impl_setcar(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value v = pit_car(rt, pit_cdr(rt, args)); - pit_setcar(rt, pit_car(rt, args), v); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value_cons_setcar(rt, pit_value_cons_car(rt, args), v); return v; } static pit_value impl_setcdr(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value v = pit_car(rt, pit_cdr(rt, args)); - pit_setcdr(rt, pit_car(rt, args), v); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value_cons_setcdr(rt, pit_value_cons_car(rt, args), v); return v; } static pit_value impl_list(pit_runtime *rt, pit_value args, void *data) { @@ -364,195 +364,195 @@ static pit_value impl_list(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_list_nth(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 n = pit_as_integer(rt, pit_car(rt, args)); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); + i64 n = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (xs != PIT_NIL && n-- > 0) { - xs = pit_cdr(rt, xs); + xs = pit_value_cons_cdr(rt, xs); } - return pit_car(rt, xs); + return pit_value_cons_car(rt, xs); } static pit_value impl_list_iota(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 n = pit_as_integer(rt, pit_car(rt, args)); + i64 n = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); pit_value ret = PIT_NIL; while (n > 0) { - ret = pit_cons(rt, pit_integer_new(rt, --n), ret); + ret = pit_value_cons(rt, pit_value_integer_new(rt, --n), ret); } return ret; } static pit_value impl_list_len(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value arr = pit_car(rt, args); - return pit_integer_new(rt, pit_list_len(rt, arr)); + pit_value arr = pit_value_cons_car(rt, args); + return pit_value_integer_new(rt, pit_value_list_len(rt, arr)); } static pit_value impl_list_reverse(pit_runtime *rt, pit_value args, void *data) { (void) data; - return pit_reverse(rt, pit_car(rt, args)); + return pit_value_list_reverse(rt, pit_value_cons_car(rt, args)); } static pit_value impl_list_uniq(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value xs = pit_car(rt, args); + pit_value xs = pit_value_cons_car(rt, args); pit_value ret = PIT_NIL; while (xs != PIT_NIL) { - pit_value x = pit_car(rt, xs); - if (pit_contains_equal(rt, x, ret) == PIT_NIL) { - ret = pit_cons(rt, x, ret); + pit_value x = pit_value_cons_car(rt, xs); + if (pit_value_list_contains_equal(rt, x, ret) == PIT_NIL) { + ret = pit_value_cons(rt, x, ret); } - xs = pit_cdr(rt, xs); + xs = pit_value_cons_cdr(rt, xs); } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_list_append(pit_runtime *rt, pit_value args, void *data) { (void) data; - args = pit_reverse(rt, args); - pit_value ret = pit_car(rt, args); - pit_value ls = pit_cdr(rt, args); + args = pit_value_list_reverse(rt, args); + pit_value ret = pit_value_cons_car(rt, args); + pit_value ls = pit_value_cons_cdr(rt, args); while (ls != PIT_NIL) { - pit_value xs = pit_reverse(rt, pit_car(rt, ls)); + pit_value xs = pit_value_list_reverse(rt, pit_value_cons_car(rt, ls)); while (xs != PIT_NIL) { - ret = pit_cons(rt, pit_car(rt, xs), ret); - xs = pit_cdr(rt, xs); + ret = pit_value_cons(rt, pit_value_cons_car(rt, xs), ret); + xs = pit_value_cons_cdr(rt, xs); } - ls = pit_cdr(rt, ls); + ls = pit_value_cons_cdr(rt, ls); } return ret; } static pit_value impl_list_concat(pit_runtime *rt, pit_value args, void *data) { (void) data; - return impl_list_append(rt, pit_car(rt, args), NULL); + return impl_list_append(rt, pit_value_cons_car(rt, args), NULL); } static pit_value impl_list_take(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 num = pit_as_integer(rt, pit_car(rt, args)); - pit_value arr = pit_car(rt, pit_cdr(rt, args)); + i64 num = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); pit_value ret = PIT_NIL; while (num > 0 && arr != PIT_NIL) { - ret = pit_cons(rt, pit_car(rt, arr), ret); - arr = pit_cdr(rt, arr); + ret = pit_value_cons(rt, pit_value_cons_car(rt, arr), ret); + arr = pit_value_cons_cdr(rt, arr); num -= 1; } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_list_drop(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 num = pit_as_integer(rt, pit_car(rt, args)); - pit_value arr = pit_car(rt, pit_cdr(rt, args)); + i64 num = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (num > 0 && arr != PIT_NIL) { - arr = pit_cdr(rt, arr); + arr = pit_value_cons_cdr(rt, arr); num -= 1; } return arr; } static pit_value impl_list_map(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); + pit_value func = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); pit_value ret = PIT_NIL; while (xs != PIT_NIL) { - pit_value y = pit_apply(rt, func, pit_cons(rt, pit_car(rt, xs), PIT_NIL)); - ret = pit_cons(rt, y, ret); - xs = pit_cdr(rt, xs); + pit_value y = pit_value_apply(rt, func, pit_value_cons(rt, pit_value_cons_car(rt, xs), PIT_NIL)); + ret = pit_value_cons(rt, y, ret); + xs = pit_value_cons_cdr(rt, xs); } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_list_foldl(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value acc = pit_car(rt, pit_cdr(rt, args)); - pit_value xs = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); + pit_value func = pit_value_cons_car(rt, args); + pit_value acc = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args))); while (xs != PIT_NIL) { - acc = pit_apply(rt, func, pit_list(rt, 2, pit_car(rt, xs), acc)); - xs = pit_cdr(rt, xs); + acc = pit_value_apply(rt, func, pit_value_list(rt, 2, pit_value_cons_car(rt, xs), acc)); + xs = pit_value_cons_cdr(rt, xs); } return acc; } static pit_value impl_list_filter(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); + pit_value func = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); pit_value ret = PIT_NIL; while (xs != PIT_NIL) { - pit_value x = pit_car(rt, xs); - pit_value y = pit_apply(rt, func, pit_cons(rt, x, PIT_NIL)); + pit_value x = pit_value_cons_car(rt, xs); + pit_value y = pit_value_apply(rt, func, pit_value_cons(rt, x, PIT_NIL)); if (y != PIT_NIL) { - ret = pit_cons(rt, x, ret); + ret = pit_value_cons(rt, x, ret); } - xs = pit_cdr(rt, xs); + xs = pit_value_cons_cdr(rt, xs); } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_list_find(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); + pit_value func = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (xs != PIT_NIL) { - pit_value x = pit_car(rt, xs); - pit_value y = pit_apply(rt, func, pit_cons(rt, x, PIT_NIL)); + pit_value x = pit_value_cons_car(rt, xs); + pit_value y = pit_value_apply(rt, func, pit_value_cons(rt, x, PIT_NIL)); if (y != PIT_NIL) { return x; } - xs = pit_cdr(rt, xs); + xs = pit_value_cons_cdr(rt, xs); } return PIT_NIL; } static pit_value impl_list_contains_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value needle = pit_car(rt, args); - pit_value haystack = pit_car(rt, pit_cdr(rt, args)); + pit_value needle = pit_value_cons_car(rt, args); + pit_value haystack = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (haystack != PIT_NIL) { - if (pit_equal(rt, needle, pit_car(rt, haystack))) return PIT_T; - haystack = pit_cdr(rt, haystack); + if (pit_value_equal(rt, needle, pit_value_cons_car(rt, haystack))) return PIT_T; + haystack = pit_value_cons_cdr(rt, haystack); } return PIT_NIL; } static pit_value impl_list_all_p(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value f = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); + pit_value f = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (xs != PIT_NIL) { - pit_value x = pit_car(rt, xs); - if (pit_apply(rt, f, pit_cons(rt, x, PIT_NIL)) == PIT_NIL) { + pit_value x = pit_value_cons_car(rt, xs); + if (pit_value_apply(rt, f, pit_value_cons(rt, x, PIT_NIL)) == PIT_NIL) { return PIT_NIL; } - xs = pit_cdr(rt, xs); + xs = pit_value_cons_cdr(rt, xs); } return PIT_T; } static pit_value impl_list_zip_with(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value f = pit_car(rt, args); - pit_value xs = pit_car(rt, pit_cdr(rt, args)); - pit_value ys = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); + pit_value f = pit_value_cons_car(rt, args); + pit_value xs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value ys = pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args))); pit_value ret = PIT_NIL; while (xs != PIT_NIL && ys != PIT_NIL) { - pit_value z = pit_apply(rt, f, pit_list(rt, 2, pit_car(rt, xs), pit_car(rt, ys))); - ret = pit_cons(rt, z, ret); - xs = pit_cdr(rt, xs); ys = pit_cdr(rt, ys); + pit_value z = pit_value_apply(rt, f, pit_value_list(rt, 2, pit_value_cons_car(rt, xs), pit_value_cons_car(rt, ys))); + ret = pit_value_cons(rt, z, ret); + xs = pit_value_cons_cdr(rt, xs); ys = pit_value_cons_cdr(rt, ys); } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_bytes_len(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value v = pit_car(rt, args); + pit_value v = pit_value_cons_car(rt, args); if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { pit_error(rt, "value is not a ref"); return PIT_NIL; } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v)); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } if (h->hsort != PIT_VALUE_HEAVY_SORT_BYTES) { pit_error(rt, "ref is not bytes"); return PIT_NIL; } - return pit_integer_new(rt, h->in.bytes.len); + return pit_value_integer_new(rt, h->in.bytes.len); } static pit_value impl_bytes_range(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 start = pit_as_integer(rt, pit_car(rt, args)); - i64 end = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - pit_value v = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); + i64 start = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 end = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args))); if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { pit_error(rt, "value is not a ref"); return PIT_NIL; } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v)); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } if (h->hsort != PIT_VALUE_HEAVY_SORT_BYTES) { pit_error(rt, "ref is not bytes"); return PIT_NIL; } if (start < 0 || start >= h->in.bytes.len) { @@ -563,43 +563,41 @@ static pit_value impl_bytes_range(pit_runtime *rt, pit_value args, void *data) { pit_error(rt, "bytes range end index out of bounds: %d", end); return PIT_NIL; } - return pit_bytes_new(rt, h->in.bytes.data + start, end - start); + return pit_value_bytes_new(rt, h->in.bytes.data + start, end - start); } static pit_value impl_array(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 scratch_reset = rt->scratch->next; - i64 len = 0; + i64 len = pit_value_list_len(rt, args); + pit_value ret = pit_value_array_new(rt, len); + i64 idx = 0; while (args != PIT_NIL) { - pit_value *cell = pit_arena_alloc_array(rt->scratch, sizeof(pit_value)); - *cell = pit_car(rt, args); - len += 1; - args = pit_cdr(rt, args); + pit_value_array_set(rt, ret, idx++, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - rt->scratch->next = scratch_reset; - return pit_array_from_buf(rt, pit_arena_get(rt->scratch, (i32) scratch_reset), len); + return ret; } static pit_value impl_array_to_list(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value arr = pit_car(rt, args); - i64 ilen = pit_array_len(rt, arr); + pit_value arr = pit_value_cons_car(rt, args); + i64 ilen = pit_value_array_len(rt, arr); pit_value ret = PIT_NIL; i64 i = 0; for (; i < ilen; ++i) { - ret = pit_cons(rt, pit_array_get(rt, arr, i), ret); + ret = pit_value_cons(rt, pit_value_array_get(rt, arr, i), ret); } - return pit_reverse(rt, ret); + return pit_value_list_reverse(rt, ret); } static pit_value impl_array_from_list(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 i = 0; - pit_value xs = pit_car(rt, args); - i64 ilen = pit_list_len(rt, xs); - pit_value ret = pit_array_new(rt, ilen); - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret)); + pit_value xs = pit_value_cons_car(rt, args); + i64 ilen = pit_value_list_len(rt, xs); + pit_value ret = pit_value_array_new(rt, ilen); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); if (!h) { pit_error(rt, "failed to deref heavy value for array"); return PIT_NIL; } while (xs != PIT_NIL) { - h->in.array.data[i] = pit_car(rt, xs); - xs = pit_cdr(rt, xs); + h->in.array.data[i] = pit_value_cons_car(rt, xs); + xs = pit_value_cons_cdr(rt, xs); i += 1; } return ret; @@ -607,11 +605,11 @@ static pit_value impl_array_from_list(pit_runtime *rt, pit_value args, void *dat static pit_value impl_array_repeat(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 i = 0; - pit_value v = pit_car(rt, args); - pit_value len = pit_car(rt, pit_cdr(rt, args)); - i64 ilen = pit_as_integer(rt, len); - pit_value ret = pit_array_new(rt, ilen); - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret)); + pit_value v = pit_value_cons_car(rt, args); + pit_value len = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + i64 ilen = pit_value_as_integer(rt, len); + pit_value ret = pit_value_array_new(rt, ilen); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); if (!h) { pit_error(rt, "failed to deref heavy value for array"); return PIT_NIL; } for (; i < ilen; ++i) { h->in.array.data[i] = v; @@ -620,98 +618,98 @@ static pit_value impl_array_repeat(pit_runtime *rt, pit_value args, void *data) } static pit_value impl_array_len(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value arr = pit_car(rt, args); - return pit_integer_new(rt, pit_array_len(rt, arr)); + pit_value arr = pit_value_cons_car(rt, args); + return pit_value_integer_new(rt, pit_value_array_len(rt, arr)); } static pit_value impl_array_get(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value idx = pit_car(rt, args); - pit_value arr = pit_car(rt, pit_cdr(rt, args)); - return pit_array_get(rt, arr, pit_as_integer(rt, idx)); + pit_value idx = pit_value_cons_car(rt, args); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_array_get(rt, arr, pit_value_as_integer(rt, idx)); } static pit_value impl_array_set(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value idx = pit_car(rt, args); - pit_value v = pit_car(rt, pit_cdr(rt, args)); - pit_value arr = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); - return pit_array_set(rt, arr, pit_as_integer(rt, idx), v); + pit_value idx = pit_value_cons_car(rt, args); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args))); + return pit_value_array_set(rt, arr, pit_value_as_integer(rt, idx), v); } static pit_value impl_array_map(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value arr = pit_car(rt, pit_cdr(rt, args)); - i64 len = pit_array_len(rt, arr); - pit_value ret = pit_array_new(rt, len); + pit_value func = pit_value_cons_car(rt, args); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + i64 len = pit_value_array_len(rt, arr); + pit_value ret = pit_value_array_new(rt, len); i64 i = 0; for (i = 0; i < len; ++i) { - pit_value y = pit_apply(rt, func, pit_cons(rt, pit_array_get(rt, arr, i), PIT_NIL)); - pit_array_set(rt, ret, i, y); + pit_value y = pit_value_apply(rt, func, pit_value_cons(rt, pit_value_array_get(rt, arr, i), PIT_NIL)); + pit_value_array_set(rt, ret, i, y); } return ret; } static pit_value impl_array_map_mut(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value func = pit_car(rt, args); - pit_value arr = pit_car(rt, pit_cdr(rt, args)); - i64 len = pit_array_len(rt, arr); + pit_value func = pit_value_cons_car(rt, args); + pit_value arr = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + i64 len = pit_value_array_len(rt, arr); i64 i = 0; for (i = 0; i < len; ++i) { - pit_value y = pit_apply(rt, func, pit_cons(rt, pit_array_get(rt, arr, i), PIT_NIL)); - pit_array_set(rt, arr, i, y); + pit_value y = pit_value_apply(rt, func, pit_value_cons(rt, pit_value_array_get(rt, arr, i), PIT_NIL)); + pit_value_array_set(rt, arr, i, y); } return arr; } static pit_value impl_abs(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - if (x < 0) return pit_integer_new(rt, -x); - return pit_integer_new(rt, x); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + if (x < 0) return pit_value_integer_new(rt, -x); + return pit_value_integer_new(rt, x); } static pit_value impl_add(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = 0; while (args != PIT_NIL) { - total += pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total += pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_sub(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = 0; while (args != PIT_NIL) { - total -= pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total -= pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_mul(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = 1; while (args != PIT_NIL) { - total *= pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total *= pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_div(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 total = pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + i64 total = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); while (args != PIT_NIL) { - i64 denom = pit_as_integer(rt, pit_car(rt, args)); + i64 denom = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); if (denom == 0) { pit_error(rt, "divide by zero"); return PIT_NIL; } total /= denom; - args = pit_cdr(rt, args); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_not(pit_runtime *rt, pit_value args, void *data) { (void) data; - if (pit_car(rt, args) == PIT_NIL) { + if (pit_value_cons_car(rt, args) == PIT_NIL) { return PIT_T; } else { return PIT_NIL; @@ -719,194 +717,194 @@ static pit_value impl_not(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_lt(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - i64 y = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - return pit_bool_new(rt, x < y); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 y = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + return pit_value_bool_new(rt, x < y); } static pit_value impl_gt(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - i64 y = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - return pit_bool_new(rt, x > y); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 y = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + return pit_value_bool_new(rt, x > y); } static pit_value impl_le(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - i64 y = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - return pit_bool_new(rt, x <= y); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 y = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + return pit_value_bool_new(rt, x <= y); } static pit_value impl_ge(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - i64 y = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - return pit_bool_new(rt, x >= y); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 y = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + return pit_value_bool_new(rt, x >= y); } static pit_value impl_bitwise_and(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = -1; while (args != PIT_NIL) { - total &= pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total &= pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_bitwise_or(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = 0; while (args != PIT_NIL) { - total |= pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total |= pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_bitwise_xor(pit_runtime *rt, pit_value args, void *data) { (void) data; i64 total = 0; while (args != PIT_NIL) { - total ^= pit_as_integer(rt, pit_car(rt, args)); - args = pit_cdr(rt, args); + total ^= pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + args = pit_value_cons_cdr(rt, args); } - return pit_integer_new(rt, total); + return pit_value_integer_new(rt, total); } static pit_value impl_bitwise_not(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 x = pit_as_integer(rt, pit_car(rt, args)); - return pit_integer_new(rt, ~x); + i64 x = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + return pit_value_integer_new(rt, ~x); } static pit_value impl_bitwise_lshift(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 val = pit_as_integer(rt, pit_car(rt, args)); - i64 shift = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); - return pit_integer_new(rt, val << shift); + i64 val = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 shift = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); + return pit_value_integer_new(rt, val << shift); } static pit_value impl_bitwise_rshift(pit_runtime *rt, pit_value args, void *data) { (void) data; - i64 val = pit_as_integer(rt, pit_car(rt, args)); - i64 shift = pit_as_integer(rt, pit_car(rt, pit_cdr(rt, args))); + i64 val = pit_value_as_integer(rt, pit_value_cons_car(rt, args)); + i64 shift = pit_value_as_integer(rt, pit_value_cons_car(rt, pit_value_cons_cdr(rt, args))); if (shift >= 64) val = 0; else val >>= shift; - return pit_integer_new(rt, val); + return pit_value_integer_new(rt, val); } void pit_install_library_essential(pit_runtime *rt) { /* special forms */ - pit_sfset(rt, pit_intern_cstr(rt, "quote"), pit_nativefunc_new(rt, impl_sf_quote)); - pit_sfset(rt, pit_intern_cstr(rt, "if"), pit_nativefunc_new(rt, impl_sf_if)); - pit_sfset(rt, pit_intern_cstr(rt, "cond"), pit_nativefunc_new(rt, impl_sf_cond)); - pit_sfset(rt, pit_intern_cstr(rt, "progn"), pit_nativefunc_new(rt, impl_sf_progn)); - pit_sfset(rt, pit_intern_cstr(rt, "or"), pit_nativefunc_new(rt, impl_sf_or)); - pit_sfset(rt, pit_intern_cstr(rt, "lambda"), pit_nativefunc_new(rt, impl_sf_lambda)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "quote"), pit_value_nativefunc_new(rt, impl_sf_quote)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "if"), pit_value_nativefunc_new(rt, impl_sf_if)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "cond"), pit_value_nativefunc_new(rt, impl_sf_cond)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "progn"), pit_value_nativefunc_new(rt, impl_sf_progn)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "or"), pit_value_nativefunc_new(rt, impl_sf_or)); + pit_symtab_sfset(rt, pit_symtab_intern_cstr(rt, "lambda"), pit_value_nativefunc_new(rt, impl_sf_lambda)); /* macros */ - 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, "defstruct!"), pit_nativefunc_new(rt, impl_m_defstruct)); - 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_mset(rt, pit_intern_cstr(rt, "case"), pit_nativefunc_new(rt, impl_m_case)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "defun!"), pit_value_nativefunc_new(rt, impl_m_defun)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "defmacro!"), pit_value_nativefunc_new(rt, impl_m_defmacro)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "defstruct!"), pit_value_nativefunc_new(rt, impl_m_defstruct)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "let"), pit_value_nativefunc_new(rt, impl_m_let)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "and"), pit_value_nativefunc_new(rt, impl_m_and)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "setq!"), pit_value_nativefunc_new(rt, impl_m_setq)); + pit_symtab_mset(rt, pit_symtab_intern_cstr(rt, "case"), pit_value_nativefunc_new(rt, impl_m_case)); /* error */ - pit_fset(rt, pit_intern_cstr(rt, "error!"), pit_nativefunc_new(rt, impl_error)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "error!"), pit_value_nativefunc_new(rt, impl_error)); /* eval */ - pit_fset(rt, pit_intern_cstr(rt, "eval!"), pit_nativefunc_new(rt, impl_eval)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "eval!"), pit_value_nativefunc_new(rt, impl_eval)); /* predicates */ - pit_fset(rt, pit_intern_cstr(rt, "eq?"), pit_nativefunc_new(rt, impl_eq_p)); - pit_fset(rt, pit_intern_cstr(rt, "equal?"), pit_nativefunc_new(rt, impl_equal_p)); - pit_fset(rt, pit_intern_cstr(rt, "integer?"), pit_nativefunc_new(rt, impl_integer_p)); - pit_fset(rt, pit_intern_cstr(rt, "double?"), pit_nativefunc_new(rt, impl_double_p)); - pit_fset(rt, pit_intern_cstr(rt, "symbol?"), pit_nativefunc_new(rt, impl_symbol_p)); - pit_fset(rt, pit_intern_cstr(rt, "cons?"), pit_nativefunc_new(rt, impl_cons_p)); - pit_fset(rt, pit_intern_cstr(rt, "array?"), pit_nativefunc_new(rt, impl_array_p)); - pit_fset(rt, pit_intern_cstr(rt, "bytes?"), pit_nativefunc_new(rt, impl_bytes_p)); - pit_fset(rt, pit_intern_cstr(rt, "function?"), pit_nativefunc_new(rt, impl_function_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "eq?"), pit_value_nativefunc_new(rt, impl_eq_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "equal?"), pit_value_nativefunc_new(rt, impl_equal_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "integer?"), pit_value_nativefunc_new(rt, impl_integer_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "double?"), pit_value_nativefunc_new(rt, impl_double_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "symbol?"), pit_value_nativefunc_new(rt, impl_symbol_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "cons?"), pit_value_nativefunc_new(rt, impl_cons_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array?"), pit_value_nativefunc_new(rt, impl_array_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bytes?"), pit_value_nativefunc_new(rt, impl_bytes_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "function?"), pit_value_nativefunc_new(rt, impl_function_p)); /* symbols */ - 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, "apply"), pit_nativefunc_new(rt, impl_apply)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "set!"), pit_value_nativefunc_new(rt, impl_set)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "fset!"), pit_value_nativefunc_new(rt, impl_fset)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "symbol-is-macro!"), pit_value_nativefunc_new(rt, impl_symbol_mark_macro)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "funcall"), pit_value_nativefunc_new(rt, impl_funcall)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "apply"), pit_value_nativefunc_new(rt, impl_apply)); /* cons cells */ - pit_fset(rt, pit_intern_cstr(rt, "cons"), pit_nativefunc_new(rt, impl_cons)); - pit_fset(rt, pit_intern_cstr(rt, "car"), pit_nativefunc_new(rt, impl_car)); - pit_fset(rt, pit_intern_cstr(rt, "cdr"), pit_nativefunc_new(rt, impl_cdr)); - pit_fset(rt, pit_intern_cstr(rt, "setcar!"), pit_nativefunc_new(rt, impl_setcar)); - pit_fset(rt, pit_intern_cstr(rt, "setcdr!"), pit_nativefunc_new(rt, impl_setcdr)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "cons"), pit_value_nativefunc_new(rt, impl_cons)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "car"), pit_value_nativefunc_new(rt, impl_car)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "cdr"), pit_value_nativefunc_new(rt, impl_cdr)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "setcar!"), pit_value_nativefunc_new(rt, impl_setcar)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "setcdr!"), pit_value_nativefunc_new(rt, impl_setcdr)); /* cons lists*/ - pit_fset(rt, pit_intern_cstr(rt, "list"), pit_nativefunc_new(rt, impl_list)); - pit_fset(rt, pit_intern_cstr(rt, "list/nth"), pit_nativefunc_new(rt, impl_list_nth)); - pit_fset(rt, pit_intern_cstr(rt, "list/iota"), pit_nativefunc_new(rt, impl_list_iota)); - pit_fset(rt, pit_intern_cstr(rt, "list/len"), pit_nativefunc_new(rt, impl_list_len)); - pit_fset(rt, pit_intern_cstr(rt, "list/reverse"), pit_nativefunc_new(rt, impl_list_reverse)); - pit_fset(rt, pit_intern_cstr(rt, "list/uniq"), pit_nativefunc_new(rt, impl_list_uniq)); - pit_fset(rt, pit_intern_cstr(rt, "list/append"), pit_nativefunc_new(rt, impl_list_append)); - pit_fset(rt, pit_intern_cstr(rt, "list/concat"), pit_nativefunc_new(rt, impl_list_concat)); - pit_fset(rt, pit_intern_cstr(rt, "list/take"), pit_nativefunc_new(rt, impl_list_take)); - pit_fset(rt, pit_intern_cstr(rt, "list/drop"), pit_nativefunc_new(rt, impl_list_drop)); - pit_fset(rt, pit_intern_cstr(rt, "list/map"), pit_nativefunc_new(rt, impl_list_map)); - pit_fset(rt, pit_intern_cstr(rt, "list/foldl"), pit_nativefunc_new(rt, impl_list_foldl)); - pit_fset(rt, pit_intern_cstr(rt, "list/filter"), pit_nativefunc_new(rt, impl_list_filter)); - pit_fset(rt, pit_intern_cstr(rt, "list/find"), pit_nativefunc_new(rt, impl_list_find)); - pit_fset(rt, pit_intern_cstr(rt, "list/contains?"), pit_nativefunc_new(rt, impl_list_contains_p)); - pit_fset(rt, pit_intern_cstr(rt, "list/all?"), pit_nativefunc_new(rt, impl_list_all_p)); - pit_fset(rt, pit_intern_cstr(rt, "list/zip-with"), pit_nativefunc_new(rt, impl_list_zip_with)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list"), pit_value_nativefunc_new(rt, impl_list)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/nth"), pit_value_nativefunc_new(rt, impl_list_nth)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/iota"), pit_value_nativefunc_new(rt, impl_list_iota)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/len"), pit_value_nativefunc_new(rt, impl_list_len)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/reverse"), pit_value_nativefunc_new(rt, impl_list_reverse)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/uniq"), pit_value_nativefunc_new(rt, impl_list_uniq)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/append"), pit_value_nativefunc_new(rt, impl_list_append)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/concat"), pit_value_nativefunc_new(rt, impl_list_concat)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/take"), pit_value_nativefunc_new(rt, impl_list_take)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/drop"), pit_value_nativefunc_new(rt, impl_list_drop)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/map"), pit_value_nativefunc_new(rt, impl_list_map)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/foldl"), pit_value_nativefunc_new(rt, impl_list_foldl)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/filter"), pit_value_nativefunc_new(rt, impl_list_filter)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/find"), pit_value_nativefunc_new(rt, impl_list_find)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/contains?"), pit_value_nativefunc_new(rt, impl_list_contains_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/all?"), pit_value_nativefunc_new(rt, impl_list_all_p)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "list/zip-with"), pit_value_nativefunc_new(rt, impl_list_zip_with)); /* bytestrings */ - pit_fset(rt, pit_intern_cstr(rt, "bytes/len"), pit_nativefunc_new(rt, impl_bytes_len)); - pit_fset(rt, pit_intern_cstr(rt, "bytes/range"), pit_nativefunc_new(rt, impl_bytes_range)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bytes/len"), pit_value_nativefunc_new(rt, impl_bytes_len)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bytes/range"), pit_value_nativefunc_new(rt, impl_bytes_range)); /* array */ - pit_fset(rt, pit_intern_cstr(rt, "array"), pit_nativefunc_new(rt, impl_array)); - pit_fset(rt, pit_intern_cstr(rt, "array/to-list"), pit_nativefunc_new(rt, impl_array_to_list)); - pit_fset(rt, pit_intern_cstr(rt, "array/from-list"), pit_nativefunc_new(rt, impl_array_from_list)); - pit_fset(rt, pit_intern_cstr(rt, "array/repeat"), pit_nativefunc_new(rt, impl_array_repeat)); - pit_fset(rt, pit_intern_cstr(rt, "array/len"), pit_nativefunc_new(rt, impl_array_len)); - pit_fset(rt, pit_intern_cstr(rt, "array/get"), pit_nativefunc_new(rt, impl_array_get)); - pit_fset(rt, pit_intern_cstr(rt, "array/set!"), pit_nativefunc_new(rt, impl_array_set)); - pit_fset(rt, pit_intern_cstr(rt, "array/map"), pit_nativefunc_new(rt, impl_array_map)); - pit_fset(rt, pit_intern_cstr(rt, "array/map!"), pit_nativefunc_new(rt, impl_array_map_mut)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array"), pit_value_nativefunc_new(rt, impl_array)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/to-list"), pit_value_nativefunc_new(rt, impl_array_to_list)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/from-list"), pit_value_nativefunc_new(rt, impl_array_from_list)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/repeat"), pit_value_nativefunc_new(rt, impl_array_repeat)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/len"), pit_value_nativefunc_new(rt, impl_array_len)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/get"), pit_value_nativefunc_new(rt, impl_array_get)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/set!"), pit_value_nativefunc_new(rt, impl_array_set)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/map"), pit_value_nativefunc_new(rt, impl_array_map)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "array/map!"), pit_value_nativefunc_new(rt, impl_array_map_mut)); /* arithmetic */ - pit_fset(rt, pit_intern_cstr(rt, "abs"), pit_nativefunc_new(rt, impl_abs)); - 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)); - pit_fset(rt, pit_intern_cstr(rt, "*"), pit_nativefunc_new(rt, impl_mul)); - pit_fset(rt, pit_intern_cstr(rt, "/"), pit_nativefunc_new(rt, impl_div)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "abs"), pit_value_nativefunc_new(rt, impl_abs)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "+"), pit_value_nativefunc_new(rt, impl_add)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "-"), pit_value_nativefunc_new(rt, impl_sub)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "*"), pit_value_nativefunc_new(rt, impl_mul)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "/"), pit_value_nativefunc_new(rt, impl_div)); /* booleans */ - pit_fset(rt, pit_intern_cstr(rt, "not"), pit_nativefunc_new(rt, impl_not)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "not"), pit_value_nativefunc_new(rt, impl_not)); /* comparisons */ - pit_fset(rt, pit_intern_cstr(rt, "<"), pit_nativefunc_new(rt, impl_lt)); - pit_fset(rt, pit_intern_cstr(rt, ">"), pit_nativefunc_new(rt, impl_gt)); - pit_fset(rt, pit_intern_cstr(rt, "<="), pit_nativefunc_new(rt, impl_le)); - pit_fset(rt, pit_intern_cstr(rt, ">="), pit_nativefunc_new(rt, impl_ge)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "<"), pit_value_nativefunc_new(rt, impl_lt)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, ">"), pit_value_nativefunc_new(rt, impl_gt)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "<="), pit_value_nativefunc_new(rt, impl_le)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, ">="), pit_value_nativefunc_new(rt, impl_ge)); /* bitwise arithmetic */ - pit_fset(rt, pit_intern_cstr(rt, "bitwise/and"), pit_nativefunc_new(rt, impl_bitwise_and)); - pit_fset(rt, pit_intern_cstr(rt, "bitwise/or"), pit_nativefunc_new(rt, impl_bitwise_or)); - pit_fset(rt, pit_intern_cstr(rt, "bitwise/xor"), pit_nativefunc_new(rt, impl_bitwise_xor)); - pit_fset(rt, pit_intern_cstr(rt, "bitwise/not"), pit_nativefunc_new(rt, impl_bitwise_not)); - pit_fset(rt, pit_intern_cstr(rt, "bitwise/lshift"), pit_nativefunc_new(rt, impl_bitwise_lshift)); - pit_fset(rt, pit_intern_cstr(rt, "bitwise/rshift"), pit_nativefunc_new(rt, impl_bitwise_rshift)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/and"), pit_value_nativefunc_new(rt, impl_bitwise_and)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/or"), pit_value_nativefunc_new(rt, impl_bitwise_or)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/xor"), pit_value_nativefunc_new(rt, impl_bitwise_xor)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/not"), pit_value_nativefunc_new(rt, impl_bitwise_not)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/lshift"), pit_value_nativefunc_new(rt, impl_bitwise_lshift)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bitwise/rshift"), pit_value_nativefunc_new(rt, impl_bitwise_rshift)); } static pit_value impl_plist_get(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value k = pit_car(rt, args); - pit_value vs = pit_car(rt, pit_cdr(rt, args)); - return pit_plist_get(rt, k, vs); + pit_value k = pit_value_cons_car(rt, args); + pit_value vs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + return pit_value_list_plist_get(rt, k, vs); } void pit_install_library_plist(pit_runtime *rt) { /* property lists / keyword arguments */ - pit_fset(rt, pit_intern_cstr(rt, "plist/get"), pit_nativefunc_new(rt, impl_plist_get)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "plist/get"), pit_value_nativefunc_new(rt, impl_plist_get)); } static pit_value impl_alist_get(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value k = pit_car(rt, args); - pit_value vs = pit_car(rt, pit_cdr(rt, args)); + pit_value k = pit_value_cons_car(rt, args); + pit_value vs = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); while (vs != PIT_NIL) { - pit_value v = pit_car(rt, vs); - if (pit_equal(rt, k, pit_car(rt, v))) { - return pit_cdr(rt, v); + pit_value v = pit_value_cons_car(rt, vs); + if (pit_value_equal(rt, k, pit_value_cons_car(rt, v))) { + return pit_value_cons_cdr(rt, v); } - vs = pit_cdr(rt, vs); + vs = pit_value_cons_cdr(rt, vs); } return PIT_NIL; } void pit_install_library_alist(pit_runtime *rt) { /* association lists */ - pit_fset(rt, pit_intern_cstr(rt, "alist/get"), pit_nativefunc_new(rt, impl_alist_get)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "alist/get"), pit_value_nativefunc_new(rt, impl_alist_get)); } diff --git a/src/main.c b/src/main.c index 7517763..157ad87 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,5 @@ int main(int argc, char **argv) { pit_repl(rt); } else { pit_load_file(rt, argv[1]); - if (pit_runtime_print_error(rt)) return -1; } } diff --git a/src/native.c b/src/native.c index 7af961b..fbf8efc 100644 --- a/src/native.c +++ b/src/native.c @@ -24,24 +24,28 @@ i64 pit_lex_file(pit_lexer *ret, char *path) { } bool pit_runtime_print_error(pit_runtime *rt) { - if (!pit_eq(rt->error, PIT_NIL)) { + if (!pit_value_eq(rt->error, PIT_NIL)) { char buf[1024] = {0}; - i64 end = pit_dump(rt, buf, sizeof(buf) - 1, rt->error, false); - buf[end] = 0; + for (i64 i = 0; i < rt->backtrace->next; ++i) { + pit_annotated_ref *a = pit_vec_get(pit_annotated_ref)(rt->backtrace, i); + if (a == NULL) continue; + fprintf(stderr, "on line %ld, column %ld\n", a->annotation.line, a->annotation.column); + } + i64 end = pit_dump(rt, buf, sizeof(buf) - 1, rt->error, false); buf[end] = 0; fprintf(stderr, "error at line %ld, column %ld: %s\n", rt->error_line, rt->error_column, buf); return true; } return false; } -void pit_trace_(pit_runtime *rt, char *format, pit_value v) { +void pit_debug_trace_(pit_runtime *rt, char *format, pit_value v) { char buf[1024] = {0}; i64 end = pit_dump(rt, buf, sizeof(buf) - 1, v, true); buf[end] = 0; fprintf(stderr, format, buf); } -pit_value pit_bytes_new_file(pit_runtime *rt, char *path) { +pit_value pit_value_bytes_new_file(pit_runtime *rt, char *path) { if (rt->error != PIT_NIL) return PIT_NIL; FILE *f = fopen(path, "r"); if (f == NULL) { @@ -59,8 +63,8 @@ pit_value pit_bytes_new_file(pit_runtime *rt, char *path) { return PIT_NIL; } fclose(f); - pit_value ret = pit_heavy_new(rt); - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret)); + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(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->in.bytes.data = dest; @@ -69,11 +73,14 @@ pit_value pit_bytes_new_file(pit_runtime *rt, char *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->expr_stack->next != 0) { + pit_error(rt, "leaked expr_stack memory! %ld", rt->expr_stack->next); + } + if (rt->result_stack->next != 0) { + pit_error(rt, "leaked result_stack memory! %ld", rt->result_stack->next); } - if (rt->scratch->next != 0) { - pit_error(rt, "leaked scratch memory! %ld", rt->scratch->next); + if (rt->program->next != 0) { + pit_error(rt, "leaked program memory! %ld", rt->program->next); } } pit_value pit_load_file(pit_runtime *rt, char *path) { @@ -91,7 +98,7 @@ pit_value pit_load_file(pit_runtime *rt, char *path) { 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); + pit_gc(rt); check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL; } check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL; @@ -144,7 +151,7 @@ void pit_repl(pit_runtime *rt) { } else { char dumpbuf[1024] = {0}; pit_dump(rt, dumpbuf, sizeof(dumpbuf) - 1, res, true); - pit_collect_garbage(rt); + pit_gc(rt); printf("%s\n> ", dumpbuf); } len = 0; @@ -165,7 +172,7 @@ static pit_value impl_diagnostics(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_print(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value x = pit_car(rt, args); + pit_value x = pit_value_cons_car(rt, args); char buf[1024] = {0}; pit_dump(rt, buf, sizeof(buf), x, true); buf[1023] = 0; @@ -174,7 +181,7 @@ static pit_value impl_print(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_princ(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value x = pit_car(rt, args); + pit_value x = pit_value_cons_car(rt, args); char buf[1024] = {0}; pit_dump(rt, buf, sizeof(buf), x, false); buf[1023] = 0; @@ -183,21 +190,21 @@ static pit_value impl_princ(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_load(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value path = pit_car(rt, args); + pit_value path = pit_value_cons_car(rt, args); char pathbuf[1024] = {0}; - i64 len = pit_as_bytes(rt, path, (u8 *) pathbuf, sizeof(pathbuf) - 1); + i64 len = pit_value_bytes_copy(rt, path, (u8 *) pathbuf, sizeof(pathbuf) - 1); if (len < 0) { pit_error(rt, "path was not a string"); return PIT_NIL; } pathbuf[len] = 0; return pit_load_file(rt, pathbuf); } void pit_install_library_io(pit_runtime *rt) { /* diagnostics */ - pit_fset(rt, pit_intern_cstr(rt, "diagnostics!"), pit_nativefunc_new(rt, impl_diagnostics)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "diagnostics!"), pit_value_nativefunc_new(rt, impl_diagnostics)); /* stream IO */ - 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_symtab_fset(rt, pit_symtab_intern_cstr(rt, "print!"), pit_value_nativefunc_new(rt, impl_print)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "princ!"), pit_value_nativefunc_new(rt, impl_princ)); /* disk IO */ - pit_fset(rt, pit_intern_cstr(rt, "load!"), pit_nativefunc_new(rt, impl_load)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "load!"), pit_value_nativefunc_new(rt, impl_load)); } struct bytestring { @@ -212,18 +219,18 @@ static pit_value impl_bs_new(pit_runtime *rt, pit_value args, void *data) { bs->len = 0; bs->cap = cap; bs->data = calloc((size_t) cap, 1); - return pit_nativedata_new(rt, pit_intern_cstr(rt, "bs"), (void *) bs); + return pit_value_nativedata_new(rt, pit_symtab_intern_cstr(rt, "bs"), (void *) bs); } static pit_value impl_bs_delete(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value v = pit_car(rt, args); - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v)); + pit_value v = pit_value_cons_car(rt, args); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } if (h->hsort != PIT_VALUE_HEAVY_SORT_NATIVEDATA) { pit_error(rt, "invalid use of value as bytestring nativedata"); return PIT_NIL; } - if (!pit_eq(h->in.nativedata.tag, pit_intern_cstr(rt, "bs"))) { + if (!pit_value_eq(h->in.nativedata.tag, pit_symtab_intern_cstr(rt, "bs"))) { pit_error(rt, "native value is not a bytestring"); return PIT_NIL; } @@ -240,11 +247,11 @@ static pit_value impl_bs_delete(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_bs_grow(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value vsz = pit_car(rt, args); - pit_value v = pit_car(rt, pit_cdr(rt, args)); - struct bytestring *bs = pit_nativedata_get(rt, pit_intern_cstr(rt, "bs"), v); + pit_value vsz = pit_value_cons_car(rt, args); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + struct bytestring *bs = pit_value_nativedata_get(rt, pit_symtab_intern_cstr(rt, "bs"), v); if (!bs) return PIT_NIL; - i64 sz = pit_as_integer(rt, vsz); + i64 sz = pit_value_as_integer(rt, vsz); if (sz > bs->len) { if (sz > bs->cap) { while (bs->cap < sz) bs->cap <<= 1; @@ -256,13 +263,13 @@ static pit_value impl_bs_grow(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_bs_spit(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value path = pit_car(rt, args); + pit_value path = pit_value_cons_car(rt, args); char pathbuf[1024] = {0}; - i64 len = pit_as_bytes(rt, path, (u8 *) pathbuf, sizeof(pathbuf) - 1); + i64 len = pit_value_bytes_copy(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 v = pit_car(rt, pit_cdr(rt, args)); - struct bytestring *bs = pit_nativedata_get(rt, pit_intern_cstr(rt, "bs"), v); + pit_value v = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + struct bytestring *bs = pit_value_nativedata_get(rt, pit_symtab_intern_cstr(rt, "bs"), v); if (!bs) return PIT_NIL; FILE *f = fopen(pathbuf, "w+"); if (!f) { pit_error(rt, "failed to open file: %s", pathbuf); return PIT_NIL; } @@ -276,13 +283,13 @@ static pit_value impl_bs_spit(pit_runtime *rt, pit_value args, void *data) { } static pit_value impl_bs_write8(pit_runtime *rt, pit_value args, void *data) { (void) data; - pit_value v = pit_car(rt, args); - pit_value vidx = pit_car(rt, pit_cdr(rt, args)); - pit_value vx = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); - struct bytestring *bs = pit_nativedata_get(rt, pit_intern_cstr(rt, "bs"), v); + pit_value v = pit_value_cons_car(rt, args); + pit_value vidx = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + pit_value vx = pit_value_cons_car(rt, pit_value_cons_cdr(rt, pit_value_cons_cdr(rt, args))); + struct bytestring *bs = pit_value_nativedata_get(rt, pit_symtab_intern_cstr(rt, "bs"), v); if (!bs) return PIT_NIL; - i64 idx = pit_as_integer(rt, vidx); - u8 x = (u8) pit_as_integer(rt, vx); + i64 idx = pit_value_as_integer(rt, vidx); + u8 x = (u8) pit_value_as_integer(rt, vx); if (idx >= bs->len) { pit_error(rt, "index %d out of bounds in bytestring (length %d)", idx, bs->len); return PIT_NIL; @@ -292,9 +299,9 @@ static pit_value impl_bs_write8(pit_runtime *rt, pit_value args, void *data) { } void pit_install_library_bytestring(pit_runtime *rt) { /* bytestrings */ - pit_fset(rt, pit_intern_cstr(rt, "bs/new!"), pit_nativefunc_new(rt, impl_bs_new)); - pit_fset(rt, pit_intern_cstr(rt, "bs/delete!"), pit_nativefunc_new(rt, impl_bs_delete)); - pit_fset(rt, pit_intern_cstr(rt, "bs/grow!"), pit_nativefunc_new(rt, impl_bs_grow)); - pit_fset(rt, pit_intern_cstr(rt, "bs/spit!"), pit_nativefunc_new(rt, impl_bs_spit)); - pit_fset(rt, pit_intern_cstr(rt, "bs/write8!"), pit_nativefunc_new(rt, impl_bs_write8)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bs/new!"), pit_value_nativefunc_new(rt, impl_bs_new)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bs/delete!"), pit_value_nativefunc_new(rt, impl_bs_delete)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bs/grow!"), pit_value_nativefunc_new(rt, impl_bs_grow)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bs/spit!"), pit_value_nativefunc_new(rt, impl_bs_spit)); + pit_symtab_fset(rt, pit_symtab_intern_cstr(rt, "bs/write8!"), pit_value_nativefunc_new(rt, impl_bs_write8)); } diff --git a/src/parser.c b/src/parser.c index 9ce0c60..0f9b167 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4,8 +4,6 @@ #include #include -#include - static pit_lex_token peek(pit_parser *st) { if (!st) return PIT_LEX_TOKEN_ERROR; return st->next.token; @@ -76,12 +74,6 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { } return PIT_NIL; case PIT_LEX_TOKEN_LPAREN: { - /* to construct a cons-list, we need the arguments "backwards" - we could reverse or build up a temporary list - (or use non-tail recursion, which is basically the temporary list on the stack) - we choose to build a temporary list on the scratch arena - */ - i64 scratch_reset = rt->scratch->next; pit_value ret = PIT_NIL; while (!match(st, PIT_LEX_TOKEN_RPAREN)) { if (match(st, PIT_LEX_TOKEN_DOT)) { @@ -93,49 +85,44 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { return PIT_NIL; } } else { - pit_value *cell = pit_arena_alloc_array(rt->scratch, sizeof(pit_value)); - *cell = pit_parse(rt, st, eof); + ret = pit_value_cons(rt, pit_parse(rt, st, eof), ret); } if (rt->error != PIT_NIL || (eof != NULL && *eof)) { pit_error(rt, "unterminated list"); return PIT_NIL; /* if we hit an error, stop!*/ } } - for (i64 i = rt->scratch->next - (i64) sizeof(pit_value); - i >= scratch_reset; - i -= (i64) sizeof(pit_value) - ) { - pit_value *v = pit_arena_get(rt->scratch, (i32) i); - ret = pit_cons(rt, *v, ret); - } - rt->scratch->next = scratch_reset; + ret = pit_value_list_reverse(rt, ret); if (pit_value_sort(ret) == PIT_VALUE_SORT_REF) { - fprintf(stderr, "adding annotation (%ld): ", pit_as_ref(rt, ret)); - pit_trace_(rt, "%s\n", ret); - pit_expr_annotations_push(rt->annotations, - pit_as_ref(rt, ret), - rt->source_line, rt->source_column - ); + pit_annotation a = {0}; + a.line = rt->source_line; + a.column = rt->source_column; + pit_annotation_set(rt, pit_value_as_ref(rt, ret), a); } return ret; } case PIT_LEX_TOKEN_LSQUARE: { - i64 scratch_reset = rt->scratch->next; + pit_value ret = PIT_NIL; + pit_value xs = PIT_NIL; i64 len = 0; while (!match(st, PIT_LEX_TOKEN_RSQUARE)) { - pit_value *cell = pit_arena_alloc_array(rt->scratch, sizeof(pit_value)); - *cell = pit_parse(rt, st, eof); + pit_value x = pit_parse(rt, st, eof); + xs = pit_value_cons(rt, x, xs); len += 1; if (rt->error != PIT_NIL || (eof != NULL && *eof)) { pit_error(rt, "unterminated array literal"); return PIT_NIL; } } - rt->scratch->next = scratch_reset; - return pit_array_from_buf(rt, pit_arena_get(rt->scratch, (i32) scratch_reset), len); + ret = pit_value_array_new(rt, len); + while (xs != PIT_NIL) { + pit_value_array_set(rt, ret, --len, pit_value_cons_car(rt, xs)); + xs = pit_value_cons_cdr(rt, xs); + } + return ret; } case PIT_LEX_TOKEN_QUOTE: - return pit_list(rt, 2, pit_intern_cstr(rt, "quote"), pit_parse(rt, st, eof)); + return pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "quote"), pit_parse(rt, st, eof)); case PIT_LEX_TOKEN_INTEGER_LITERAL: { i64 idx = st->cur.start; i64 base = 10; @@ -165,7 +152,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { pit_error(rt, "integer literal too large"); return PIT_NIL; } } - return pit_integer_new(rt, neg ? -total : total); + return pit_value_integer_new(rt, neg ? -total : total); } case PIT_LEX_TOKEN_STRING_LITERAL: { char buf[256] = {0}; @@ -177,12 +164,12 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { else if (buf[i] != '"') buf[cur++] = buf[i]; else break; } - return pit_bytes_new(rt, (u8 *) buf, cur); + return pit_value_bytes_new(rt, (u8 *) buf, cur); } case PIT_LEX_TOKEN_SYMBOL: { char buf[256] = {0}; get_token_string(st, buf, sizeof(buf)); - return pit_intern_cstr(rt, buf); + return pit_symtab_intern_cstr(rt, buf); } default: pit_error(rt, "unexpected token: %s", pit_lex_token_name(t)); diff --git a/src/runtime.c b/src/runtime.c index f961c19..a8428c7 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -4,8 +4,6 @@ #include #include -#include - 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; */ @@ -30,15 +28,12 @@ pit_runtime *pit_runtime_new(u8 *buf, i64 len) { i64 heap_size = len / 4; i64 annotations_size = len / 32; i64 symtab_size = len / 16; - i64 scratch_size = len / 32; i64 stack_size = len / 32; ret->heap = pit_arena_new(pit_arena_alloc_back(a, heap_size), heap_size, sizeof(pit_value_heavy)); ret->backbuffer = pit_arena_new(pit_arena_alloc_back(a, heap_size), heap_size, sizeof(pit_value_heavy)); - ret->annotations = pit_expr_annotations_new(pit_arena_alloc_back(a, annotations_size), annotations_size); - ret->annotations_backbuffer = pit_expr_annotations_new(pit_arena_alloc_back(a, annotations_size), annotations_size); - ret->symtab = pit_arena_new(pit_arena_alloc_back(a, symtab_size), symtab_size, sizeof(pit_symtab_entry)); - ret->symtab_len = 0; - ret->scratch = pit_arena_new(pit_arena_alloc_back(a, scratch_size), scratch_size, sizeof(u8)); + ret->annotations = pit_vec_new(pit_annotated_ref)(pit_arena_alloc_back(a, annotations_size), annotations_size); + ret->backtrace = pit_vec_new(pit_annotated_ref)(pit_arena_alloc_back(a, annotations_size), annotations_size); + ret->symtab = pit_vec_new(pit_symtab_entry)(pit_arena_alloc_back(a, symtab_size), symtab_size); ret->expr_stack = pit_vec_new(pit_value)(pit_arena_alloc_back(a, stack_size), stack_size); ret->result_stack = pit_vec_new(pit_value)(pit_arena_alloc_back(a, stack_size), stack_size); ret->program = pit_vec_new(pit_runtime_eval_ins)(pit_arena_alloc_back(a, stack_size), stack_size); @@ -48,10 +43,10 @@ pit_runtime *pit_runtime_new(u8 *buf, i64 len) { 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"); - pit_set(ret, truth, truth); + pit_value nil = pit_symtab_intern_cstr(ret, "nil"); /* nil must be the 0th symbol for PIT_NIL to work */ + pit_symtab_set(ret, nil, PIT_NIL); + pit_value truth = pit_symtab_intern_cstr(ret, "t"); + pit_symtab_set(ret, truth, truth); pit_runtime_freeze(ret); return ret; } @@ -65,106 +60,7 @@ void pit_runtime_reset(pit_runtime *rt) { rt->symtab->next = rt->frozen_symtab; } -#define CHECK_BUF if (buf >= end) { return buf - start; } -#define CHECK_BUF_LABEL(label) if (buf >= end) { goto label; } -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)) { - case PIT_VALUE_SORT_DOUBLE: - #ifndef PIT_NO_DOUBLE - return pit_libc_string_snprintf(buf, (size_t) len, "%lf", pit_as_double(rt, v)); - #else - return pit_string_snprintf(buf, (size_t) len, ""); - #endif - case PIT_VALUE_SORT_INTEGER: - return pit_libc_string_snprintf(buf, (size_t) len, "%ld", pit_as_integer(rt, v)); - case PIT_VALUE_SORT_SYMBOL: { - pit_symtab_entry *ent = pit_symtab_lookup(rt, v); - if (ent - && pit_value_sort(ent->name) == PIT_VALUE_SORT_REF - && (h = pit_deref(rt, pit_as_ref(rt, ent->name))) - ) { - i64 i = 0; - for (; i < h->in.bytes.len && i < len - 1; ++i) { - buf[i] = (char) h->in.bytes.data[i]; - } - return i; - } else { - return pit_libc_string_snprintf(buf, (size_t) len, "", pit_as_symbol(rt, v)); - } - } - case PIT_VALUE_SORT_REF: { - pit_ref r = pit_as_ref(rt, v); - char *end = buf + len; - char *start = buf; - h = pit_deref(rt, r); - if (!h) pit_libc_string_snprintf(buf, (size_t) len, "", r); - else { - switch (h->hsort) { - case PIT_VALUE_HEAVY_SORT_CELL: { - CHECK_BUF; *(buf++) = '{'; - CHECK_BUF; buf += pit_dump(rt, buf, end - buf, pit_car(rt, h->in.cell), readable); - CHECK_BUF; *(buf++) = '}'; - return buf - start; - } - case PIT_VALUE_HEAVY_SORT_CONS: { - pit_value cur = v; - CHECK_BUF_LABEL(list_end); - do { - if (pit_is_cons(rt, cur)) { - CHECK_BUF_LABEL(list_end); *(buf++) = ' '; - CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, pit_car(rt, cur), readable); - } else { - CHECK_BUF_LABEL(list_end); buf += pit_libc_string_snprintf(buf, (size_t) (end - buf), " . "); - CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, cur, readable); - } - } while (!pit_eq((cur = pit_cdr(rt, cur)), PIT_NIL)); - CHECK_BUF_LABEL(list_end); *(buf++) = ')'; - list_end: - *start = '('; - return buf - start; - } - case PIT_VALUE_HEAVY_SORT_ARRAY: { - i64 i = 0; - CHECK_BUF_LABEL(array_end); - if (h->in.array.len == 0) { - CHECK_BUF_LABEL(array_end); *(buf++) = '['; - } else for (; i < h->in.array.len; ++i) { - CHECK_BUF_LABEL(array_end); *(buf++) = ' '; - CHECK_BUF_LABEL(array_end); buf += pit_dump(rt, buf, end - buf, h->in.array.data[i], readable); - } - CHECK_BUF_LABEL(array_end); *(buf++) = ']'; - array_end: - *start = '['; - return buf - start; - } - case PIT_VALUE_HEAVY_SORT_BYTES: { - i64 i = 0; - if (readable) { CHECK_BUF; buf[i++] = '"'; } - i64 maxlen = len - i; - for (i64 j = 0; i < maxlen && j < h->in.bytes.len;) { - if (buf[i - 1] != '\\' && (h->in.bytes.data[j] == '\\' || h->in.bytes.data[j] == '"')) { - CHECK_BUF; buf[i++] = '\\'; - } - else { - CHECK_BUF; buf[i++] = (char) h->in.bytes.data[j++]; - } - } - if (readable && i < len - 1) buf[i++] = '"'; - return i; - } - default: - return pit_libc_string_snprintf(buf, (size_t) len, "", r); - } - } - break; - } - } - return 0; -} - -pit_value pit_get_error(pit_runtime *rt) { +pit_value pit_error_get(pit_runtime *rt) { pit_value ret = rt->error; rt->error = PIT_NIL; return ret; @@ -178,753 +74,29 @@ void pit_error(pit_runtime *rt, char *format, ...) { pit_libc_string_snprintf(buf, sizeof(buf), format, vargs); va_end(vargs); rt->error = PIT_T; /* we set the error now to prevent infinite recursion */ - rt->error = pit_bytes_new_cstr(rt, buf); /* in case this errs also */ + rt->error = pit_value_bytes_new_cstr(rt, buf); /* in case this errs also */ if (rt->error == PIT_NIL) rt->error = PIT_T; rt->error_line = rt->source_line; rt->error_column = rt->source_column; } } -pit_value pit_value_new(pit_runtime *rt, enum pit_value_sort s, u64 data) { - if (s == PIT_VALUE_SORT_DOUBLE) { - /* if (((data >> 52) & 0b011111111111) == 0b011111111111 && ((data >> 51) & 0b1) == 0) { */ - if (((data >> 52) & 0x7ff) == 0x7ff && ((data >> 51) & 1) == 0) { - pit_error(rt, "attempted to create a signalling NaN double"); - return PIT_NIL; - } - return data; - } - return - /* 0b1111111111110000000000000000000000000000000000000000000000000000 */ - 0xfff0000000000000 - /* | (((u64) (s & 0b11)) << 49) */ - | (((u64) (s & 3)) << 49) - /* | (data & 0b1111111111111111111111111111111111111111111111111); */ - | (data & 0x1ffffffffffff); -} - -#ifndef PIT_NO_DOUBLE -double pit_as_double(pit_runtime *rt, pit_value v) { - if (pit_value_sort(v) != PIT_VALUE_SORT_DOUBLE) { - pit_error(rt, "invalid use of value as double"); - return 0.0; - } - union { double dval; u64 ival; } x; - x.ival = v; - return x.dval; -} -pit_value pit_double_new(pit_runtime *rt, double d) { - union { double dval; u64 ival; } x; - x.dval = d; - return pit_value_new(rt, PIT_VALUE_SORT_DOUBLE, x.ival); -} -#endif - -i64 pit_as_integer(pit_runtime *rt, pit_value v) { - if (pit_value_sort(v) != PIT_VALUE_SORT_INTEGER) { - pit_error(rt, "invalid use of value as integer"); - return -1; - } - u64 lo = pit_value_data(v); - return ((i64) (lo << 15)) >> 15; /* sign-extend low 49 bits */ - -} -pit_value pit_integer_new(pit_runtime *rt, i64 i) { - return pit_value_new(rt, PIT_VALUE_SORT_INTEGER, 0x1ffffffffffff & (u64) i); -} -pit_value pit_bool_new(pit_runtime *rt, bool i) { - (void) rt; - return i ? PIT_T : PIT_NIL; -} - -pit_symbol pit_as_symbol(pit_runtime *rt, pit_value v) { - if (pit_value_sort(v) != PIT_VALUE_SORT_SYMBOL) { - pit_error(rt, "invalid use of value as symbol"); - return -1; - } - return (pit_symbol) (pit_value_data(v) & 0xffffffff); -} -pit_value pit_symbol_new(pit_runtime *rt, pit_symbol s) { - return pit_value_new(rt, PIT_VALUE_SORT_SYMBOL, (u64) s); -} - -pit_ref pit_as_ref(pit_runtime *rt, pit_value v) { - if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { - pit_error(rt, "invalid use of value as ref"); - return -1; - } - return (pit_ref) (pit_value_data(v) & 0xffffffff); -} -pit_value pit_ref_new(pit_runtime *rt, pit_ref r) { - return pit_value_new(rt, PIT_VALUE_SORT_REF, (u64) r); -} - -pit_value pit_heavy_new(pit_runtime *rt) { - pit_arena_index idx = pit_arena_alloc_index(rt->heap); - if (idx < 0) { - pit_error(rt, "failed to allocate space for heavy value"); - return PIT_NIL; - } - return pit_ref_new(rt, idx); -} - -pit_value_heavy *pit_deref(pit_runtime *rt, pit_ref p) { - return pit_arena_get(rt->heap, p); -} - -bool pit_is_integer(pit_runtime *rt, pit_value a) { - (void) rt; - return pit_value_sort(a) == PIT_VALUE_SORT_INTEGER; -} -bool pit_is_double(pit_runtime *rt, pit_value a) { - (void) rt; - return pit_value_sort(a) == PIT_VALUE_SORT_DOUBLE; -} -bool pit_is_symbol(pit_runtime *rt, pit_value a) { - (void) rt; - return pit_value_sort(a) == PIT_VALUE_SORT_SYMBOL; -} -bool pit_is_value_heavy_sort(pit_runtime *rt, pit_value a, enum pit_value_heavy_sort e) { - switch (pit_value_sort(a)) { - case PIT_VALUE_SORT_REF: { - pit_value_heavy *ha = pit_deref(rt, pit_as_ref(rt, a)); - if (!ha) { pit_error(rt, "bad ref"); return false; } - return ha->hsort == e; - } - default: - break; - } - return false; -} -bool pit_is_cell(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_CELL); -} -bool pit_is_cons(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_CONS); -} -bool pit_is_array(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_ARRAY); -} -bool pit_is_bytes(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_BYTES); -} -bool pit_is_func(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_FUNC); -} -bool pit_is_nativefunc(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_NATIVEFUNC); -} -bool pit_is_nativedata(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_NATIVEDATA); -} -bool pit_is_forwarding_pointer(pit_runtime *rt, pit_value a) { - return pit_is_value_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER); -} -bool pit_eq(pit_value a, pit_value b) { - return a == b; -} -bool pit_equal(pit_runtime *rt, pit_value a, pit_value b) { - if (pit_value_sort(a) != pit_value_sort(b)) return false; - switch (pit_value_sort(a)) { - case PIT_VALUE_SORT_DOUBLE: - case PIT_VALUE_SORT_INTEGER: - case PIT_VALUE_SORT_SYMBOL: - return pit_value_data(a) == pit_value_data(b); - case PIT_VALUE_SORT_REF: { - pit_value_heavy *ha = pit_deref(rt, pit_as_ref(rt, a)); - if (!ha) { pit_error(rt, "bad ref"); return false; } - pit_value_heavy *hb = pit_deref(rt, pit_as_ref(rt, b)); - if (!hb) { pit_error(rt, "bad ref"); return false; } - if (ha->hsort != hb->hsort) return false; - switch (ha->hsort) { - case PIT_VALUE_HEAVY_SORT_CELL: - return pit_equal(rt, ha->in.cell, hb->in.cell); - case PIT_VALUE_HEAVY_SORT_CONS: - return pit_equal(rt, ha->in.cons.car, hb->in.cons.car) - && pit_equal(rt, ha->in.cons.cdr, hb->in.cons.cdr); - case PIT_VALUE_HEAVY_SORT_ARRAY: { - if (ha->in.array.len != hb->in.array.len) return false; - for (i64 i = 0; i < ha->in.array.len; ++i) { - if (!pit_equal(rt, ha->in.array.data[i], hb->in.array.data[i])) return false; - } - return true; - } - case PIT_VALUE_HEAVY_SORT_BYTES: { - if (ha->in.bytes.len != hb->in.bytes.len) return false; - for (i64 i = 0; i < ha->in.bytes.len; ++i) { - if (ha->in.bytes.data[i] != hb->in.bytes.data[i]) return false; - } - return true; - } - case PIT_VALUE_HEAVY_SORT_FUNC: - return - pit_equal(rt, ha->in.func.env, hb->in.func.env) - && pit_equal(rt, ha->in.func.args, hb->in.func.args) - && pit_equal(rt, ha->in.func.body, hb->in.func.body); - case PIT_VALUE_HEAVY_SORT_NATIVEFUNC: - return ha->in.nativefunc.f == hb->in.nativefunc.f - && ha->in.nativefunc.data == hb->in.nativefunc.data; - case PIT_VALUE_HEAVY_SORT_NATIVEDATA: - return - pit_eq(ha->in.nativedata.tag, hb->in.nativedata.tag) - && ha->in.nativedata.data == hb->in.nativedata.data; - case PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER: - return ha->in.forwarding_pointer == hb->in.forwarding_pointer; - } - } - } - return false; -} -pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len) { - u8 *dest = pit_arena_alloc_back(rt->heap, len); - if (!dest) { pit_error(rt, "failed to allocate bytes"); return PIT_NIL; } - pit_libc_string_memcpy(dest, buf, (size_t) len); - 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 bytes"); return PIT_NIL; } - h->hsort = PIT_VALUE_HEAVY_SORT_BYTES; - h->in.bytes.data = dest; - h->in.bytes.len = len; - return ret; -} -pit_value pit_bytes_new_cstr(pit_runtime *rt, char *s) { - return pit_bytes_new(rt, (u8 *) s, (i64) pit_libc_string_strlen(s)); -} -/* 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; - 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) return false; - if (h->in.bytes.len != len) return false; - for (i64 i = 0; i < len; ++i) - if (h->in.bytes.data[i] != buf[i]) { - return false; - } - 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) { pit_error(rt, "not a 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->in.bytes.len ? maxlen : h->in.bytes.len; - for (i64 i = 0; i < len; ++i) { - buf[i] = h->in.bytes.data[i]; - } - return len; -} - -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_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); - } - pit_arena_index idx = pit_arena_alloc_index(rt->symtab); - 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; - ent->function = PIT_NIL; - ent->is_macro = false; - ent->is_special_form = false; - ent->is_keyword = len >= 1 && nm[0] == ':'; - rt->symtab_len += 1; - return pit_symbol_new(rt, idx); -} -pit_value pit_intern_cstr(pit_runtime *rt, char *nm) { - return pit_intern(rt, (u8 *) nm, (i64) pit_libc_string_strlen(nm)); -} -pit_value pit_symbol_name(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } - return ent->name; -} -bool pit_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } - return pit_bytes_match(rt, ent->name, buf, len); -} -bool pit_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s) { - return pit_symbol_name_match(rt, sym, (u8 *) s, (i64) pit_libc_string_strlen(s)); -} -pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym) { - pit_symbol s = pit_as_symbol(rt, sym); - 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); - if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } - return ent->value; -} -pit_value pit_get_function_cell(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } - return ent->function; -} -pit_value pit_get(pit_runtime *rt, pit_value sym) { - return pit_cell_get(rt, pit_get_value_cell(rt, sym), 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) { - ent->value = pit_cell_new(rt, PIT_NIL); - } - pit_cell_set(rt, ent->value, v, sym); -} -pit_value pit_fget(pit_runtime *rt, pit_value sym) { - return pit_cell_get(rt, pit_get_function_cell(rt, sym), 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) { - ent->function = pit_cell_new(rt, PIT_NIL); - } - pit_cell_set(rt, ent->function, v, sym); -} -bool pit_is_symbol_macro(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return false; } - return ent->is_macro; -} -void pit_symbol_is_macro(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return; } - ent->is_macro = true; -} -void pit_mset(pit_runtime *rt, pit_value sym, pit_value v) { - pit_fset(rt, sym, v); - pit_symbol_is_macro(rt, sym); -} -bool pit_is_symbol_special_form(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return false; } - return ent->is_special_form; -} -void pit_symbol_is_special_form(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return; } - ent->is_special_form = true; -} -void pit_sfset(pit_runtime *rt, pit_value sym, pit_value v) { - pit_fset(rt, sym, 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; } - if (pit_vec_push(pit_value)(rt->saved_bindings, ent->value) < 0) pit_error(rt, "binding stack overflow"); - ent->value = cell; -} -pit_value pit_unbind(pit_runtime *rt, pit_value sym) { - pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); - if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } - pit_value old = ent->value; - if (pit_vec_pop(pit_value)(rt->saved_bindings, &ent->value) < 0) pit_error(rt, "binding stack underflow"); - return old; -} - -pit_value pit_cell_new(pit_runtime *rt, pit_value v) { - 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 cell"); return PIT_NIL; } - h->hsort = PIT_VALUE_HEAVY_SORT_CELL; - h->in.cell = v; - return ret; -} -pit_value pit_cell_get(pit_runtime *rt, pit_value cell, pit_value sym) { - if (pit_value_sort(cell) != PIT_VALUE_SORT_REF) { - char buf[256]; - i64 end = pit_dump(rt, buf, sizeof(buf) - 1, sym, false); - buf[end] = 0; - pit_error(rt, "attempted to get unbound variable/function: %s", buf); - return PIT_NIL; - } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, cell)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_CELL) { - pit_error(rt, "cell value ref does not point to cell"); - return PIT_NIL; - } - return h->in.cell; -} -void pit_cell_set(pit_runtime *rt, pit_value cell, pit_value v, pit_value sym) { - if (pit_value_sort(cell) != PIT_VALUE_SORT_REF) { - char buf[256]; - i64 end = pit_dump(rt, buf, sizeof(buf) - 1, sym, false); - buf[end] = 0; - pit_error(rt, "attempted to set unbound variable/function: %s", buf); - return; - } - 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"); - return; - } - h->in.cell = v; -} - -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; } - i64 byte_len = 0; pit_mul(&byte_len, sizeof(pit_value), len); - pit_value *dest = pit_arena_alloc_array(rt->heap, byte_len); - if (!dest) { pit_error(rt, "failed to allocate array"); return 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; } - h->hsort = PIT_VALUE_HEAVY_SORT_ARRAY; - h->in.array.data = dest; - h->in.array.len = len; - return ret; -} -pit_value pit_array_from_buf(pit_runtime *rt, pit_value *xs, i64 len) { - pit_value ret = pit_array_new(rt, len); - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret)); - if (!h) { pit_error(rt, "failed to deref heavy value for array"); return PIT_NIL; } - pit_libc_string_memcpy((u8 *) h->in.array.data, (u8 *) xs, (size_t) len * (size_t) sizeof(pit_value)); - return ret; -} -i64 pit_array_len(pit_runtime *rt, pit_value arr) { - if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return -1; } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, arr)); - if (!h) { pit_error(rt, "bad ref"); return -1; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return -1; } - return h->in.array.len; -} -pit_value pit_array_get(pit_runtime *rt, pit_value arr, i64 idx) { - if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return PIT_NIL; } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, arr)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return PIT_NIL; } - if (idx < 0 || idx >= h->in.array.len) { - pit_error(rt, "array index out of bounds: %d", idx); - return PIT_NIL; - } - return h->in.array.data[idx]; -} -pit_value pit_array_set(pit_runtime *rt, pit_value arr, i64 idx, pit_value v) { - if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return PIT_NIL; } - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, arr)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return PIT_NIL; } - if (idx < 0 || idx >= h->in.array.len) { - pit_error(rt, "array index out of bounds: %d", idx); - return PIT_NIL; - } - h->in.array.data[idx] = v; - return v; -} - -pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr) { - 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 cons"); return PIT_NIL; } - h->hsort = PIT_VALUE_HEAVY_SORT_CONS; - h->in.cons.car = car; - h->in.cons.cdr = cdr; - return ret; -} -pit_value pit_list(pit_runtime *rt, i64 num, ...) { - pit_value temp[64] = {0}; - pit_value ret = PIT_NIL; - if (num > 64) { pit_error(rt, "failed to create list of size %d\n", num); return PIT_NIL; } - va_list elems; - va_start(elems, num); - for (i64 i = 0; i < num; ++i) { - temp[i] = va_arg(elems, pit_value); - } - va_end(elems); - for (i64 i = 0; i < num; ++i) { - ret = pit_cons(rt, temp[num - i - 1], ret); - } - return ret; -} -i64 pit_list_len(pit_runtime *rt, pit_value xs) { - i64 ret = 0; - while (xs != PIT_NIL) { - ret += 1; - xs = pit_cdr(rt, xs); - } - 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)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) return PIT_NIL; - return h->in.cons.car; -} -pit_value pit_cdr(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)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) return PIT_NIL; - return h->in.cons.cdr; -} -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_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->in.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_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->in.cons.cdr = x; -} -pit_value pit_append(pit_runtime *rt, pit_value xs, pit_value ys) { - pit_value ret = ys; - xs = pit_reverse(rt, xs); - while (xs != PIT_NIL) { - ret = pit_cons(rt, pit_car(rt, xs), ret); - xs = pit_cdr(rt, xs); - } - return ret; +void pit_annotation_set(struct pit_runtime *rt, pit_ref ref, pit_annotation annotation) { + pit_annotated_ref a; + a.ref = ref; + a.annotation = annotation; + if (pit_vec_push(pit_annotated_ref)(rt->annotations, a) < 0) + pit_error(rt, "annotation overflow"); } -pit_value pit_reverse(pit_runtime *rt, pit_value xs) { - pit_value ret = PIT_NIL; - while (xs != PIT_NIL) { - ret = pit_cons(rt, pit_car(rt, xs), ret); - xs = pit_cdr(rt, xs); - } - return ret; -} -pit_value pit_contains_eq(pit_runtime *rt, pit_value needle, pit_value haystack) { - while (haystack != PIT_NIL) { - if (pit_eq(needle, pit_car(rt, haystack))) return PIT_T; - haystack = pit_cdr(rt, haystack); - } - return PIT_NIL; -} -pit_value pit_contains_equal(pit_runtime *rt, pit_value needle, pit_value haystack) { - while (haystack != PIT_NIL) { - if (pit_equal(rt, needle, pit_car(rt, haystack))) return PIT_T; - haystack = pit_cdr(rt, haystack); - } - return PIT_NIL; -} -pit_value pit_plist_get(pit_runtime *rt, pit_value k, pit_value vs) { - while (vs != PIT_NIL) { - if (pit_eq(k, pit_car(rt, vs))) { - return pit_car(rt, pit_cdr(rt, vs)); - } - vs = pit_cdr(rt, vs); - } - return PIT_NIL; -} - -pit_value pit_free_vars(pit_runtime *rt, pit_value initial_bound, pit_value body) { - i64 expr_stack_reset = rt->expr_stack->next; - pit_value ret = PIT_NIL; - if (pit_vec_push(pit_value)(rt->expr_stack, pit_cons(rt, initial_bound, body)) < 0) - pit_error(rt, "free variable search stack overflow"); - while (rt->expr_stack->next > expr_stack_reset) { - pit_value boundscur, bound, cur; - if (pit_vec_pop(pit_value)(rt->expr_stack, &boundscur) < 0) - pit_error(rt, "free variable search stack underflow"); - bound = pit_car(rt, boundscur); - cur = pit_cdr(rt, boundscur); - if (pit_is_cons(rt, cur)) { - pit_value fsym = pit_car(rt, cur); - bool is_symbol = pit_is_symbol(rt, fsym); - pit_value fargs = pit_cdr(rt, cur); - if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "lambda")) { - pit_value new_bound = pit_append(rt, pit_car(rt, fargs), bound); - fargs = pit_cdr(rt, fargs); - while (fargs != PIT_NIL) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_cons(rt, new_bound, pit_car(rt, fargs))) < 0) - pit_error(rt, "free variable search stack overflow"); - fargs = pit_cdr(rt, fargs); - } - } 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 (fargs != PIT_NIL) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_cons(rt, bound, pit_car(rt, fargs))) < 0) - pit_error(rt, "free variable search stack overflow"); - fargs = pit_cdr(rt, fargs); - } - if (!is_symbol) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_cons(rt, bound, fsym)) < 0) - pit_error(rt, "free variable search stack overflow"); - } - } - } else if (pit_is_symbol(rt, cur)) { - if (pit_contains_eq(rt, cur, bound) == PIT_NIL) { - ret = pit_cons(rt, cur, ret); - } - } - } - rt->expr_stack->next = 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, pit_as_ref(rt, ret)); - if (!h) { pit_error(rt, "failed to create new heavy value for lambda"); return PIT_NIL; } - pit_value expanded = pit_expand_macros(rt, pit_cons(rt, pit_intern_cstr(rt, "progn"), body)); - pit_value freevars = pit_free_vars(rt, args, expanded); - pit_value env = PIT_NIL; - while (freevars != PIT_NIL) { - pit_value sym = pit_car(rt, freevars); - pit_value cell = pit_get_value_cell(rt, sym); - env = pit_cons(rt, pit_cons(rt, sym, cell), env); - freevars = pit_cdr(rt, freevars); - } - h->hsort = PIT_VALUE_HEAVY_SORT_FUNC; - pit_value arg_cells = PIT_NIL; - pit_value arg_rest_nm = PIT_NIL; - pit_value separator = pit_intern_cstr(rt, "&"); - while (args != PIT_NIL) { - pit_value nm = pit_car(rt, args); - if (pit_eq(nm, separator)) { - pit_value next_nm = pit_car(rt, pit_cdr(rt, args)); - if (next_nm == PIT_NIL) { pit_error(rt, "invalid & in lambda list"); return PIT_NIL; } - arg_rest_nm = next_nm; - arg_cells = pit_cons(rt, next_nm, arg_cells); - break; - } else { - arg_cells = pit_cons(rt, nm, arg_cells); - args = pit_cdr(rt, args); - } - } - arg_cells = pit_reverse(rt, arg_cells); - h->in.func.args = arg_cells; - h->in.func.arg_rest_nm = arg_rest_nm; - h->in.func.env = env; - h->in.func.body = expanded; - return ret; -} -pit_value pit_nativefunc_new_with_data(pit_runtime *rt, pit_nativefunc f, void *data) { - 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 nativefunc"); return PIT_NIL; } - h->hsort = PIT_VALUE_HEAVY_SORT_NATIVEFUNC; - h->in.nativefunc.f = f; - h->in.nativefunc.data = data; - return ret; -} -pit_value pit_nativefunc_new(pit_runtime *rt, pit_nativefunc f) { - return pit_nativefunc_new_with_data(rt, f, NULL); -} -pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args) { - char buf[256] = {0}; - if (pit_is_symbol(rt, f)) { - f = pit_fget(rt, f); - } - /* if f is not a symbol, assume it is a func or nativefunc - most commonly, this happens when you funcall a variable - with a function in the value cell, e.g. passing a lambda to a function */ - switch (pit_value_sort(f)) { - case PIT_VALUE_SORT_REF: { - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, f)); - if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } - if (h->hsort == PIT_VALUE_HEAVY_SORT_FUNC) { - /* calling a Lisp function is simple! */ - pit_value bound = PIT_NIL; - pit_value env = h->in.func.env; - while (env != PIT_NIL) { /* first, bind all entries in the closure */ - pit_value b = pit_car(rt, env); - pit_value nm = pit_car(rt, b); - pit_bind(rt, nm, pit_cdr(rt, b)); - bound = pit_cons(rt, nm, bound); - env = pit_cdr(rt, env); - } - pit_value anames = h->in.func.args; - while (anames != PIT_NIL) { /* bind all argument names to their values */ - pit_value nm = pit_car(rt, anames); - pit_value cell = pit_cell_new(rt, PIT_NIL); - if (h->in.func.arg_rest_nm != PIT_NIL && pit_eq(nm, h->in.func.arg_rest_nm)) { - pit_cell_set(rt, cell, args, nm); - pit_bind(rt, nm, cell); - break; - } else { - pit_cell_set(rt, cell, pit_car(rt, args), nm); - pit_bind(rt, nm, cell); - } - bound = pit_cons(rt, nm, bound); - args = pit_cdr(rt, args); - anames = pit_cdr(rt, anames); - } - pit_value ret = pit_eval(rt, h->in.func.body); /* evaluate the body */ - while (bound != PIT_NIL) { /* unbind everything we bound earlier, in reverse */ - pit_unbind(rt, pit_car(rt, bound)); - bound = pit_cdr(rt, bound); - } - return ret; - } else if (h->hsort == PIT_VALUE_HEAVY_SORT_NATIVEFUNC) { - /* calling native functions is even simpler */ - return h->in.nativefunc.f(rt, args, h->in.nativefunc.data); - } else { - i64 end = pit_dump(rt, buf, sizeof(buf) - 1, f, true); - buf[end] = 0; - pit_error(rt, "attempted to apply non-function ref: %s", buf); - return PIT_NIL; +pit_annotated_ref *pit_annotation_get(struct pit_runtime *rt, pit_ref ref) { + for (i64 i = 0; i < rt->annotations->next; ++i) { + pit_annotated_ref *a = pit_vec_get(pit_annotated_ref)(rt->annotations, i); + if (a == NULL) pit_error(rt, "failed to get annotation"); + else if (a->ref == ref) { + return a; } } - default: { - i64 end = pit_dump(rt, buf, sizeof(buf) - 1, f, true); - buf[end] = 0; - pit_error(rt, "attempted to apply non-function value: %s", buf); - return PIT_NIL; - } - } -} - -pit_value pit_nativedata_new(pit_runtime *rt, pit_value tag, void *d) { - 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 nativedata"); return PIT_NIL; } - h->hsort = PIT_VALUE_HEAVY_SORT_NATIVEDATA; - h->in.nativedata.tag = tag; - h->in.nativedata.data = d; - return ret; -} -void *pit_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v) { - pit_value_heavy *h = NULL; - if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { - pit_error(rt, "value was not a reference"); - return NULL; - } - h = pit_deref(rt, pit_as_ref(rt, v)); - if (!h) { pit_error(rt, "bad ref"); return NULL; } - if (h->hsort != PIT_VALUE_HEAVY_SORT_NATIVEDATA) { - pit_error(rt, "invalid use of value as nativedata"); - return NULL; - } - if (!pit_eq(h->in.nativedata.tag, tag)) { - pit_error(rt, "native value does not match tag"); - return NULL; - } - if (!h->in.nativedata.data) { - pit_error(rt, "nativedata was already freed"); - return NULL; - } - return h->in.nativedata.data; + return NULL; } void pit_runtime_eval_program_push_literal(pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, pit_value x) { @@ -934,350 +106,11 @@ void pit_runtime_eval_program_push_literal(pit_runtime *rt, pit_vec(pit_runtime_ if (pit_vec_push(pit_runtime_eval_ins)(s, ent) < 0) pit_error(rt, "evaluation program overflow"); } -void pit_runtime_eval_program_push_apply(pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, i64 arity) { +void pit_runtime_eval_program_push_apply(pit_runtime *rt, pit_vec(pit_runtime_eval_ins) *s, i64 arity, pit_annotated_ref *annotation) { pit_runtime_eval_ins ent; ent.sort = PIT_RUNTIME_EVAL_INS_APPLY; - ent.in.apply = arity; + ent.in.apply.arity = arity; + ent.in.apply.annotation = annotation; if (pit_vec_push(pit_runtime_eval_ins)(s, ent) < 0) pit_error(rt, "evaluation program overflow"); } - -pit_expr_annotations *pit_expr_annotations_new(u8 *buf, i64 buf_len) { - uintptr_t base = (uintptr_t) buf; - uintptr_t aligned = pit_align_up(base, sizeof(void *)); - pit_expr_annotations *ret = (pit_expr_annotations *) aligned; - uintptr_t data = aligned + sizeof(pit_arena); - i64 offset = (i64) data - (i64) base; - i64 remaining = (i64) (buf_len - offset); - i64 cap = remaining / (i64) sizeof(pit_expr_annotation); - ret->next = 0; - ret->capacity = cap; - return ret; -} -void pit_expr_annotations_push(pit_expr_annotations *s, pit_ref ref, i64 line, i64 column) { - pit_expr_annotation *ent = &s->data[s->next++]; - ent->ref = ref; - ent->line = line; - ent->column = column; -} - -pit_expr_annotation *pit_expr_annotations_lookup(pit_expr_annotations *s, pit_ref ref) { - for (i64 i = 0; i < s->next; ++i) { - if (s->data[i].ref == ref) return &s->data[i]; - } - return NULL; -} - -pit_value pit_expand_macros(pit_runtime *rt, pit_value top) { - i64 expr_stack_reset = rt->expr_stack->next; - i64 result_stack_reset = rt->result_stack->next; - i64 program_reset = rt->program->next; - if (pit_vec_push(pit_value)(rt->expr_stack, top) < 0) - pit_error(rt, "macro expansion stack overflow"); - while (rt->expr_stack->next > expr_stack_reset) { - pit_value cur; - if (rt->error != PIT_NIL) goto end; - if (pit_vec_pop(pit_value)(rt->expr_stack, &cur) < 0) - pit_error(rt, "macro expansion stack underflow"); - if (pit_is_cons(rt, cur)) { - pit_value fsym = pit_car(rt, cur); - bool is_symbol = pit_is_symbol(rt, fsym); - if (is_symbol && pit_is_symbol_macro(rt, fsym)) { - pit_value f = pit_fget(rt, fsym); - pit_value args = pit_cdr(rt, cur); - pit_value res = pit_apply(rt, f, args); - if (pit_vec_push(pit_value)(rt->expr_stack, res) < 0) - pit_error(rt, "macro expansion stack overflow"); - } else if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "defer")) { - pit_value args = pit_cdr(rt, cur); - pit_runtime_eval_program_push_literal(rt, rt->program, pit_car(rt, args)); - } else if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "quote")) { - pit_runtime_eval_program_push_literal(rt, rt->program, cur); - } else if (is_symbol && pit_symbol_name_match_cstr(rt, fsym, "lambda")) { - pit_value args = pit_cdr(rt, cur); - pit_value bindings = pit_car(rt, args); - pit_value body = pit_cdr(rt, args); - i64 argcount = 0; - if (pit_vec_push(pit_value)(rt->expr_stack, pit_list(rt, 2, pit_intern_cstr(rt, "defer"), bindings)) < 0) - pit_error(rt, "macro expansion stack overflow"); - while (body != PIT_NIL) { - pit_value a = pit_car(rt, body); - if (pit_vec_push(pit_value)(rt->expr_stack, a) < 0) - pit_error(rt, "macro expansion stack overflow"); - body = pit_cdr(rt, body); - argcount += 1; - } - pit_runtime_eval_program_push_apply(rt, rt->program, argcount + 1); - pit_runtime_eval_program_push_literal(rt, rt->program, fsym); - } else { - pit_value args = pit_cdr(rt, cur); - i64 argcount = 0; - while (args != PIT_NIL) { - pit_value a = pit_car(rt, args); - if (pit_vec_push(pit_value)(rt->expr_stack, a) < 0) - pit_error(rt, "macro expansion stack overflow"); - args = pit_cdr(rt, args); - argcount += 1; - } - if (!is_symbol) { - if (pit_vec_push(pit_value)(rt->expr_stack, fsym) < 0) - pit_error(rt, "macro expansion stack overflow"); - } - pit_runtime_eval_program_push_apply(rt, rt->program, argcount); - if (is_symbol) { - pit_runtime_eval_program_push_literal(rt, rt->program, fsym); - } - } - } else { - pit_runtime_eval_program_push_literal(rt, rt->program, cur); - } - } - for (i64 idx = rt->program->next - 1; idx >= program_reset; --idx) { - pit_runtime_eval_ins *ent = pit_vec_get(pit_runtime_eval_ins)(rt->program, idx); - if (ent == NULL) pit_error(rt, "macro expansion program invalid"); - if (rt->error != PIT_NIL) goto end; - switch (ent->sort) { - case PIT_RUNTIME_EVAL_INS_LITERAL: - if (pit_vec_push(pit_value)(rt->result_stack, ent->in.literal) < 0) - pit_error(rt, "macro expansion stack overflow"); - break; - case PIT_RUNTIME_EVAL_INS_APPLY: { - pit_value f = PIT_NIL; - pit_value args = PIT_NIL; - if (pit_vec_pop(pit_value)(rt->result_stack, &f) < 0) - pit_error(rt, "macro expansion stack underflow"); - for (i64 i = 0; i < ent->in.apply; ++i) { - pit_value a; - if (pit_vec_pop(pit_value)(rt->result_stack, &a) < 0) - pit_error(rt, "macro expansion stack underflow"); - args = pit_cons(rt, a, args); - } - if (pit_vec_push(pit_value)(rt->result_stack, pit_cons(rt, f, args)) < 0) - pit_error(rt, "macro expansion stack overflow"); - break; - } - default: - pit_error(rt, "unknown program entry"); - goto end; - } - } -end: { - pit_value ret = PIT_NIL; - if (pit_vec_pop(pit_value)(rt->result_stack, &ret) < 0) - pit_error(rt, "macro expansion stack underflow"); - 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->next; - i64 result_stack_reset = rt->result_stack->next; - i64 program_reset = rt->program->next; - if (pit_vec_push(pit_value)(rt->expr_stack, top) < 0) - pit_error(rt, "evaluation stack overflow"); - /* first, convert the expression tree into "polish notation" in program */ - while (rt->expr_stack->next > expr_stack_reset) { - pit_value cur = PIT_NIL; - if (rt->error != PIT_NIL) goto end; - if (pit_vec_pop(pit_value)(rt->expr_stack, &cur) < 0) - pit_error(rt, "evaluation stack underflow"); - if (pit_is_cons(rt, cur)) { /* compound expressions: function/macro application special forms */ - pit_value fsym = pit_car(rt, cur); - bool is_symbol = pit_is_symbol(rt, fsym); - pit_expr_annotation *ann = pit_expr_annotations_lookup(rt->annotations, pit_as_ref(rt, cur)); - fprintf(stderr, "looking up annotation (%ld): ", pit_as_ref(rt, cur)); - pit_trace_(rt, "%s\n", cur); - if (ann) { - fprintf(stderr, "%ld:%ld\n", ann->line, ann->column); - rt->source_line = ann->line; - rt->source_column = ann->column; - } else { - fprintf(stderr, "failed to find ann\n"); - } - if (is_symbol && pit_is_symbol_special_form(rt, fsym)) { /* special forms */ - pit_value f = pit_fget(rt, fsym); - pit_value args = pit_cdr(rt, cur); - /* special forms are nativefuncs that directly manipulate the stacks - basically macros, but we don't need to evaluate the return value */ - pit_apply(rt, f, args); - } else if (is_symbol && pit_is_symbol_macro(rt, fsym)) { /* macros */ - pit_value f = pit_fget(rt, fsym); - pit_value args = pit_cdr(rt, cur); - pit_value res = pit_apply(rt, f, args); - if (pit_vec_push(pit_value)(rt->expr_stack, res) < 0) - pit_error(rt, "evaluation stack overflow"); - } else { /* normal functions */ - pit_value args = pit_cdr(rt, cur); - i64 argcount = 0; - while (args != PIT_NIL) { - if (pit_vec_push(pit_value)(rt->expr_stack, pit_car(rt, args)) < 0) - pit_error(rt, "evaluation stack overflow"); - args = pit_cdr(rt, args); - argcount += 1; - } - if (!is_symbol) { - if (pit_vec_push(pit_value)(rt->expr_stack, fsym) < 0) - pit_error(rt, "evaluation stack overflow"); - } - pit_runtime_eval_program_push_apply(rt, rt->program, argcount); - if (is_symbol) { - pit_value f = pit_fget(rt, fsym); - pit_runtime_eval_program_push_literal(rt, rt->program, f); - } - } - } else if (pit_is_symbol(rt, cur)) { /* unquoted symbols: variable lookup */ - pit_symtab_entry *ent = pit_symtab_lookup(rt, cur); - if (ent->is_keyword) { - pit_runtime_eval_program_push_literal(rt, rt->program, cur); - } else { - pit_runtime_eval_program_push_literal(rt, rt->program, pit_get(rt, cur)); - } - } else { /* other expressions evaluate to themselves! */ - pit_runtime_eval_program_push_literal(rt, rt->program, cur); - } - } - /* 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->next - 1; idx >= program_reset; --idx) { - pit_runtime_eval_ins *ent = pit_vec_get(pit_runtime_eval_ins)(rt->program, idx); - if (ent == NULL) pit_error(rt, "evaluation program invalid"); - if (rt->error != PIT_NIL) goto end; - switch (ent->sort) { - case PIT_RUNTIME_EVAL_INS_LITERAL: - if (pit_vec_push(pit_value)(rt->result_stack, ent->in.literal) < 0) - pit_error(rt, "evaluation result stack overflow"); - break; - case PIT_RUNTIME_EVAL_INS_APPLY: { - pit_value f = PIT_NIL; - pit_value args = PIT_NIL; - if (pit_vec_pop(pit_value)(rt->result_stack, &f) < 0) - pit_error(rt, "evaluation result stack underflow"); - for (i64 i = 0; i < ent->in.apply; ++i) { - pit_value a = PIT_NIL; - if (pit_vec_pop(pit_value)(rt->result_stack, &a) < 0) - pit_error(rt, "evaluation result stack underflow"); - args = pit_cons(rt, a, args); - } - if (pit_vec_push(pit_value)(rt->result_stack, pit_apply(rt, f, args)) < 0) - pit_error(rt, "evaluation result stack underflow"); - break; - } - default: - pit_error(rt, "unknown program entry"); - goto end; - } - } -end: { - pit_value ret = PIT_NIL; - if (pit_vec_pop(pit_value)(rt->result_stack, &ret) < 0) - pit_error(rt, "evaluation result stack underflow"); - rt->expr_stack->next = expr_stack_reset; - rt->result_stack->next = result_stack_reset; - rt->program->next = program_reset; - return ret; - } -} - -static i64 gc_copy(pit_arena *tospace, pit_value_heavy *h) { - if (h->hsort == PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER) { - return h->in.forwarding_pointer; - } else { - i64 ret = tospace->next; - pit_value_heavy *g = pit_arena_alloc(tospace); - *g = *h; - h->hsort = PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER; - h->in.forwarding_pointer = ret; - return ret; - } -} -static pit_value gc_copy_value(pit_runtime *rt, pit_arena *tospace, pit_value v) { - if (pit_value_sort(v) == PIT_VALUE_SORT_REF) { - pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, v)); - i64 new = gc_copy(tospace, h); - return pit_ref_new(rt, new); - } else { - return v; - } -} -void pit_collect_garbage(pit_runtime *rt) { - return; // TODO - 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_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->next; ++i) { - pit_value *v = pit_vec_get(pit_value)(rt->saved_bindings, i); - if (v != NULL) *v = gc_copy_value(rt, tospace, *v); /* TODO handle failure here */ - } - for (i64 scan = 0; scan < tospace->next; ++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); - break; - case PIT_VALUE_HEAVY_SORT_CONS: - 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: { - 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) { - data[i] = gc_copy_value(rt, tospace, h->in.array.data[i]); - } - h->in.array.data = data; - 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); - h->in.func.arg_rest_nm = gc_copy_value(rt, tospace, h->in.func.arg_rest_nm); - h->in.func.body = gc_copy_value(rt, tospace, h->in.func.body); - break; - case PIT_VALUE_HEAVY_SORT_NATIVEFUNC: break; - case PIT_VALUE_HEAVY_SORT_NATIVEDATA: - h->in.nativedata.tag = gc_copy_value(rt, tospace, h->in.nativedata.tag); - break; - case PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER: - pit_error(rt, "garbage collection broken! encountered forwarding pointer in to-space"); - break; - } - } - rt->heap = tospace; - rt->backbuffer = fromspace; -} - -int pit_runtime_test(u8 *out, i64 out_len, u8 *buf, i64 len) { - pit_runtime *rt = pit_runtime_new(buf, len); - pit_install_library_essential(rt); - pit_install_library_plist(rt); - pit_install_library_alist(rt); - pit_lexer lex; - pit_parser parse; - pit_lex_cstr(&lex, "(cons (list 1 2 3) (cons '(a b c) 21))"); - pit_parser_from_lexer(&parse, &lex); - bool eof = false; - pit_value p = pit_parse(rt, &parse, &eof); - pit_value res = pit_eval(rt, p); - pit_dump(rt, (char *) out, out_len, res, false); - return 0; -} diff --git a/src/runtime/dump.c b/src/runtime/dump.c new file mode 100644 index 0000000..3d5ec9c --- /dev/null +++ b/src/runtime/dump.c @@ -0,0 +1,100 @@ +#include + +#define CHECK_BUF if (buf >= end) { return buf - start; } +#define CHECK_BUF_LABEL(label) if (buf >= end) { goto label; } +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)) { + case PIT_VALUE_SORT_DOUBLE: + #ifndef PIT_NO_DOUBLE + return pit_libc_string_snprintf(buf, (size_t) len, "%lf", pit_value_as_double(rt, v)); + #else + return pit_string_snprintf(buf, (size_t) len, ""); + #endif + case PIT_VALUE_SORT_INTEGER: + return pit_libc_string_snprintf(buf, (size_t) len, "%ld", pit_value_as_integer(rt, v)); + case PIT_VALUE_SORT_SYMBOL: { + pit_symtab_entry *ent = pit_symtab_lookup(rt, v); + if (ent + && pit_value_sort(ent->name) == PIT_VALUE_SORT_REF + && (h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ent->name))) + ) { + i64 i = 0; + for (; i < h->in.bytes.len && i < len - 1; ++i) { + buf[i] = (char) h->in.bytes.data[i]; + } + return i; + } else { + return pit_libc_string_snprintf(buf, (size_t) len, "", pit_value_as_symbol(rt, v)); + } + } + case PIT_VALUE_SORT_REF: { + pit_ref r = pit_value_as_ref(rt, v); + char *end = buf + len; + char *start = buf; + h = pit_value_ref_deref(rt, r); + if (!h) pit_libc_string_snprintf(buf, (size_t) len, "", r); + else { + switch (h->hsort) { + case PIT_VALUE_HEAVY_SORT_CELL: { + CHECK_BUF; *(buf++) = '{'; + CHECK_BUF; buf += pit_dump(rt, buf, end - buf, pit_value_cons_car(rt, h->in.cell), readable); + CHECK_BUF; *(buf++) = '}'; + return buf - start; + } + case PIT_VALUE_HEAVY_SORT_CONS: { + pit_value cur = v; + CHECK_BUF_LABEL(list_end); + do { + if (pit_value_is_cons(rt, cur)) { + CHECK_BUF_LABEL(list_end); *(buf++) = ' '; + CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, pit_value_cons_car(rt, cur), readable); + } else { + CHECK_BUF_LABEL(list_end); buf += pit_libc_string_snprintf(buf, (size_t) (end - buf), " . "); + CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, cur, readable); + } + } while (!pit_value_eq((cur = pit_value_cons_cdr(rt, cur)), PIT_NIL)); + CHECK_BUF_LABEL(list_end); *(buf++) = ')'; + list_end: + *start = '('; + return buf - start; + } + case PIT_VALUE_HEAVY_SORT_ARRAY: { + i64 i = 0; + CHECK_BUF_LABEL(array_end); + if (h->in.array.len == 0) { + CHECK_BUF_LABEL(array_end); *(buf++) = '['; + } else for (; i < h->in.array.len; ++i) { + CHECK_BUF_LABEL(array_end); *(buf++) = ' '; + CHECK_BUF_LABEL(array_end); buf += pit_dump(rt, buf, end - buf, h->in.array.data[i], readable); + } + CHECK_BUF_LABEL(array_end); *(buf++) = ']'; + array_end: + *start = '['; + return buf - start; + } + case PIT_VALUE_HEAVY_SORT_BYTES: { + i64 i = 0; + if (readable) { CHECK_BUF; buf[i++] = '"'; } + i64 maxlen = len - i; + for (i64 j = 0; i < maxlen && j < h->in.bytes.len;) { + if (buf[i - 1] != '\\' && (h->in.bytes.data[j] == '\\' || h->in.bytes.data[j] == '"')) { + CHECK_BUF; buf[i++] = '\\'; + } + else { + CHECK_BUF; buf[i++] = (char) h->in.bytes.data[j++]; + } + } + if (readable && i < len - 1) buf[i++] = '"'; + return i; + } + default: + return pit_libc_string_snprintf(buf, (size_t) len, "", r); + } + } + break; + } + } + return 0; +} diff --git a/src/runtime/eval.c b/src/runtime/eval.c new file mode 100644 index 0000000..f5eba97 --- /dev/null +++ b/src/runtime/eval.c @@ -0,0 +1,107 @@ +#include + +pit_value pit_eval(pit_runtime *rt, pit_value top) { + i64 expr_stack_reset = rt->expr_stack->next; + i64 result_stack_reset = rt->result_stack->next; + i64 program_reset = rt->program->next; + // pit_vec_reset(pit_annotated_ref)(rt->backtrace); + if (pit_vec_push(pit_value)(rt->expr_stack, top) < 0) + pit_error(rt, "evaluation stack overflow"); + /* first, convert the expression tree into "polish notation" in program */ + while (rt->expr_stack->next > expr_stack_reset) { + pit_value cur = PIT_NIL; + if (rt->error != PIT_NIL) goto end; + if (pit_vec_pop(pit_value)(rt->expr_stack, &cur) < 0) + pit_error(rt, "evaluation stack underflow"); + if (pit_value_is_cons(rt, cur)) { /* compound expressions: function/macro application special forms */ + pit_value fsym = pit_value_cons_car(rt, cur); + bool is_symbol = pit_value_is_symbol(rt, fsym); + pit_annotated_ref *ann = pit_annotation_get(rt, pit_value_as_ref(rt, cur)); + if (is_symbol && pit_symtab_is_symbol_special_form(rt, fsym)) { /* special forms */ + pit_value f = pit_symtab_fget(rt, fsym); + pit_value args = pit_value_cons_cdr(rt, cur); + /* special forms are nativefuncs that directly manipulate the stacks + basically macros, but we don't need to evaluate the return value */ + pit_value_apply(rt, f, args); + } else if (is_symbol && pit_symtab_is_symbol_macro(rt, fsym)) { /* macros */ + pit_value f = pit_symtab_fget(rt, fsym); + pit_value args = pit_value_cons_cdr(rt, cur); + pit_value res = pit_value_apply(rt, f, args); + if (pit_vec_push(pit_value)(rt->expr_stack, res) < 0) + pit_error(rt, "evaluation stack overflow"); + } else { /* normal functions */ + pit_value args = pit_value_cons_cdr(rt, cur); + i64 argcount = 0; + while (args != PIT_NIL) { + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons_car(rt, args)) < 0) + pit_error(rt, "evaluation stack overflow"); + args = pit_value_cons_cdr(rt, args); + argcount += 1; + } + if (!is_symbol) { + if (pit_vec_push(pit_value)(rt->expr_stack, fsym) < 0) + pit_error(rt, "evaluation stack overflow"); + } + pit_runtime_eval_program_push_apply(rt, rt->program, argcount, ann); + if (is_symbol) { + pit_value f = pit_symtab_fget(rt, fsym); + pit_runtime_eval_program_push_literal(rt, rt->program, f); + } + } + } else if (pit_value_is_symbol(rt, cur)) { /* unquoted symbols: variable lookup */ + pit_symtab_entry *ent = pit_symtab_lookup(rt, cur); + if (ent->is_keyword) { + pit_runtime_eval_program_push_literal(rt, rt->program, cur); + } else { + pit_runtime_eval_program_push_literal(rt, rt->program, pit_symtab_get(rt, cur)); + } + } else { /* other expressions evaluate to themselves! */ + pit_runtime_eval_program_push_literal(rt, rt->program, cur); + } + } + /* 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->next - 1; idx >= program_reset; --idx) { + pit_runtime_eval_ins *ent = pit_vec_get(pit_runtime_eval_ins)(rt->program, idx); + if (ent == NULL) pit_error(rt, "evaluation program invalid"); + if (rt->error != PIT_NIL) goto end; + switch (ent->sort) { + case PIT_RUNTIME_EVAL_INS_LITERAL: + if (pit_vec_push(pit_value)(rt->result_stack, ent->in.literal) < 0) + pit_error(rt, "evaluation result stack overflow"); + break; + case PIT_RUNTIME_EVAL_INS_APPLY: { + pit_value f = PIT_NIL; + pit_value args = PIT_NIL; + if (pit_vec_pop(pit_value)(rt->result_stack, &f) < 0) + pit_error(rt, "evaluation result stack underflow"); + for (i64 i = 0; i < ent->in.apply.arity; ++i) { + pit_value a = PIT_NIL; + if (pit_vec_pop(pit_value)(rt->result_stack, &a) < 0) + pit_error(rt, "evaluation result stack underflow"); + args = pit_value_cons(rt, a, args); + } + if (ent->in.apply.annotation != NULL) { + rt->source_line = ent->in.apply.annotation->annotation.line; + rt->source_column = ent->in.apply.annotation->annotation.column; + pit_vec_push(pit_annotated_ref)(rt->backtrace, *ent->in.apply.annotation); + } + if (pit_vec_push(pit_value)(rt->result_stack, pit_value_apply(rt, f, args)) < 0) + pit_error(rt, "evaluation result stack underflow"); + break; + } + default: + pit_error(rt, "unknown program entry"); + goto end; + } + } +end: { + pit_value ret = PIT_NIL; + if (pit_vec_pop(pit_value)(rt->result_stack, &ret) < 0) + pit_error(rt, "evaluation result stack underflow"); + rt->expr_stack->next = expr_stack_reset; + rt->result_stack->next = result_stack_reset; + rt->program->next = program_reset; + return ret; + } +} diff --git a/src/runtime/gc.c b/src/runtime/gc.c new file mode 100644 index 0000000..fcb5f89 --- /dev/null +++ b/src/runtime/gc.c @@ -0,0 +1,100 @@ +#include + +static i64 gc_copy(pit_runtime *rt, pit_value_heavy *h) { + if (h->hsort == PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER) { + return h->in.forwarding_pointer; + } else { + i64 ret = rt->backbuffer->next; + pit_value_heavy *g = pit_arena_alloc(rt->backbuffer); + *g = *h; + h->hsort = PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER; + h->in.forwarding_pointer = ret; + return ret; + } +} +static pit_value gc_copy_value(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) == PIT_VALUE_SORT_REF) { + pit_ref r = pit_value_as_ref(rt, v); + pit_value_heavy *h = pit_value_ref_deref(rt, r); + i64 new = gc_copy(rt, h); + pit_annotated_ref *ann = pit_annotation_get(rt, r); + if (ann != NULL) { + pit_annotated_ref newann = *ann; + newann.ref = new; + if (pit_vec_push(pit_annotated_ref)(rt->backtrace, newann) < 0) + pit_error(rt, "annotation overflow"); + } + return pit_value_ref_new(rt, new); + } else { + return v; + } +} +void pit_gc(pit_runtime *rt) { + rt->frozen_values = 0; + rt->frozen_symtab = 0; + pit_arena *fromspace = rt->heap; + pit_arena *tospace = rt->backbuffer; + pit_vec(pit_annotated_ref) *fromspace_ann = rt->annotations; + pit_vec(pit_annotated_ref) *tospace_ann = rt->backtrace; + pit_arena_reset(tospace); + pit_vec_reset(pit_annotated_ref)(tospace_ann); + /* populate tospace with immediately reachable values */ + for (i64 i = 0; i < rt->symtab->next; ++i) { + pit_symtab_entry *ent = pit_vec_get(pit_symtab_entry)(rt->symtab, i); + if (ent == NULL) continue; /* TODO warn on failure here? */ + ent->name = gc_copy_value(rt, ent->name); + ent->value = gc_copy_value(rt, ent->value); + ent->function = gc_copy_value(rt, ent->function); + } + for (i64 i = 0; i < rt->saved_bindings->next; ++i) { + pit_value *v = pit_vec_get(pit_value)(rt->saved_bindings, i); + if (v != NULL) *v = gc_copy_value(rt, *v); /* TODO warn on failure here? */ + } + for (i64 scan = 0; scan < tospace->next; ++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, h->in.cell); + break; + case PIT_VALUE_HEAVY_SORT_CONS: + h->in.cons.car = gc_copy_value(rt, h->in.cons.car); + h->in.cons.cdr = gc_copy_value(rt, h->in.cons.cdr); + break; + 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) { + data[i] = gc_copy_value(rt, h->in.array.data[i]); + } + h->in.array.data = data; + 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, h->in.func.env); + h->in.func.args = gc_copy_value(rt, h->in.func.args); + h->in.func.arg_rest_nm = gc_copy_value(rt, h->in.func.arg_rest_nm); + h->in.func.body = gc_copy_value(rt, h->in.func.body); + break; + case PIT_VALUE_HEAVY_SORT_NATIVEFUNC: break; + case PIT_VALUE_HEAVY_SORT_NATIVEDATA: + h->in.nativedata.tag = gc_copy_value(rt, h->in.nativedata.tag); + break; + case PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER: + pit_error(rt, "garbage collection broken! encountered forwarding pointer in to-space"); + break; + } + } + rt->heap = tospace; + rt->backbuffer = fromspace; + rt->annotations = tospace_ann; + rt->backtrace = fromspace_ann; + pit_vec_reset(pit_annotated_ref)(rt->backtrace); +} diff --git a/src/runtime/macroexpand.c b/src/runtime/macroexpand.c new file mode 100644 index 0000000..13a4fdd --- /dev/null +++ b/src/runtime/macroexpand.c @@ -0,0 +1,111 @@ +#include + +pit_value pit_macroexpand(pit_runtime *rt, pit_value top) { + i64 expr_stack_reset = rt->expr_stack->next; + i64 result_stack_reset = rt->result_stack->next; + i64 program_reset = rt->program->next; + if (pit_vec_push(pit_value)(rt->expr_stack, top) < 0) + pit_error(rt, "macro expansion stack overflow"); + while (rt->expr_stack->next > expr_stack_reset) { + pit_value cur; + if (rt->error != PIT_NIL) goto end; + if (pit_vec_pop(pit_value)(rt->expr_stack, &cur) < 0) + pit_error(rt, "macro expansion stack underflow"); + if (pit_value_is_cons(rt, cur)) { + pit_value fsym = pit_value_cons_car(rt, cur); + bool is_symbol = pit_value_is_symbol(rt, fsym); + pit_annotated_ref *ann = pit_annotation_get(rt, pit_value_as_ref(rt, cur)); + if (is_symbol && pit_symtab_is_symbol_macro(rt, fsym)) { + pit_value f = pit_symtab_fget(rt, fsym); + pit_value args = pit_value_cons_cdr(rt, cur); + pit_value res = pit_value_apply(rt, f, args); + if (pit_vec_push(pit_value)(rt->expr_stack, res) < 0) + pit_error(rt, "macro expansion stack overflow"); + } else if (is_symbol && pit_symtab_symbol_name_match_cstr(rt, fsym, "defer")) { + pit_value args = pit_value_cons_cdr(rt, cur); + pit_runtime_eval_program_push_literal(rt, rt->program, pit_value_cons_car(rt, args)); + } else if (is_symbol && pit_symtab_symbol_name_match_cstr(rt, fsym, "quote")) { + pit_runtime_eval_program_push_literal(rt, rt->program, cur); + } else if (is_symbol && pit_symtab_symbol_name_match_cstr(rt, fsym, "lambda")) { + pit_value args = pit_value_cons_cdr(rt, cur); + pit_value bindings = pit_value_cons_car(rt, args); + pit_value body = pit_value_cons_cdr(rt, args); + i64 argcount = 0; + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_list(rt, 2, pit_symtab_intern_cstr(rt, "defer"), bindings)) < 0) + pit_error(rt, "macro expansion stack overflow"); + while (body != PIT_NIL) { + pit_value a = pit_value_cons_car(rt, body); + if (pit_vec_push(pit_value)(rt->expr_stack, a) < 0) + pit_error(rt, "macro expansion stack overflow"); + body = pit_value_cons_cdr(rt, body); + argcount += 1; + } + pit_runtime_eval_program_push_apply(rt, rt->program, argcount + 1, ann); + pit_runtime_eval_program_push_literal(rt, rt->program, fsym); + } else { + pit_value args = pit_value_cons_cdr(rt, cur); + i64 argcount = 0; + while (args != PIT_NIL) { + pit_value a = pit_value_cons_car(rt, args); + if (pit_vec_push(pit_value)(rt->expr_stack, a) < 0) + pit_error(rt, "macro expansion stack overflow"); + args = pit_value_cons_cdr(rt, args); + argcount += 1; + } + if (!is_symbol) { + if (pit_vec_push(pit_value)(rt->expr_stack, fsym) < 0) + pit_error(rt, "macro expansion stack overflow"); + } + pit_runtime_eval_program_push_apply(rt, rt->program, argcount, ann); + if (is_symbol) { + pit_runtime_eval_program_push_literal(rt, rt->program, fsym); + } + } + } else { + pit_runtime_eval_program_push_literal(rt, rt->program, cur); + } + } + for (i64 idx = rt->program->next - 1; idx >= program_reset; --idx) { + pit_runtime_eval_ins *ent = pit_vec_get(pit_runtime_eval_ins)(rt->program, idx); + if (ent == NULL) pit_error(rt, "macro expansion program invalid"); + if (rt->error != PIT_NIL) goto end; + switch (ent->sort) { + case PIT_RUNTIME_EVAL_INS_LITERAL: + if (pit_vec_push(pit_value)(rt->result_stack, ent->in.literal) < 0) + pit_error(rt, "macro expansion stack overflow"); + break; + case PIT_RUNTIME_EVAL_INS_APPLY: { + pit_value f = PIT_NIL; + pit_value args = PIT_NIL; + pit_value app = PIT_NIL; + if (pit_vec_pop(pit_value)(rt->result_stack, &f) < 0) + pit_error(rt, "macro expansion stack underflow"); + for (i64 i = 0; i < ent->in.apply.arity; ++i) { + pit_value a; + if (pit_vec_pop(pit_value)(rt->result_stack, &a) < 0) + pit_error(rt, "macro expansion stack underflow"); + args = pit_value_cons(rt, a, args); + } + app = pit_value_cons(rt, f, args); + if (ent->in.apply.annotation != NULL) { + pit_annotation_set(rt, pit_value_as_ref(rt, app), ent->in.apply.annotation->annotation); + } + if (pit_vec_push(pit_value)(rt->result_stack, app) < 0) + pit_error(rt, "macro expansion stack overflow"); + break; + } + default: + pit_error(rt, "unknown program entry"); + goto end; + } + } +end: { + pit_value ret = PIT_NIL; + if (pit_vec_pop(pit_value)(rt->result_stack, &ret) < 0) + pit_error(rt, "macro expansion stack underflow"); + rt->expr_stack->next = expr_stack_reset; + rt->result_stack->next = result_stack_reset; + rt->program->next = program_reset; + return ret; + } +} diff --git a/src/runtime/symtab.c b/src/runtime/symtab.c new file mode 100644 index 0000000..d2bc51e --- /dev/null +++ b/src/runtime/symtab.c @@ -0,0 +1,118 @@ +#include + +pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym) { + pit_symbol s = pit_value_as_symbol(rt, sym); + return pit_vec_get(pit_symtab_entry)(rt->symtab, s); +} +pit_value pit_symtab_intern(pit_runtime *rt, u8 *nm, i64 len) { + if (rt->error != PIT_NIL) return PIT_NIL; + for (i64 sidx = 0; sidx < rt->symtab->next; ++sidx) { + pit_symtab_entry *sent = pit_vec_get(pit_symtab_entry)(rt->symtab, sidx); + if (sent == NULL) { pit_error(rt, "corrupted symbol table"); return PIT_NIL; } + if (pit_value_bytes_match(rt, sent->name, nm, len)) return pit_value_symbol_new(rt, sidx); + } + pit_symtab_entry ent; + ent.name = pit_value_bytes_new(rt, nm, len); + ent.value = PIT_NIL; + ent.function = PIT_NIL; + ent.is_macro = false; + ent.is_special_form = false; + ent.is_keyword = len >= 1 && nm[0] == ':'; + i64 idx = pit_vec_push(pit_symtab_entry)(rt->symtab, ent); + if (idx < 0) { pit_error(rt, "failed to allocate symtab entry"); return PIT_NIL; } + return pit_value_symbol_new(rt, idx); +} +pit_value pit_symtab_intern_cstr(pit_runtime *rt, char *nm) { + return pit_symtab_intern(rt, (u8 *) nm, (i64) pit_libc_string_strlen(nm)); +} +pit_value pit_symtab_symbol_name(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } + return ent->name; +} +bool pit_symtab_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } + return pit_value_bytes_match(rt, ent->name, buf, len); +} +bool pit_symtab_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s) { + return pit_symtab_symbol_name_match(rt, sym, (u8 *) s, (i64) pit_libc_string_strlen(s)); +} +pit_value pit_symtab_get_value_cell(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } + return ent->value; +} +pit_value pit_symtab_get_function_cell(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } + return ent->function; +} +pit_value pit_symtab_get(pit_runtime *rt, pit_value sym) { + return pit_value_cell_get(rt, pit_symtab_get_value_cell(rt, sym), sym); +} +void pit_symtab_set(pit_runtime *rt, pit_value sym, pit_value v) { + pit_symbol idx = pit_value_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) { + ent->value = pit_value_cell_new(rt, PIT_NIL); + } + pit_value_cell_set(rt, ent->value, v, sym); +} +pit_value pit_symtab_fget(pit_runtime *rt, pit_value sym) { + return pit_value_cell_get(rt, pit_symtab_get_function_cell(rt, sym), sym); +} +void pit_symtab_fset(pit_runtime *rt, pit_value sym, pit_value v) { + pit_symbol idx = pit_value_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) { + ent->function = pit_value_cell_new(rt, PIT_NIL); + } + pit_value_cell_set(rt, ent->function, v, sym); +} +bool pit_symtab_is_symbol_macro(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return false; } + return ent->is_macro; +} +void pit_symtab_symbol_mark_macro(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return; } + ent->is_macro = true; +} +void pit_symtab_mset(pit_runtime *rt, pit_value sym, pit_value v) { + pit_symtab_fset(rt, sym, v); + pit_symtab_symbol_mark_macro(rt, sym); +} +bool pit_symtab_is_symbol_special_form(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return false; } + return ent->is_special_form; +} +void pit_symtab_symbol_mark_special_form(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return; } + ent->is_special_form = true; +} +void pit_symtab_sfset(pit_runtime *rt, pit_value sym, pit_value v) { + pit_symtab_fset(rt, sym, v); + pit_symtab_symbol_mark_special_form(rt, sym); +} +void pit_symtab_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; } + if (pit_vec_push(pit_value)(rt->saved_bindings, ent->value) < 0) pit_error(rt, "binding stack overflow"); + ent->value = cell; +} +pit_value pit_symtab_unbind(pit_runtime *rt, pit_value sym) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return PIT_NIL; } + pit_value old = ent->value; + if (pit_vec_pop(pit_value)(rt->saved_bindings, &ent->value) < 0) pit_error(rt, "binding stack underflow"); + return old; +} diff --git a/src/runtime/value.c b/src/runtime/value.c new file mode 100644 index 0000000..1e9d543 --- /dev/null +++ b/src/runtime/value.c @@ -0,0 +1,76 @@ +#include + +pit_value pit_value_new(pit_runtime *rt, enum pit_value_sort s, u64 data) { + if (s == PIT_VALUE_SORT_DOUBLE) { + /* if (((data >> 52) & 0b011111111111) == 0b011111111111 && ((data >> 51) & 0b1) == 0) { */ + if (((data >> 52) & 0x7ff) == 0x7ff && ((data >> 51) & 1) == 0) { + pit_error(rt, "attempted to create a signalling NaN double"); + return PIT_NIL; + } + return data; + } + return + /* 0b1111111111110000000000000000000000000000000000000000000000000000 */ + 0xfff0000000000000 + /* | (((u64) (s & 0b11)) << 49) */ + | (((u64) (s & 3)) << 49) + /* | (data & 0b1111111111111111111111111111111111111111111111111); */ + | (data & 0x1ffffffffffff); +} + +bool pit_value_eq(pit_value a, pit_value b) { + return a == b; +} + +bool pit_value_equal(pit_runtime *rt, pit_value a, pit_value b) { + if (pit_value_sort(a) != pit_value_sort(b)) return false; + switch (pit_value_sort(a)) { + case PIT_VALUE_SORT_DOUBLE: + case PIT_VALUE_SORT_INTEGER: + case PIT_VALUE_SORT_SYMBOL: + return pit_value_data(a) == pit_value_data(b); + case PIT_VALUE_SORT_REF: { + pit_value_heavy *ha = pit_value_ref_deref(rt, pit_value_as_ref(rt, a)); + if (!ha) { pit_error(rt, "bad ref"); return false; } + pit_value_heavy *hb = pit_value_ref_deref(rt, pit_value_as_ref(rt, b)); + if (!hb) { pit_error(rt, "bad ref"); return false; } + if (ha->hsort != hb->hsort) return false; + switch (ha->hsort) { + case PIT_VALUE_HEAVY_SORT_CELL: + return pit_value_equal(rt, ha->in.cell, hb->in.cell); + case PIT_VALUE_HEAVY_SORT_CONS: + return pit_value_equal(rt, ha->in.cons.car, hb->in.cons.car) + && pit_value_equal(rt, ha->in.cons.cdr, hb->in.cons.cdr); + case PIT_VALUE_HEAVY_SORT_ARRAY: { + if (ha->in.array.len != hb->in.array.len) return false; + for (i64 i = 0; i < ha->in.array.len; ++i) { + if (!pit_value_equal(rt, ha->in.array.data[i], hb->in.array.data[i])) return false; + } + return true; + } + case PIT_VALUE_HEAVY_SORT_BYTES: { + if (ha->in.bytes.len != hb->in.bytes.len) return false; + for (i64 i = 0; i < ha->in.bytes.len; ++i) { + if (ha->in.bytes.data[i] != hb->in.bytes.data[i]) return false; + } + return true; + } + case PIT_VALUE_HEAVY_SORT_FUNC: + return + pit_value_equal(rt, ha->in.func.env, hb->in.func.env) + && pit_value_equal(rt, ha->in.func.args, hb->in.func.args) + && pit_value_equal(rt, ha->in.func.body, hb->in.func.body); + case PIT_VALUE_HEAVY_SORT_NATIVEFUNC: + return ha->in.nativefunc.f == hb->in.nativefunc.f + && ha->in.nativefunc.data == hb->in.nativefunc.data; + case PIT_VALUE_HEAVY_SORT_NATIVEDATA: + return + pit_value_eq(ha->in.nativedata.tag, hb->in.nativedata.tag) + && ha->in.nativedata.data == hb->in.nativedata.data; + case PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER: + return ha->in.forwarding_pointer == hb->in.forwarding_pointer; + } + } + } + return false; +} diff --git a/src/runtime/value/array.c b/src/runtime/value/array.c new file mode 100644 index 0000000..1af84fd --- /dev/null +++ b/src/runtime/value/array.c @@ -0,0 +1,57 @@ +#include + +bool pit_value_is_array(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_ARRAY); +} + +pit_value pit_value_array_new(pit_runtime *rt, i64 len) { + if (len < 0) { pit_error(rt, "failed to create array of negative size"); return PIT_NIL; } + i64 byte_len = 0; pit_mul(&byte_len, sizeof(pit_value), len); + pit_value *dest = pit_arena_alloc_array(rt->heap, byte_len); + if (!dest) { pit_error(rt, "failed to allocate array"); return PIT_NIL; } + for (i64 i = 0; i < len; ++i) dest[i] = PIT_NIL; + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for array"); return PIT_NIL; } + h->hsort = PIT_VALUE_HEAVY_SORT_ARRAY; + h->in.array.data = dest; + h->in.array.len = len; + return ret; +} +pit_value pit_value_array_from_buf(pit_runtime *rt, pit_value *xs, i64 len) { + pit_value ret = pit_value_array_new(rt, len); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to deref heavy value for array"); return PIT_NIL; } + pit_libc_string_memcpy((u8 *) h->in.array.data, (u8 *) xs, (size_t) len * (size_t) sizeof(pit_value)); + return ret; +} +i64 pit_value_array_len(pit_runtime *rt, pit_value arr) { + if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return -1; } + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, arr)); + if (!h) { pit_error(rt, "bad ref"); return -1; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return -1; } + return h->in.array.len; +} +pit_value pit_value_array_get(pit_runtime *rt, pit_value arr, i64 idx) { + if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return PIT_NIL; } + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, arr)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return PIT_NIL; } + if (idx < 0 || idx >= h->in.array.len) { + pit_error(rt, "array index out of bounds: %d", idx); + return PIT_NIL; + } + return h->in.array.data[idx]; +} +pit_value pit_value_array_set(pit_runtime *rt, pit_value arr, i64 idx, pit_value v) { + if (pit_value_sort(arr) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return PIT_NIL; } + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, arr)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_ARRAY) { pit_error(rt, "not an array"); return PIT_NIL; } + if (idx < 0 || idx >= h->in.array.len) { + pit_error(rt, "array index out of bounds: %d", idx); + return PIT_NIL; + } + h->in.array.data[idx] = v; + return v; +} diff --git a/src/runtime/value/bytes.c b/src/runtime/value/bytes.c new file mode 100644 index 0000000..6a6edb6 --- /dev/null +++ b/src/runtime/value/bytes.c @@ -0,0 +1,47 @@ +#include + +bool pit_value_is_bytes(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_BYTES); +} +pit_value pit_value_bytes_new(pit_runtime *rt, u8 *buf, i64 len) { + u8 *dest = pit_arena_alloc_back(rt->heap, len); + if (!dest) { pit_error(rt, "failed to allocate bytes"); return PIT_NIL; } + pit_libc_string_memcpy(dest, buf, (size_t) len); + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(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->in.bytes.data = dest; + h->in.bytes.len = len; + return ret; +} +pit_value pit_value_bytes_new_cstr(pit_runtime *rt, char *s) { + return pit_value_bytes_new(rt, (u8 *) s, (i64) pit_libc_string_strlen(s)); +} +/* return true if v is a reference to bytes that are the same as those in buf */ +bool pit_value_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len) { + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return false; + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); + if (!h) { pit_error(rt, "bad ref"); return false; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_BYTES) return false; + if (h->in.bytes.len != len) return false; + for (i64 i = 0; i < len; ++i) + if (h->in.bytes.data[i] != buf[i]) { + return false; + } + return true; +} +i64 pit_value_bytes_copy(pit_runtime *rt, pit_value v, u8 *buf, i64 maxlen) { + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { pit_error(rt, "not a ref"); return -1; } + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_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->in.bytes.len ? maxlen : h->in.bytes.len; + for (i64 i = 0; i < len; ++i) { + buf[i] = h->in.bytes.data[i]; + } + return len; +} diff --git a/src/runtime/value/cell.c b/src/runtime/value/cell.c new file mode 100644 index 0000000..34b9226 --- /dev/null +++ b/src/runtime/value/cell.c @@ -0,0 +1,47 @@ +#include + +bool pit_value_is_cell(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_CELL); +} +pit_value pit_value_cell_new(pit_runtime *rt, pit_value v) { + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for cell"); return PIT_NIL; } + h->hsort = PIT_VALUE_HEAVY_SORT_CELL; + h->in.cell = v; + return ret; +} +pit_value pit_value_cell_get(pit_runtime *rt, pit_value cell, pit_value sym) { + if (pit_value_sort(cell) != PIT_VALUE_SORT_REF) { + char buf[256]; + i64 end = pit_dump(rt, buf, sizeof(buf) - 1, sym, false); + buf[end] = 0; + pit_error(rt, "attempted to get unbound variable/function: %s", buf); + return PIT_NIL; + } + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, cell)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_CELL) { + pit_error(rt, "cell value ref does not point to cell"); + return PIT_NIL; + } + return h->in.cell; +} +void pit_value_cell_set(pit_runtime *rt, pit_value cell, pit_value v, pit_value sym) { + if (pit_value_sort(cell) != PIT_VALUE_SORT_REF) { + char buf[256]; + i64 end = pit_dump(rt, buf, sizeof(buf) - 1, sym, false); + buf[end] = 0; + pit_error(rt, "attempted to set unbound variable/function: %s", buf); + return; + } + pit_ref idx = pit_value_as_ref(rt, cell); + if (idx < rt->frozen_values) { pit_error(rt, "attempt to modify frozen cell"); return; } + pit_value_heavy *h = pit_value_ref_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"); + return; + } + h->in.cell = v; +} diff --git a/src/runtime/value/cons.c b/src/runtime/value/cons.c new file mode 100644 index 0000000..0f35631 --- /dev/null +++ b/src/runtime/value/cons.c @@ -0,0 +1,110 @@ +#include + +bool pit_value_is_cons(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_CONS); +} +pit_value pit_value_cons(pit_runtime *rt, pit_value car, pit_value cdr) { + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for cons"); return PIT_NIL; } + h->hsort = PIT_VALUE_HEAVY_SORT_CONS; + h->in.cons.car = car; + h->in.cons.cdr = cdr; + return ret; +} +pit_value pit_value_cons_car(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return PIT_NIL; + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) return PIT_NIL; + return h->in.cons.car; +} +pit_value pit_value_cons_cdr(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) return PIT_NIL; + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_CONS) return PIT_NIL; + return h->in.cons.cdr; +} +void pit_value_cons_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_ref idx = pit_value_as_ref(rt, v); + if (idx < rt->frozen_values) { pit_error(rt, "attempted to modify frozen cons"); return; } + pit_value_heavy *h = pit_value_ref_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->in.cons.car = x; +} +void pit_value_cons_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_ref idx = pit_value_as_ref(rt, v); + if (idx < rt->frozen_values) { pit_error(rt, "attempted to modify frozen cons"); return; } + pit_value_heavy *h = pit_value_ref_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->in.cons.cdr = x; +} + +pit_value pit_value_list(pit_runtime *rt, i64 num, ...) { + pit_value temp[64] = {0}; + pit_value ret = PIT_NIL; + if (num > 64) { pit_error(rt, "failed to create list of size %d\n", num); return PIT_NIL; } + va_list elems; + va_start(elems, num); + for (i64 i = 0; i < num; ++i) { + temp[i] = va_arg(elems, pit_value); + } + va_end(elems); + for (i64 i = 0; i < num; ++i) { + ret = pit_value_cons(rt, temp[num - i - 1], ret); + } + return ret; +} +i64 pit_value_list_len(pit_runtime *rt, pit_value xs) { + i64 ret = 0; + while (xs != PIT_NIL) { + ret += 1; + xs = pit_value_cons_cdr(rt, xs); + } + return ret; +} +pit_value pit_value_list_append(pit_runtime *rt, pit_value xs, pit_value ys) { + pit_value ret = ys; + xs = pit_value_list_reverse(rt, xs); + while (xs != PIT_NIL) { + ret = pit_value_cons(rt, pit_value_cons_car(rt, xs), ret); + xs = pit_value_cons_cdr(rt, xs); + } + return ret; +} +pit_value pit_value_list_reverse(pit_runtime *rt, pit_value xs) { + pit_value ret = PIT_NIL; + while (xs != PIT_NIL) { + ret = pit_value_cons(rt, pit_value_cons_car(rt, xs), ret); + xs = pit_value_cons_cdr(rt, xs); + } + return ret; +} +pit_value pit_value_list_contains_eq(pit_runtime *rt, pit_value needle, pit_value haystack) { + while (haystack != PIT_NIL) { + if (pit_value_eq(needle, pit_value_cons_car(rt, haystack))) return PIT_T; + haystack = pit_value_cons_cdr(rt, haystack); + } + return PIT_NIL; +} +pit_value pit_value_list_contains_equal(pit_runtime *rt, pit_value needle, pit_value haystack) { + while (haystack != PIT_NIL) { + if (pit_value_equal(rt, needle, pit_value_cons_car(rt, haystack))) return PIT_T; + haystack = pit_value_cons_cdr(rt, haystack); + } + return PIT_NIL; +} +pit_value pit_value_list_plist_get(pit_runtime *rt, pit_value k, pit_value vs) { + while (vs != PIT_NIL) { + if (pit_value_eq(k, pit_value_cons_car(rt, vs))) { + return pit_value_cons_car(rt, pit_value_cons_cdr(rt, vs)); + } + vs = pit_value_cons_cdr(rt, vs); + } + return PIT_NIL; +} diff --git a/src/runtime/value/func.c b/src/runtime/value/func.c new file mode 100644 index 0000000..af039eb --- /dev/null +++ b/src/runtime/value/func.c @@ -0,0 +1,177 @@ +#include + +static pit_value free_vars(pit_runtime *rt, pit_value initial_bound, pit_value body) { + i64 expr_stack_reset = rt->expr_stack->next; + pit_value ret = PIT_NIL; + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons(rt, initial_bound, body)) < 0) { + pit_error(rt, "free variable search stack overflow"); + return PIT_NIL; + } + while (rt->expr_stack->next > expr_stack_reset) { + pit_value boundscur, bound, cur; + if (pit_vec_pop(pit_value)(rt->expr_stack, &boundscur) < 0) { + pit_error(rt, "free variable search stack underflow"); + return PIT_NIL; + } + bound = pit_value_cons_car(rt, boundscur); + cur = pit_value_cons_cdr(rt, boundscur); + if (pit_value_is_cons(rt, cur)) { + pit_value fsym = pit_value_cons_car(rt, cur); + bool is_symbol = pit_value_is_symbol(rt, fsym); + pit_value fargs = pit_value_cons_cdr(rt, cur); + if (is_symbol && pit_symtab_symbol_name_match_cstr(rt, fsym, "lambda")) { + pit_value new_bound = pit_value_list_append(rt, pit_value_cons_car(rt, fargs), bound); + fargs = pit_value_cons_cdr(rt, fargs); + while (fargs != PIT_NIL) { + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons(rt, new_bound, pit_value_cons_car(rt, fargs))) < 0) { + pit_error(rt, "free variable search stack overflow"); + return PIT_NIL; + } + fargs = pit_value_cons_cdr(rt, fargs); + } + } else if (is_symbol && pit_symtab_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 (fargs != PIT_NIL) { + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons(rt, bound, pit_value_cons_car(rt, fargs))) < 0) { + pit_error(rt, "free variable search stack overflow"); + return PIT_NIL; + } + fargs = pit_value_cons_cdr(rt, fargs); + } + if (!is_symbol) { + if (pit_vec_push(pit_value)(rt->expr_stack, pit_value_cons(rt, bound, fsym)) < 0) { + pit_error(rt, "free variable search stack overflow"); + return PIT_NIL; + } + } + } + } else if (pit_value_is_symbol(rt, cur)) { + if (pit_value_list_contains_eq(rt, cur, bound) == PIT_NIL) { + ret = pit_value_cons(rt, cur, ret); + } + } + } + rt->expr_stack->next = expr_stack_reset; + return ret; +} + +bool pit_value_is_func(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_FUNC); +} +bool pit_value_is_nativefunc(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_NATIVEFUNC); +} +pit_value pit_value_func_lambda(pit_runtime *rt, pit_value args, pit_value body) { + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for lambda"); return PIT_NIL; } + pit_value expanded = pit_macroexpand(rt, pit_value_cons(rt, pit_symtab_intern_cstr(rt, "progn"), body)); + pit_value freevars = free_vars(rt, args, expanded); + pit_value env = PIT_NIL; + while (freevars != PIT_NIL) { + pit_value sym = pit_value_cons_car(rt, freevars); + pit_value cell = pit_symtab_get_value_cell(rt, sym); + env = pit_value_cons(rt, pit_value_cons(rt, sym, cell), env); + freevars = pit_value_cons_cdr(rt, freevars); + } + h->hsort = PIT_VALUE_HEAVY_SORT_FUNC; + pit_value arg_cells = PIT_NIL; + pit_value arg_rest_nm = PIT_NIL; + pit_value separator = pit_symtab_intern_cstr(rt, "&"); + while (args != PIT_NIL) { + pit_value nm = pit_value_cons_car(rt, args); + if (pit_value_eq(nm, separator)) { + pit_value next_nm = pit_value_cons_car(rt, pit_value_cons_cdr(rt, args)); + if (next_nm == PIT_NIL) { pit_error(rt, "invalid & in lambda list"); return PIT_NIL; } + arg_rest_nm = next_nm; + arg_cells = pit_value_cons(rt, next_nm, arg_cells); + break; + } else { + arg_cells = pit_value_cons(rt, nm, arg_cells); + args = pit_value_cons_cdr(rt, args); + } + } + arg_cells = pit_value_list_reverse(rt, arg_cells); + h->in.func.args = arg_cells; + h->in.func.arg_rest_nm = arg_rest_nm; + h->in.func.env = env; + h->in.func.body = expanded; + return ret; +} +pit_value pit_value_nativefunc_new_with_data(pit_runtime *rt, pit_nativefunc f, void *data) { + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for nativefunc"); return PIT_NIL; } + h->hsort = PIT_VALUE_HEAVY_SORT_NATIVEFUNC; + h->in.nativefunc.f = f; + h->in.nativefunc.data = data; + return ret; +} +pit_value pit_value_nativefunc_new(pit_runtime *rt, pit_nativefunc f) { + return pit_value_nativefunc_new_with_data(rt, f, NULL); +} +pit_value pit_value_apply(pit_runtime *rt, pit_value f, pit_value args) { + char buf[256] = {0}; + if (pit_value_is_symbol(rt, f)) { + f = pit_symtab_fget(rt, f); + } + /* if f is not a symbol, assume it is a func or nativefunc + most commonly, this happens when you funcall a variable + with a function in the value cell, e.g. passing a lambda to a function */ + switch (pit_value_sort(f)) { + case PIT_VALUE_SORT_REF: { + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, f)); + if (!h) { pit_error(rt, "bad ref"); return PIT_NIL; } + if (h->hsort == PIT_VALUE_HEAVY_SORT_FUNC) { + /* calling a Lisp function is simple! */ + pit_value bound = PIT_NIL; + pit_value env = h->in.func.env; + while (env != PIT_NIL) { /* first, bind all entries in the closure */ + pit_value b = pit_value_cons_car(rt, env); + pit_value nm = pit_value_cons_car(rt, b); + pit_symtab_bind(rt, nm, pit_value_cons_cdr(rt, b)); + bound = pit_value_cons(rt, nm, bound); + env = pit_value_cons_cdr(rt, env); + } + pit_value anames = h->in.func.args; + while (anames != PIT_NIL) { /* bind all argument names to their values */ + pit_value nm = pit_value_cons_car(rt, anames); + pit_value cell = pit_value_cell_new(rt, PIT_NIL); + if (h->in.func.arg_rest_nm != PIT_NIL && pit_value_eq(nm, h->in.func.arg_rest_nm)) { + pit_value_cell_set(rt, cell, args, nm); + pit_symtab_bind(rt, nm, cell); + break; + } else { + pit_value_cell_set(rt, cell, pit_value_cons_car(rt, args), nm); + pit_symtab_bind(rt, nm, cell); + } + bound = pit_value_cons(rt, nm, bound); + args = pit_value_cons_cdr(rt, args); + anames = pit_value_cons_cdr(rt, anames); + } + pit_value ret = pit_eval(rt, h->in.func.body); /* evaluate the body */ + while (bound != PIT_NIL) { /* unbind everything we bound earlier, in reverse */ + pit_symtab_unbind(rt, pit_value_cons_car(rt, bound)); + bound = pit_value_cons_cdr(rt, bound); + } + return ret; + } else if (h->hsort == PIT_VALUE_HEAVY_SORT_NATIVEFUNC) { + /* calling native functions is even simpler */ + return h->in.nativefunc.f(rt, args, h->in.nativefunc.data); + } else { + i64 end = pit_dump(rt, buf, sizeof(buf) - 1, f, true); + buf[end] = 0; + pit_error(rt, "attempted to apply non-function ref: %s", buf); + return PIT_NIL; + } + } + default: { + i64 end = pit_dump(rt, buf, sizeof(buf) - 1, f, true); + buf[end] = 0; + pit_error(rt, "attempted to apply non-function value: %s", buf); + return PIT_NIL; + } + } +} diff --git a/src/runtime/value/nativedata.c b/src/runtime/value/nativedata.c new file mode 100644 index 0000000..5c6fe2b --- /dev/null +++ b/src/runtime/value/nativedata.c @@ -0,0 +1,36 @@ +#include + +bool pit_value_is_nativedata(pit_runtime *rt, pit_value a) { + return pit_value_is_ref_heavy_sort(rt, a, PIT_VALUE_HEAVY_SORT_NATIVEDATA); +} +pit_value pit_value_nativedata_new(pit_runtime *rt, pit_value tag, void *d) { + pit_value ret = pit_value_ref_heavy_new(rt); + pit_value_heavy *h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ret)); + if (!h) { pit_error(rt, "failed to create new heavy value for nativedata"); return PIT_NIL; } + h->hsort = PIT_VALUE_HEAVY_SORT_NATIVEDATA; + h->in.nativedata.tag = tag; + h->in.nativedata.data = d; + return ret; +} +void *pit_value_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v) { + pit_value_heavy *h = NULL; + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { + pit_error(rt, "value was not a reference"); + return NULL; + } + h = pit_value_ref_deref(rt, pit_value_as_ref(rt, v)); + if (!h) { pit_error(rt, "bad ref"); return NULL; } + if (h->hsort != PIT_VALUE_HEAVY_SORT_NATIVEDATA) { + pit_error(rt, "invalid use of value as nativedata"); + return NULL; + } + if (!pit_value_eq(h->in.nativedata.tag, tag)) { + pit_error(rt, "native value does not match tag"); + return NULL; + } + if (!h->in.nativedata.data) { + pit_error(rt, "nativedata was already freed"); + return NULL; + } + return h->in.nativedata.data; +} diff --git a/src/runtime/value/small.c b/src/runtime/value/small.c new file mode 100644 index 0000000..f07e405 --- /dev/null +++ b/src/runtime/value/small.c @@ -0,0 +1,96 @@ +#include + +#ifndef PIT_NO_DOUBLE +double pit_value_as_double(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_DOUBLE) { + pit_error(rt, "invalid use of value as double"); + return 0.0; + } + union { double dval; u64 ival; } x; + x.ival = v; + return x.dval; +} +bool pit_value_is_double(pit_runtime *rt, pit_value a) { + (void) rt; + return pit_value_sort(a) == PIT_VALUE_SORT_DOUBLE; +} +pit_value pit_value_double_new(pit_runtime *rt, double d) { + union { double dval; u64 ival; } x; + x.dval = d; + return pit_value_new(rt, PIT_VALUE_SORT_DOUBLE, x.ival); +} +#endif + +i64 pit_value_as_integer(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_INTEGER) { + pit_error(rt, "invalid use of value as integer"); + return -1; + } + u64 lo = pit_value_data(v); + return ((i64) (lo << 15)) >> 15; /* sign-extend low 49 bits */ + +} +bool pit_value_is_integer(pit_runtime *rt, pit_value a) { + (void) rt; + return pit_value_sort(a) == PIT_VALUE_SORT_INTEGER; +} +pit_value pit_value_integer_new(pit_runtime *rt, i64 i) { + return pit_value_new(rt, PIT_VALUE_SORT_INTEGER, 0x1ffffffffffff & (u64) i); +} +pit_value pit_value_bool_new(pit_runtime *rt, bool i) { + (void) rt; + return i ? PIT_T : PIT_NIL; +} + +pit_symbol pit_value_as_symbol(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_SYMBOL) { + pit_error(rt, "invalid use of value as symbol"); + return -1; + } + return (pit_symbol) (pit_value_data(v) & 0xffffffff); +} +bool pit_value_is_symbol(pit_runtime *rt, pit_value a) { + (void) rt; + return pit_value_sort(a) == PIT_VALUE_SORT_SYMBOL; +} +pit_value pit_value_symbol_new(pit_runtime *rt, pit_symbol s) { + return pit_value_new(rt, PIT_VALUE_SORT_SYMBOL, (u64) s); +} + +pit_ref pit_value_as_ref(pit_runtime *rt, pit_value v) { + if (pit_value_sort(v) != PIT_VALUE_SORT_REF) { + pit_error(rt, "invalid use of value as ref"); + return -1; + } + return (pit_ref) (pit_value_data(v) & 0xffffffff); +} +bool pit_value_is_ref(pit_runtime *rt, pit_value a) { + (void) rt; + return pit_value_sort(a) == PIT_VALUE_SORT_REF; +} +pit_value pit_value_ref_new(pit_runtime *rt, pit_ref r) { + return pit_value_new(rt, PIT_VALUE_SORT_REF, (u64) r); +} +pit_value pit_value_ref_heavy_new(pit_runtime *rt) { + pit_arena_index idx = pit_arena_alloc_index(rt->heap); + if (idx < 0) { + pit_error(rt, "failed to allocate space for heavy value"); + return PIT_NIL; + } + return pit_value_ref_new(rt, idx); +} +pit_value_heavy *pit_value_ref_deref(pit_runtime *rt, pit_ref p) { + return pit_arena_get(rt->heap, p); +} +bool pit_value_is_ref_heavy_sort(pit_runtime *rt, pit_value a, enum pit_value_heavy_sort e) { + switch (pit_value_sort(a)) { + case PIT_VALUE_SORT_REF: { + pit_value_heavy *ha = pit_value_ref_deref(rt, pit_value_as_ref(rt, a)); + if (!ha) { pit_error(rt, "bad ref"); return false; } + return ha->hsort == e; + } + default: + break; + } + return false; +} -- cgit v1.2.3