diff --git a/c/builtins.c b/c/builtins.c index 4001cdc..16453ca 100644 --- a/c/builtins.c +++ b/c/builtins.c @@ -748,7 +748,12 @@ static Value bi_string_ref(Value *a, int n, Env *e) { int idx = (int)as_number_int(a[1]); ULString *s = AS_STRING(a[0]); if (idx < 0 || idx >= (int)s->len) lisp_error("string-ref: index out of range"); - return VAL_CHAR(s->data[idx]); + /* Cast through unsigned char so bytes 0x80..0xFF map to codepoints + * 128..255 rather than sign-extending to negative ints — emit-stream + * stores binary op bytes through (make-string 1 (integer->char b)) + * + (string-ref s 0); without this, char->integer of 0xFF returned + * -1, so u64-le's serialization produced a sentinel-shaped giant. */ + return VAL_CHAR((unsigned char)s->data[idx]); } static Value bi_substring(Value *a, int n, Env *e) { @@ -1595,6 +1600,13 @@ static void pack_u64_slot(char *buf, Value v) { uint64_t u; if (v == VAL_FALSE) { u = 0xFFFFFFFFFFFFFFFFULL; + } else if (IS_BIGNUM(v)) { + /* Bignum sentinel (e.g. *no-slot* = 2^64-1) — extract low 64 + * bits of magnitude. Python tier passes the literal big-int so + * cross-tier emit-stream code stays unchanged. */ + Bignum *b = AS_BIGNUM(v); + u = b->n_limbs > 0 ? b->limbs[0] : 0; + if (b->sign < 0) u = ~u + 1; } else { u = (uint64_t)as_int(v); }