diff --git a/moo/kernel/Mill.moo b/moo/kernel/Mill.moo index dd6e37e..15f4027 100644 --- a/moo/kernel/Mill.moo +++ b/moo/kernel/Mill.moo @@ -90,6 +90,7 @@ class MyObject(Object) ifFalse: [ (ffi call: #getpid signature: ')i' arguments: nil) dump. (ffi call: #printf signature: 's|iis)i' arguments: #(S'A=>%d B=>%d Hello, world %s\n' 1 2 'fly away')) dump. + (ffi call: #printf signature: 's|iis)i' arguments: #(S'A=>%d B=>%d Hello, world %s\n' 1 2 'jump down')) dump. ffi close. ] } diff --git a/moo/lib/main.c b/moo/lib/main.c index a6ba2f1..053ca6d 100644 --- a/moo/lib/main.c +++ b/moo/lib/main.c @@ -651,6 +651,7 @@ int main (int argc, char* argv[]) return -1; } + { moo_oow_t tab_size; diff --git a/moo/lib/moo-utl.h b/moo/lib/moo-utl.h index 357e895..a4acda5 100644 --- a/moo/lib/moo-utl.h +++ b/moo/lib/moo-utl.h @@ -303,7 +303,6 @@ MOO_EXPORT int moo_convutf8toucstr ( ); - MOO_EXPORT moo_oow_t moo_uctoutf8 ( moo_uch_t uc, moo_bch_t* utf8, diff --git a/moo/lib/moo.h b/moo/lib/moo.h index f7e4672..5631a61 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1434,6 +1434,66 @@ int moo_convutobcstr ( moo_oow_t* bcslen ); + +#if defined(MOO_OOCH_IS_UCH) +# define moo_dupootobchars(moo,oocs,oocslen,bcslen) moo_duputobchars(moo,oocs,oocslen,bcslen) +# define moo_dupbtooochars(moo,bcs,bcslen,oocslen) moo_dupbtouchars(moo,bcs,bcslen,oocslen) +# define moo_dupootobcstr(moo,oocs,bcslen) moo_duputobcstr(moo,oocs,bcslen) +# define moo_dupbtooocstr(moo,bcs,oocslen) moo_dupbtoucstr(moo,bcs,oocslen) +#else +# define moo_dupootouchars(moo,oocs,oocslen,ucslen) moo_dupbtouchars(moo,oocs,oocslen,ucslen) +# define moo_duputooochars(moo,ucs,ucslen,oocslen) moo_duputobchars(moo,ucs,ucslen,oocslen) +# define moo_dupootoucstr(moo,oocs,ucslen) moo_dupbtoucstr(moo,oocs,ucslen) +# define moo_duputooocstr(moo,ucs,oocslen) moo_duputobcstr(moo,ucs,oocslen) +#endif + + +MOO_EXPORT moo_uch_t* moo_dupbtouchars ( + moo_t* moo, + const moo_bch_t* bcs, + moo_oow_t bcslen, + moo_oow_t* ucslen +); + +MOO_EXPORT moo_bch_t* moo_duputobchars ( + moo_t* moo, + const moo_uch_t* ucs, + moo_oow_t ucslen, + moo_oow_t* bcslen +); + +MOO_EXPORT moo_uch_t* moo_dupbtoucstr ( + moo_t* moo, + const moo_bch_t* bcs, + moo_oow_t* ucslen /* optional: length of returned string */ +); + +MOO_EXPORT moo_bch_t* moo_duputobcstr ( + moo_t* moo, + const moo_uch_t* ucs, + moo_oow_t* bcslen /* optional: length of returned string */ +); + + +#if defined(MOO_OOCH_IS_UCH) +# define moo_dupoochars(moo,oocs,oocslen) moo_dupuchars(moo,oocs,oocslen) +#else +# define moo_dupoochars(moo,oocs,oocslen) moo_dupbchars(moo,oocs,oocslen) +#endif + +MOO_EXPORT moo_uch_t* moo_dupuchars ( + moo_t* moo, + const moo_uch_t* ucs, + moo_oow_t ucslen +); + +MOO_EXPORT moo_bch_t* moo_dupbchars ( + moo_t* moo, + const moo_bch_t* bcs, + moo_oow_t bcslen +); + + /* ========================================================================= * MOO VM LOGGING * ========================================================================= */ diff --git a/moo/lib/utl.c b/moo/lib/utl.c index 52aa5eb..ea5d46f 100644 --- a/moo/lib/utl.c +++ b/moo/lib/utl.c @@ -672,40 +672,117 @@ int moo_convutobcstr (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* ucslen, moo_b moo_uch_t* moo_dupbtouchars (moo_t* moo, const moo_bch_t* bcs, moo_oow_t bcslen, moo_oow_t* ucslen) { - moo_oow_t inlen, reqlen; + moo_oow_t inlen, outlen; moo_uch_t* ptr; inlen = bcslen; - if (moo_convbtouchars (moo, bcs, &inlen, MOO_NULL, &reqlen) <= -1) + if (moo_convbtouchars (moo, bcs, &inlen, MOO_NULL, &outlen) <= -1) { - /* note it's also an error if no full conversion is possible in this function */ + /* note it's also an error if no full conversion is made in this function */ return MOO_NULL; } - ptr = moo_allocmem (moo, reqlen * MOO_SIZEOF(moo_uch_t)); + ptr = moo_allocmem (moo, (outlen + 1) * MOO_SIZEOF(moo_uch_t)); if (!ptr) return MOO_NULL; inlen = bcslen; - moo_convbtouchars (moo, bcs, &inlen, ptr, ucslen); + moo_convbtouchars (moo, bcs, &inlen, ptr, &outlen); + + /* moo_convbtouchars() doesn't null-terminate the target. + * but in moo_dupbtouchars(), i allocate space. so i don't mind + * null-terminating it with 1 extra character overhead */ + ptr[outlen] = '\0'; + if (ucslen) *ucslen = outlen; return ptr; } moo_bch_t* moo_duputobchars (moo_t* moo, const moo_uch_t* ucs, moo_oow_t ucslen, moo_oow_t* bcslen) { - moo_oow_t inlen, reqlen; + moo_oow_t inlen, outlen; moo_bch_t* ptr; inlen = ucslen; - if (moo_convutobchars (moo, ucs, &inlen, MOO_NULL, &reqlen) <= -1) + if (moo_convutobchars (moo, ucs, &inlen, MOO_NULL, &outlen) <= -1) { - /* note it's also an error if no full conversion is possible in this function */ + /* note it's also an error if no full conversion is made in this function */ return MOO_NULL; } - ptr = moo_allocmem (moo, reqlen * MOO_SIZEOF(moo_bch_t)); + ptr = moo_allocmem (moo, (outlen + 1) * MOO_SIZEOF(moo_bch_t)); if (!ptr) return MOO_NULL; inlen = ucslen; - moo_convutobchars (moo, ucs, &inlen, ptr, bcslen); + moo_convutobchars (moo, ucs, &inlen, ptr, &outlen); + + ptr[outlen] = '\0'; + if (bcslen) *bcslen = outlen; return ptr; } + +moo_uch_t* moo_dupbtoucstr (moo_t* moo, const moo_bch_t* bcs, moo_oow_t* ucslen) +{ + moo_oow_t inlen, outlen; + moo_uch_t* ptr; + + if (moo_convbtoucstr (moo, bcs, &inlen, MOO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MOO_NULL; + } + + outlen++; + ptr = moo_allocmem (moo, outlen * MOO_SIZEOF(moo_uch_t)); + if (!ptr) return MOO_NULL; + + moo_convbtoucstr (moo, bcs, &inlen, ptr, &outlen); + if (ucslen) *ucslen = outlen; + return ptr; +} + +moo_bch_t* moo_duputobcstr (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* bcslen) +{ + moo_oow_t inlen, outlen; + moo_bch_t* ptr; + + if (moo_convutobcstr (moo, ucs, &inlen, MOO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MOO_NULL; + } + + outlen++; + ptr = moo_allocmem (moo, outlen * MOO_SIZEOF(moo_bch_t)); + if (!ptr) return MOO_NULL; + + moo_convutobcstr (moo, ucs, &inlen, ptr, &outlen); + if (bcslen) *bcslen = outlen; + return ptr; +} + + +/* ----------------------------------------------------------------------- */ + +moo_uch_t* moo_dupuchars (moo_t* moo, const moo_uch_t* ucs, moo_oow_t ucslen) +{ + moo_uch_t* ptr; + + ptr = moo_allocmem (moo, (ucslen + 1) * MOO_SIZEOF(moo_uch_t)); + if (!ptr) return MOO_NULL; + + moo_copyuchars (ptr, ucs, ucslen); + ptr[ucslen] = '\0'; + return ptr; +} + +moo_bch_t* moo_dupbchars (moo_t* moo, const moo_bch_t* bcs, moo_oow_t bcslen) +{ + moo_bch_t* ptr; + + ptr = moo_allocmem (moo, (bcslen + 1) * MOO_SIZEOF(moo_bch_t)); + if (!ptr) return MOO_NULL; + + moo_copybchars (ptr, bcs, bcslen); + ptr[bcslen] = '\0'; + return ptr; +} + diff --git a/moo/mod/ffi.c b/moo/mod/ffi.c index f96720f..2cbd874 100644 --- a/moo/mod/ffi.c +++ b/moo/mod/ffi.c @@ -62,7 +62,7 @@ static moo_pfrc_t pf_open (moo_t* moo, moo_ooi_t nargs) if (nargs != 1) { moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + goto softfail; } rcv = (ffi_t*)MOO_STACK_GETRCV(moo, nargs); @@ -71,23 +71,23 @@ static moo_pfrc_t pf_open (moo_t* moo, moo_ooi_t nargs) if (!MOO_ISTYPEOF(moo, name, MOO_OBJ_TYPE_CHAR) || !MOO_OBJ_GET_FLAGS_EXTRA(name)) /* TODO: better null check instead of FLAGS_EXTREA check */ { moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + goto softfail; } if (!moo->vmprim.dl_open) { moo_seterrnum (moo, MOO_ENOIMPL); - goto reterr; + goto softfail; } rcv->handle = moo->vmprim.dl_open (moo, ((moo_oop_char_t)name)->slot, 0); - if (!rcv->handle) goto reterr; + if (!rcv->handle) goto softfail; MOO_DEBUG3 (moo, " %.*js => %p\n", MOO_OBJ_GET_SIZE(name), ((moo_oop_char_t)name)->slot, rcv->handle); MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; -reterr: +softfail: MOO_STACK_SETRETTOERROR (moo, nargs); return MOO_PF_SUCCESS; } @@ -99,7 +99,7 @@ static moo_pfrc_t pf_close (moo_t* moo, moo_ooi_t nargs) if (nargs != 0) { moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + goto softfail; } rcv = (ffi_t*)MOO_STACK_GETRCV(moo, nargs); @@ -107,7 +107,7 @@ static moo_pfrc_t pf_close (moo_t* moo, moo_ooi_t nargs) if (!moo->vmprim.dl_open) { moo_seterrnum (moo, MOO_ENOIMPL); - goto reterr; + goto softfail; } MOO_DEBUG1 (moo, " %p\n", rcv->handle); @@ -118,31 +118,11 @@ static moo_pfrc_t pf_close (moo_t* moo, moo_ooi_t nargs) MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; -reterr: +softfail: MOO_STACK_SETRETTOERROR (moo, nargs); return MOO_PF_SUCCESS; } -/* -struct bcstr_node_t -{ - stix_bch_t* ptr; - bcstr_node_t* next; -}; - -static bcstr_node_t* dupbcstr (moo_t* moo, bcstr_node_t* bcstr, const moo_bch_t* ptr) -{ - - moo_freemem ( -} - -static void free_bcstr_node (moo_t* moo, bcstr_node_t* bcstr) -{ - moo_freemem (moo, bcstr->ptr); - moo_freemem (moo, bcstr); -} -*/ - static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) { #if defined(USE_DYNCALL) @@ -153,31 +133,19 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) void* f; moo_oop_oop_t arr; int ellipsis = 0; - struct bcstr_node_t* bcstr; - if (nargs < 3) - { - moo_seterrnum (moo, MOO_EINVAL); - goto reterr; - } + if (nargs < 3) goto inval; rcv = (ffi_t*)MOO_STACK_GETRCV(moo, nargs); fun = MOO_STACK_GETARG(moo, nargs, 0); sig = MOO_STACK_GETARG(moo, nargs, 1); args = MOO_STACK_GETARG(moo, nargs, 2); - if (!MOO_ISTYPEOF(moo, sig, MOO_OBJ_TYPE_CHAR) || MOO_OBJ_GET_SIZE(sig) <= 0) - { - moo_seterrnum (moo, MOO_EINVAL); - goto reterr; - } + if (!MOO_ISTYPEOF(moo, sig, MOO_OBJ_TYPE_CHAR) || MOO_OBJ_GET_SIZE(sig) <= 0) goto inval; #if 0 - if (MOO_OBJ_GET_SIZE(sig) > 1 && MOO_CLASSOF(moo,args) != moo->_array) /* TODO: check if arr is a kind of array??? or check if it's indexed */ - { - moo_seterrnum (moo, MOO_EINVAL); - goto reterr; - } + /* TODO: check if arr is a kind of array??? or check if it's indexed */ + if (MOO_OBJ_GET_SIZE(sig) > 1 && MOO_CLASSOF(moo,args) != moo->_array) goto inval; #endif f = MOO_OOP_TO_SMPTR(fun); @@ -187,24 +155,21 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) if (!dc) { moo_seterrnum (moo, moo_syserrtoerrnum(errno)); - goto reterr; + goto softfail; } MOO_DEBUG2 (moo, " %p in %p\n", f, rcv->handle); - /*dcMode (dc, DC_CALL_C_DEFAULT); - dcReset (dc);*/ + dcMode (dc, DC_CALL_C_DEFAULT); + dcReset (dc); i = 0; if (i < MOO_OBJ_GET_SIZE(sig) && ((moo_oop_char_t)sig)->slot[i] == '|') { dcMode (dc, DC_CALL_C_ELLIPSIS); - if (dcGetError(dc) != DC_ERROR_NONE) - { - /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ - moo_seterrnum (moo, MOO_ENOIMPL); - goto reterr; - } + + /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ + if (dcGetError(dc) != DC_ERROR_NONE) goto noimpl; dcReset (dc); ellipsis = 1; i++; @@ -213,6 +178,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) for (j = 0; i < MOO_OBJ_GET_SIZE(sig); i++) { moo_ooch_t fmtc; + moo_oop_t arg; fmtc = ((moo_oop_char_t)sig)->slot[i]; @@ -227,46 +193,43 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) { dcMode (dc, DC_CALL_C_ELLIPSIS_VARARGS); - if (dcGetError(dc) != DC_ERROR_NONE) - { - /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ - moo_seterrnum (moo, MOO_ENOIMPL); - goto reterr; - } + /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ + if (dcGetError(dc) != DC_ERROR_NONE) goto noimpl; } continue; } - if (j >= MOO_OBJ_GET_SIZE(arr)) - { - moo_seterrnum (moo, MOO_EINVAL); - goto reterr; - } + /* more items in signature than the actual argument */ + if (j >= MOO_OBJ_GET_SIZE(arr)) goto inval; + arg = arr->slot[j]; switch (fmtc) { /* TODO: support more types... */ case 'c': - /* TODO: sanity check on the argument type */ + + if (!MOO_OOP_IS_CHAR(arg)) goto inval; dcArgChar (dc, MOO_OOP_TO_CHAR(arr->slot[j])); j++; break; case 'i': /* TODO: use moo_inttoooi () */ - dcArgInt (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + if (!MOO_OOP_IS_SMOOI(arg)) goto inval; + dcArgInt (dc, MOO_OOP_TO_SMOOI(arg)); j++; break; case 'l': +/* TODO: sanity check on the argument type - check if arr->slot[j] is SMOOI or bigint... */ /* TODO: use moo_inttoooi () */ - dcArgLong (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + dcArgLong (dc, MOO_OOP_TO_SMOOI(arg)); j++; break; case 'L': /* TODO: use moo_inttoooi () */ - dcArgLongLong (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + dcArgLongLong (dc, MOO_OOP_TO_SMOOI(arg)); j++; break; @@ -275,15 +238,34 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) #endif case 's': { - moo_oow_t bcslen, ucslen; - moo_bch_t bcs[1024]; /*TODO: dynamic length.... */ + moo_bch_t* ptr; - ucslen = MOO_OBJ_GET_SIZE(arr->slot[j]); - bcslen = MOO_COUNTOF(bcs); - moo_convootobcstr (moo, ((moo_oop_char_t)arr->slot[j])->slot, &ucslen, bcs, &bcslen); /* proper string conversion */ +/* TOOD: check if arg is a string. */ +/* TODO: free all duplicated strings after call */ + #if defined(MOO_OOCH_IS_UCH) + ptr = moo_dupootobchars (moo, ((moo_oop_char_t)arg)->slot, MOO_OBJ_GET_SIZE(arg), MOO_NULL); + if (!ptr) goto softfail; /* out of system memory or conversion error - soft failure */ + #else + ptr = moo_dupoochars (moo, ((moo_oop_char_t)arg)->slot, MOO_OBJ_GET_SIZE(arg)); + #endif - bcs[bcslen] = '\0'; - dcArgPointer (dc, bcs); + dcArgPointer (dc, ptr); + j++; + break; + } + + case 'S': + { + moo_uch_t* ptr; + + #if defined(MOO_OOCH_IS_UCH) + ptr = moo_dupoochars (moo, ((moo_oop_char_t)arg)->slot, MOO_OBJ_GET_SIZE(arg)); + #else + ptr = moo_dupootouchars (moo, ((moo_oop_char_t)arg)->slot, MOO_OBJ_GET_SIZE(arg), MOO_NULL); + if (!ptr) goto softfail; /* out of system memory or conversion error - soft failure */ + #endif + + dcArgPointer (dc, ptr); j++; break; } @@ -294,6 +276,8 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) } } +/* TODO: clean up strings duplicated... using moo_dupootobchars... */ + if (i >= MOO_OBJ_GET_SIZE(sig)) goto call_void; switch (((moo_oop_char_t)sig)->slot[i]) @@ -312,7 +296,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) moo_oop_t r; r = moo_ooitoint (moo, dcCallInt (dc, f)); - if (!r) goto oops; + if (!r) goto hardfail; MOO_STACK_SETRET (moo, nargs, r); break; } @@ -321,7 +305,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) { moo_oop_t r; r = moo_ooitoint (moo, dcCallLong (dc, f)); - if (!r) goto oops; + if (!r) goto hardfail; MOO_STACK_SETRET (moo, nargs, r); break; } @@ -337,7 +321,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) #else # error TODO:... #endif - if (!rr) goto oops; + if (!rr) goto hardfail; MOO_STACK_SETRET (moo, nargs, r); break; @@ -352,16 +336,45 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) case 's': { - moo_oow_t bcslen, ucslen; - moo_ooch_t ucs[1024]; /* TOOD: buffer size... */ moo_oop_t s; - char* r = dcCallPointer (dc, f); + moo_bch_t* r; + moo_ooch_t* ptr; + moo_oow_t len; - bcslen = strlen(r); - moo_convbtooochars (moo, r, &bcslen, ucs, &ucslen); /* error check... */ + r = dcCallPointer (dc, f); - s = moo_makestring(moo, ucs, ucslen); - if (!s) goto oops; + #if defined(MOO_OOCH_IS_UCH) + ptr = moo_dupbtooocstr (moo, r, &len); + if (!ptr) goto softfail; /* out of system memory or conversion error - still soft failure */ + s = moo_makestring(moo, ptr, len); + moo_freemem (moo, ptr); + #else + s = moo_makestring(moo, r, moo_countbcstr(r)); + #endif + if (!s) goto hardfail; /* out of object memory - hard failure*/ + + MOO_STACK_SETRET (moo, nargs, s); + break; + } + + case 'S': + { + moo_oop_t s; + moo_uch_t* r; + moo_ooch_t* ptr; + moo_oow_t len; + + r = dcCallPointer (dc, f); + + #if defined(MOO_OOCH_IS_UCH) + s = moo_makestring(moo, r, moo_countucstr(r)); + #else + ptr = moo_dupbtooocstr (moo, r, &len); + if (!ptr) goto softfail; /* out of system memory or conversion error - still soft failure */ + s = moo_makestring(moo, ptr, len); + moo_freemem (moo, ptr); + #endif + if (!s) goto hardfail; /* out of object memory - hard failure*/ MOO_STACK_SETRET (moo, nargs, s); break; @@ -374,15 +387,26 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) break; } +/* TODO: free all duplicated string arguments... */ dcFree (dc); return MOO_PF_SUCCESS; -reterr: +noimpl: + moo_seterrnum (moo, MOO_ENOIMPL); + goto softfail; + +inval: + moo_seterrnum (moo, MOO_EINVAL); + goto softfail; + +softfail: +/* TODO: free all duplicated string arguments... */ if (dc) dcFree(dc); MOO_STACK_SETRETTOERROR (moo, nargs); return MOO_PF_SUCCESS; -oops: +hardfail: +/* TODO: free all duplicated string arguments... */ if (dc) dcFree(dc); return MOO_PF_HARD_FAILURE; @@ -402,7 +426,7 @@ static moo_pfrc_t pf_getsym (moo_t* moo, moo_ooi_t nargs) if (nargs != 1) { moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + goto softfail; } rcv = (ffi_t*)MOO_STACK_GETRCV(moo, nargs); @@ -411,17 +435,17 @@ static moo_pfrc_t pf_getsym (moo_t* moo, moo_ooi_t nargs) if (!MOO_ISTYPEOF(moo,name,MOO_OBJ_TYPE_CHAR)) /* TODO: null check on the symbol name? */ { moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + goto softfail; } if (!moo->vmprim.dl_getsym) { moo_seterrnum (moo, MOO_ENOIMPL); - goto reterr; + goto softfail; } sym = moo->vmprim.dl_getsym (moo, rcv->handle, ((moo_oop_char_t)name)->slot); - if (!sym) goto reterr; + if (!sym) goto softfail; MOO_DEBUG4 (moo, " %.*js => %p in %p\n", MOO_OBJ_GET_SIZE(name), ((moo_oop_char_t)name)->slot, sym, rcv->handle); @@ -429,7 +453,7 @@ static moo_pfrc_t pf_getsym (moo_t* moo, moo_ooi_t nargs) MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(sym)); return MOO_PF_SUCCESS; -reterr: +softfail: MOO_STACK_SETRETTOERROR (moo, nargs); return MOO_PF_SUCCESS; }