diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 81c3c6a5..a4893b3a 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -1404,58 +1404,56 @@ B getNsNS(void) { typedef struct CastType { usz s; bool c; } CastType; -static bool isCharType(u8 t) { - return t==t_c8arr || t==t_c16arr || t==t_c32arr - || t==t_c8slice || t==t_c16slice || t==t_c32slice; +static bool isCharArr(B x) { + return elChr(TI(x,elType)); } -static CastType getCastType(B e, B v) { +static CastType getCastType(B e, bool hasVal, B val) { // returns a valid type (doesn't check if it can apply to val) usz s; bool c; if (isNum(e)) { s = o2s(e); - c = q_N(v) ? 0 : isCharType(TY(v)); + if (s!=1 && s!=8 && s!=16 && s!=32 && s!=64) thrF("•bit._cast: unsupported width %s", s); + c = hasVal? isCharArr(val) : 0; } else { if (!isArr(e) || RNK(e)!=1 || IA(e)!=2) thrM("•bit._cast: 𝕗 elements must be numbers or two-element lists"); SGetU(e) s = o2s(GetU(e,0)); u32 t = o2c(GetU(e,1)); c = t=='c'; - if (t=='n'); // generic number - else if (c ) { if (s<8||s>32) thrM("•bit._cast: unsupported character width"); } - else if (t=='i') { if (s<8||s>32) thrM("•bit._cast: unsupported integer width"); } - else if (t=='u') { if ( s>32) thrM("•bit._cast: unsupported integer width"); } - else if (t=='f') { if (s!=64) thrM("•bit._cast: type f only supports width 64"); } + if (c ) { if (s!=8 && s!=16 && s!=32) { badWidth: thrF("•bit._cast: unsupported width %s for type '%c'", s, (char)t); } } + else if (t=='i') { if (s!=8 && s!=16 && s!=32) goto badWidth; } + else if (t=='u') { if (s!=1) goto badWidth; } + else if (t=='f') { if (s!=64) goto badWidth; } else thrM("•bit._cast: type descriptor in 𝕗 must be one of \"iufnc\""); + } return (CastType) { s, c }; + } static B convert(CastType t, B x) { - switch (t.s) { + switch (t.s) { default: UD; case 1: return taga(toBitArr(x)); case 8: return t.c ? toC8Any (x) : toI8Any (x); case 16: return t.c ? toC16Any(x) : toI16Any(x); case 32: return t.c ? toC32Any(x) : toI32Any(x); case 64: return toF64Any(x); - default: thrM("•bit._cast: unsupported input width"); } } static TyArr* copy(CastType t, B x) { - switch (t.s) { + switch (t.s) { default: UD; case 1: return (TyArr*) (cpyBitArr(x)); case 8: return (TyArr*) (t.c ? cpyC8Arr (x) : cpyI8Arr (x)); case 16: return (TyArr*) (t.c ? cpyC16Arr(x) : cpyI16Arr(x)); case 32: return (TyArr*) (t.c ? cpyC32Arr(x) : cpyI32Arr(x)); case 64: return (TyArr*) (cpyF64Arr(x)); - default: thrM("•bit._cast: unsupported input width"); } } static u8 typeOfCast(CastType t) { - switch (t.s) { + switch (t.s) { default: UD; case 1: return t_bitarr; case 8: return t.c ? t_c8arr : t_i8arr ; case 16: return t.c ? t_c16arr : t_i16arr; case 32: return t.c ? t_c32arr : t_i32arr; case 64: return t_f64arr; - default: thrM("•bit._cast: unsupported result width"); } } static B set_bit_result(B r, u8 rt, ur rr, usz rl, usz *sh) { @@ -1484,8 +1482,8 @@ B bitcast_impl(B el0, B el1, B x) { ur xr; if (!isArr(x) || (xr=RNK(x))<1) thrM("•bit._cast: 𝕩 must have rank at least 1"); - CastType xct = getCastType(el0, x); - CastType rct = getCastType(el1, bi_N); + CastType xct = getCastType(el0, true, x); + CastType rct = getCastType(el1, false, m_f64(0)); usz* sh = SH(x); u64 s=xct.s*(u64)sh[xr-1], rl=s/rct.s; if (rl*rct.s != s) thrM("•bit._cast: incompatible lengths"); @@ -1553,7 +1551,7 @@ B bitop1(B f, B x, enum BitOp1 op, char* name) { if ((s & (ow-1)) || (rl<=USZ_MAX) thrF("•bit._%U: output too large", name); - x = convert((CastType){ xw, isCharType(TY(x)) }, x); + x = convert((CastType){ xw, isCharArr(x) }, x); u8 rt = typeOfCast((CastType){ rw, 0 }); u64* xp = tyany_ptr(x); B r; u64* rp; @@ -1628,8 +1626,8 @@ B bitop2(B f, B w, B x, enum BitOp2 op, char* name) { if ((t & (ow-1)) || (rl<=USZ_MAX) thrF("•bit._%U: output too large", name); - w = convert((CastType){ ww, isCharType(TY(w)) }, w); - x = convert((CastType){ xw, isCharType(TY(x)) }, x); + w = convert((CastType){ ww, isCharArr(w) }, w); + x = convert((CastType){ xw, isCharArr(x) }, x); u8 rt = typeOfCast((CastType){ rw, 0 }); Arr* ra = m_arr(offsetof(TyArr,a) + (n+7)/8, rt, n>>rws); arr_shCopyUnchecked(ra, x); diff --git a/test/cases/system.bqn b/test/cases/system.bqn index 0be77907..ee2cc756 100644 --- a/test/cases/system.bqn +++ b/test/cases/system.bqn @@ -282,6 +282,26 @@ r←•MakeRand 1 ⋄ ! 1¨⊸≡ ∊{𝕊: 500 r.Deal 1000}¨ ↕4 ! 10‿1 ≡ ≢8‿16•bit._cast c←0↓2↕'a'+11 •rand.Range 26 ⋄ ! 10‿2 ≡ ≢c ! 10‿1 ≡ ≢8‿16•bit._cast c← 2↕'a'+11 •rand.Range 26 ⋄ ! 10‿2 ≡ ≢c ⊑ 8‿32•bit._cast 3↓↕7 %% 100992003 +!"•bit._cast: incompatible lengths" % 1‿8•bit._cast 1⥊0 +!"•bit._cast: incompatible lengths" % 8‿32•bit._cast 2⥊0 +!"•bit._cast: incompatible lengths" % 8‿32•bit._cast 10⥊0 + +!"•bit._cast: unsupported width 1073741824" % (2⥊2⋆30)•bit._cast ⋈0 +!"Integer out of range: 1125899906842624" % (2⥊2⋆50)•bit._cast ⋈0 +!"Integer out of range: ∞" % (2⥊∞)•bit._cast ⋈0 + +!"•bit._cast: unsupported width 12" % 1‿12•bit._cast 11⥊0 +!"•bit._cast: unsupported width 12" % 12‿32•bit._cast (12×32)⥊0 +!"•bit._cast: unsupported width 12" % 8‿12•bit._cast (8×12)⥊0 +!"•bit._cast: unsupported width 0" % 0‿32•bit._cast 128⥊0 +!"•bit._cast: unsupported width 0" % 8‿0•bit._cast 128⥊0 + +!"•bit._cast: unsupported width 16 for type 'f'" % ⟨16‿'f',32⟩•bit._cast 128⥊0 +!"•bit._cast: unsupported width 32 for type 'f'" % ⟨32,32‿'f'⟩•bit._cast 128⥊0 +!"•bit._cast: unsupported width 0 for type 'u'" % ⟨0‿'u',32⟩•bit._cast 128⥊0 +!"•bit._cast: unsupported width 8 for type 'u'" % ⟨8‿'u',32⟩•bit._cast 128⥊0 +!"•bit._cast: unsupported width 32 for type 'u'" % ⟨8,32‿'u'⟩•bit._cast 128⥊0 +!"•bit._cast: unsupported width 1 for type 'i'" % ⟨8, 1‿'i'⟩•bit._cast 128⥊0 # •platform Str ← {!=𝕩 ⋄ !×≠𝕩 ⋄ ! ∧´2=•Type¨𝕩} ⋄ Str •platform.os ⋄ Str •platform.cpu.arch ⋄ Str •platform.bqn.impl_version ⋄ Str •platform.environment