diff --git a/src/README.md b/src/README.md index f6fc2a91..6499b7c8 100644 --- a/src/README.md +++ b/src/README.md @@ -216,5 +216,6 @@ A fancier message can be created with `thrF(message, …)` with printf-like (but ``` See `#define CATCH` in `src/h.h` for how to catch errors. -Use `assert(predicate)` for checks (for optimized builds they're replaced with `if (!predicate) invoke_undefined_behavior();` so it's still invoked!!). +Use `assert(predicate)` for checks (for optimized builds they're replaced with `if (!predicate) invoke_undefined_behavior();` so it's still invoked!!). `UD;` can be used to explicitly invoke undefined behavior (equivalent in behavior to `assert(false);`), which is useful for things like untaken `default` branches in `switch` statements. + There's also `err("message")` that (at least currently) is kept in optimized builds as-is, and always kills the process on being called. \ No newline at end of file diff --git a/src/builtins/sfns.c b/src/builtins/sfns.c index d8c386a5..7e38a23c 100644 --- a/src/builtins/sfns.c +++ b/src/builtins/sfns.c @@ -130,10 +130,11 @@ B shape_c2(B t, B w, B x) { } else { xf = getFillQ(x); if (xia<=1) { - if (xia==0) { + if (RARE(xia==0)) { thrM("⥊: Empty 𝕩 and non-empty result"); - dec(x); - x = inc(xf); + // if (xf.u == bi_noFill.u) thrM("⥊: No fill for empty array"); + // dec(x); + // x = inc(xf); } else { B n = TI(x,get)(x,0); dec(x); @@ -186,11 +187,11 @@ B shape_c2(B t, B w, B x) { extern B rt_pick; B pick_c1(B t, B x) { if (isAtm(x)) return x; - if (a(x)->ia==0) { + if (RARE(a(x)->ia==0)) { thrM("⊑: Argument cannot be empty"); - B r = getFillE(x); - dec(x); - return r; + // B r = getFillE(x); + // dec(x); + // return r; } B r = TI(x,get)(x, 0); dec(x); diff --git a/src/core.h b/src/core.h index b4c81187..2b1a5f80 100644 --- a/src/core.h +++ b/src/core.h @@ -10,7 +10,7 @@ #elif MM==2 #include "opt/mm_2buddy.h" #else - #error bad MM value + #error "bad MM value" #endif #include "core/gstack.h" diff --git a/src/core/mm.c b/src/core/mm.c index d4db6bf6..c39a26a4 100644 --- a/src/core/mm.c +++ b/src/core/mm.c @@ -7,5 +7,5 @@ #elif MM==2 #include "../opt/mm_2buddy.c" #else - #error bad MM value + #error "bad MM value" #endif diff --git a/src/h.h b/src/h.h index e61e8be2..0ee360f8 100644 --- a/src/h.h +++ b/src/h.h @@ -146,6 +146,9 @@ static const u16 VAL_TAG = 0b1111111111110 ; // FFF. 1111111111110............ void cbqn_init(void); +#if __STDC_IEC_559__ == 0 + #error "IEEE 754 floating point number support is required for CBQN" +#endif typedef union B { u64 u; f64 f; diff --git a/src/jit/nvm_x86_64.c b/src/jit/nvm_x86_64.c index e534f0ee..0c0ccec9 100644 --- a/src/jit/nvm_x86_64.c +++ b/src/jit/nvm_x86_64.c @@ -124,6 +124,10 @@ INS B i_SETM(B s, B f, B x, Scope** pscs, u32* bc) { POS_UPD; v_set(pscs, s, r, true); dec(s); return r; } +INS void i_SETH(B s, B x, Scope** pscs, u32* bc) { POS_UPD; + bool ok = v_seth(pscs, s, x); + if (!ok) thrM("VM: Header fallback NYI"); +} INS B i_SETNi( B x, Scope* sc, u32 p, u32* bc) { POS_UPD; v_setI(sc, p, inc(x), false); return x; } INS B i_SETUi( B x, Scope* sc, u32 p, u32* bc) { POS_UPD; v_setI(sc, p, inc(x), true ); return x; } INS B i_SETMi(B f, B x, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c2(f,v_getI(sc, p),x); dec(f); v_setI(sc, p, inc(r), true); return r; } @@ -571,6 +575,7 @@ Nvm_res m_nvm(Body* body) { case SETN: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETN); break; // (B s, B x, Scope** pscs, u32* bc) case SETU: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETU); break; // (B s, B x, Scope** pscs, u32* bc) case SETM: TOPp; GET(R_A1,1,1) GET(R_A2,2,1); LEAi(R_A3,R_SP,VAR(pscs,0)); IMM(R_A4,off); CCALL(i_SETM); break; // (B s, B f, B x, Scope** pscs, u32* bc) + case SETH: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETH); break; // (B s, B x, Scope** pscs, u32* bc) // TODO SETNi doesn't really need to update gStack case SETNi:TOPp; { u64 d=*bc++; u64 p=*bc++; GET(R_A1,0,2); LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); CCALL(i_SETNi); break; } // ( B x, Scope* sc, u32 p, u32* bc) case SETUi:TOPp; { u64 d=*bc++; u64 p=*bc++; GET(R_A1,0,2); LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); CCALL(i_SETUi); break; } // ( B x, Scope* sc, u32 p, u32* bc) diff --git a/src/vm.c b/src/vm.c index 156f44be..a0596703 100644 --- a/src/vm.c +++ b/src/vm.c @@ -47,8 +47,8 @@ i32 stackDiff(u32* p) { switch(*p) { default: UD; // case ARRO: case ARRM: return 1-p[1]; case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 1; case FN1Ci:case FN1Oi:case CHKV: case VFYM: case FLDO: case FLDM: case RETD: case NSPM: return 0; - case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case POPS: case OP2H: case SETH: case RETN: return -1; - case OP2D: case TR3D: case FN2C: case FN2O: case TR3O: return -2; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case POPS: case OP2H: case RETN: return -1; + case OP2D: case TR3D: case FN2C: case FN2O: case TR3O: case SETH: return -2; case SETN: return -1; case SETNi:return 0; case SETNv:return -1; case SETU: return -1; case SETUi:return 0; case SETUv:return -1; @@ -420,31 +420,55 @@ NOINLINE void v_setR(Scope* pscs[], B s, B x, bool upd) { B* sp = harr_ptr(s); usz ia = a(s)->ia; if (isAtm(x) || !eqShape(s, x)) { - if (isNsp(x)) { - for (u64 i = 0; i < ia; i++) { - B c = sp[i]; - if (isVar(c)) { - Scope* sc = pscs[(u16)(c.u>>32)]; - i32 nameID = sc->body->varIDs[(u32)c.u]; - v_set(pscs, c, ns_getU(x, sc->body->nsDesc->nameList, nameID), upd); - } else if (isExt(c)) { - ScopeExt* ext = pscs[(u16)(c.u>>32)]->ext; - v_set(pscs, c, ns_getNU(x, ext->vars[(u32)c.u + ext->varAm]), upd); - } else if (isObj(c)) { - assert(v(c)->type == t_fldAlias); - Scope* sc = pscs[0]; - FldAlias* cf = c(FldAlias,c); - v_set(pscs, cf->obj, ns_getU(x, sc->body->nsDesc->nameList, cf->p), upd); - } else thrM("Assignment: extracting non-name from namespace"); - } - return; + if (!isNsp(x)) thrM("Assignment: Mismatched shape for spread assignment"); + for (u64 i = 0; i < ia; i++) { + B c = sp[i]; + if (isVar(c)) { + Scope* sc = pscs[(u16)(c.u>>32)]; + i32 nameID = sc->body->varIDs[(u32)c.u]; + v_set(pscs, c, ns_getU(x, sc->body->nsDesc->nameList, nameID), upd); + } else if (isExt(c)) { + ScopeExt* ext = pscs[(u16)(c.u>>32)]->ext; + v_set(pscs, c, ns_getNU(x, ext->vars[(u32)c.u + ext->varAm]), upd); + } else if (isObj(c)) { + assert(v(c)->type == t_fldAlias); + Scope* sc = pscs[0]; + FldAlias* cf = c(FldAlias,c); + v_set(pscs, cf->obj, ns_getU(x, sc->body->nsDesc->nameList, cf->p), upd); + } else thrM("Assignment: extracting non-name from namespace"); } - thrM("Assignment: Mismatched shape for spread assignment"); + return; } BS2B xgetU = TI(x,getU); for (u64 i = 0; i < ia; i++) v_set(pscs, sp[i], xgetU(x,i), upd); } } +NOINLINE bool v_sethR(Scope* pscs[], B s, B x) { + assert(!isExt(s)); + VTY(s, t_harr); + B* sp = harr_ptr(s); + usz ia = a(s)->ia; + if (isAtm(x) || !eqShape(s, x)) { + if (!isNsp(x)) return false; + for (u64 i = 0; i < ia; i++) { + B c = sp[i]; + if (isVar(c)) { + Scope* sc = pscs[(u16)(c.u>>32)]; + i32 nameID = sc->body->varIDs[(u32)c.u]; + if (!v_seth(pscs, c, ns_getU(x, sc->body->nsDesc->nameList, nameID))) return false; + } else if (isObj(c)) { + assert(v(c)->type == t_fldAlias); + Scope* sc = pscs[0]; + FldAlias* cf = c(FldAlias,c); + if (!v_seth(pscs, cf->obj, ns_getU(x, sc->body->nsDesc->nameList, cf->p))) return false; + } else return false; + } + return true; + } + BS2B xgetU = TI(x,getU); + for (u64 i = 0; i < ia; i++) if (!v_seth(pscs, sp[i], xgetU(x,i))) return false; + return true; +} @@ -637,6 +661,11 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume ADD(r); break; } + case SETH: { P(s) P(x) GS_UPD; POS_UPD; + bool ok = v_seth(pscs, s, x); + if (!ok) thrM("VM: Header fallback NYI"); + break; + } case FLDO: { P(ns) GS_UPD; u32 p = *bc++; POS_UPD; if (!isNsp(ns)) thrM("Trying to read a field from non-namespace"); ADD(inc(ns_getU(ns, sc->body->nsDesc->nameList, p))); diff --git a/src/vm.h b/src/vm.h index 81b6c72d..7f77312b 100644 --- a/src/vm.h +++ b/src/vm.h @@ -195,6 +195,7 @@ static inline B v_get(Scope* pscs[], B s) { // get value representing s, replaci } NOINLINE void v_setR(Scope* pscs[], B s, B x, bool upd); // doesn't consume +NOINLINE bool v_sethR(Scope* pscs[], B s, B x); // doesn't consume static inline void v_setI(Scope* sc, u32 p, B x, bool upd) { // consumes x B prev = sc->vars[p]; if (upd) { @@ -207,3 +208,13 @@ static inline void v_set(Scope* pscs[], B s, B x, bool upd) { // doesn't consume if (RARE(!isVar(s))) v_setR(pscs, s, x, upd); else v_setI(pscs[(u16)(s.u>>32)], (u32)s.u, inc(x), upd); } + +static inline bool v_seth(Scope* pscs[], B s, B x) { // consumes both; s cannot contain extended variables + if (RARE(!isVar(s))) { + bool r = v_sethR(pscs, s, x); + dec(s); dec(x); + return r; + } + v_setI(pscs[(u16)(s.u>>32)], (u32)s.u, x, false); + return true; +}