initial very basic support of bigints.
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Fri, 10 Jul 2026 00:18:59 +0000 (17:18 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Fri, 10 Jul 2026 00:18:59 +0000 (17:18 -0700)
(the parsing is very memory inefficient. i will rethink the general
 memory management strategy of this stuff, i promise!)

20 files changed:
Makefile
src/data/data.c
src/data/integer.c
src/data/integer.h
src/data/value.c
src/data/value.h
src/global.h
src/lib/lib.c
src/lib/method.h
src/lib/method/integer.c
src/lib/method/list.c
src/lib/method/string.c
src/lib/module.h
src/lib/module/global.c
src/mem/buffer.h
src/parse/parser.c
src/parse/scanner.c
src/parse/token.h
src/vm/exec.c
src/vm/operations.c

index a52d086..e40a60d 100644 (file)
--- 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
index f0c54a2..013ed30 100644 (file)
@@ -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"
 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();
 }
index 7af907b..ca4c32b 100644 (file)
@@ -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. */
 
 #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;
+  }
+}
index c279545..bf0a2cd 100644 (file)
@@ -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);
index 45298b5..41c8402 100644 (file)
@@ -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!");
   }
 }
 
index f08c2df..804eb13 100644 (file)
@@ -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 })
 #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, // <hashtable_tombstone>
 };
 
@@ -57,6 +61,7 @@ typedef struct hV {
     u64 boolean;
     double float_val;
     sbBuiltinFunc builtin;
+    struct sbLibTable *module;
     u64 data;
   };
 } hV;
index 3963451..4f7c920 100644 (file)
@@ -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 <stdio.h>
index ebfe0a1..edd339f 100644 (file)
@@ -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!");
   }
index e7da22f..36ed223 100644 (file)
@@ -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);
index ea9f8a8..f5e7698 100644 (file)
@@ -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);
 }
index d874be8..0fbc761 100644 (file)
@@ -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);
index 37f03d6..5fc1125 100644 (file)
@@ -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);
 }
index 36bd9d8..e76b073 100644 (file)
@@ -1,3 +1,4 @@
 extern sbLibTable g_global_module;
 
 void sbLib_loadmodule_global();
+void sbLib_loadmodule_math();
index cb5b752..a99645a 100644 (file)
@@ -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));
 }
 
 /* --- */
index cbab2ac..fab97fa 100644 (file)
@@ -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;
index 077bee8..082bdac 100644 (file)
@@ -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);
   }
index bf799b3..5808532 100644 (file)
@@ -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);
             }
         }
     }
index beedd84..7a63b4b 100644 (file)
@@ -102,7 +102,7 @@ typedef struct sbLexToken {
         hString hstr;
         hSymbol symb;
         float fl;
-        int i;
+        hInteger i;
     };
 } sbLexToken;
 
index 7ec60ff..3989faa 100644 (file)
@@ -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);
   }
 }
index 9208eec..8eb5973 100644 (file)
@@ -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);
   }