lib: retire os.assert/abort shims — assert/abort are builtins (#58 respell)
The flat checker scope makes ANY decl named assert/abort anywhere in the combined unit disable the builtin unit-wide (the #45 shadow shape: scope_lookup_prefer's cross-module fallback finds it). lib carried three colliding @symbol("rt_abort") shims (os, time, strconv/stof) plus the os.assert wrapper, so a bare assert(cond) in ANY program importing os mis-bound os.assert and failed arity — a hard blocker for regex fold-5 (regex.ha:660/670 bring builtin-assert mass). Ruled respell-now per the recurrence test (#45 -> #58). Delete the shims and the os.assert wrapper; every bare abort(msg) caller (regex, strings, utf8, hash, getopt, encoding/*, time, stof) now lands on the builtin, and the ~40 os.assert(c, m) sites respell to the builtin assert(c, m) — restoring the exact Hare spelling the lib ports diverged from (e.g. ref/hare/bytes/tokenize.ha:23). os.assert had no Hare counterpart (Hare's assert is a language builtin); rule-9 wrapper removed. temp/dirs/bufio already use the non-colliding rtabort spelling and keep it. Now-dead 'import os;' lines kept (pre-existing precedent: lib/strconv/strconv.ww carries one); a tree-wide dead-import sweep is a separate concern. regex.ww's if+abort workarounds citing #58 stay for the fold-5 owner to fold back into assert. combined.ww regenerated for all five selfhost tools + the smoke fixture via make.
This commit is contained in:
@@ -378,8 +378,8 @@ export fn intern(s: str) i32 = {
|
||||
if (streqid(s, sym_off[i], sym_len[i])) { return i; };
|
||||
i += 1;
|
||||
};
|
||||
os.assert(sym_count < SYM_CAP, "sym table full");
|
||||
os.assert(sym_blobuse + s.len <= SYM_BLOBSZ, "sym blob full");
|
||||
assert(sym_count < SYM_CAP, "sym table full");
|
||||
assert(sym_blobuse + s.len <= SYM_BLOBSZ, "sym blob full");
|
||||
let off: i32 = sym_blobuse;
|
||||
let j: i32 = 0;
|
||||
for (j < s.len) {
|
||||
|
||||
@@ -145,7 +145,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -160,7 +160,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -228,8 +228,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -245,8 +245,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -400,7 +400,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -438,7 +438,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -507,7 +507,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -531,7 +531,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ fn sumfn(h: *hash.hash, buf: []u8) void = {
|
||||
case let e: io.error => abort("sha256.sum: length write errored");
|
||||
};
|
||||
|
||||
os.assert(st.nx == 0: size, "sha256.sum: residual partial block");
|
||||
assert(st.nx == 0: size, "sha256.sum: residual partial block");
|
||||
|
||||
let stride: i32 = size(u32): i32;
|
||||
let i: i32 = 0;
|
||||
|
||||
@@ -63,7 +63,7 @@ export fn close(h: *hash) void = {
|
||||
// [[sz]] bytes. ref/hare/hash/hash.ha:35-38. ww spells Hare's `h.sum(...)`
|
||||
// as the explicit fn-ptr call `(*h.sum)(...)` (#193).
|
||||
export fn sum(h: *hash, buf: []u8) void = {
|
||||
os.assert((buf.len: size) >= h.sz,
|
||||
assert((buf.len: size) >= h.sz,
|
||||
"hash.sum buffer does not meet minimum required size for this hash function");
|
||||
(*h.sum)(h, buf);
|
||||
};
|
||||
|
||||
@@ -13,13 +13,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// (when no continue exists in the loop).
|
||||
// - Hare `fn foo() T = if (cond) {...} else expr;` expression body
|
||||
// → ww requires a `{}` block body throughout.
|
||||
// - Hare bare `assert(cond)` builtin → `os.assert(cond, msg)`;
|
||||
// - Hare bare `assert(cond)` builtin → `assert(cond, msg)`;
|
||||
// wwstage cgen has no `assert` intercept (deferred fold).
|
||||
// - In-file instances of the above hoist pattern: `i_sz` (line 93)
|
||||
// hoists a per-iteration size cast out of a for-loop comparison
|
||||
@@ -110,7 +110,7 @@ fn leftshift(d: *decimal, k: u32) void = {
|
||||
let SZ_BOUND: size = (len(d.digits): size);
|
||||
let kU64: u64 = (k: u64);
|
||||
let MAXSHIFT_U32: u32 = (maxshift: u32);
|
||||
os.assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
if (d.nd == (0u64: size)) { return; };
|
||||
let nn: u32 = leftshift_newdigits(d, k);
|
||||
let r: int = (d.nd: int) - 1;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// (stof.ww hex_to_bits precedent).
|
||||
// - `&&=` → `x = x && y`. `ibool=if(b)1 else 0` expr-body → block.
|
||||
// comma `let a=…, b=…` → split. `if/else` expr-yield → pre-bound
|
||||
// local + block. `assert()` → `os.assert(cond,msg)`.
|
||||
// local + block. `assert()` → `assert(cond,msg)`.
|
||||
// - 2D row-bind `mul=TBL[base]` → direct double-index `TBL[base][0/1]`
|
||||
// (#155 / #156, stof.ww eisel_lemire precedent).
|
||||
// - ibool's u8 result + the u8 BITCOUNT defs cast explicitly to u32/u64
|
||||
@@ -62,7 +62,7 @@ import os;
|
||||
// (u128mul + the r128 struct live in stof.ww, fold-4's first consumer;
|
||||
// reused in-package here.)
|
||||
fn u128rshift(lo: u64, hi: u64, s: u32) u64 = {
|
||||
os.assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
return (hi << (64u64 - (s: u64))) | (lo >> (s: u64));
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ fn pow5fac(v: u64) u32 = {
|
||||
let n_div_5: u64 = 3689348814741910323u64;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
value *= m_inv_5;
|
||||
if (value > n_div_5) { break; };
|
||||
count += 1u32;
|
||||
@@ -92,8 +92,8 @@ fn pow5multiple(v: u64, p: u32) bool = { return pow5fac(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:69.
|
||||
fn pow2multiple(v: u64, p: u32) bool = {
|
||||
os.assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
os.assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
return (v & ((1u64 << (p: u64)) - 1u64)) == 0u64;
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ fn mulshiftall64(m: u64, mul0: u64, mul1: u64, j: i32, mm_shift: u32) ryuv = {
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:140.
|
||||
fn log2pow5(e: u32) u32 = {
|
||||
os.assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
return (e * 1217359u32) >> 19u32;
|
||||
};
|
||||
|
||||
@@ -146,13 +146,13 @@ fn pow5bits(e: u32) u32 = { return ceil_log2pow5(e); };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:149.
|
||||
fn log10pow2(e: u32) u32 = {
|
||||
os.assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
return (e * 78913u32) >> 18u32;
|
||||
};
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:154.
|
||||
fn log10pow5(e: u32) u32 = {
|
||||
os.assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
return (e * 732923u32) >> 20u32;
|
||||
};
|
||||
|
||||
@@ -343,15 +343,15 @@ fn f64todecf64(mantissa: u64, exponent: u32) decf64 = {
|
||||
// u64 siblings at 32-bit width; they reuse the SHARED f64computeinvpow5/
|
||||
// f64computepow5 (and thus the f64 SPLIT2 tables) per ftos_ryu.ha — there
|
||||
// is no separate f32 table. Same scalar-PARAM-mutation → copy-to-local,
|
||||
// comma-split, assert → os.assert, expr-yield → block divergences as the
|
||||
// f64 path above. ====
|
||||
// comma-split, expr-yield → block divergences as the f64 path
|
||||
// above. ====
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:52. Largest p with 5^p | value (32-bit).
|
||||
fn pow5fac32(v: u32) u32 = {
|
||||
let value: u32 = v;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
let q: u32 = value / 5u32;
|
||||
let r: u32 = value % 5u32;
|
||||
if (r != 0u32) { break; };
|
||||
@@ -366,8 +366,8 @@ fn pow5multiple32(v: u32, p: u32) bool = { return pow5fac32(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:75.
|
||||
fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
os.assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
os.assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
return (v & ((1u32 << p) - 1u32)) == 0u32;
|
||||
};
|
||||
|
||||
@@ -377,14 +377,14 @@ fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
// (lib/types/types.ww — no `export`), so Hare's `types::U32_MAX` can't be
|
||||
// referenced cross-package.
|
||||
fn mulshift32(m: u32, a: u64, s: u32) u32 = {
|
||||
os.assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
let a_lo: u64 = (a: u32): u64;
|
||||
let a_hi: u64 = a >> 32u64;
|
||||
let b0: u64 = (m: u64) * a_lo;
|
||||
let b1: u64 = (m: u64) * a_hi;
|
||||
let sum: u64 = (b0 >> 32u64) + b1;
|
||||
let ss: u64 = sum >> ((s: u64) - 32u64);
|
||||
os.assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
return ss: u32;
|
||||
};
|
||||
|
||||
@@ -533,7 +533,7 @@ fn f32todecf32(mantissa: u32, exponent: u32) decf32 = {
|
||||
|
||||
// ref/hare/strconv/ftos.ha:49. Decimal digit-count of n (n <= 1e17).
|
||||
fn declen(n: u64) uint = {
|
||||
os.assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
if (n >= 100000000000000000u64) { return (18u32: uint); };
|
||||
if (n >= 10000000000000000u64) { return (17u32: uint); };
|
||||
if (n >= 1000000000000000u64) { return (16u32: uint); };
|
||||
@@ -621,7 +621,7 @@ fn encode_f_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
// logic only): no precision zeros, lowercase 'e', no '+'/two-digit pad.
|
||||
fn encode_e_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
let o: i32 = out;
|
||||
os.assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
buf[o] = (d.digits[0] + 48u8): u8;
|
||||
o += 1i32;
|
||||
if ((d.nd: i32) > 1i32) {
|
||||
|
||||
@@ -97,8 +97,6 @@ fn todig(c: u8) u8 = {
|
||||
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
|
||||
};
|
||||
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// ref/hare/strconv/stof.ha:25.
|
||||
type fast_parsed_float = struct {
|
||||
mantissa: u64,
|
||||
@@ -280,7 +278,7 @@ fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
|
||||
|
||||
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
|
||||
fn leading_zeroes(n: u64) uint = {
|
||||
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
let b: u64 = 0u64;
|
||||
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
|
||||
n >>= 32u64;
|
||||
@@ -599,7 +597,7 @@ export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof64: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
@@ -652,7 +650,7 @@ export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof32: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
|
||||
@@ -223,7 +223,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -239,8 +239,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -668,7 +668,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -682,7 +682,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -1003,7 +995,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -1018,7 +1010,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -1086,8 +1078,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1103,8 +1095,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1258,7 +1250,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1296,7 +1288,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1365,7 +1357,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -1389,7 +1381,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2068,7 +2060,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -2084,8 +2076,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -2513,7 +2505,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -2527,7 +2519,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -1003,7 +995,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -1018,7 +1010,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -1086,8 +1078,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1103,8 +1095,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1258,7 +1250,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1296,7 +1288,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1365,7 +1357,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -1389,7 +1381,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2068,7 +2060,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -2084,8 +2076,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -2513,7 +2505,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -2527,7 +2519,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -2816,7 +2808,7 @@ export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
||||
// (when no continue exists in the loop).
|
||||
// - Hare `fn foo() T = if (cond) {...} else expr;` expression body
|
||||
// → ww requires a `{}` block body throughout.
|
||||
// - Hare bare `assert(cond)` builtin → `os.assert(cond, msg)`;
|
||||
// - Hare bare `assert(cond)` builtin → `assert(cond, msg)`;
|
||||
// wwstage cgen has no `assert` intercept (deferred fold).
|
||||
// - In-file instances of the above hoist pattern: `i_sz` (line 93)
|
||||
// hoists a per-iteration size cast out of a for-loop comparison
|
||||
@@ -2904,7 +2896,7 @@ fn leftshift(d: *decimal, k: u32) void = {
|
||||
let SZ_BOUND: size = (len(d.digits): size);
|
||||
let kU64: u64 = (k: u64);
|
||||
let MAXSHIFT_U32: u32 = (maxshift: u32);
|
||||
os.assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
if (d.nd == (0u64: size)) { return; };
|
||||
let nn: u32 = leftshift_newdigits(d, k);
|
||||
let r: int = (d.nd: int) - 1;
|
||||
@@ -3448,7 +3440,7 @@ export fn absi64(n: i64) u64 = {
|
||||
// (stof.ww hex_to_bits precedent).
|
||||
// - `&&=` → `x = x && y`. `ibool=if(b)1 else 0` expr-body → block.
|
||||
// comma `let a=…, b=…` → split. `if/else` expr-yield → pre-bound
|
||||
// local + block. `assert()` → `os.assert(cond,msg)`.
|
||||
// local + block. `assert()` → `assert(cond,msg)`.
|
||||
// - 2D row-bind `mul=TBL[base]` → direct double-index `TBL[base][0/1]`
|
||||
// (#155 / #156, stof.ww eisel_lemire precedent).
|
||||
// - ibool's u8 result + the u8 BITCOUNT defs cast explicitly to u32/u64
|
||||
@@ -3468,7 +3460,7 @@ import os;
|
||||
// (u128mul + the r128 struct live in stof.ww, fold-4's first consumer;
|
||||
// reused in-package here.)
|
||||
fn u128rshift(lo: u64, hi: u64, s: u32) u64 = {
|
||||
os.assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
return (hi << (64u64 - (s: u64))) | (lo >> (s: u64));
|
||||
};
|
||||
|
||||
@@ -3479,7 +3471,7 @@ fn pow5fac(v: u64) u32 = {
|
||||
let n_div_5: u64 = 3689348814741910323u64;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
value *= m_inv_5;
|
||||
if (value > n_div_5) { break; };
|
||||
count += 1u32;
|
||||
@@ -3498,8 +3490,8 @@ fn pow5multiple(v: u64, p: u32) bool = { return pow5fac(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:69.
|
||||
fn pow2multiple(v: u64, p: u32) bool = {
|
||||
os.assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
os.assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
return (v & ((1u64 << (p: u64)) - 1u64)) == 0u64;
|
||||
};
|
||||
|
||||
@@ -3542,7 +3534,7 @@ fn mulshiftall64(m: u64, mul0: u64, mul1: u64, j: i32, mm_shift: u32) ryuv = {
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:140.
|
||||
fn log2pow5(e: u32) u32 = {
|
||||
os.assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
return (e * 1217359u32) >> 19u32;
|
||||
};
|
||||
|
||||
@@ -3552,13 +3544,13 @@ fn pow5bits(e: u32) u32 = { return ceil_log2pow5(e); };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:149.
|
||||
fn log10pow2(e: u32) u32 = {
|
||||
os.assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
return (e * 78913u32) >> 18u32;
|
||||
};
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:154.
|
||||
fn log10pow5(e: u32) u32 = {
|
||||
os.assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
return (e * 732923u32) >> 20u32;
|
||||
};
|
||||
|
||||
@@ -3749,15 +3741,15 @@ fn f64todecf64(mantissa: u64, exponent: u32) decf64 = {
|
||||
// u64 siblings at 32-bit width; they reuse the SHARED f64computeinvpow5/
|
||||
// f64computepow5 (and thus the f64 SPLIT2 tables) per ftos_ryu.ha — there
|
||||
// is no separate f32 table. Same scalar-PARAM-mutation → copy-to-local,
|
||||
// comma-split, assert → os.assert, expr-yield → block divergences as the
|
||||
// f64 path above. ====
|
||||
// comma-split, expr-yield → block divergences as the f64 path
|
||||
// above. ====
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:52. Largest p with 5^p | value (32-bit).
|
||||
fn pow5fac32(v: u32) u32 = {
|
||||
let value: u32 = v;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
let q: u32 = value / 5u32;
|
||||
let r: u32 = value % 5u32;
|
||||
if (r != 0u32) { break; };
|
||||
@@ -3772,8 +3764,8 @@ fn pow5multiple32(v: u32, p: u32) bool = { return pow5fac32(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:75.
|
||||
fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
os.assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
os.assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
return (v & ((1u32 << p) - 1u32)) == 0u32;
|
||||
};
|
||||
|
||||
@@ -3783,14 +3775,14 @@ fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
// (lib/types/types.ww — no `export`), so Hare's `types::U32_MAX` can't be
|
||||
// referenced cross-package.
|
||||
fn mulshift32(m: u32, a: u64, s: u32) u32 = {
|
||||
os.assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
let a_lo: u64 = (a: u32): u64;
|
||||
let a_hi: u64 = a >> 32u64;
|
||||
let b0: u64 = (m: u64) * a_lo;
|
||||
let b1: u64 = (m: u64) * a_hi;
|
||||
let sum: u64 = (b0 >> 32u64) + b1;
|
||||
let ss: u64 = sum >> ((s: u64) - 32u64);
|
||||
os.assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
return ss: u32;
|
||||
};
|
||||
|
||||
@@ -3939,7 +3931,7 @@ fn f32todecf32(mantissa: u32, exponent: u32) decf32 = {
|
||||
|
||||
// ref/hare/strconv/ftos.ha:49. Decimal digit-count of n (n <= 1e17).
|
||||
fn declen(n: u64) uint = {
|
||||
os.assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
if (n >= 100000000000000000u64) { return (18u32: uint); };
|
||||
if (n >= 10000000000000000u64) { return (17u32: uint); };
|
||||
if (n >= 1000000000000000u64) { return (16u32: uint); };
|
||||
@@ -4027,7 +4019,7 @@ fn encode_f_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
// logic only): no precision zeros, lowercase 'e', no '+'/two-digit pad.
|
||||
fn encode_e_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
let o: i32 = out;
|
||||
os.assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
buf[o] = (d.digits[0] + 48u8): u8;
|
||||
o += 1i32;
|
||||
if ((d.nd: i32) > 1i32) {
|
||||
@@ -4612,8 +4604,6 @@ fn todig(c: u8) u8 = {
|
||||
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
|
||||
};
|
||||
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// ref/hare/strconv/stof.ha:25.
|
||||
type fast_parsed_float = struct {
|
||||
mantissa: u64,
|
||||
@@ -4795,7 +4785,7 @@ fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
|
||||
|
||||
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
|
||||
fn leading_zeroes(n: u64) uint = {
|
||||
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
let b: u64 = 0u64;
|
||||
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
|
||||
n >>= 32u64;
|
||||
@@ -5114,7 +5104,7 @@ export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof64: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
@@ -5167,7 +5157,7 @@ export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof32: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -1003,7 +995,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -1018,7 +1010,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -1086,8 +1078,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1103,8 +1095,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1258,7 +1250,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1296,7 +1288,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1365,7 +1357,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -1389,7 +1381,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2068,7 +2060,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -2084,8 +2076,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -2513,7 +2505,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -2527,7 +2519,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -1003,7 +995,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -1018,7 +1010,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -1086,8 +1078,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1103,8 +1095,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -1258,7 +1250,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1296,7 +1288,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -1365,7 +1357,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -1389,7 +1381,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2068,7 +2060,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -2084,8 +2076,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -2513,7 +2505,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -2527,7 +2519,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -813,7 +805,7 @@ export fn exists(path: str) bool = {
|
||||
// (when no continue exists in the loop).
|
||||
// - Hare `fn foo() T = if (cond) {...} else expr;` expression body
|
||||
// → ww requires a `{}` block body throughout.
|
||||
// - Hare bare `assert(cond)` builtin → `os.assert(cond, msg)`;
|
||||
// - Hare bare `assert(cond)` builtin → `assert(cond, msg)`;
|
||||
// wwstage cgen has no `assert` intercept (deferred fold).
|
||||
// - In-file instances of the above hoist pattern: `i_sz` (line 93)
|
||||
// hoists a per-iteration size cast out of a for-loop comparison
|
||||
@@ -901,7 +893,7 @@ fn leftshift(d: *decimal, k: u32) void = {
|
||||
let SZ_BOUND: size = (len(d.digits): size);
|
||||
let kU64: u64 = (k: u64);
|
||||
let MAXSHIFT_U32: u32 = (maxshift: u32);
|
||||
os.assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
if (d.nd == (0u64: size)) { return; };
|
||||
let nn: u32 = leftshift_newdigits(d, k);
|
||||
let r: int = (d.nd: int) - 1;
|
||||
@@ -1445,7 +1437,7 @@ export fn absi64(n: i64) u64 = {
|
||||
// (stof.ww hex_to_bits precedent).
|
||||
// - `&&=` → `x = x && y`. `ibool=if(b)1 else 0` expr-body → block.
|
||||
// comma `let a=…, b=…` → split. `if/else` expr-yield → pre-bound
|
||||
// local + block. `assert()` → `os.assert(cond,msg)`.
|
||||
// local + block. `assert()` → `assert(cond,msg)`.
|
||||
// - 2D row-bind `mul=TBL[base]` → direct double-index `TBL[base][0/1]`
|
||||
// (#155 / #156, stof.ww eisel_lemire precedent).
|
||||
// - ibool's u8 result + the u8 BITCOUNT defs cast explicitly to u32/u64
|
||||
@@ -1465,7 +1457,7 @@ import os;
|
||||
// (u128mul + the r128 struct live in stof.ww, fold-4's first consumer;
|
||||
// reused in-package here.)
|
||||
fn u128rshift(lo: u64, hi: u64, s: u32) u64 = {
|
||||
os.assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
return (hi << (64u64 - (s: u64))) | (lo >> (s: u64));
|
||||
};
|
||||
|
||||
@@ -1476,7 +1468,7 @@ fn pow5fac(v: u64) u32 = {
|
||||
let n_div_5: u64 = 3689348814741910323u64;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
value *= m_inv_5;
|
||||
if (value > n_div_5) { break; };
|
||||
count += 1u32;
|
||||
@@ -1495,8 +1487,8 @@ fn pow5multiple(v: u64, p: u32) bool = { return pow5fac(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:69.
|
||||
fn pow2multiple(v: u64, p: u32) bool = {
|
||||
os.assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
os.assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
return (v & ((1u64 << (p: u64)) - 1u64)) == 0u64;
|
||||
};
|
||||
|
||||
@@ -1539,7 +1531,7 @@ fn mulshiftall64(m: u64, mul0: u64, mul1: u64, j: i32, mm_shift: u32) ryuv = {
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:140.
|
||||
fn log2pow5(e: u32) u32 = {
|
||||
os.assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
return (e * 1217359u32) >> 19u32;
|
||||
};
|
||||
|
||||
@@ -1549,13 +1541,13 @@ fn pow5bits(e: u32) u32 = { return ceil_log2pow5(e); };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:149.
|
||||
fn log10pow2(e: u32) u32 = {
|
||||
os.assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
return (e * 78913u32) >> 18u32;
|
||||
};
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:154.
|
||||
fn log10pow5(e: u32) u32 = {
|
||||
os.assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
return (e * 732923u32) >> 20u32;
|
||||
};
|
||||
|
||||
@@ -1746,15 +1738,15 @@ fn f64todecf64(mantissa: u64, exponent: u32) decf64 = {
|
||||
// u64 siblings at 32-bit width; they reuse the SHARED f64computeinvpow5/
|
||||
// f64computepow5 (and thus the f64 SPLIT2 tables) per ftos_ryu.ha — there
|
||||
// is no separate f32 table. Same scalar-PARAM-mutation → copy-to-local,
|
||||
// comma-split, assert → os.assert, expr-yield → block divergences as the
|
||||
// f64 path above. ====
|
||||
// comma-split, expr-yield → block divergences as the f64 path
|
||||
// above. ====
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:52. Largest p with 5^p | value (32-bit).
|
||||
fn pow5fac32(v: u32) u32 = {
|
||||
let value: u32 = v;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
let q: u32 = value / 5u32;
|
||||
let r: u32 = value % 5u32;
|
||||
if (r != 0u32) { break; };
|
||||
@@ -1769,8 +1761,8 @@ fn pow5multiple32(v: u32, p: u32) bool = { return pow5fac32(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:75.
|
||||
fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
os.assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
os.assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
return (v & ((1u32 << p) - 1u32)) == 0u32;
|
||||
};
|
||||
|
||||
@@ -1780,14 +1772,14 @@ fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
// (lib/types/types.ww — no `export`), so Hare's `types::U32_MAX` can't be
|
||||
// referenced cross-package.
|
||||
fn mulshift32(m: u32, a: u64, s: u32) u32 = {
|
||||
os.assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
let a_lo: u64 = (a: u32): u64;
|
||||
let a_hi: u64 = a >> 32u64;
|
||||
let b0: u64 = (m: u64) * a_lo;
|
||||
let b1: u64 = (m: u64) * a_hi;
|
||||
let sum: u64 = (b0 >> 32u64) + b1;
|
||||
let ss: u64 = sum >> ((s: u64) - 32u64);
|
||||
os.assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
return ss: u32;
|
||||
};
|
||||
|
||||
@@ -1936,7 +1928,7 @@ fn f32todecf32(mantissa: u32, exponent: u32) decf32 = {
|
||||
|
||||
// ref/hare/strconv/ftos.ha:49. Decimal digit-count of n (n <= 1e17).
|
||||
fn declen(n: u64) uint = {
|
||||
os.assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
if (n >= 100000000000000000u64) { return (18u32: uint); };
|
||||
if (n >= 10000000000000000u64) { return (17u32: uint); };
|
||||
if (n >= 1000000000000000u64) { return (16u32: uint); };
|
||||
@@ -2024,7 +2016,7 @@ fn encode_f_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
// logic only): no precision zeros, lowercase 'e', no '+'/two-digit pad.
|
||||
fn encode_e_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
let o: i32 = out;
|
||||
os.assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
buf[o] = (d.digits[0] + 48u8): u8;
|
||||
o += 1i32;
|
||||
if ((d.nd: i32) > 1i32) {
|
||||
@@ -2497,7 +2489,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -2512,7 +2504,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -2580,8 +2572,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -2597,8 +2589,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -2752,7 +2744,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -2790,7 +2782,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -2859,7 +2851,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2883,7 +2875,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -3585,7 +3577,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -3601,8 +3593,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -4030,7 +4022,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -4044,7 +4036,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -4612,8 +4604,6 @@ fn todig(c: u8) u8 = {
|
||||
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
|
||||
};
|
||||
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// ref/hare/strconv/stof.ha:25.
|
||||
type fast_parsed_float = struct {
|
||||
mantissa: u64,
|
||||
@@ -4795,7 +4785,7 @@ fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
|
||||
|
||||
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
|
||||
fn leading_zeroes(n: u64) uint = {
|
||||
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
let b: u64 = 0u64;
|
||||
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
|
||||
n >>= 32u64;
|
||||
@@ -5114,7 +5104,7 @@ export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof64: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
@@ -5167,7 +5157,7 @@ export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof32: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
package time;
|
||||
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
def SYS_CLOCK_GETTIME: i64 = 228;
|
||||
|
||||
@@ -111,13 +110,6 @@ import time;
|
||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// Hare-style runtime check. Caller passes a message that's printed
|
||||
// to stderr before exit(1).
|
||||
export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
// Linux amd64 syscall numbers. Internal to this module — passed as
|
||||
// the first arg of syscall0..4 via libwwrt's rt_syscall trampoline.
|
||||
@@ -813,7 +805,7 @@ export fn exists(path: str) bool = {
|
||||
// (when no continue exists in the loop).
|
||||
// - Hare `fn foo() T = if (cond) {...} else expr;` expression body
|
||||
// → ww requires a `{}` block body throughout.
|
||||
// - Hare bare `assert(cond)` builtin → `os.assert(cond, msg)`;
|
||||
// - Hare bare `assert(cond)` builtin → `assert(cond, msg)`;
|
||||
// wwstage cgen has no `assert` intercept (deferred fold).
|
||||
// - In-file instances of the above hoist pattern: `i_sz` (line 93)
|
||||
// hoists a per-iteration size cast out of a for-loop comparison
|
||||
@@ -901,7 +893,7 @@ fn leftshift(d: *decimal, k: u32) void = {
|
||||
let SZ_BOUND: size = (len(d.digits): size);
|
||||
let kU64: u64 = (k: u64);
|
||||
let MAXSHIFT_U32: u32 = (maxshift: u32);
|
||||
os.assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
assert(k <= MAXSHIFT_U32, "strconv.leftshift: k > maxshift");
|
||||
if (d.nd == (0u64: size)) { return; };
|
||||
let nn: u32 = leftshift_newdigits(d, k);
|
||||
let r: int = (d.nd: int) - 1;
|
||||
@@ -1445,7 +1437,7 @@ export fn absi64(n: i64) u64 = {
|
||||
// (stof.ww hex_to_bits precedent).
|
||||
// - `&&=` → `x = x && y`. `ibool=if(b)1 else 0` expr-body → block.
|
||||
// comma `let a=…, b=…` → split. `if/else` expr-yield → pre-bound
|
||||
// local + block. `assert()` → `os.assert(cond,msg)`.
|
||||
// local + block. `assert()` → `assert(cond,msg)`.
|
||||
// - 2D row-bind `mul=TBL[base]` → direct double-index `TBL[base][0/1]`
|
||||
// (#155 / #156, stof.ww eisel_lemire precedent).
|
||||
// - ibool's u8 result + the u8 BITCOUNT defs cast explicitly to u32/u64
|
||||
@@ -1465,7 +1457,7 @@ import os;
|
||||
// (u128mul + the r128 struct live in stof.ww, fold-4's first consumer;
|
||||
// reused in-package here.)
|
||||
fn u128rshift(lo: u64, hi: u64, s: u32) u64 = {
|
||||
os.assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
assert(s <= 64u32, "strconv.u128rshift: s > 64");
|
||||
return (hi << (64u64 - (s: u64))) | (lo >> (s: u64));
|
||||
};
|
||||
|
||||
@@ -1476,7 +1468,7 @@ fn pow5fac(v: u64) u32 = {
|
||||
let n_div_5: u64 = 3689348814741910323u64;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
assert(value != 0u64, "strconv.pow5fac: value == 0");
|
||||
value *= m_inv_5;
|
||||
if (value > n_div_5) { break; };
|
||||
count += 1u32;
|
||||
@@ -1495,8 +1487,8 @@ fn pow5multiple(v: u64, p: u32) bool = { return pow5fac(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:69.
|
||||
fn pow2multiple(v: u64, p: u32) bool = {
|
||||
os.assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
os.assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
assert(v > 0u64, "strconv.pow2multiple: v == 0");
|
||||
assert(p < 64u32, "strconv.pow2multiple: p >= 64");
|
||||
return (v & ((1u64 << (p: u64)) - 1u64)) == 0u64;
|
||||
};
|
||||
|
||||
@@ -1539,7 +1531,7 @@ fn mulshiftall64(m: u64, mul0: u64, mul1: u64, j: i32, mm_shift: u32) ryuv = {
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:140.
|
||||
fn log2pow5(e: u32) u32 = {
|
||||
os.assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
assert(e <= 3528u32, "strconv.log2pow5: e > 3528");
|
||||
return (e * 1217359u32) >> 19u32;
|
||||
};
|
||||
|
||||
@@ -1549,13 +1541,13 @@ fn pow5bits(e: u32) u32 = { return ceil_log2pow5(e); };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:149.
|
||||
fn log10pow2(e: u32) u32 = {
|
||||
os.assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
assert(e <= 1650u32, "strconv.log10pow2: e > 1650");
|
||||
return (e * 78913u32) >> 18u32;
|
||||
};
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:154.
|
||||
fn log10pow5(e: u32) u32 = {
|
||||
os.assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
assert(e <= 2620u32, "strconv.log10pow5: e > 2620");
|
||||
return (e * 732923u32) >> 20u32;
|
||||
};
|
||||
|
||||
@@ -1746,15 +1738,15 @@ fn f64todecf64(mantissa: u64, exponent: u32) decf64 = {
|
||||
// u64 siblings at 32-bit width; they reuse the SHARED f64computeinvpow5/
|
||||
// f64computepow5 (and thus the f64 SPLIT2 tables) per ftos_ryu.ha — there
|
||||
// is no separate f32 table. Same scalar-PARAM-mutation → copy-to-local,
|
||||
// comma-split, assert → os.assert, expr-yield → block divergences as the
|
||||
// f64 path above. ====
|
||||
// comma-split, expr-yield → block divergences as the f64 path
|
||||
// above. ====
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:52. Largest p with 5^p | value (32-bit).
|
||||
fn pow5fac32(v: u32) u32 = {
|
||||
let value: u32 = v;
|
||||
let count: u32 = 0u32;
|
||||
for (true) {
|
||||
os.assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
assert(value != 0u32, "strconv.pow5fac32: value == 0");
|
||||
let q: u32 = value / 5u32;
|
||||
let r: u32 = value % 5u32;
|
||||
if (r != 0u32) { break; };
|
||||
@@ -1769,8 +1761,8 @@ fn pow5multiple32(v: u32, p: u32) bool = { return pow5fac32(v) >= p; };
|
||||
|
||||
// ref/hare/strconv/ftos_ryu.ha:75.
|
||||
fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
os.assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
os.assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
assert(v > 0u32, "strconv.pow2multiple32: v == 0");
|
||||
assert(p < 32u32, "strconv.pow2multiple32: p >= 32");
|
||||
return (v & ((1u32 << p) - 1u32)) == 0u32;
|
||||
};
|
||||
|
||||
@@ -1780,14 +1772,14 @@ fn pow2multiple32(v: u32, p: u32) bool = {
|
||||
// (lib/types/types.ww — no `export`), so Hare's `types::U32_MAX` can't be
|
||||
// referenced cross-package.
|
||||
fn mulshift32(m: u32, a: u64, s: u32) u32 = {
|
||||
os.assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
assert(s > 32u32, "strconv.mulshift32: s <= 32");
|
||||
let a_lo: u64 = (a: u32): u64;
|
||||
let a_hi: u64 = a >> 32u64;
|
||||
let b0: u64 = (m: u64) * a_lo;
|
||||
let b1: u64 = (m: u64) * a_hi;
|
||||
let sum: u64 = (b0 >> 32u64) + b1;
|
||||
let ss: u64 = sum >> ((s: u64) - 32u64);
|
||||
os.assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
assert(ss <= 4294967295u64, "strconv.mulshift32: ss > U32_MAX");
|
||||
return ss: u32;
|
||||
};
|
||||
|
||||
@@ -1936,7 +1928,7 @@ fn f32todecf32(mantissa: u32, exponent: u32) decf32 = {
|
||||
|
||||
// ref/hare/strconv/ftos.ha:49. Decimal digit-count of n (n <= 1e17).
|
||||
fn declen(n: u64) uint = {
|
||||
os.assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
assert(n <= 100000000000000000u64, "strconv.declen: n > 1e17");
|
||||
if (n >= 100000000000000000u64) { return (18u32: uint); };
|
||||
if (n >= 10000000000000000u64) { return (17u32: uint); };
|
||||
if (n >= 1000000000000000u64) { return (16u32: uint); };
|
||||
@@ -2024,7 +2016,7 @@ fn encode_f_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
// logic only): no precision zeros, lowercase 'e', no '+'/two-digit pad.
|
||||
fn encode_e_dec(d: *decimal, buf: []u8, out: i32) i32 = {
|
||||
let o: i32 = out;
|
||||
os.assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
assert(d.nd > (0u64: size), "strconv.encode_e_dec: nd == 0");
|
||||
buf[o] = (d.digits[0] + 48u8): u8;
|
||||
o += 1i32;
|
||||
if ((d.nd: i32) > 1i32) {
|
||||
@@ -2497,7 +2489,7 @@ export fn contains(s: []u8, needles: (u8 | []u8)...) bool = {
|
||||
// ltrim — borrowed view of `in` with leading bytes in `trim` stripped.
|
||||
// `trim` must be non-empty. ref/hare/bytes/trim.ha:7.
|
||||
export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.ltrim called with empty trim set");
|
||||
let i: i32 = 0;
|
||||
for (i < in.len && contains(trim, in[i])) { i += 1; };
|
||||
let r: []u8;
|
||||
@@ -2512,7 +2504,7 @@ export fn ltrim(in: []u8, trim: u8...) []u8 = {
|
||||
// `size` underflow at i==0 to terminate; ww indices are signed i32, so
|
||||
// the equivalent termination is spelled `i >= 0` explicitly.
|
||||
export fn rtrim(in: []u8, trim: u8...) []u8 = {
|
||||
os.assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
assert(trim.len > 0, "bytes.rtrim called with empty trim set");
|
||||
let i: i32 = in.len - 1;
|
||||
for (i >= 0 && contains(trim, in[i])) { i -= 1; };
|
||||
let r: []u8;
|
||||
@@ -2580,8 +2572,8 @@ export fn zero(s: []u8) void = {
|
||||
// `delim` is borrowed; caller keeps it valid for the tokenizer's
|
||||
// lifetime. ref/hare/bytes/tokenize.ha:22.
|
||||
export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.tokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.tokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -2597,8 +2589,8 @@ export fn tokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
// rtokenize — reverse-direction tokenize. First next_token yields the
|
||||
// last token, last next_token yields the first. ref/hare/bytes/tokenize.ha:40.
|
||||
export fn rtokenize(in: []u8, delim: u8...) tokenizer = {
|
||||
os.assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
os.assert((in.len: i64) < types.I64_MAX,
|
||||
assert(delim.len > 0, "bytes.rtokenize called with empty slice");
|
||||
assert((in.len: i64) < types.I64_MAX,
|
||||
"bytes.rtokenize: input length exceeds I64_MAX");
|
||||
let t: tokenizer;
|
||||
t.in = in;
|
||||
@@ -2752,7 +2744,7 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:156.
|
||||
export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.splitn must not be called with an empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -2790,7 +2782,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
//
|
||||
// ref/hare/bytes/tokenize.ha:186.
|
||||
export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
os.assert(delim.len > 0,
|
||||
assert(delim.len > 0,
|
||||
"bytes.rsplitn called with empty delimiter");
|
||||
let toks: [][]u8;
|
||||
toks.ptr = nil: *[]u8;
|
||||
@@ -2859,7 +2851,7 @@ export fn cut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.cut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -2883,7 +2875,7 @@ export fn rcut(in: []u8, delim: (u8 | []u8)) ([]u8, []u8) = {
|
||||
let ln: i32 = match (delim) {
|
||||
case let c: u8 => yield 1i32;
|
||||
case let sub: []u8 => {
|
||||
os.assert(sub.len > 0,
|
||||
assert(sub.len > 0,
|
||||
"bytes.rcut called with empty delimiter");
|
||||
yield sub.len;
|
||||
};
|
||||
@@ -3585,7 +3577,7 @@ fn utf8bytelenbounded(it: *iterator, end: i32) i32 = {
|
||||
// defaulting end=END is omitted: ww has no default-parameter syntax
|
||||
// (filed as #37). Byte-indexed counterpart: [[bytesub]].
|
||||
export fn sub(s: str, start: i32, end: i32) str = {
|
||||
os.assert(start <= end, "strings.sub: start is higher than end");
|
||||
assert(start <= end, "strings.sub: start is higher than end");
|
||||
let it: iterator = iter(s);
|
||||
let starti: i32 = utf8bytelenbounded(&it, start);
|
||||
let endi: i32 = utf8bytelenbounded(&it, end - start);
|
||||
@@ -3601,8 +3593,8 @@ export fn sub(s: str, start: i32, end: i32) str = {
|
||||
// codepoint); the equivalent Hare predicate is `s[i] & 0xc0 == 0x80`
|
||||
// at ref/hare/strings/sub.ha:72-73.
|
||||
export fn bytesub(s: str, start: i32, end: i32) (str | utf8.invalid) = {
|
||||
os.assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
os.assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
assert(start <= end, "strings.bytesub: start is higher than end");
|
||||
assert(end <= s.len, "strings.bytesub: end exceeds string length");
|
||||
if (start < s.len && (s[start] & 0xC0u8) == 0x80u8) {
|
||||
let e: utf8.invalid; return e;
|
||||
};
|
||||
@@ -4030,7 +4022,7 @@ export fn tokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.tokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -4044,7 +4036,7 @@ export fn rtokenize(s: str, delim: str) tokenizer = {
|
||||
let d: []u8 = toutf8(delim);
|
||||
let i: i32 = 0;
|
||||
for (i < d.len) {
|
||||
os.assert((d[i] & 0x80u8) == 0u8,
|
||||
assert((d[i] & 0x80u8) == 0u8,
|
||||
"strings.rtokenize cannot tokenize on non-ASCII delimiters");
|
||||
i += 1;
|
||||
};
|
||||
@@ -4612,8 +4604,6 @@ fn todig(c: u8) u8 = {
|
||||
return 0u8; // unreachable; rt_abort is void-typed (path-cov)
|
||||
};
|
||||
|
||||
@symbol("rt_abort") fn abort(msg: str) void;
|
||||
|
||||
// ref/hare/strconv/stof.ha:25.
|
||||
type fast_parsed_float = struct {
|
||||
mantissa: u64,
|
||||
@@ -4795,7 +4785,7 @@ fn decimal_parse(d: *decimal, s: str) (void | invalid) = {
|
||||
|
||||
// ref/hare/strconv/stof.ha:173. Count of leading zero bits in n>0.
|
||||
fn leading_zeroes(n: u64) uint = {
|
||||
os.assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
assert(n > 0u64, "strconv.leading_zeroes: n == 0");
|
||||
let b: u64 = 0u64;
|
||||
if ((n & 0xFFFFFFFF00000000u64) > 0u64) {
|
||||
n >>= 32u64;
|
||||
@@ -5114,7 +5104,7 @@ export fn stof64(s: str, b: base) (f64 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof64: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
@@ -5167,7 +5157,7 @@ export fn stof32(s: str, b: base) (f32 | invalid | overflow) = {
|
||||
} else if (bb == base.HEX_LOWER) {
|
||||
bb = base.HEX;
|
||||
};
|
||||
os.assert(bb == base.DEC || bb == base.HEX,
|
||||
assert(bb == base.DEC || bb == base.HEX,
|
||||
"strconv.stof32: base must be DEC or HEX");
|
||||
|
||||
if (s.len == 0) {
|
||||
|
||||
@@ -400,7 +400,7 @@ static const struct row rows[] = {
|
||||
" let p: *point = alloc(point { x = 7, y = 35 })!;\n"
|
||||
" let r: i64 = p.x + p.y;\n"
|
||||
" free(p);\n"
|
||||
" os.assert(r == 42, \"sum mismatch\\n\");\n"
|
||||
" assert(r == 42, \"sum mismatch\\n\");\n"
|
||||
" return r: i32;\n"
|
||||
"};", 42 },
|
||||
/* Hare-style struct embedding: bare-name embed + anonymous
|
||||
|
||||
@@ -36,7 +36,7 @@ static const char *modules[] = {
|
||||
* post-Commit B; lib/errors.errno references os.errno / os.E* /
|
||||
* os.strerror (ww folds Hare's sys role into os); lib/strings.iterator
|
||||
* + lib/strings.next reference utf8.decoder / utf8.done;
|
||||
* lib/bytes.tokenize references os.assert + types.I64_MAX/MIN per
|
||||
* lib/bytes.tokenize references the assert builtin + types.I64_MAX/MIN per
|
||||
* ref/hare/bytes/tokenize.ha:23-24,42-43; lib/encoding/hex and
|
||||
* lib/encoding/base64 graduated to Hare's io-streaming surface
|
||||
* (hex references io.handle / fmt.fprint / memio.dynamic / strconv /
|
||||
|
||||
Reference in New Issue
Block a user