diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index 10146f8..fc0a2d3 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -122,6 +122,7 @@ extend Apex method(#dual,#primitive) basicAt: index. method(#dual,#primitive) basicAt: index put: value. + method(#dual,#primitive) basicAt: index test: test oldvalue put: newvalue. method(#dual,#primitive) basicFillFrom: sindex with: value count: count. method(#dual,#primitive) basicShiftFrom: sindex to: dindex count: count. diff --git a/moo/kernel/Except.moo b/moo/kernel/Except.moo index 4f5d2db..69c72e0 100644 --- a/moo/kernel/Except.moo +++ b/moo/kernel/Except.moo @@ -174,7 +174,8 @@ extend Context if (eb notNil) { /* position of the temporary variable in the ensureBlock that indicates - * if the block has been evaluated */ + * if the block has been evaluated. see the method BlockContext>>ensure:. + * it is the position of the last temporary variable of the method */ pending_pos := ctx basicSize - 1. if (ctx basicAt: pending_pos) { diff --git a/moo/lib/exec.c b/moo/lib/exec.c index 8f70339..2a222cd 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -4048,6 +4048,7 @@ static pf_t pftab[] = { "Apex_addToBeFinalized", { pf_add_to_be_finalized, 0, 0 } }, { "Apex_basicAt:", { moo_pf_basic_at, 1, 1 } }, { "Apex_basicAt:put:", { moo_pf_basic_at_put, 2, 2 } }, + { "Apex_basicAt:test:put:", { moo_pf_basic_at_test_put, 3, 3 } }, { "Apex_basicFillFrom:with:count:", { moo_pf_basic_fill, 3, 3 } }, { "Apex_basicNew", { moo_pf_basic_new, 0, 0 } }, { "Apex_basicNew:", { moo_pf_basic_new, 1, 1 } }, diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 0869807..78cef41 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -1614,6 +1614,7 @@ moo_pfrc_t moo_pf_class (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); moo_pfrc_t moo_pf_basic_size (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); moo_pfrc_t moo_pf_basic_at (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); moo_pfrc_t moo_pf_basic_at_put (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); +moo_pfrc_t moo_pf_basic_at_test_put (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); moo_pfrc_t moo_pf_basic_fill (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); moo_pfrc_t moo_pf_basic_shift (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs); diff --git a/moo/lib/pf-basic.c b/moo/lib/pf-basic.c index 0b17f48..f937a24 100644 --- a/moo/lib/pf-basic.c +++ b/moo/lib/pf-basic.c @@ -378,7 +378,7 @@ moo_pfrc_t moo_pf_basic_at_put (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) pos = MOO_STACK_GETARG(moo, nargs, 0); val = MOO_STACK_GETARG(moo, nargs, 1); - if (moo_inttooow (moo, pos, &idx) <= 0) + if (moo_inttooow(moo, pos, &idx) <= 0) { /* negative integer or not integer */ moo_seterrbfmt (moo, MOO_EINVAL, "invalid position - %O", pos); @@ -428,7 +428,106 @@ moo_pfrc_t moo_pf_basic_at_put (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { moo_oow_t w; - if (moo_inttooow (moo, val, &w) <= 0) + if (moo_inttooow(moo, val, &w) <= 0) + { + /* the value is not a number, out of range, or negative */ + moo_seterrbfmt (moo, MOO_EINVAL, "value not a word integer - %O", val); + return MOO_PF_FAILURE; + } + MOO_OBJ_SET_WORD_VAL (rcv, idx, MOO_OOP_TO_SMOOI(val)); + break; + } + + case MOO_OBJ_TYPE_OOP: + MOO_STORE_OOP (moo, MOO_OBJ_GET_OOP_PTR(rcv, idx), val); + break; + + default: + moo_seterrnum (moo, MOO_EINTERN); + return MOO_PF_HARD_FAILURE; + } + +/* TODO: return receiver or value? */ + MOO_STACK_SETRET (moo, nargs, val); + return MOO_PF_SUCCESS; +} + +moo_pfrc_t moo_pf_basic_at_test_put (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + moo_oop_t rcv, pos, oldval, newval; + moo_oow_t idx; + + MOO_ASSERT (moo, nargs == 3); + + rcv = MOO_STACK_GETRCV(moo, nargs); + if (!MOO_OOP_IS_POINTER(rcv)) + { + /* the receiver is a special numeric object, not a normal pointer */ + moo_seterrbfmt (moo, MOO_EMSGRCV, "receiver not indexable - %O", rcv); + return MOO_PF_FAILURE; + } + + if (MOO_OBJ_GET_FLAGS_RDONLY(rcv)) + { + moo_seterrbfmt (moo, MOO_EPERM, "not allowed to change a read-only object - %O", rcv); + return MOO_PF_FAILURE; + } + + pos = MOO_STACK_GETARG(moo, nargs, 0); + oldval = MOO_STACK_GETARG(moo, nargs, 1); + newval = MOO_STACK_GETARG(moo, nargs, 1); + + if (moo_inttooow(moo, pos, &idx) <= 0) + { + /* negative integer or not integer */ + moo_seterrbfmt (moo, MOO_EINVAL, "invalid position - %O", pos); + return MOO_PF_FAILURE; + } + if (idx >= MOO_OBJ_GET_SIZE(rcv)) + { + /* index out of range */ + moo_seterrbfmt (moo, MOO_ERANGE, "position out of bound - %zu", idx); + return MOO_PF_FAILURE; + } + + switch (MOO_OBJ_GET_FLAGS_TYPE(rcv)) + { + case MOO_OBJ_TYPE_BYTE: + if (!MOO_OOP_IS_SMOOI(val)) + { + moo_seterrbfmt (moo, MOO_EINVAL, "value not a byte - %O", val); + return MOO_PF_FAILURE; + } +/* TOOD: must I check the range of the value? */ + MOO_OBJ_SET_BYTE_VAL (rcv, idx, MOO_OOP_TO_SMOOI(val)); + break; + + case MOO_OBJ_TYPE_CHAR: + if (!MOO_OOP_IS_CHAR(val)) + { + moo_seterrbfmt (moo, MOO_EINVAL, "value not a character - %O", val); + return MOO_PF_FAILURE; + } + MOO_OBJ_SET_CHAR_VAL (rcv, idx, MOO_OOP_TO_CHAR(val)); + break; + + case MOO_OBJ_TYPE_HALFWORD: + if (!MOO_OOP_IS_SMOOI(val)) + { + /* the value is not a number */ + moo_seterrbfmt (moo, MOO_EINVAL, "value not a half-word integer - %O", val); + return MOO_PF_FAILURE; + } + + /* if the small integer is too large, it will get truncated */ + MOO_OBJ_SET_HALFWORD_VAL (rcv, idx, MOO_OOP_TO_SMOOI(val)); + break; + + case MOO_OBJ_TYPE_WORD: + { + moo_oow_t w; + + if (moo_inttooow(moo, val, &w) <= 0) { /* the value is not a number, out of range, or negative */ moo_seterrbfmt (moo, MOO_EINVAL, "value not a word integer - %O", val);