lib/strconv: stoi/stou/stoz machine-word int parse (strconv-int fold-1 C2)
Add the int/uint/size entry points (ref/hare/strconv/stoi.ha:53, stou.ha:107,113). Hare clamps to types::INT_MIN/MAX, UINT_MAX, SIZE_MAX via stoiminmax/stoumax; ww's int/uint/size are 8B machine words (INT/UINT/SIZE limits == I64/U64 per lib/types/types.ww:30-37), so the clamp is a no-op — the full i64/u64 range parses with no spurious overflow. Documented at-site (the bound consts are package-private, so inlining them would just re-encode I64/U64_MAX). Tests: extend inttest.ww with test_stoi_stou_stoz — value path, sign, overflow pass-through, and the no-clamp fidelity (I64_MAX/U64_MAX parse without overflow) plus hex/bin bases through the shared parseint core. combined.ww regen: w6c + wwdump main.combined.ww.
This commit is contained in:
@@ -274,6 +274,23 @@ export fn stoi8(s: str, b: base) (i8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stoi — parse signed base-b number into an int. Mirrors Hare's
|
||||||
|
// strconv::stoi (ref/hare/strconv/stoi.ha:53), which clamps to
|
||||||
|
// types::INT_MIN/INT_MAX via stoiminmax. ww's int is a machine word
|
||||||
|
// (8B → i64-width, so INT_MIN/INT_MAX == I64_MIN/I64_MAX per
|
||||||
|
// lib/types/types.ww:30-31), so stoi64's result always fits and the
|
||||||
|
// clamp is a no-op — omitted, not inlined (the bound consts are
|
||||||
|
// package-private; see the inline note at mulshift32 in ftos.ww).
|
||||||
|
export fn stoi(s: str, b: base) (int | invalid | overflow) = {
|
||||||
|
let r = stoi64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: i64 => return v: int;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
||||||
let r = stou64(s, b);
|
let r = stou64(s, b);
|
||||||
match (r) {
|
match (r) {
|
||||||
@@ -313,6 +330,34 @@ export fn stou8(s: str, b: base) (u8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stou — parse unsigned base-b number into a uint. Mirrors Hare's
|
||||||
|
// strconv::stou (ref/hare/strconv/stou.ha:107), which clamps to
|
||||||
|
// types::UINT_MAX via stoumax. ww's uint is a machine word (8B →
|
||||||
|
// u64-width, so UINT_MAX == U64_MAX per lib/types/types.ww:33), so
|
||||||
|
// stou64's result always fits and the clamp is a no-op.
|
||||||
|
export fn stou(s: str, b: base) (uint | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: uint;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// stoz — parse unsigned base-b number into a size. Mirrors Hare's
|
||||||
|
// strconv::stoz (ref/hare/strconv/stou.ha:113). ww's size is u64-width
|
||||||
|
// (SIZE_MAX == U64_MAX per lib/types/types.ww:37), so the clamp is a no-op.
|
||||||
|
export fn stoz(s: str, b: base) (size | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: size;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
||||||
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
||||||
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
||||||
|
|||||||
@@ -99,6 +99,51 @@ fn cki32(id: i32, s: str, b: base, want: i32) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn ck_int(id: i32, s: str, b: base, want: int) void = {
|
||||||
|
signalled = id;
|
||||||
|
match (stoi(s, b)) {
|
||||||
|
case let v: int => if (v != want) { fail(); };
|
||||||
|
case let e: invalid => fail();
|
||||||
|
case let e: overflow => fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ck_uint(id: i32, s: str, b: base, want: uint) void = {
|
||||||
|
signalled = id;
|
||||||
|
match (stou(s, b)) {
|
||||||
|
case let v: uint => if (v != want) { fail(); };
|
||||||
|
case let e: invalid => fail();
|
||||||
|
case let e: overflow => fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ck_size(id: i32, s: str, b: base, want: size) void = {
|
||||||
|
signalled = id;
|
||||||
|
match (stoz(s, b)) {
|
||||||
|
case let v: size => if (v != want) { fail(); };
|
||||||
|
case let e: invalid => fail();
|
||||||
|
case let e: overflow => fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ck_int_ovf(id: i32, s: str, b: base) void = {
|
||||||
|
signalled = id;
|
||||||
|
match (stoi(s, b)) {
|
||||||
|
case let v: int => fail();
|
||||||
|
case let e: invalid => fail();
|
||||||
|
case let e: overflow => { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ck_uint_ovf(id: i32, s: str, b: base) void = {
|
||||||
|
signalled = id;
|
||||||
|
match (stou(s, b)) {
|
||||||
|
case let v: uint => fail();
|
||||||
|
case let e: invalid => fail();
|
||||||
|
case let e: overflow => { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// ref/hare/strconv/stoi.ha:56-79.
|
// ref/hare/strconv/stoi.ha:56-79.
|
||||||
@test fn test_stoi64() void = {
|
@test fn test_stoi64() void = {
|
||||||
cki_inv(1, "", base.DEC, 0);
|
cki_inv(1, "", base.DEC, 0);
|
||||||
@@ -164,10 +209,35 @@ fn cki32(id: i32, s: str, b: base, want: i32) void = {
|
|||||||
cku(45, "110101", base.BIN, 53u64); // 0b110101
|
cku(45, "110101", base.BIN, 53u64); // 0b110101
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stoi / stou / stoz — int/uint/size machine-word wrappers
|
||||||
|
// (ref/hare/strconv/stoi.ha:53, stou.ha:107,113). ww's int/uint/size are
|
||||||
|
// 8B, so the iN/uN clamp is a no-op: the full i64/u64 range parses with
|
||||||
|
// no spurious overflow. That no-clamp fidelity is what these check.
|
||||||
|
@test fn test_stoi_stou_stoz() void = {
|
||||||
|
ck_int(50, "0", base.DEC, 0);
|
||||||
|
ck_int(51, "-1", base.DEC, -1);
|
||||||
|
ck_int(52, "9223372036854775807", base.DEC, 9223372036854775807i64: int); // I64_MAX fits int
|
||||||
|
ck_int_ovf(53, "9223372036854775808", base.DEC);
|
||||||
|
ck_int_ovf(54, "-9223372036854775809", base.DEC);
|
||||||
|
|
||||||
|
ck_uint(55, "0", base.DEC, 0u64: uint);
|
||||||
|
ck_uint(56, "18446744073709551615", base.DEC, 18446744073709551615u64: uint); // U64_MAX fits uint
|
||||||
|
ck_uint_ovf(57, "18446744073709551616", base.DEC);
|
||||||
|
ck_uint_ovf(58, "-1", base.DEC);
|
||||||
|
|
||||||
|
ck_size(59, "0", base.DEC, 0u64: size);
|
||||||
|
ck_size(60, "18446744073709551615", base.DEC, 18446744073709551615u64: size); // U64_MAX fits size
|
||||||
|
|
||||||
|
// bases route through the same parseint core.
|
||||||
|
ck_int(61, "-7f", base.HEX, -127i64: int); // -0x7f
|
||||||
|
ck_uint(62, "110101", base.BIN, 53u64: uint); // 0b110101
|
||||||
|
};
|
||||||
|
|
||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
test_stoi64();
|
test_stoi64();
|
||||||
test_stoi64_bases();
|
test_stoi64_bases();
|
||||||
test_stou64();
|
test_stou64();
|
||||||
test_stou64_bases();
|
test_stou64_bases();
|
||||||
|
test_stoi_stou_stoz();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6234,6 +6234,23 @@ export fn stoi8(s: str, b: base) (i8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stoi — parse signed base-b number into an int. Mirrors Hare's
|
||||||
|
// strconv::stoi (ref/hare/strconv/stoi.ha:53), which clamps to
|
||||||
|
// types::INT_MIN/INT_MAX via stoiminmax. ww's int is a machine word
|
||||||
|
// (8B → i64-width, so INT_MIN/INT_MAX == I64_MIN/I64_MAX per
|
||||||
|
// lib/types/types.ww:30-31), so stoi64's result always fits and the
|
||||||
|
// clamp is a no-op — omitted, not inlined (the bound consts are
|
||||||
|
// package-private; see the inline note at mulshift32 in ftos.ww).
|
||||||
|
export fn stoi(s: str, b: base) (int | invalid | overflow) = {
|
||||||
|
let r = stoi64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: i64 => return v: int;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
||||||
let r = stou64(s, b);
|
let r = stou64(s, b);
|
||||||
match (r) {
|
match (r) {
|
||||||
@@ -6273,6 +6290,34 @@ export fn stou8(s: str, b: base) (u8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stou — parse unsigned base-b number into a uint. Mirrors Hare's
|
||||||
|
// strconv::stou (ref/hare/strconv/stou.ha:107), which clamps to
|
||||||
|
// types::UINT_MAX via stoumax. ww's uint is a machine word (8B →
|
||||||
|
// u64-width, so UINT_MAX == U64_MAX per lib/types/types.ww:33), so
|
||||||
|
// stou64's result always fits and the clamp is a no-op.
|
||||||
|
export fn stou(s: str, b: base) (uint | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: uint;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// stoz — parse unsigned base-b number into a size. Mirrors Hare's
|
||||||
|
// strconv::stoz (ref/hare/strconv/stou.ha:113). ww's size is u64-width
|
||||||
|
// (SIZE_MAX == U64_MAX per lib/types/types.ww:37), so the clamp is a no-op.
|
||||||
|
export fn stoz(s: str, b: base) (size | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: size;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
||||||
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
||||||
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
||||||
|
|||||||
@@ -6234,6 +6234,23 @@ export fn stoi8(s: str, b: base) (i8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stoi — parse signed base-b number into an int. Mirrors Hare's
|
||||||
|
// strconv::stoi (ref/hare/strconv/stoi.ha:53), which clamps to
|
||||||
|
// types::INT_MIN/INT_MAX via stoiminmax. ww's int is a machine word
|
||||||
|
// (8B → i64-width, so INT_MIN/INT_MAX == I64_MIN/I64_MAX per
|
||||||
|
// lib/types/types.ww:30-31), so stoi64's result always fits and the
|
||||||
|
// clamp is a no-op — omitted, not inlined (the bound consts are
|
||||||
|
// package-private; see the inline note at mulshift32 in ftos.ww).
|
||||||
|
export fn stoi(s: str, b: base) (int | invalid | overflow) = {
|
||||||
|
let r = stoi64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: i64 => return v: int;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
||||||
let r = stou64(s, b);
|
let r = stou64(s, b);
|
||||||
match (r) {
|
match (r) {
|
||||||
@@ -6273,6 +6290,34 @@ export fn stou8(s: str, b: base) (u8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stou — parse unsigned base-b number into a uint. Mirrors Hare's
|
||||||
|
// strconv::stou (ref/hare/strconv/stou.ha:107), which clamps to
|
||||||
|
// types::UINT_MAX via stoumax. ww's uint is a machine word (8B →
|
||||||
|
// u64-width, so UINT_MAX == U64_MAX per lib/types/types.ww:33), so
|
||||||
|
// stou64's result always fits and the clamp is a no-op.
|
||||||
|
export fn stou(s: str, b: base) (uint | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: uint;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// stoz — parse unsigned base-b number into a size. Mirrors Hare's
|
||||||
|
// strconv::stoz (ref/hare/strconv/stou.ha:113). ww's size is u64-width
|
||||||
|
// (SIZE_MAX == U64_MAX per lib/types/types.ww:37), so the clamp is a no-op.
|
||||||
|
export fn stoz(s: str, b: base) (size | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: size;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
||||||
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
||||||
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
||||||
|
|||||||
@@ -6234,6 +6234,23 @@ export fn stoi8(s: str, b: base) (i8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stoi — parse signed base-b number into an int. Mirrors Hare's
|
||||||
|
// strconv::stoi (ref/hare/strconv/stoi.ha:53), which clamps to
|
||||||
|
// types::INT_MIN/INT_MAX via stoiminmax. ww's int is a machine word
|
||||||
|
// (8B → i64-width, so INT_MIN/INT_MAX == I64_MIN/I64_MAX per
|
||||||
|
// lib/types/types.ww:30-31), so stoi64's result always fits and the
|
||||||
|
// clamp is a no-op — omitted, not inlined (the bound consts are
|
||||||
|
// package-private; see the inline note at mulshift32 in ftos.ww).
|
||||||
|
export fn stoi(s: str, b: base) (int | invalid | overflow) = {
|
||||||
|
let r = stoi64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: i64 => return v: int;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
export fn stou32(s: str, b: base) (u32 | invalid | overflow) = {
|
||||||
let r = stou64(s, b);
|
let r = stou64(s, b);
|
||||||
match (r) {
|
match (r) {
|
||||||
@@ -6273,6 +6290,34 @@ export fn stou8(s: str, b: base) (u8 | invalid | overflow) = {
|
|||||||
return 0: invalid;
|
return 0: invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// stou — parse unsigned base-b number into a uint. Mirrors Hare's
|
||||||
|
// strconv::stou (ref/hare/strconv/stou.ha:107), which clamps to
|
||||||
|
// types::UINT_MAX via stoumax. ww's uint is a machine word (8B →
|
||||||
|
// u64-width, so UINT_MAX == U64_MAX per lib/types/types.ww:33), so
|
||||||
|
// stou64's result always fits and the clamp is a no-op.
|
||||||
|
export fn stou(s: str, b: base) (uint | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: uint;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// stoz — parse unsigned base-b number into a size. Mirrors Hare's
|
||||||
|
// strconv::stoz (ref/hare/strconv/stou.ha:113). ww's size is u64-width
|
||||||
|
// (SIZE_MAX == U64_MAX per lib/types/types.ww:37), so the clamp is a no-op.
|
||||||
|
export fn stoz(s: str, b: base) (size | invalid | overflow) = {
|
||||||
|
let r = stou64(s, b);
|
||||||
|
match (r) {
|
||||||
|
case let v: u64 => return v: size;
|
||||||
|
case let e: invalid => return e;
|
||||||
|
case let e: overflow => return e;
|
||||||
|
};
|
||||||
|
return 0: invalid;
|
||||||
|
};
|
||||||
|
|
||||||
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
// f64tos — graduated to the Ryū shortest-round-trippable implementation
|
||||||
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
// in ftos.ww (strconv #106 fold-5). The old lossy fixed-point version
|
||||||
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
// (6 fractional digits, "huge" fallback ≥9e18, no NaN/Inf) was deleted
|
||||||
|
|||||||
Reference in New Issue
Block a user