From b9b90fbe8f6a131890e3ecf034776f1fa7e7b65e Mon Sep 17 00:00:00 2001 From: dzaima Date: Tue, 5 Dec 2023 16:47:23 +0200 Subject: [PATCH] improve error messages of o2i/o2i64/o2u64 & usum --- src/builtins/fold.c | 22 ++++++++++++++-------- src/core/stuff.c | 28 ++++++++++++++++++++++++++++ src/core/stuff.h | 1 + src/h.h | 15 +++++++++------ test/cases/prims.bqn | 22 +++++++++++++--------- 5 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/builtins/fold.c b/src/builtins/fold.c index 1919830c..f40d0f6e 100644 --- a/src/builtins/fold.c +++ b/src/builtins/fold.c @@ -300,6 +300,15 @@ NOINLINE i64 bit_sum(u64* x, u64 am) { return r; } +NOINLINE static u64 usum_generic(B x, usz xia) { + SGetU(x) + u64 r = 0; + for (usz i = 0; i < xia; i++) { + u64 c = o2u64(GetU(x,i)); + if (addOn(r,c)) thrM("Sum too big"); + } + return r; +} u64 usum(B x) { // doesn't consume; will error on non-integers, or elements <0, or if sum overflows u64 assert(isArr(x)); u64 r = 0; @@ -313,22 +322,19 @@ u64 usum(B x) { // doesn't consume; will error on non-integers, or elements <0, f64* p = f64any_ptr(x); for (usz i = 0; i < xia; i++) { f64 c = p[i]; + if (!q_fu64(c)) expU_f64(c); u64 ci = (u64)c; - if (c!=ci) thrM("Expected integer"); if (ci<0) goto neg; if (addOn(r,ci)) goto overflow; } } else { - SGetU(x) - for (usz i = 0; i < xia; i++) { - u64 c = o2u64(GetU(x,i)); - if (c<0) thrM("Didn't expect negative integer"); - if (addOn(r,c)) goto overflow; - } + return usum_generic(x, xia); } + return r; + overflow: thrM("Sum too big"); - neg: thrM("Didn't expect negative integer"); + neg: return usum_generic(x, xia); // ensure proper error message } B select_c1(B, B); diff --git a/src/core/stuff.c b/src/core/stuff.c index 4d54253d..380ce6a0 100644 --- a/src/core/stuff.c +++ b/src/core/stuff.c @@ -360,6 +360,34 @@ NOINLINE void thrF(char* p, ...) { thr(r); } +char* genericDesc(B x) { + if (isNum(x)) return "number"; + if (isC32(x)) return "character"; + if (isArr(x)) return "array"; + if (isFun(x)) return "function"; + if (isMd1(x)) return "1-modifier"; + if (isMd2(x)) return "2-modifier"; + if (isNsp(x)) return "namespace"; + return "object of unknown type"; +} + +NOINLINE NORETURN void expI_B(B what) { + if (isF64(what)) expI_f64(o2fG(what)); + thrF("Expected integer, got %S", genericDesc(what)); +} +NOINLINE NORETURN void expU_B(B what) { + if (isF64(what)) expU_f64(o2fG(what)); + thrF("Expected non-negative integer, got %S", genericDesc(what)); +} +NOINLINE NORETURN void expI_f64(f64 what) { + if (what != floor(what)) thrF("Expected integer, got %f", what); + thrF("Integer out of range: %f", what); +} +NOINLINE NORETURN void expU_f64(f64 what) { + if (what != floor(what) || what < 0) thrF("Expected non-negative integer, got %f", what); + thrF("Integer out of range: %f", what); +} + usz depthF(B x) { // doesn't consume diff --git a/src/core/stuff.h b/src/core/stuff.h index 99930a34..b61063b6 100644 --- a/src/core/stuff.h +++ b/src/core/stuff.h @@ -227,6 +227,7 @@ char* pfn_repr(u8 u); char* pm1_repr(u8 u); char* pm2_repr(u8 u); char* eltype_repr(u8 u); +char* genericDesc(B x); // doesn't consume bool isPureFn(B x); // doesn't consume bool isStr(B x); // doesn't consume; returns if x is a rank 1 array of characters (includes any empty array) B bqn_merge(B x, u32 type); // consumes diff --git a/src/h.h b/src/h.h index 517d3621..89377bb6 100644 --- a/src/h.h +++ b/src/h.h @@ -95,6 +95,7 @@ typedef size_t ux; #define I32_MIN -2147483648 #define I32_MAX 2147483647 #define I64_MIN ((i64)(1ULL<<63)) +#define I64_MAX ((i64)((1ULL<<63)-1)) #define CHR_MAX 1114111 #define U8_MAX ((u8 )~(u8 )0) #define U16_MAX ((u16)~(u16)0) @@ -474,13 +475,15 @@ FORCE_INLINE bool q_N (B x) { return x.u==bi_N.u; } // is · FORCE_INLINE bool noFill(B x) { return x.u==bi_noFill.u; } +NORETURN void expI_f64(f64 what); NORETURN void expI_B(B what); +NORETURN void expU_f64(f64 what); NORETURN void expU_B(B what); FORCE_INLINE bool o2bG(B x) { return(x.u<<1)!=0;} FORCE_INLINE bool o2b(B x) { i32 t=(i32)x.f; if(t!=x.f || t!=0&t!=1)thrM("Expected boolean"); return o2bG(x); } -FORCE_INLINE i32 o2iG(B x) { return (i32)x.f; } FORCE_INLINE i32 o2i(B x) { if (!q_i32(x)) thrM("Expected integer"); return o2iG(x); } -FORCE_INLINE u32 o2cG(B x) { return (u32)x.u; } FORCE_INLINE u32 o2c(B x) { if (!isC32(x)) thrM("Expected character"); return o2cG(x); } -FORCE_INLINE usz o2sG(B x) { return (usz)x.f; } FORCE_INLINE usz o2s(B x) { if (!q_usz(x)) thrM("Expected non-negative integer"); return o2sG(x); } -FORCE_INLINE f64 o2fG(B x) { return x.f; } FORCE_INLINE f64 o2f(B x) { if (!isNum(x)) thrM("Expected number"); return o2fG(x); } -FORCE_INLINE i64 o2i64G(B x) { return (i64)x.f; } FORCE_INLINE i64 o2i64(B x) { if (!q_i64(x)) thrM("Expected integer"); return o2i64G(x); } -FORCE_INLINE u64 o2u64G(B x) { return (u64)x.f; } FORCE_INLINE u64 o2u64(B x) { if (!q_u64(x)) thrM("Expected integer"); return o2u64G(x); } +FORCE_INLINE i32 o2iG(B x) { return (i32)x.f; } FORCE_INLINE i32 o2i(B x) { if (!q_i32(x)) expI_B(x); return o2iG(x); } +FORCE_INLINE u32 o2cG(B x) { return (u32)x.u; } FORCE_INLINE u32 o2c(B x) { if (!isC32(x)) thrM("Expected character"); return o2cG(x); } +FORCE_INLINE usz o2sG(B x) { return (usz)x.f; } FORCE_INLINE usz o2s(B x) { if (!q_usz(x)) expU_B(x); return o2sG(x); } +FORCE_INLINE f64 o2fG(B x) { return x.f; } FORCE_INLINE f64 o2f(B x) { if (!isNum(x)) thrM("Expected number"); return o2fG(x); } +FORCE_INLINE i64 o2i64G(B x) { return (i64)x.f; } FORCE_INLINE i64 o2i64(B x) { if (!q_i64(x)) expI_B(x); return o2i64G(x); } +FORCE_INLINE u64 o2u64G(B x) { return (u64)x.f; } FORCE_INLINE u64 o2u64(B x) { if (!q_u64(x)) expU_B(x); return o2u64G(x); } // some aliases for macro-generated code typedef u8 c8; typedef u16 c16; typedef u32 c32; diff --git a/test/cases/prims.bqn b/test/cases/prims.bqn index a325295c..3ab9747d 100644 --- a/test/cases/prims.bqn +++ b/test/cases/prims.bqn @@ -62,16 +62,20 @@ 2‿3‿0‿1/4‿3⥊↕⋈12 %% ⋈¨6‿3⥊0‿1‿2‿0‿1‿2‿3‿4‿5‿3‿4‿5‿3‿4‿5‿9‿10‿11 2‿3‿0‿1/↕4 %% 6⥊0‿0‿1‿1‿1‿3 2‿3‿0‿1/↕⋈4 %% ⋈¨6⥊0‿0‿1‿1‿1‿3 -!"Didn't expect negative integer" % 2‿¯3/↕2 +!"Expected non-negative integer, got ¯3" % 2‿¯3/↕2 +!"Expected non-negative integer, got ¯3e20" % 2‿¯3e20/↕2 !"/: Lengths of components of 𝕨 must match 𝕩 (3 ≠ 4)" % 1‿2‿3/4‿5‿6‿7 -!"Didn't expect negative integer" % (4/1000‿¯1000) / 8⥊1 -!"Didn't expect negative integer" % (4/1000‿¯1000) / 8⥊1 +!"Expected non-negative integer, got ¯1000" % (4/1000‿¯1000) / 8⥊1 +!"Expected non-negative integer, got ¯1000" % (4/1000‿¯1000) / 8⥊1 +%USE tvar ⋄ ∧⍷ ⥊ 2‿4e19 0∘/⎊(•CurrentError∘@) _tvar ↕2 %% ⟨"Integer out of range: 4e19"⟩ # /𝕩 -!"Didn't expect negative integer" % / 4/1000‿¯1000 +!"Expected non-negative integer, got ¯1000" % / 4/1000‿¯1000 !"/: Argument must have rank 1 (3‿3 ≡ ≢𝕩)" % /↕3‿3 !"/: Argument must have rank 1 (⟨⟩ ≡ ≢𝕩)" % /0 -%USE tvar ⋄ ∧⍷ /⎊•CurrentError _tvar ¯1⌾(100⊸⊑) 200⥊10 %% "Didn't expect negative integer"‿"Expected integer" # TODO shouldn't have different error messages +%USE tvar ⋄ ∧⍷ 0∘/⎊•CurrentError _tvar ¯1⌾(100⊸⊑) 200⥊10 %% ⟨"Expected non-negative integer, got ¯1"⟩ +%USE tvar ⋄ ∧⍷ 0∘/⎊•CurrentError _tvar 1e2⥊2⋆62 %% ⟨"Sum too big"⟩ +%USE tvar ⋄ ∧⍷ 0∘/⎊•CurrentError _tvar 1e20⌾(100⊸⊑) 200⥊10 %% ⟨"Integer out of range: 1e20"⟩ ! (//⁼)⊸≡8‿15‿25‿32‿90‿101‿155‿165‿584‿594‿894‿912‿1312‿1328‿1350‿1367‿1391‿1407‿1469‿1486‿1559‿1566‿1576‿1582‿1592‿1599‿1609‿1616‿1626‿1635‿4086‿4093‿4114‿4122‿4141‿4149‿4169‿4177 # 𝕨⊏𝕩 @@ -83,10 +87,10 @@ !"⊏: Indexing out-of-bounds (¯24∊𝕨, 4≡≠𝕩)" % 1‿¯24⊏↕4‿4 !"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % (1‿¯26∾@)⊏@∾↕5 !"⊏: Indexing out-of-bounds (¯26∊𝕨, 5≡≠𝕩)" % ¯26⊏↕5 -!"Expected integer" % ¯26.5⊏↕5 +!"Expected integer, got ¯26.5" % ¯26.5⊏↕5 !"⊏: Indexing out-of-bounds (¯26∊𝕨, 5≡≠𝕩)" % 1‿¯26⊏↕5 !"⊏: Indexing out-of-bounds (26∊𝕨, 5≡≠𝕩)" % 1‿26⊏↕5 -!"Expected integer" % 0‿1.1‿2 ⊏ ↕10 +!"Expected integer, got 1.1" % 0‿1.1‿2 ⊏ ↕10 !"⊏: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % 0‿0‿1 ⊏ 1‿3⥊↕10000 !"⊏: Indexing out-of-bounds (2∊𝕨, 2≡≠𝕩)" % (1+9=↕10)⊏⟨1‿2,3⟩ %USE tvar ⋄ !∘≡¨⟜⊏ ∾ {⥊𝕨 ⊏⎊(•CurrentError∘⊢) _tvar 𝕩}´¨ ⟨⟨0‿1, ⋈0⟩ ⋄ ⟨0‿1, "?"⟩ ⋄ ⟨0‿1, ≍0‿1⟩⟩ @@ -226,8 +230,8 @@ w←1‿1⥊1 ⋄ x←2⥊1 ⋄ w‿x <¨↩ ⋄ {! (∾⟨•Repr𝕩,": Expe !"⊔: ≠𝕨 must be either ≠𝕩 or one bigger (2≡≠𝕨, 3≡≠𝕩)" % 0‿0⊔↕3 # ↕𝕩 -!"Expected non-negative integer" % ↕@ -!"Expected non-negative integer" % ↕"hi" +!"Expected non-negative integer, got character" % ↕@ +!"Expected non-negative integer, got character" % ↕"hi" !"↕: Argument must be either an integer or integer list (had rank 2)" % ↕2‿2⥊1 !"↕: Result rank too large (300≡≠𝕩)" % ↕300⥊1