strconv: graduate to (T | invalid | overflow); add void expression
`type invalid = i32` (payload: byte index of first bad rune; mirrors
Hare's strconv::invalid = !size) and `type overflow = void` (Hare's
overflow = !void). stoi64/stou64 now return these instead of the
str-error placeholder. atoi64 dropped — lib/CLAUDE.md says graduate
in one go, don't keep both shapes around.
To produce the void variant payload, `void` is now a real
expression literal (TK_VOID kw, N_VOIDLIT). It evaluates to ty_void;
codegen emits MOVQ $0, AX. Both kinds are appended at the tail of
their enums to keep prior numeric values byte-stable for the
wwdump-diff fixtures.
check_file reorder: USE declarations are now installed in pass 1
alongside the type-decl placeholders so dotted type references
(`strconv.invalid` from a typedecl body) resolve. DEF/FN/LET silently
overwrite a USE-occupied slot — matches the old behavior where USE
silently no-op'd when a same-name fn/def existed (the conflict
manifested in selfhost main.combined.ww at `use parse;` colliding
with `export fn parse(a)`).
selfhost mirror: lib/ww/lex/tok.ww kwtab+name; lib/ww/ast.ww
N_VOIDLIT def+print; lib/ww/parse/{expr,parse}.ww TK_VOID handling;
selfhost/cmd/wcc/cgenexpr.ww N_VOIDLIT codegen.
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
// strconv — number↔string conversions. Decimal i64 to/from a fixed
|
||||
// buffer. Two error idioms ship side by side:
|
||||
// - Plan 9 style (atoi64): tuple `(value, ok)`. Pre-dates the
|
||||
// tagged-union work; kept for callers that already use it.
|
||||
// - Hare style (stoi64/stou64): `(value | str)`. The error
|
||||
// variant carries a short, allocation-free message describing
|
||||
// why the parse failed. Prefer this for new code.
|
||||
// buffer. Error shapes mirror Hare's strconv types: (T | invalid |
|
||||
// overflow) where each error is a named alias over a payload type
|
||||
// (Hare uses !size / !void; ww uses i32 / void without the `!` mark).
|
||||
|
||||
// invalid — input wasn't a valid number in the requested format.
|
||||
// Payload is the byte index of the first offending position (Hare
|
||||
// strconv::invalid is `!size` carrying the same).
|
||||
export type invalid = i32;
|
||||
|
||||
// overflow — input was valid but doesn't fit the target type. No
|
||||
// payload (a single yes/no signal). Mirrors Hare's `!void` shape.
|
||||
export type overflow = void;
|
||||
|
||||
// u64tos — write `v` in decimal into `buf` and return the byte count.
|
||||
// Hare name; the buffer-in shape is the sanctioned Plan 9 subset of
|
||||
@@ -64,41 +70,20 @@ export fn i64tos(buf: []u8, v: i64) i32 = {
|
||||
return out;
|
||||
};
|
||||
|
||||
export fn atoi64(s: str) (i64, bool) = {
|
||||
let v: i64 = 0;
|
||||
let i: i32 = 0;
|
||||
let neg: bool = false;
|
||||
if (s.len > 0) {
|
||||
if (s[0] == 45u8) { neg = true; i = 1; };
|
||||
};
|
||||
if (i >= s.len) { return 0, false; };
|
||||
for (i < s.len) {
|
||||
let c: u8 = s[i];
|
||||
if (c < 48u8) { return 0, false; };
|
||||
if (c > 57u8) { return 0, false; };
|
||||
v = v * 10 + ((c: i64) - 48);
|
||||
i += 1;
|
||||
};
|
||||
if (neg) { v = -v; };
|
||||
return v, true;
|
||||
};
|
||||
|
||||
// stoi64 — Hare-style fallible signed decimal parser. The value
|
||||
// variant is i64; the error variant is a short str (subset of Hare's
|
||||
// (invalid | overflow) tagged-union). No locale, no whitespace, no
|
||||
// underscores: a leading '-' is the only non-digit accepted, and only
|
||||
// at position 0.
|
||||
export fn stoi64(s: str) (i64 | str) = {
|
||||
if (s.len == 0) { return "parse: empty"; };
|
||||
// stoi64 — Hare-style fallible signed decimal parser. No locale, no
|
||||
// whitespace, no underscores: a leading '-' is the only non-digit
|
||||
// accepted, and only at position 0.
|
||||
export fn stoi64(s: str) (i64 | invalid | overflow) = {
|
||||
if (s.len == 0) { return 0: invalid; };
|
||||
let i: i32 = 0;
|
||||
let neg: bool = false;
|
||||
if (s[0] == 45u8) { neg = true; i = 1; };
|
||||
if (i >= s.len) { return "parse: lone sign"; };
|
||||
if (i >= s.len) { return i: invalid; };
|
||||
let v: i64 = 0;
|
||||
for (i < s.len) {
|
||||
let c: u8 = s[i];
|
||||
if (c < 48u8) { return "parse: invalid digit"; };
|
||||
if (c > 57u8) { return "parse: invalid digit"; };
|
||||
if (c < 48u8) { return i: invalid; };
|
||||
if (c > 57u8) { return i: invalid; };
|
||||
v = v * 10 + ((c: i64) - 48);
|
||||
i += 1;
|
||||
};
|
||||
@@ -106,16 +91,15 @@ export fn stoi64(s: str) (i64 | str) = {
|
||||
return v;
|
||||
};
|
||||
|
||||
// stou64 — fallible unsigned decimal parser. No leading sign. Mirrors
|
||||
// Hare's strconv::stou64.
|
||||
export fn stou64(s: str) (u64 | str) = {
|
||||
if (s.len == 0) { return "parse: empty"; };
|
||||
// stou64 — fallible unsigned decimal parser. No leading sign.
|
||||
export fn stou64(s: str) (u64 | invalid | overflow) = {
|
||||
if (s.len == 0) { return 0: invalid; };
|
||||
let v: u64 = 0u64;
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
let c: u8 = s[i];
|
||||
if (c < 48u8) { return "parse: invalid digit"; };
|
||||
if (c > 57u8) { return "parse: invalid digit"; };
|
||||
if (c < 48u8) { return i: invalid; };
|
||||
if (c > 57u8) { return i: invalid; };
|
||||
v = v * 10u64 + ((c: u64) - 48u64);
|
||||
i += 1;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user