From f5dd8de68e70d6948005aa8bdcde1a9c80a6c0ea Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Tue, 23 Sep 2025 04:30:25 -0400 Subject: Add let --- src/library.c | 92 ++++++++++++++++++++++++++++++++ src/library.h | 8 +++ src/main.c | 34 ------------ src/parser.c | 17 +++--- src/runtime.c | 165 ++++++++++++++++++++++++++++++++++++++++++---------------- src/runtime.h | 60 ++++++++++++++++++--- 6 files changed, 284 insertions(+), 92 deletions(-) create mode 100644 src/library.c create mode 100644 src/library.h (limited to 'src') diff --git a/src/library.c b/src/library.c new file mode 100644 index 0000000..64ed071 --- /dev/null +++ b/src/library.c @@ -0,0 +1,92 @@ +#include "runtime.h" + +static pit_value impl_sf_quote(pit_runtime *rt, pit_value args) { + pit_runtime_eval_program_push(rt, rt->program, (pit_runtime_eval_program_entry) { + .sort = EVAL_PROGRAM_ENTRY_LITERAL, + .literal = pit_car(rt, args) + }); + return PIT_NIL; +} + +static pit_value impl_sf_if(pit_runtime *rt, pit_value args) { + pit_value c = pit_car(rt, args); + if (pit_eval(rt, c) != PIT_NIL) { + pit_values_push(rt, rt->expr_stack, pit_car(rt, pit_cdr(rt, args))); + } else { + pit_values_push(rt, rt->expr_stack, pit_car(rt, pit_cdr(rt, pit_cdr(rt, args)))); + } + return PIT_NIL; +} + +static pit_value impl_sf_progn(pit_runtime *rt, pit_value args) { + 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); + } + pit_runtime_eval_program_push(rt, rt->program, (pit_runtime_eval_program_entry) { + .sort = EVAL_PROGRAM_ENTRY_LITERAL, + .bind = final, + }); + return PIT_NIL; +} + +static pit_value impl_sf_let(pit_runtime *rt, pit_value args) { + pit_value binds = pit_car(rt, args); + pit_value unbinds = PIT_NIL; + 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)); + pit_value v = pit_eval(rt, expr); + pit_bind(rt, sym, v); + binds = pit_cdr(rt, binds); + unbinds = pit_cons(rt, bind, unbinds); + } + impl_sf_progn(rt, pit_cdr(rt, args)); + while (unbinds != PIT_NIL) { + pit_value unbind = pit_car(rt, unbinds); + pit_value sym = pit_car(rt, unbind); + pit_unbind(rt, sym); + unbinds = pit_cdr(rt, unbinds); + } + return PIT_NIL; +} + +static pit_value impl_set(pit_runtime *rt, pit_value args) { + pit_value sym = pit_car(rt, args); + pit_value v = pit_car(rt, pit_cdr(rt, args)); + pit_set(rt, sym, v); + return v; +} + +static pit_value impl_print(pit_runtime *rt, pit_value args) { + pit_value x = pit_car(rt, args); + pit_trace(rt, x); + return x; +} + +static pit_value impl_add(pit_runtime *rt, pit_value args) { + 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_integer_new(rt, x + y); +} + +static pit_value impl_sub(pit_runtime *rt, pit_value args) { + 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_integer_new(rt, x - y); +} + +void pit_install_library_essential(pit_runtime *rt) { + 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, "progn"), pit_nativefunc_new(rt, impl_sf_progn)); + pit_sfset(rt, pit_intern_cstr(rt, "let"), pit_nativefunc_new(rt, impl_sf_let)); + + pit_fset(rt, pit_intern_cstr(rt, "print"), pit_nativefunc_new(rt, impl_print)); + pit_fset(rt, pit_intern_cstr(rt, "set"), pit_nativefunc_new(rt, impl_set)); + pit_fset(rt, pit_intern_cstr(rt, "+"), pit_nativefunc_new(rt, impl_add)); + pit_fset(rt, pit_intern_cstr(rt, "-"), pit_nativefunc_new(rt, impl_sub)); +} diff --git a/src/library.h b/src/library.h new file mode 100644 index 0000000..a472642 --- /dev/null +++ b/src/library.h @@ -0,0 +1,8 @@ +#ifndef LIBRARY_H +#define LIBRARY_H + +#include "runtime.h" + +void pit_install_library_essential(pit_runtime *rt); + +#endif diff --git a/src/main.c b/src/main.c index c6bd833..215e485 100644 --- a/src/main.c +++ b/src/main.c @@ -5,45 +5,11 @@ #include "parser.h" #include "runtime.h" -pit_value test_print(pit_runtime *rt, pit_value args) { - pit_value x = pit_car(rt, args); - pit_trace(rt, x); - return x; -} - -pit_value test_if(pit_runtime *rt, pit_value args) { - pit_value cform = pit_car(rt, args); - pit_value tform = pit_car(rt, pit_cdr(rt, args)); - pit_value eform = pit_car(rt, pit_cdr(rt, pit_cdr(rt, args))); - pit_value c = pit_eval(rt, cform); - if (c != PIT_NIL) { - return pit_eval(rt, tform); - } else { - return pit_eval(rt, eform); - } -} - -pit_value test_add(pit_runtime *rt, pit_value args) { - 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_integer_new(rt, x + y); -} - -pit_value test_sub(pit_runtime *rt, pit_value args) { - 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_integer_new(rt, x - y); -} - int main(int argc, char **argv) { if (argc < 2) pit_panic("usage: %s FILE", argv[0]); pit_runtime *rt = pit_runtime_new(); pit_check_error_maybe_panic(rt); - pit_fset(rt, pit_intern_cstr(rt, "print"), pit_nativefunc_new(rt, test_print)); - pit_fset(rt, pit_intern_cstr(rt, "+"), pit_nativefunc_new(rt, test_add)); - pit_fset(rt, pit_intern_cstr(rt, "-"), pit_nativefunc_new(rt, test_sub)); - pit_mset(rt, pit_intern_cstr(rt, "if"), pit_nativefunc_new(rt, test_if)); pit_lexer *lex = pit_lex_file(argv[1]); diff --git a/src/parser.c b/src/parser.c index 34472d2..cb75817 100644 --- a/src/parser.c +++ b/src/parser.c @@ -57,17 +57,22 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st) { pit_error(rt, "end-of-file while parsing"); return PIT_NIL; case PIT_LEX_TOKEN_LPAREN: { - i64 arg = 0; i64 args_cap = 32; - pit_value *args = calloc(args_cap, sizeof(pit_value)); + // 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; while (!match(st, PIT_LEX_TOKEN_RPAREN)) { - args[arg++] = pit_parse(rt, st); + pit_value *cell = pit_arena_alloc_bulk(rt->scratch, sizeof(pit_value)); + *cell = pit_parse(rt, st); if (rt->error != PIT_NIL) return PIT_NIL; // if we hit an error, stop! - if (arg >= args_cap) args = realloc(args, (args_cap <<= 1) * sizeof(pit_value)); } pit_value ret = PIT_NIL; - for (int i = 0; i < arg; ++i) { - ret = pit_cons(rt, args[arg - i - 1], ret); + for (i64 i = rt->scratch->next - sizeof(pit_value); i >= scratch_reset; i -= sizeof(pit_value)) { + pit_value *v = pit_arena_idx(rt->scratch, i); + ret = pit_cons(rt, *v, ret); } + rt->scratch->next = scratch_reset; return ret; } case PIT_LEX_TOKEN_QUOTE: diff --git a/src/runtime.c b/src/runtime.c index 57e3335..cf82550 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -7,6 +7,7 @@ #include "utils.h" #include "runtime.h" +#include "library.h" pit_arena *pit_arena_new(i64 capacity, i64 elem_size) { pit_arena *a = malloc(sizeof(pit_arena) + capacity * elem_size); @@ -67,8 +68,14 @@ pit_runtime *pit_runtime_new() { ret->bytes = pit_arena_new(64 * 1024, sizeof(u8)); ret->symtab = pit_arena_new(1024, sizeof(pit_symtab_entry)); ret->symtab_len = 0; + ret->scratch = pit_arena_new(64 * 1024, sizeof(u8)); + ret->expr_stack = pit_values_new(1024); + ret->result_stack = pit_values_new(1024); + ret->program = pit_runtime_eval_program_new(64 * 1024); + ret->saved_bindings = pit_values_new(1024); ret->error = PIT_NIL; - pit_intern_cstr(ret, "nil"); + pit_intern_cstr(ret, "nil"); // nil must be the 0th symbol for PIT_NIL to work + pit_install_library_essential(ret); return ret; } @@ -350,6 +357,7 @@ pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len) { ent->value = PIT_NIL; ent->function = PIT_NIL; ent->is_macro = false; + ent->is_special_form = false; rt->symtab_len += 1; return pit_symbol_new(rt, idx); } @@ -362,6 +370,14 @@ pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym) { pit_symbol s = pit_as_symbol(rt, sym); return pit_arena_idx(rt->symtab, s); } +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, strlen(s)); +} pit_value pit_get(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; } @@ -396,6 +412,33 @@ 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 v) { + pit_symtab_entry *ent = pit_symtab_lookup(rt, sym); + if (!ent) { pit_error(rt, "bad symbol"); return; } + pit_values_push(rt, rt->saved_bindings, ent->value); + ent->value = v; +} +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; + ent->value = pit_values_pop(rt, rt->saved_bindings); + return old; +} pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr) { pit_value ret = pit_heavy_new(rt); @@ -408,7 +451,8 @@ pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr) { } pit_value pit_list(pit_runtime *rt, i64 num, ...) { - pit_value *temp = calloc(num, sizeof(pit_value)); + pit_value temp[64]; + 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) { @@ -462,80 +506,111 @@ pit_value pit_apply(pit_runtime *rt, pit_value f, pit_value args) { } } -struct eval_stack { - i64 top, cap; - pit_value *data; -}; -static struct eval_stack *eval_stack_new() { - struct eval_stack *ret = malloc(sizeof(*ret)); +pit_values *pit_values_new(i64 capacity) { + i64 cap = capacity / sizeof(pit_value); + pit_values *ret = malloc(sizeof(*ret) + cap * sizeof(pit_value)); ret->top = 0; - ret->cap = 32; - ret->data = calloc(ret->cap, sizeof(pit_value)); + ret->cap = cap; return ret; } -static void eval_stack_destroy(struct eval_stack *s) { - if (s) { - if (s->data) free(s->data); - free(s); - } -} -static void eval_stack_push(pit_runtime *rt, struct eval_stack *s, pit_value x) { +void pit_values_push(pit_runtime *rt, pit_values *s, pit_value x) { (void) rt; s->data[s->top++] = x; - if (s->top >= s->cap) s->data = realloc(s->data, (s->cap <<= 1) * sizeof(pit_value)); + if (s->top >= s->cap) { pit_error(rt, "evaluation stack overflow"); } } -static pit_value eval_stack_pop(pit_runtime *rt, struct eval_stack *s) { +pit_value pit_values_pop(pit_runtime *rt, pit_values *s) { if (s->top == 0) { pit_error(rt, "evaluation stack underflow"); return PIT_NIL; } return s->data[--s->top]; } +pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity) { + i64 cap = capacity / sizeof(pit_runtime_eval_program_entry); + pit_runtime_eval_program *ret = malloc(sizeof(*ret) + cap * sizeof(pit_runtime_eval_program_entry)); + ret->top = 0; + ret->cap = cap; + return ret; +} +void pit_runtime_eval_program_push(pit_runtime *rt, pit_runtime_eval_program *s, pit_runtime_eval_program_entry x) { + (void) rt; + s->data[s->top++] = x; + if (s->top >= s->cap) { pit_error(rt, "evaluation program overflow"); } +} + pit_value pit_eval(pit_runtime *rt, pit_value top) { - struct eval_stack *expr_stack = eval_stack_new(); - struct eval_stack *program = eval_stack_new(); - eval_stack_push(rt, expr_stack, top); + i64 expr_stack_reset = rt->expr_stack->top; + i64 result_stack_reset = rt->result_stack->top; + i64 program_reset = rt->program->top; + pit_values_push(rt, rt->expr_stack, top); // first, convert the expression tree into "polish notation" in program - while (expr_stack->top > 0) { - pit_value cur = eval_stack_pop(rt, expr_stack); + while (rt->expr_stack->top > 0) { + pit_value cur = pit_values_pop(rt, rt->expr_stack); if (pit_is_cons(rt, cur)) { // compound expressions: function/macro application special forms pit_value fsym = pit_car(rt, cur); pit_value f = pit_fget(rt, fsym); pit_value args = pit_cdr(rt, cur); - if (pit_is_symbol_macro(rt, fsym)) { + if (pit_is_symbol_special_form(rt, fsym)) { // special forms + // 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 (pit_is_symbol_macro(rt, fsym)) { // macros pit_value res = pit_apply(rt, f, args); - eval_stack_push(rt, expr_stack, res); - } else { + pit_values_push(rt, rt->expr_stack, res); + } else { // normal functions i64 argcount = 0; while (args != PIT_NIL) { - eval_stack_push(rt, expr_stack, pit_car(rt, args)); + pit_values_push(rt, rt->expr_stack, pit_car(rt, args)); args = pit_cdr(rt, args); argcount += 1; } - eval_stack_push(rt, program, pit_cons(rt, f, pit_integer_new(rt, argcount))); + pit_runtime_eval_program_push(rt, rt->program, (pit_runtime_eval_program_entry) { + .sort = EVAL_PROGRAM_ENTRY_APPLY, + .apply.arity = argcount, + .apply.func = f, + }); } } else if (pit_is_symbol(rt, cur)) { // unquoted symbols: variable lookup - eval_stack_push(rt, program, pit_get(rt, cur)); - } else { // other values: used literally - eval_stack_push(rt, program, cur); + pit_runtime_eval_program_push(rt, rt->program, (pit_runtime_eval_program_entry) { + .sort = EVAL_PROGRAM_ENTRY_LITERAL, + .literal = pit_get(rt, cur), + }); + } else { // other expressions evaluate to themselves! + pit_runtime_eval_program_push(rt, rt->program, (pit_runtime_eval_program_entry) { + .sort = EVAL_PROGRAM_ENTRY_LITERAL, + .literal = cur, + }); } } - struct eval_stack *result_stack = eval_stack_new(); // 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 = program->top - 1; idx >= 0; --idx) { - pit_value expr = program->data[idx]; - if (pit_is_cons(rt, expr)) { // this is a function call + for (i64 idx = rt->program->top - 1; idx >= program_reset; --idx) { + pit_runtime_eval_program_entry *ent = &rt->program->data[idx]; + switch (ent->sort) { + case EVAL_PROGRAM_ENTRY_LITERAL: + pit_values_push(rt, rt->result_stack, ent->literal); + break; + case EVAL_PROGRAM_ENTRY_APPLY: pit_value args = PIT_NIL; - for (i64 i = 0; i < pit_as_integer(rt, pit_cdr(rt, expr)); ++i) { - args = pit_cons(rt, eval_stack_pop(rt, result_stack), args); + for (i64 i = 0; i < ent->apply.arity; ++i) { + args = pit_cons(rt, pit_values_pop(rt, rt->result_stack), args); } - eval_stack_push(rt, result_stack, pit_apply(rt, pit_car(rt, expr), args)); - } else { // this is an atom - eval_stack_push(rt, result_stack, expr); + pit_values_push(rt, rt->result_stack, pit_apply(rt, ent->apply.func, args)); + break; + case EVAL_PROGRAM_ENTRY_BIND: + pit_value v = pit_values_pop(rt, rt->result_stack); + pit_bind(rt, ent->bind, v); + break; + case EVAL_PROGRAM_ENTRY_UNBIND: + pit_unbind(rt, ent->unbind); + break; + default: + pit_error(rt, "unknown program entry"); + goto end; } } - pit_value ret = eval_stack_pop(rt, result_stack); - eval_stack_destroy(expr_stack); - eval_stack_destroy(program); - eval_stack_destroy(result_stack); +end: + pit_value ret = pit_values_pop(rt, rt->result_stack); + rt->expr_stack->top = expr_stack_reset; + rt->result_stack->top = result_stack_reset; + rt->program->top = program_reset; return ret; } diff --git a/src/runtime.h b/src/runtime.h index 26ac1c1..2db4ee8 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -4,13 +4,19 @@ #include "types.h" #include "utils.h" +struct pit_runtime; + +// arenas typedef struct { i64 elem_size, capacity, next; u8 data[]; } pit_arena; pit_arena *pit_arena_new(i64 capacity, i64 elem_size); i32 pit_arena_alloc_idx(pit_arena *a); +i32 pit_arena_alloc_bulk_idx(pit_arena *a, i64 num); +void *pit_arena_idx(pit_arena *a, i32 idx); void *pit_arena_alloc(pit_arena *a); +void *pit_arena_alloc_bulk(pit_arena *a, i64 num); // nil is always the symbol with index 0 #define PIT_NIL 0b1111111111110100000000000000000000000000000000000000000000000000 @@ -26,7 +32,14 @@ typedef u64 pit_value; enum pit_value_sort pit_value_sort(pit_value v); u64 pit_value_data(pit_value v); -struct pit_runtime; +typedef struct { + i64 top, cap; + pit_value data[]; +} pit_values; +pit_values *pit_values_new(i64 capacity); +void pit_values_push(struct pit_runtime *rt, pit_values *s, pit_value x); +pit_value pit_values_pop(struct pit_runtime *rt, pit_values *s); + typedef pit_value (*pit_nativefunc)(struct pit_runtime *rt, pit_value args); typedef struct { // "heavy" values, the targets of refs enum pit_value_heavy_sort { @@ -47,16 +60,42 @@ typedef struct { pit_value name; pit_value value; pit_value function; - bool is_macro; + bool is_macro, is_special_form; } pit_symtab_entry; +// "programs"; vectors of "instructions" for a very simple VM used by the evaluator +typedef struct { + enum { + EVAL_PROGRAM_ENTRY_LITERAL, + EVAL_PROGRAM_ENTRY_APPLY, + EVAL_PROGRAM_ENTRY_BIND, + EVAL_PROGRAM_ENTRY_UNBIND, + } sort; + union { + pit_value literal; + struct { i64 arity; pit_value func; } apply; + pit_value bind; // symbol to bind + pit_value unbind; // symbol to unbind + }; +} pit_runtime_eval_program_entry; +typedef struct { + i64 top, cap; + pit_runtime_eval_program_entry data[]; +} pit_runtime_eval_program; +pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity); +void pit_runtime_eval_program_push(struct pit_runtime *rt, pit_runtime_eval_program *s, pit_runtime_eval_program_entry x); + typedef struct pit_runtime { - pit_arena *values; - pit_arena *bytes; - pit_arena *symtab; i64 symtab_len; - pit_value error; + pit_arena *values; // all heavy values - effectively an array of pit_value_heavy + pit_arena *bytes; // all bytestrings (including symbol names) + pit_arena *symtab; i64 symtab_len; // all symbols - effectively an array of pit_symtab_entry + pit_arena *scratch; // temporary arena used during parsing and evaluation + pit_values *saved_bindings; // stack used to save old values of bindings to be restored ("shallow binding") + pit_values *expr_stack; // stack of subexpressions to evaluate during evaluation + pit_values *result_stack; // stack of intermediate values during evaluation + pit_runtime_eval_program *program; // intermediate stack-based program constructed during evaluation + pit_value error; // error value - if this is non-nil, an error has occured! only tracks the first error } pit_runtime; - pit_runtime *pit_runtime_new(); i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v); @@ -101,6 +140,8 @@ bool pit_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len); // working with the symbol table pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len); pit_value pit_intern_cstr(pit_runtime *rt, char *nm); +bool pit_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len); +bool pit_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s); pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym); pit_value pit_get(pit_runtime *rt, pit_value sym); void pit_set(pit_runtime *rt, pit_value sym, pit_value v); @@ -109,6 +150,11 @@ 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 cons cells pit_value pit_cons(pit_runtime *rt, pit_value car, pit_value cdr); -- cgit v1.2.3