From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Fri, 10 Jul 2026 00:18:59 +0000 (-0700) Subject: initial very basic support of bigints. X-Git-Url: https://www.git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=3d5ce9efb8e1495922778303cda9874fa8f6e7da;p=sarabande.git initial very basic support of bigints. (the parsing is very memory inefficient. i will rethink the general memory management strategy of this stuff, i promise!) --- diff --git a/Makefile b/Makefile index a52d086..e40a60d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-Wall -g -Og -DDEBUG -fsanitize=undefined #CFLAGS=-Wall -O3 -flto -LIBS= +LIBS=-lm SRC := src OBJ := obj diff --git a/src/data/data.c b/src/data/data.c index f0c54a2..013ed30 100644 --- a/src/data/data.c +++ b/src/data/data.c @@ -3,6 +3,7 @@ #include "data/string.h" #include "data/hashtable.h" #include "data/symbol.h" +#include "data/integer.h" #include "data/list.h" #include "data/reference.h" #include "data/closure.h" @@ -12,11 +13,12 @@ extern sbPool g_closure_pool; void data_sys_init() { - sbString_sys_init(); sbHash_sys_init(); + sbSymbol_sys_init(); + sbString_sys_init(); sbRef_sys_init(); + sbInteger_sys_init(); sbClosure_sys_init(); - sbSymbol_sys_init(); sbList_sys_init(); sbLib_sys_init(); @@ -25,10 +27,11 @@ void data_sys_init() { void data_sys_deinit() { sbLib_sys_deinit(); - sbSymbol_sys_deinit(); sbList_sys_deinit(); sbClosure_sys_deinit(); + sbInteger_sys_deinit(); sbRef_sys_deinit(); - sbHash_sys_deinit(); sbString_sys_deinit(); + sbSymbol_sys_deinit(); + sbHash_sys_deinit(); } diff --git a/src/data/integer.c b/src/data/integer.c index 7af907b..ca4c32b 100644 --- a/src/data/integer.c +++ b/src/data/integer.c @@ -6,6 +6,8 @@ #define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name))) +#define BIGINT_PIECE_MAX 1000000000 + /* 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. */ @@ -13,33 +15,34 @@ #define NUM_PER_BLOCK 256 -sbBuffer g_bigint_blocks = {0}; +typedef u32 Piece; + +/* TODO don't want to have these global i think */ +sbPool g_bigint_pool; typedef struct bigint { - flag allocated; + flag allocated : 1; + flag sign_bit : 1; 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 usize int_size(bigint *bi); +static i8 int_sign(bigint *bi, hInteger h); static void set_bigint_size(bigint *i, usize new_size); -static bigint *find_int_for_handle(hInteger handle); +static bigint *new_bigint_to_fit(bigint *a, bigint *b); +static bigint *find_bigint_for_handle(hInteger handle); static bigint *new_bigint(usize initial_size); +static u64 int_piece(bigint *bi, hInteger h, usize index); +static void trim_bigint(bigint *bi); void sbInteger_sys_init() { - sbBuffer_initialize(&g_bigint_blocks, sizeof(intblk*)); + sbPool_initialize(&g_bigint_pool, sizeof(bigint), NUM_PER_BLOCK); +} + +void sbInteger_sys_deinit() { + //sbPool_deinitialize(&g_bigint_pool); } hInteger sbInteger_new(i64 value) { @@ -61,12 +64,36 @@ hInteger sbInteger_new(i64 value) { 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); + } else { + bigint *biga = find_bigint_for_handle(a); + bigint *bigb = find_bigint_for_handle(b); + if (int_sign(biga, a) < 0 || int_sign(bigb, b) < 0) { + PANIC("I haven't implemented this one yet!"); + } + + bigint *result = new_bigint_to_fit(biga, bigb); + + usize asize = int_size(biga); + usize bsize = int_size(bigb); + u64 carry = 0; + /* + 1 here because we might need to carry into another slice */ + for (int i = 0; i < asize || i < bsize; i++) { + u64 a_piece = int_piece(biga, a, i); + u64 b_piece = int_piece(bigb, b, i); + + u64 digit_sum = (u64)a_piece + (u64)b_piece + carry; + BUFFER_INDEX_SET(result->buf, Piece, i, digit_sum % BIGINT_PIECE_MAX); + carry = 0; + if (digit_sum > BIGINT_PIECE_MAX) { + carry = digit_sum / BIGINT_PIECE_MAX; + } + } + + trim_bigint(result); + + return result->handle; } - PANIC("I haven't implemented this yet!"); } hInteger sbInteger_diff(hInteger a, hInteger b) { @@ -78,12 +105,20 @@ hInteger sbInteger_diff(hInteger a, hInteger b) { } if (is_bigint(a)) { /* i will use this later */ - bigint *i = find_int_for_handle(a); + bigint *i = find_bigint_for_handle(a); (void)i; } PANIC("I haven't implemented this yet!"); } +double sbInteger_as_double(hInteger a) { + if (!is_bigint(a)) { + return (double)a; + } else { + PANIC("agh! i haven't done this!"); + } +} + hInteger sbInteger_mul(hInteger a, hInteger b) { if (!is_bigint(a) && !is_bigint(b)) { flag zero_ok = (a == 0); @@ -93,7 +128,34 @@ hInteger sbInteger_mul(hInteger a, hInteger b) { return sbInteger_new(a * b); } } - PANIC("I haven't implemented this yet!"); + + bigint *biga = find_bigint_for_handle(a); + bigint *bigb = find_bigint_for_handle(b); + + usize asize = int_size(biga); + usize bsize = int_size(bigb); + bigint *result = new_bigint(asize + bsize); + result->sign_bit = int_sign(biga, a) < 0 || int_sign(bigb, b) < 0; + + u64 carry = 0; + for (int bi = 0; bi < bsize; bi++) { + /* + 1 because we might need to carry into an extra piece after both numbers finish */ + for (int ai = 0; ai < asize + 1; ai++) { + u64 a_piece = int_piece(biga, a, ai); + u64 b_piece = int_piece(bigb, b, bi); + + u64 digit_sum = a_piece * b_piece + carry; + BUFFER_INDEX_SET(result->buf, Piece, ai + bi, digit_sum % BIGINT_PIECE_MAX); + carry = 0; + if (digit_sum > BIGINT_PIECE_MAX) { + carry = digit_sum / BIGINT_PIECE_MAX; + } + } + } + + trim_bigint(result); + + return result->handle; } hInteger sbInteger_floordiv(hInteger a, hInteger b) { @@ -103,30 +165,26 @@ hInteger sbInteger_floordiv(hInteger a, hInteger b) { PANIC("I haven't implemented this yet!"); } -void sbInteger_method(hVm vm) { - hV *target = sbVm_pop(vm); - if (target->type != IT_INTEGER) { - CHECK("can't call sbInteger_method on something that isn't an integer"); - } - hV *argc = sbVm_pop(vm); - if (argc->type != IT_INTEGER) { - CHECK("argc of send should be integer!"); - } - - /* subtract 1 because the method name is itself a param */ - usize num_params = argc->integer - 1; - hV *method_name_val = sbVm_peek(vm, num_params); - if (method_name_val->type != IT_SYMBOL) { - /* TODO this may become not true */ - PANIC("method name for list must be symbol!"); - } - - const char *method_name = sbSymbol_name(method_name_val->symbol); - /* TODO: Need a better way of resolving these */ - /* also TODO shouldn't be 'to_string' */ - if (METHOD_IS("to_string")) { +void sbInteger_fprint(FILE *out, hInteger a) { + if (!is_bigint(a)) { + fprintf(out, "%lld", (long long)a); } else { - PANIC("unknown method name for integer"); + bigint *big = find_bigint_for_handle(a); + i8 sgn = int_sign(big, a); + if (sgn == 0) { + fprintf(out, "0"); + return; + } else if (sgn < 0) { + fprintf(out, "-"); + } + isize sz = int_size(big); + for (isize i = sz - 1; i >= 0; i--) { + if (i == sz - 1) { + fprintf(out, "%lld", (long long)int_piece(big, a, i)); + } else { + fprintf(out, "%09lld", (long long)int_piece(big, a, i)); + } + } } } @@ -139,68 +197,89 @@ flag is_bigint(hInteger n) { return (n > 0 && (n & FLAG_BIGINT)) || (n < 0 && !(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 void set_bigint_size(bigint *bi, usize new_size) { + sbBuffer_set_size(&bi->buf, new_size * sizeof(Piece)); } -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 usize int_size(bigint *bi) { + if (bi == NULL) return 1; + return bi->buf.size / sizeof(Piece); } -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; +static i8 int_sign(bigint *bi, hInteger h) { + if (bi == NULL) { + if (h == 0) { + return 0; + } else if (h < 0) { + return -1; + } else { + return 1; + } + } else { + /* scan to see if it is zero, but short circuit if it isn't */ + usize len = int_size(bi); + for (usize i = 0; i < len; i++) { + if (int_piece(bi, h, i) != 0) { + if (bi->sign_bit) { + return -1; + } else { + return 1; + } + } + } + return 0; } - 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 *find_bigint_for_handle(hInteger handle) { + if (!is_bigint(handle)) { + return NULL; + } else { + hInteger h = handle & ~FLAG_BIGINT; + return sbPool_get_entry(&g_bigint_pool, h); + } } static bigint *new_bigint(usize initial_size) { - bigint *i = find_free_entry(find_free_block()); + usize index; + bigint *i = sbPool_alloc(&g_bigint_pool, &index); + sbBuffer_initialize(&i->buf, initial_size * sizeof(u32)); set_bigint_size(i, initial_size); + i->handle = index | FLAG_BIGINT; return i; } +static bigint *new_bigint_to_fit(bigint *a, bigint *b) { + usize a_size = int_size(a); + usize b_size = int_size(b); + return new_bigint(a_size > b_size ? a_size + 1 : b_size + 1); +} +static void trim_bigint(bigint *a) { + if (!a) return; + usize trim_count = 0; + usize sz = int_size(a); + for (isize i = sz - 1; i >= 0; i --) { + if (BUFFER_INDEX(a->buf, Piece, i) != 0) { + break; + } + trim_count ++; + } + if (trim_count > 0) { + set_bigint_size(a, sz - trim_count); + } +} + +static u64 int_piece(bigint *bi, hInteger h, usize index) { + if (!bi) { + if (index == 0) { + return h; + } else { + return 0; + } + } else if (index < int_size(bi)) { + return BUFFER_INDEX(bi->buf, Piece, index); + } else { + return 0; + } +} diff --git a/src/data/integer.h b/src/data/integer.h index c279545..bf0a2cd 100644 --- a/src/data/integer.h +++ b/src/data/integer.h @@ -2,11 +2,13 @@ #include "data/value.h" -#define SARABANDE_INT_MAX ((1LL << 62) - 1) -#define SARABANDE_INT_MIN (-(1LL << 62) + 1) +#define SARABANDE_INT_MAX ((1LL << 31) - 1) +#define SARABANDE_INT_MIN (-(1LL << 31) + 1) void sbInteger_sys_init(); +void sbInteger_sys_deinit(); + hInteger sbInteger_new(i64 value); hInteger sbInteger_sum(hInteger a, hInteger b); @@ -17,4 +19,6 @@ hInteger sbInteger_mul(hInteger a, hInteger b); hInteger sbInteger_floordiv(hInteger a, hInteger b); +void sbInteger_fprint(FILE *out, hInteger a); + void sbInteger_method(hVm vm); diff --git a/src/data/value.c b/src/data/value.c index 45298b5..41c8402 100644 --- a/src/data/value.c +++ b/src/data/value.c @@ -74,7 +74,7 @@ flag sbV_c_eq(const hV *a, const hV *b) { switch (a->type) { case IT_NIL: /* if a and b share a type, and it's nil, they must be equal */ - return TRUE; + 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); @@ -95,7 +95,7 @@ flag sbV_c_eq(const hV *a, const hV *b) { * right now, we'll just see if they point to the same hash ("is"). */ return a->hash == b->hash; default: - return a == b; + PANIC("never implemented == for this case!"); } } diff --git a/src/data/value.h b/src/data/value.h index f08c2df..804eb13 100644 --- a/src/data/value.h +++ b/src/data/value.h @@ -6,6 +6,7 @@ #define FLAG_SQUIGGLY (1ULL << 62) #define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n }) +#define HVFLOAT(f) ((hV) { .type = IT_FLOAT, .float_val = f }) #define HVSTR(s) ((hV) { .type = IT_STRING, .string = s }) #define HVSYM(s) ((hV) { .type = IT_SYMBOL, .symbol = s }) #define HVBOOL(b) ((hV) { .type = IT_BOOLEAN, .boolean = b }) @@ -16,8 +17,10 @@ #define HVFUNC(i, c) ((hV) { .type = i, .closure = c }) #define HVFUNC2(i, c) ((hV) { .type = i | FLAG_SQUIGGLY, .closure = c }) #define HVBUILTIN(b) ((hV) { .type = IT_BUILTIN, .builtin = b }) +#define HVMODULE(m) ((hV) { .type = IT_MODULE, .module = m }) struct sbVm; +struct sbLibTable; typedef u64 hHash; typedef u64 hString; @@ -37,10 +40,11 @@ enum intrinsic_type { IT_INTEGER = -5, // 324892 IT_FLOAT = -6, // 0.0345 IT_DATETIME = -7, // unix timestamp - IT_REF = -8, // pointer \abc + IT_REF = -8, // pointer &abc IT_LIST = -9, // list [1, 3, 5, 7] IT_HASH = -10, // hash {a: 1, b: 2} - IT_BUILTIN = -12, // c function + IT_BUILTIN = -11, // c function + IT_MODULE = -12, // builtin module (math, op...) ITX_TOMBSTONE = -13, // }; @@ -57,6 +61,7 @@ typedef struct hV { u64 boolean; double float_val; sbBuiltinFunc builtin; + struct sbLibTable *module; u64 data; }; } hV; diff --git a/src/global.h b/src/global.h index 3963451..4f7c920 100644 --- a/src/global.h +++ b/src/global.h @@ -7,8 +7,8 @@ #define debug(...) printf(__VA_ARGS__) #else #define PANIC(...) do { fprintf(stderr, "BUGCHECK: " __VA_ARGS__); fprintf(stderr, "\n"); abort(); } while (0) -#define CHECK(...) 0 -#define debug(...) 0 +#define CHECK(...) ((void)0) +#define debug(...) ((void)0) #endif #include diff --git a/src/lib/lib.c b/src/lib/lib.c index ebfe0a1..edd339f 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -7,23 +7,19 @@ #include "lib/module.h" void sbLib_sys_init() { - sbLibTable_initialize(&g_global_module, 16, FALSE); - sbLib_loadmodule_global(); - sbLibTable_initialize(&g_list_methods, 16, TRUE); - sbLibTable_initialize(&g_string_methods, 16, TRUE); - sbLibTable_initialize(&g_integer_methods, 16, TRUE); - sbList_create_methods(); sbString_create_methods(); sbInteger_create_methods(); + sbFloat_create_methods(); } void sbLib_sys_deinit() { sbLibTable_deinitialize(&g_list_methods); sbLibTable_deinitialize(&g_string_methods); sbLibTable_deinitialize(&g_integer_methods); + sbLibTable_deinitialize(&g_float_methods); sbLibTable_deinitialize(&g_global_module); } @@ -53,6 +49,9 @@ void sbLib_resolve_method(hVm vm) { case IT_INTEGER: table_to_use = &g_integer_methods; break; + case IT_FLOAT: + table_to_use = &g_float_methods; + break; default: PANIC("Have not implemented this method table yet!"); } diff --git a/src/lib/method.h b/src/lib/method.h index e7da22f..36ed223 100644 --- a/src/lib/method.h +++ b/src/lib/method.h @@ -1,7 +1,9 @@ extern sbLibTable g_list_methods; extern sbLibTable g_string_methods; extern sbLibTable g_integer_methods; +extern sbLibTable g_float_methods; -void sbList_create_methods(); -void sbString_create_methods(); -void sbInteger_create_methods(); +void sbList_create_methods(void); +void sbString_create_methods(void); +void sbInteger_create_methods(void); +void sbFloat_create_methods(void); diff --git a/src/lib/method/integer.c b/src/lib/method/integer.c index ea9f8a8..f5e7698 100644 --- a/src/lib/method/integer.c +++ b/src/lib/method/integer.c @@ -23,5 +23,6 @@ static void to_string(hVm vm, hV *target, usize num_params) { } void sbInteger_create_methods(void) { + sbLibTable_initialize(&g_integer_methods, 16, TRUE); REGISTER_METHOD(&g_integer_methods, "to_string", to_string); } diff --git a/src/lib/method/list.c b/src/lib/method/list.c index d874be8..0fbc761 100644 --- a/src/lib/method/list.c +++ b/src/lib/method/list.c @@ -121,6 +121,7 @@ static void all_p(hVm vm, hV *list, usize num_params) { } void sbList_create_methods(void) { + sbLibTable_initialize(&g_list_methods, 16, TRUE); REGISTER_METHOD(&g_list_methods, "length", length); REGISTER_METHOD(&g_list_methods, "push", push); REGISTER_METHOD(&g_list_methods, "reverse", reverse); diff --git a/src/lib/method/string.c b/src/lib/method/string.c index 37f03d6..5fc1125 100644 --- a/src/lib/method/string.c +++ b/src/lib/method/string.c @@ -36,6 +36,7 @@ static void to_string(hVm vm, hV *target, usize num_params) { } void sbString_create_methods(void) { + sbLibTable_initialize(&g_string_methods, 16, TRUE); REGISTER_METHOD(&g_string_methods, "split", split); REGISTER_METHOD(&g_string_methods, "to_string", to_string); } diff --git a/src/lib/module.h b/src/lib/module.h index 36bd9d8..e76b073 100644 --- a/src/lib/module.h +++ b/src/lib/module.h @@ -1,3 +1,4 @@ extern sbLibTable g_global_module; void sbLib_loadmodule_global(); +void sbLib_loadmodule_math(); diff --git a/src/lib/module/global.c b/src/lib/module/global.c index cb5b752..a99645a 100644 --- a/src/lib/module/global.c +++ b/src/lib/module/global.c @@ -1,6 +1,7 @@ #include "common.h" #include "lib/table.h" +#include "lib/module.h" #include "data/list.h" #include "data/string.h" #include "data/symbol.h" @@ -11,6 +12,8 @@ sbCFuncStatus println_cfunc(hVm vm, flag init); sbLibTable g_global_module; +extern sbLibTable g_math_module; + static void print(hVm vm, usize argc) { sbVm_push_immediate(vm, &HVINT(argc)); sbVm_call_c_func(vm, print_cfunc); @@ -22,8 +25,12 @@ static void println(hVm vm, usize argc) { } void sbLib_loadmodule_global() { + sbLibTable_initialize(&g_global_module, 16, FALSE); REGISTER_VALUE(&g_global_module, "print", &HVBUILTIN(print)); REGISTER_VALUE(&g_global_module, "println", &HVBUILTIN(println)); + + sbLib_loadmodule_math(); + REGISTER_VALUE(&g_global_module, "math", &HVMODULE(&g_math_module)); } /* --- */ diff --git a/src/mem/buffer.h b/src/mem/buffer.h index cbab2ac..fab97fa 100644 --- a/src/mem/buffer.h +++ b/src/mem/buffer.h @@ -12,6 +12,7 @@ #define BUFFER_ITER_FROM(buf, type, var, from) \ for (type *var = (type*)((buf).data + (from * sizeof(type))); (var) < ((type*)(buf).data + (buf).size / sizeof(type)); var ++) #define BUFFER_INDEX(buf, type, index) (((type*)((buf).data))[index]) +#define BUFFER_INDEX_SET(buf, type, index, value) (((type*)(buf.data))[index] = value) typedef struct sbBuffer { usize size; diff --git a/src/parse/parser.c b/src/parse/parser.c index 077bee8..082bdac 100644 --- a/src/parse/parser.c +++ b/src/parse/parser.c @@ -2,6 +2,7 @@ #include "parse/filereader.h" #include "data/symbol.h" +#include "data/integer.h" static sbAst do_parse(hParser pr); @@ -226,7 +227,9 @@ static void fprint_token(FILE *out, sbLexToken t) { } else if (t.type == T_SYMBOL) { fprintf(out, " ':%s'", sbSymbol_name(t.symb)); } else if (t.type == T_INTEGER) { - fprintf(out, " '%d'", t.i); + fprintf(out, " '"); + sbInteger_fprint(out, t.i); + fprintf(out, "'"); } else if (t.type == T_FLOAT) { fprintf(out, " '%g'", t.fl); } diff --git a/src/parse/scanner.c b/src/parse/scanner.c index bf799b3..5808532 100644 --- a/src/parse/scanner.c +++ b/src/parse/scanner.c @@ -2,6 +2,7 @@ #include "data/string.h" #include "data/symbol.h" +#include "data/integer.h" /* This is like, the pre lexing stage. I mean, this does a lot of the tokenizing, * but it includes stuff like spaces and newlines, too. Think of this as 'normalizing' @@ -202,7 +203,7 @@ static usize read_symbol(hScanner sc) { static void read_integer(hScanner sc, sbLexToken *new_token, flag negative) { new_token->type = T_INTEGER; - i64 intval = 0; + hInteger intval = 0; int base = 10; int num_done = FALSE; char ch = PEEK; @@ -233,9 +234,8 @@ static void read_integer(hScanner sc, sbLexToken *new_token, flag negative) { if (!num_done) { do { - /* TODO: promote to bigint, don't allow overflow */ - intval *= base; - intval += base_digit_value(ch); + intval = sbInteger_mul(intval, base); + intval = sbInteger_sum(intval, base_digit_value(ch)); do { /* skip over underscores in numeric literals */ ch = NEXT; @@ -249,7 +249,7 @@ static void read_integer(hScanner sc, sbLexToken *new_token, flag negative) { } else { new_token->i = intval; if (negative) { - new_token->i *= -1; + new_token->i = sbInteger_mul(intval, -1); } } } diff --git a/src/parse/token.h b/src/parse/token.h index beedd84..7a63b4b 100644 --- a/src/parse/token.h +++ b/src/parse/token.h @@ -102,7 +102,7 @@ typedef struct sbLexToken { hString hstr; hSymbol symb; float fl; - int i; + hInteger i; }; } sbLexToken; diff --git a/src/vm/exec.c b/src/vm/exec.c index 7ec60ff..3989faa 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -98,7 +98,6 @@ void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func) { if (result == CFUNC_END) { /* if c_func didn't call another callback, return from it */ - printf("returning\n"); return_from_block(vm); } } diff --git a/src/vm/operations.c b/src/vm/operations.c index 9208eec..8eb5973 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -5,6 +5,7 @@ #include "data/list.h" #include "data/hashtable.h" #include "data/string.h" +#include "lib/table.h" hV sbV_add(const hV *a, const hV *b) { if (a->type == IT_INTEGER && b->type == IT_INTEGER) { @@ -77,6 +78,17 @@ hV sbV_lt(const hV *a, const hV *b) { } else { return HVBOOL(FALSE); } + } else if (a->type == IT_FLOAT || b->type == IT_FLOAT) { + if (a->type == IT_INTEGER) { + /* integer < float */ + return HVBOOL(a->integer < (double)b->float_val); + } else if (b->type == IT_INTEGER) { + /* float < integer */ + return HVBOOL(a->float_val < (double)b->integer); + } else { + /* two floats */ + return HVBOOL(a->float_val < b->float_val); + } } else { PANIC("todo"); } @@ -89,6 +101,17 @@ hV sbV_le(const hV *a, const hV *b) { } else { return HVBOOL(FALSE); } + } else if (a->type == IT_FLOAT || b->type == IT_FLOAT) { + if (a->type == IT_INTEGER) { + /* integer <= float */ + return HVBOOL(a->integer <= (double)b->float_val); + } else if (b->type == IT_INTEGER) { + /* float <= integer */ + return HVBOOL(a->float_val <= (double)b->integer); + } else { + /* two floats */ + return HVBOOL(a->float_val <= b->float_val); + } } else { PANIC("todo"); } @@ -108,6 +131,12 @@ hV *sbV_index(hV *a, hV *b) { return sbList_index(a->list, b->integer); } else if (a->type == IT_HASH) { return sbHash_find(a->hash, b); + } else if (a->type == IT_MODULE) { + if (b->type == IT_SYMBOL) { + return sbLibTable_find_value(a->module, b->symbol); + } else { + PANIC("module cannot be indexed by non-symbol"); + } } else { PANIC("todo %lld %lld", (long long)a->type, (long long)b->type); }