lib/fmt: render i64::MIN via math.absi64, not in-i64 negate (#67)
i64dec computed the magnitude with `n = -n` inside i64, which wraps at i64::MIN (-MIN == MIN stays negative), so the `for (n > 0)` loop never ran and println(i64::MIN) emitted only the bare '-'. The whole print/ println/fprint family was affected at the single boundary value (and int MIN, since int is 8B). ref/hare/fmt/print.ha:124-129 takes the magnitude through math::absi64 into a u64; do the same (math.absi64 exists, lib/math/math.ww:12). ww's own printf path was already correct ((-v): u64), so print and printf now agree. fmttest gains fprinti64min + fprintintmin pinning the boundary.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
package fmt;
|
package fmt;
|
||||||
|
|
||||||
import io;
|
import io;
|
||||||
|
import math;
|
||||||
import memio;
|
import memio;
|
||||||
import os;
|
import os;
|
||||||
import strings;
|
import strings;
|
||||||
@@ -38,16 +39,18 @@ let i64dec_buf: [21]u8;
|
|||||||
// of strconv.i64tos for the pre-printf-family print path; the
|
// of strconv.i64tos for the pre-printf-family print path; the
|
||||||
// printf-family path below dispatches through strconv directly.
|
// printf-family path below dispatches through strconv directly.
|
||||||
fn i64dec(v: i64) str = {
|
fn i64dec(v: i64) str = {
|
||||||
let neg: bool = false;
|
// ref/hare/fmt/print.ha:124-129: magnitude via math::absi64 into u64,
|
||||||
let n: i64 = v;
|
// sign tested separately. `n = -n` on an i64 wraps at i64::MIN
|
||||||
if (n < 0) { neg = true; n = -n; };
|
// (-MIN == MIN), so the old loop never ran and only the '-' printed.
|
||||||
|
let neg: bool = v < 0;
|
||||||
|
let n: u64 = math.absi64(v);
|
||||||
let tmp: [20]u8;
|
let tmp: [20]u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
if (n == 0) { tmp[0] = '0'; i = 1; };
|
if (n == 0u64) { tmp[0] = '0'; i = 1; };
|
||||||
for (n > 0) {
|
for (n > 0u64) {
|
||||||
let d: i64 = n % 10i64;
|
let d: u64 = n % 10u64;
|
||||||
tmp[i] = (d + 48i64): u8;
|
tmp[i] = (d + 48u64): u8;
|
||||||
n = n / 10i64;
|
n = n / 10u64;
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
let out: i32 = 0;
|
let out: i32 = 0;
|
||||||
|
|||||||
@@ -76,6 +76,44 @@ fn errsource() io.stream = {
|
|||||||
match (c) { case void => {}; case let eioe: io.error => abort(); };
|
match (c) { case void => {}; case let eioe: io.error => abort(); };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---- fprint: i64::MIN / int MIN whole-magnitude (#67) ------------------
|
||||||
|
// i64dec used `n = -n` within i64, which wraps at i64::MIN (-MIN == MIN),
|
||||||
|
// so the digit loop never ran and only the bare '-' was emitted. The fix
|
||||||
|
// takes the magnitude through math.absi64 into u64. These rows pin the
|
||||||
|
// boundary value plus a normal negative, zero, and int MIN.
|
||||||
|
|
||||||
|
@test fn fprinti64min() void = {
|
||||||
|
let mem: memio.stream = memio.dynamic();
|
||||||
|
let s: io.stream = &mem.vt;
|
||||||
|
|
||||||
|
let m: i64 = -9223372036854775807i64 - 1i64;
|
||||||
|
let r: (size | io.error) = fmt.fprint(s, m);
|
||||||
|
match (r) {
|
||||||
|
case let n: size => { assert(!(n: i32 != 20)); };
|
||||||
|
case let eioe: io.error => abort();
|
||||||
|
};
|
||||||
|
assert(!(!streq(memio.string(&mem), "-9223372036854775808")));
|
||||||
|
|
||||||
|
let c: (void | io.error) = io.close(s);
|
||||||
|
match (c) { case void => {}; case let eioe: io.error => abort(); };
|
||||||
|
};
|
||||||
|
|
||||||
|
@test fn fprintintmin() void = {
|
||||||
|
let mem: memio.stream = memio.dynamic();
|
||||||
|
let s: io.stream = &mem.vt;
|
||||||
|
|
||||||
|
let m: int = -9223372036854775807 - 1;
|
||||||
|
let r: (size | io.error) = fmt.fprint(s, m, -7i64, 0i64);
|
||||||
|
match (r) {
|
||||||
|
case let n: size => { assert(!(n: i32 != 25)); }; // "-9223372036854775808 -7 0"
|
||||||
|
case let eioe: io.error => abort();
|
||||||
|
};
|
||||||
|
assert(!(!streq(memio.string(&mem), "-9223372036854775808 -7 0")));
|
||||||
|
|
||||||
|
let c: (void | io.error) = io.close(s);
|
||||||
|
match (c) { case void => {}; case let eioe: io.error => abort(); };
|
||||||
|
};
|
||||||
|
|
||||||
// ---- fprint: bool + rune renders as "true A" --------------------------
|
// ---- fprint: bool + rune renders as "true A" --------------------------
|
||||||
|
|
||||||
@test fn fprintboolrune() void = {
|
@test fn fprintboolrune() void = {
|
||||||
|
|||||||
Reference in New Issue
Block a user