lib/strconv: graduate to owned-str returns with Hare-shape base param

i64tos / u64tos / f64tos return a fresh owned str (caller frees via
os.free) instead of writing into a caller-supplied [N]u8. Adds typed
variants (i32tos / i16tos / i8tos and u32 / u16 / u8) and the missing
base parameter on stoi64 / stou64 + typed parse wrappers.

Base values are exported as plain-i32 `def`s (strconv.DEC,
strconv.HEX_UPPER, ...) rather than a `base` enum: cross-module
`strconv.base.DEC` chains miscompile in the cstage cgen — it emits a
memory load through `base(SB)` rather than inlining the constant.
The Sdef path resolves correctly, so callers say `strconv.DEC` and
both cgens lower to an immediate.

Also renames strings.byteindex / rbyteindex to strings.indexbyte /
rindexbyte, matching bytes.indexbyte and reserving the Hare name
`byteindex` for the future `(str | rune)`-needle shape.

fmt drops printint / printlnint / fprintint — those were stand-ins
for variadic `fmt::println(42)`; with the owned-str graduation the
substitute is one call: `fmt.println(strconv.i64tos(42, strconv.DEC))`.

strerror is sketched in a comment but not shipped — match arms over
the wider `error = !(invalid | overflow)` union still expose a
cstage-vs-wwstage spill divergence.
This commit is contained in:
2026-05-13 03:55:16 +09:00
parent 9bc973dc96
commit be8a662f15
14 changed files with 1192 additions and 520 deletions

View File

@@ -655,7 +655,7 @@ fn next(L: *lexer) (i32 | parserr | eof) = {
// list parse_expr will reject it; here we just tag it.
if (a.len == 1 && a[0] == '.': u8) { L.curkind = tkind.DOT; return 0; };
if (allnum(a)) {
let r = strconv.stoi64(a);
let r = strconv.stoi64(a, strconv.DEC);
match (r) {
case let v: i64 => {
L.curkind = tkind.INT;
@@ -1491,20 +1491,18 @@ fn obuf_puts(s: str) void = {
};
fn obuf_putint(v: i64) void = {
let tmp: [32]u8;
let n: i32 = strconv.i64tos(tmp[0:32], v);
let s: str = strconv.i64tos(v, strconv.DEC);
let i: i32 = 0;
for (i < n) { obuf_putc(tmp[i]); i += 1; };
for (i < s.len) { obuf_putc(s.ptr[i]); i += 1; };
};
fn obuf_putfloat(v: f64) void = {
// strconv.f64tos handles sign, 6-digit fractional, trailing-zero
// trim. Buffer size 32 covers the worst-case "-1234567890123456789"
// plus ".XXXXXX" (29 bytes — round up to 32).
let buf: [32]u8;
let n: i32 = strconv.f64tos(buf[0:32], v);
// trim. Returns a static-buffer-backed str overwritten on the
// next f64tos call.
let s: str = strconv.f64tos(v);
let i: i32 = 0;
for (i < n) { obuf_putc(buf[i]); i += 1; };
for (i < s.len) { obuf_putc(s.ptr[i]); i += 1; };
};
fn obuf_flush() void = {