From: cassowarii Date: Fri, 26 Jun 2026 05:07:18 +0000 (-0700) Subject: much more value things, symbol table, etc. X-Git-Url: https://www.git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=8341559d68e66fa4941e04c2e1d5035d506fe15a;p=sarabande.git much more value things, symbol table, etc. --- diff --git a/src/data/handle.c b/src/data/handle.c deleted file mode 100644 index 93dd728..0000000 --- a/src/data/handle.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "data/handle.h" - -#include "data/string.h" -#include "data/hashtable.h" - -#define FLAG_NONINTRINSIC (1ULL << 63) - -hV sbV_nil() { - return (hV) {0}; -} - -hV sbV_string(hString str) { - return (hV) { - .type = IT_STRING, - .string = str, - }; -} - -flag sbV_eq(hV *a, hV *b) { - if (a->type != b->type) return FALSE; - if (a->type == ITX_TOMBSTONE || b->type == ITX_TOMBSTONE) return FALSE; - if (a->type == IT_NOTHING || b->type == IT_NOTHING) return FALSE; - - if (a->type == IT_STRING) { - return sbString_eq(a->string, b->string); - } else { - return a == b; - } -} - -void sbV_retain(hV *a) { - /* for some classes (e.g. nil, float), we don't need to retain them at all - * because they are trivially copiable. some classes (integer, string) need - * to sometimes be retained but sometimes not, so we delegate to them to - * figure out if they need to or not. */ - if (a->type == IT_STRING) { - sbString_clone(a->string); - } -} - -void sbV_release(hV *a) { - if (a->type == IT_STRING) { - sbString_release(a->string); - } -} - -/* --- */ - -flag val_is_intrinsic(hV val) { - return (val.type & FLAG_NONINTRINSIC) != 0; -} diff --git a/src/data/hashtable.c b/src/data/hashtable.c index beb1cc3..23a8505 100644 --- a/src/data/hashtable.c +++ b/src/data/hashtable.c @@ -1,7 +1,7 @@ #include "data/hashtable.h" #include "data/string.h" -#include "data/handle.h" +#include "data/value.h" #define HASHES_PER_BLOCK 256 #define INLINE_TABLE_LENGTH 64 diff --git a/src/data/hashtable.h b/src/data/hashtable.h index 56748cd..e523f95 100644 --- a/src/data/hashtable.h +++ b/src/data/hashtable.h @@ -1,6 +1,6 @@ #include "common.h" -#include "data/handle.h" +#include "data/value.h" /* Open-hashing hash table of object handle keys -> object handle values. */ diff --git a/src/data/integer.c b/src/data/integer.c new file mode 100644 index 0000000..37d91b7 --- /dev/null +++ b/src/data/integer.c @@ -0,0 +1,167 @@ +#include "integer.h" + +/* reserve high bit for sign bit. + * second-highest bit marks this as a handle to a bigint, which + * means normally integers have to be less than +/- 2^62. */ +#define FLAG_BIGINT (1LL << 62) + +#define NUM_PER_BLOCK 256 + +sbBuffer g_bigint_blocks = {0}; + +typedef struct bigint { + flag allocated; + hInteger handle; + flag sign_bit; + sbBuffer buf; +} bigint; + +typedef struct intblk { + usize id; + usize used_count; + usize last_index; + bigint entries[NUM_PER_BLOCK]; +} intblk; + +flag is_bigint(hInteger n); +static intblk *alloc_new_block(); +static intblk *find_free_block(); +static intblk *get_block(usize index); +static bigint *find_free_entry(intblk *blk); +static void set_bigint_size(bigint *i, usize new_size); +static bigint *find_int_for_handle(hInteger handle); +static bigint *new_bigint(usize initial_size); + +void sbInteger_sys_init() { + sbBuffer_initialize(&g_bigint_blocks, sizeof(intblk*)); +} + +hInteger sbInteger_new(u64 value) { + if (value >= SARABANDE_INT_MIN && value <= SARABANDE_INT_MAX) { + return value; + } else { + bigint *i = new_bigint(2); + + if (value < 0) { + i->sign_bit = 1; + value *= -1; + } + i->buf.data[0] = (value & 0xFFFFFFFF); + i->buf.data[1] = ((value >> 32) & 0xFFFFFFFF); + + return i->handle; + } +} + +hInteger sbInteger_sum(hInteger a, hInteger b) { + if (!is_bigint(a) && !is_bigint(b)) { + /* if the sum is too big, this will create a bigint. we don't need to + * worry about signed overflow, because non-bigints are limited to + * 62 bits of magnitude, so the sum of two can't be bigger than 2^63 */ + return sbInteger_new(a + b); + } + PANIC("I haven't implemented this yet!"); +} + +hInteger sbInteger_diff(hInteger a, hInteger b) { + if (!is_bigint(a) && !is_bigint(b)) { + /* if the sum is too big, this will create a bigint. we don't need to + * worry about signed overflow, because non-bigints are limited to + * 62 bits of magnitude, so the sum of two can't be bigger than 2^63 */ + return sbInteger_new(a - b); + } + if (is_bigint(a)) { + /* i will use this later */ + bigint *i = find_int_for_handle(a); + (void)i; + } + PANIC("I haven't implemented this yet!"); +} + +hInteger sbInteger_mul(hInteger a, hInteger b) { + if (!is_bigint(a) && !is_bigint(b)) { + if (b < SARABANDE_INT_MAX / a && b > SARABANDE_INT_MIN / a) { + return sbInteger_new(a * b); + } + } + PANIC("I haven't implemented this yet!"); +} + +hInteger sbInteger_floordiv(hInteger a, hInteger b) { + if (!is_bigint(a) && !is_bigint(b)) { + return sbInteger_new(a / b); + } + PANIC("I haven't implemented this yet!"); +} + +/* --- */ + +flag is_bigint(hInteger n) { + return (n & FLAG_BIGINT); +} + +static intblk *alloc_new_block() { + usize nblocks = g_bigint_blocks.size / sizeof(intblk*); + intblk *new_block = calloc(1, sizeof(intblk)); + new_block->id = nblocks; + sbBuffer_append(&g_bigint_blocks, &new_block, sizeof(intblk*)); + return new_block; +} + +static intblk *find_free_block() { + usize nblocks = g_bigint_blocks.size / sizeof(intblk*); + intblk *free_block = NULL; + for (usize i = 0; i < nblocks; i++) { + if (((intblk**)g_bigint_blocks.data)[i]->used_count < NUM_PER_BLOCK) { + free_block = ((intblk**)g_bigint_blocks.data)[i]; + break; + } + } + + if (free_block == NULL) { + free_block = alloc_new_block(); + } + + return free_block; +} + +static intblk *get_block(usize index) { + usize nblocks = g_bigint_blocks.size / sizeof(intblk*); + if (index > nblocks) PANIC("request for a bigint block (#%zu) that does not exist!", index); + return ((intblk**)g_bigint_blocks.data)[index]; +} + +static bigint *find_free_entry(intblk *blk) { + if (blk->used_count >= NUM_PER_BLOCK) PANIC("request for new entry in full intblk!"); + + while (blk->entries[blk->last_index].allocated) { + blk->last_index++; + blk->last_index %= NUM_PER_BLOCK; + } + blk->entries[blk->last_index].allocated = 1; + blk->used_count ++; + + bigint *result = &blk->entries[blk->last_index]; + + result->handle = ((blk->id * NUM_PER_BLOCK + blk->last_index) | FLAG_BIGINT); + + return result; +} + +static void set_bigint_size(bigint *i, usize new_size) { + sbBuffer_set_size(&i->buf, new_size * sizeof(u32)); +} + +static bigint *find_int_for_handle(hInteger handle) { + hInteger h = handle & ~FLAG_BIGINT; + intblk *block = get_block(h / NUM_PER_BLOCK); + return &block->entries[h % NUM_PER_BLOCK]; +} + +static bigint *new_bigint(usize initial_size) { + bigint *i = find_free_entry(find_free_block()); + set_bigint_size(i, initial_size); + return i; +} + + diff --git a/src/data/integer.h b/src/data/integer.h new file mode 100644 index 0000000..a0a6d15 --- /dev/null +++ b/src/data/integer.h @@ -0,0 +1,18 @@ +#include "common.h" + +#include "data/value.h" + +#define SARABANDE_INT_MAX ((1LL << 62) - 1) +#define SARABANDE_INT_MIN (-(1LL << 62) + 1) + +void sbInteger_sys_init(); + +hInteger sbInteger_new(u64 value); + +hInteger sbInteger_sum(hInteger a, hInteger b); + +hInteger sbInteger_diff(hInteger a, hInteger b); + +hInteger sbInteger_mul(hInteger a, hInteger b); + +hInteger sbInteger_floordiv(hInteger a, hInteger b); diff --git a/src/data/string.h b/src/data/string.h index 5f916c9..2406c2c 100644 --- a/src/data/string.h +++ b/src/data/string.h @@ -2,7 +2,7 @@ #define OBJSL(value) (sbString_new(value, sizeof(value) - 1)) -#include "data/handle.h" +#include "data/value.h" /* create hString: * diff --git a/src/data/symbol.h b/src/data/symbol.h index d400e07..091b66e 100644 --- a/src/data/symbol.h +++ b/src/data/symbol.h @@ -1,6 +1,6 @@ #include "common.h" -#include "handle.h" +#include "data/value.h" void sbSymbol_sys_init(); diff --git a/src/data/value.c b/src/data/value.c new file mode 100644 index 0000000..1475de6 --- /dev/null +++ b/src/data/value.c @@ -0,0 +1,104 @@ +#include "data/value.h" + +#include "data/string.h" +#include "data/hashtable.h" + +#define FLAG_NONINTRINSIC (1ULL << 63) + +hV sbV_nil() { + return (hV) {0}; +} + +hV sbV_boolean(flag value) { + return (hV) { + .type = IT_BOOLEAN, + .boolean = (value == 0) ? 0 : 1, + }; +} + +hV sbV_string(hString str) { + return (hV) { + .type = IT_STRING, + .string = str, + }; +} + +hV sbV_symbol(hSymbol sym) { + return (hV) { + .type = IT_SYMBOL, + .symbol = sym, + }; +} + +hV sbV_float(double fl) { + return (hV) { + .type = IT_FLOAT, + .float_val = fl, + }; +} + +hV sbV_hash(hHash hash) { + return (hV) { + .type = IT_HASH, + .hash = hash, + }; +} + +hV sbV_int(hInteger i) { + return (hV) { + .type = IT_INTEGER, + .integer = i, + }; +} + +flag sbV_eq(hV *a, hV *b) { + if (a->type != b->type) return FALSE; + if (a->type == ITX_TOMBSTONE || b->type == ITX_TOMBSTONE) return FALSE; + if (a->type == IT_NOTHING || b->type == IT_NOTHING) return FALSE; + + switch (a->type) { + case IT_NIL: + /* if a and b share a type, and it's nil, they must be equal */ + return TRUE; + case IT_BOOLEAN: + /* for booleans, they are equal if both zero or neither zero */ + return (a->boolean == 0 && b->boolean == 0) || (a->boolean != 0 && b->boolean != 0); + case IT_SYMBOL: + /* symbols are deduplicated so just compare pointers */ + return a->symbol == b->symbol; + case IT_FLOAT: + /* floats are just comparable as 64 bit values by cursed float-logic */ + return a->float_val == b->float_val; + case IT_STRING: + /* strings can be compared for equality character by character */ + return sbString_eq(a->string, b->string); + case IT_HASH: + /* hashes should (but currently don't) check that they are the same by value. + * right now, we'll just see if they point to the same hash ("is"). */ + return a->hash == b->hash; + default: + return a == b; + } +} + +void sbV_retain(hV *a) { + /* for some classes (e.g. nil, float), we don't need to retain them at all + * because they are trivially copiable. some classes (integer, string) need + * to sometimes be retained but sometimes not, so we delegate to them to + * figure out if they need to or not. */ + if (a->type == IT_STRING) { + sbString_clone(a->string); + } +} + +void sbV_release(hV *a) { + if (a->type == IT_STRING) { + sbString_release(a->string); + } +} + +/* --- */ + +flag val_is_intrinsic(hV val) { + return (val.type & FLAG_NONINTRINSIC) != 0; +} diff --git a/src/data/handle.h b/src/data/value.h similarity index 80% rename from src/data/handle.h rename to src/data/value.h index 8886c41..746637f 100644 --- a/src/data/handle.h +++ b/src/data/value.h @@ -6,8 +6,9 @@ typedef u64 hHash; typedef u64 hString; typedef u64 hSymbol; +typedef i64 hInteger; -typedef enum intrinsic_type { +enum intrinsic_type { IT_NOTHING, // sentinel for "no value here" IT_NIL, // nil ("there is a value here, but it's nil") IT_BOOLEAN, // true / false @@ -20,9 +21,8 @@ typedef enum intrinsic_type { IT_LIST, // list [1, 3, 5, 7] IT_HASH, // hash {a: 1, b: 2} IT_FUNCTION, // function => a, b { a + b } - N_INTRINSIC_TYPES, ITX_TOMBSTONE, // -} intrinsic_type; +}; typedef struct hV { u64 type; @@ -30,11 +30,18 @@ typedef struct hV { hString string; hSymbol symbol; hHash hash; + hInteger integer; + u64 boolean; + double float_val; }; } hV; hV sbV_nil(); hV sbV_string(hString str); +hV sbV_symbol(hSymbol sym); +hV sbV_float(double fl); +hV sbV_hash(hHash hash); +hV sbV_int(hInteger i); flag sbV_eq(hV *a, hV *b); diff --git a/src/mem/arena.c b/src/mem/arena.c index d62e236..fec89a3 100644 --- a/src/mem/arena.c +++ b/src/mem/arena.c @@ -69,7 +69,7 @@ void sbArena_reset(hArena arena) { arena->current = arena->first; } -void sbArena_destroy(hArena arena) { +void sbArena_deinitialize(hArena arena) { struct block *blk = arena->first; struct block *blk_next = arena->first->next; do { diff --git a/src/mem/arena.h b/src/mem/arena.h index 270b15a..e597de7 100644 --- a/src/mem/arena.h +++ b/src/mem/arena.h @@ -21,4 +21,4 @@ void *sbArena_alloc(hArena arena, usize size); void sbArena_reset(hArena arena); -void sbArena_destroy(hArena arena); +void sbArena_deinitialize(hArena arena); diff --git a/src/parse/token.h b/src/parse/token.h index 4f3b94d..24e2c42 100644 --- a/src/parse/token.h +++ b/src/parse/token.h @@ -3,7 +3,7 @@ #include "common.h" -#include "data/handle.h" +#include "data/value.h" typedef enum sbTokenType { T_NULL = 0,