diff --git a/moo/kernel/Mill.moo b/moo/kernel/Mill.moo index dcad1a1..dd6e37e 100644 --- a/moo/kernel/Mill.moo +++ b/moo/kernel/Mill.moo @@ -88,8 +88,9 @@ class MyObject(Object) (ffi isError) ifTrue: [System logNl: 'cannot open libc.so' ] ifFalse: [ - (ffi call: #getpid signature: 'i' arguments: nil) dump. + (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 close. ] } -} +} \ No newline at end of file diff --git a/moo/kernel/test-014.moo b/moo/kernel/test-014.moo index 6968b4b..d2ad668 100644 --- a/moo/kernel/test-014.moo +++ b/moo/kernel/test-014.moo @@ -242,4 +242,4 @@ extend MyObject System logNl: JJJ. System logNl: -200 asString. } -} +} \ No newline at end of file diff --git a/moo/lib/moo-rbt.h b/moo/lib/moo-rbt.h index 1ebe75e..3c414de 100644 --- a/moo/lib/moo-rbt.h +++ b/moo/lib/moo-rbt.h @@ -29,14 +29,14 @@ #include "moo-cmn.h" -/**@file +/**\file * This file provides a red-black tree encapsulated in the #moo_rbt_t type that * implements a self-balancing binary search tree.Its interface is very close * to #moo_htb_t. * * This sample code adds a series of keys and values and print them * in descending key order. - * @code + * \code * #include * #include * #include @@ -67,7 +67,7 @@ * moo_rbt_close (s1); * return 0; * } - * @endcode + * \endcode */ typedef struct moo_rbt_t moo_rbt_t; @@ -99,9 +99,9 @@ typedef enum moo_rbt_id_t moo_rbt_id_t; * The moo_rbt_copier_t type defines a pair contruction callback. */ typedef void* (*moo_rbt_copier_t) ( - moo_rbt_t* rbt /* red-black tree */, - void* dptr /* pointer to a key or a value */, - moo_oow_t dlen /* length of a key or a value */ + moo_rbt_t* rbt /**< red-black tree */, + void* dptr /**< pointer to a key or a value */, + moo_oow_t dlen /**< length of a key or a value */ ); /** @@ -109,7 +109,7 @@ typedef void* (*moo_rbt_copier_t) ( */ typedef void (*moo_rbt_freeer_t) ( moo_rbt_t* rbt, /**< red-black tree */ - void* dptr, /**< pointer to a key or a value */ + void* dptr, /**< pointer to a key or a value */ moo_oow_t dlen /**< length of a key or a value */ ); @@ -123,9 +123,9 @@ typedef void (*moo_rbt_freeer_t) ( typedef int (*moo_rbt_comper_t) ( const moo_rbt_t* rbt, /**< red-black tree */ const void* kptr1, /**< key pointer */ - moo_oow_t klen1, /**< key length */ + moo_oow_t klen1, /**< key length */ const void* kptr2, /**< key pointer */ - moo_oow_t klen2 /**< key length */ + moo_oow_t klen2 /**< key length */ ); /** @@ -152,8 +152,8 @@ typedef moo_rbt_walk_t (*moo_rbt_walker_t) ( /** * The moo_rbt_cbserter_t type defines a callback function for moo_rbt_cbsert(). * The moo_rbt_cbserter() function calls it to allocate a new pair for the - * key pointed to by @a kptr of the length @a klen and the callback context - * @a ctx. The second parameter @a pair is passed the pointer to the existing + * key pointed to by \a kptr of the length \a klen and the callback context + * \a ctx. The second parameter \a pair is passed the pointer to the existing * pair for the key or #MOO_NULL in case of no existing key. The callback * must return a pointer to a new or a reallocated pair. When reallocating the * existing pair, this callback must destroy the existing pair and return the @@ -162,9 +162,9 @@ typedef moo_rbt_walk_t (*moo_rbt_walker_t) ( typedef moo_rbt_pair_t* (*moo_rbt_cbserter_t) ( moo_rbt_t* rbt, /**< red-black tree */ moo_rbt_pair_t* pair, /**< pair pointer */ - void* kptr, /**< key pointer */ - moo_oow_t klen, /**< key length */ - void* ctx /**< callback context */ + void* kptr, /**< key pointer */ + moo_oow_t klen, /**< key length */ + void* ctx /**< callback context */ ); /** @@ -177,7 +177,7 @@ struct moo_rbt_pair_t { struct { - void* ptr; + void* ptr; moo_oow_t len; } key; @@ -290,13 +290,13 @@ MOO_EXPORT const moo_rbt_style_t* moo_getrbtstyle ( /** * The moo_rbt_open() function creates a red-black tree. - * @return moo_rbt_t pointer on success, MOO_NULL on failure. + * \return moo_rbt_t pointer on success, MOO_NULL on failure. */ MOO_EXPORT moo_rbt_t* moo_rbt_open ( moo_t* moo, moo_oow_t xtnsize, /**< extension size in bytes */ - int kscale, /**< key scale */ - int vscale /**< value scale */ + int kscale, /**< key scale */ + int vscale /**< value scale */ ); /** @@ -312,8 +312,8 @@ MOO_EXPORT void moo_rbt_close ( MOO_EXPORT int moo_rbt_init ( moo_rbt_t* rbt, /**< red-black tree */ moo_t* moo, - int kscale, /**< key scale */ - int vscale /**< value scale */ + int kscale, /**< key scale */ + int vscale /**< value scale */ ); /** @@ -357,13 +357,13 @@ MOO_EXPORT moo_oow_t moo_rbt_getsize ( * The moo_rbt_search() function searches red-black tree to find a pair with a * matching key. It returns the pointer to the pair found. If it fails * to find one, it returns MOO_NULL. - * @return pointer to the pair with a maching key, + * \return pointer to the pair with a maching key, * or MOO_NULL if no match is found. */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_search ( const moo_rbt_t* rbt, /**< red-black tree */ - const void* kptr, /**< key pointer */ - moo_oow_t klen /**< the size of the key */ + const void* kptr, /**< key pointer */ + moo_oow_t klen /**< the size of the key */ ); /** @@ -371,56 +371,56 @@ MOO_EXPORT moo_rbt_pair_t* moo_rbt_search ( * matching key. If one is found, it updates the pair. Otherwise, it inserts * a new pair with the key and the value given. It returns the pointer to the * pair updated or inserted. - * @return a pointer to the updated or inserted pair on success, + * \return a pointer to the updated or inserted pair on success, * MOO_NULL on failure. */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_upsert ( moo_rbt_t* rbt, /**< red-black tree */ - void* kptr, /**< key pointer */ - moo_oow_t klen, /**< key length */ - void* vptr, /**< value pointer */ - moo_oow_t vlen /**< value length */ + void* kptr, /**< key pointer */ + moo_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + moo_oow_t vlen /**< value length */ ); /** * The moo_rbt_ensert() function inserts a new pair with the key and the value * given. If there exists a pair with the key given, the function returns * the pair containing the key. - * @return pointer to a pair on success, MOO_NULL on failure. + * \return pointer to a pair on success, MOO_NULL on failure. */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_ensert ( moo_rbt_t* rbt, /**< red-black tree */ - void* kptr, /**< key pointer */ - moo_oow_t klen, /**< key length */ - void* vptr, /**< value pointer */ - moo_oow_t vlen /**< value length */ + void* kptr, /**< key pointer */ + moo_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + moo_oow_t vlen /**< value length */ ); /** * The moo_rbt_insert() function inserts a new pair with the key and the value * given. If there exists a pair with the key given, the function returns * MOO_NULL without channging the value. - * @return pointer to the pair created on success, MOO_NULL on failure. + * \return pointer to the pair created on success, MOO_NULL on failure. */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_insert ( moo_rbt_t* rbt, /**< red-black tree */ - void* kptr, /**< key pointer */ - moo_oow_t klen, /**< key length */ - void* vptr, /**< value pointer */ - moo_oow_t vlen /**< value length */ + void* kptr, /**< key pointer */ + moo_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + moo_oow_t vlen /**< value length */ ); /** * The moo_rbt_update() function updates the value of an existing pair * with a matching key. - * @return pointer to the pair on success, MOO_NULL on no matching pair + * \return pointer to the pair on success, MOO_NULL on no matching pair */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_update ( moo_rbt_t* rbt, /**< red-black tree */ void* kptr, /**< key pointer */ - moo_oow_t klen, /**< key length */ + moo_oow_t klen, /**< key length */ void* vptr, /**< value pointer */ - moo_oow_t vlen /**< value length */ + moo_oow_t vlen /**< value length */ ); /** @@ -431,7 +431,7 @@ MOO_EXPORT moo_rbt_pair_t* moo_rbt_update ( * a new pair if the key is not found and appends the new value to the * existing value delimited by a comma if the key is found. * - * @code + * \code * moo_rbt_walk_t print_map_pair (moo_rbt_t* map, moo_rbt_pair_t* pair, void* ctx) * { * moo_printf (MOO_T("%.*s[%d] => %.*s[%d]\n"), @@ -508,24 +508,24 @@ MOO_EXPORT moo_rbt_pair_t* moo_rbt_update ( * moo_rbt_close (s1); * return 0; * } - * @endcode + * \endcode */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_cbsert ( moo_rbt_t* rbt, /**< red-black tree */ - void* kptr, /**< key pointer */ + void* kptr, /**< key pointer */ moo_oow_t klen, /**< key length */ moo_rbt_cbserter_t cbserter, /**< callback function */ - void* ctx /**< callback context */ + void* ctx /**< callback context */ ); /** * The moo_rbt_delete() function deletes a pair with a matching key - * @return 0 on success, -1 on failure + * \return 0 on success, -1 on failure */ MOO_EXPORT int moo_rbt_delete ( - moo_rbt_t* rbt, /**< red-black tree */ - const void* kptr, /**< key pointer */ - moo_oow_t klen /**< key size */ + moo_rbt_t* rbt, /**< red-black tree */ + const void* kptr, /**< key pointer */ + moo_oow_t klen /**< key size */ ); /** @@ -542,7 +542,7 @@ MOO_EXPORT void moo_rbt_clear ( MOO_EXPORT void moo_rbt_walk ( moo_rbt_t* rbt, /**< red-black tree */ moo_rbt_walker_t walker, /**< callback function for each pair */ - void* ctx /**< pointer to user-specific data */ + void* ctx /**< pointer to user-specific data */ ); /** @@ -552,32 +552,32 @@ MOO_EXPORT void moo_rbt_walk ( MOO_EXPORT void moo_rbt_rwalk ( moo_rbt_t* rbt, /**< red-black tree */ moo_rbt_walker_t walker, /**< callback function for each pair */ - void* ctx /**< pointer to user-specific data */ + void* ctx /**< pointer to user-specific data */ ); /** * The moo_rbt_allocpair() function allocates a pair for a key and a value - * given. But it does not chain the pair allocated into the red-black tree @a rbt. + * given. But it does not chain the pair allocated into the red-black tree \a rbt. * Use this function at your own risk. * * Take note of he following special behavior when the copier is * #MOO_RBT_COPIER_INLINE. - * - If @a kptr is #MOO_NULL, the key space of the size @a klen is reserved but + * - If \a kptr is #MOO_NULL, the key space of the size \a klen is reserved but * not propagated with any data. - * - If @a vptr is #MOO_NULL, the value space of the size @a vlen is reserved + * - If \a vptr is #MOO_NULL, the value space of the size \a vlen is reserved * but not propagated with any data. */ MOO_EXPORT moo_rbt_pair_t* moo_rbt_allocpair ( - moo_rbt_t* rbt, + moo_rbt_t* rbt, void* kptr, - moo_oow_t klen, + moo_oow_t klen, void* vptr, - moo_oow_t vlen + moo_oow_t vlen ); /** * The moo_rbt_freepair() function destroys a pair. But it does not detach - * the pair destroyed from the red-black tree @a rbt. Use this function at your + * the pair destroyed from the red-black tree \a rbt. Use this function at your * own risk. */ MOO_EXPORT void moo_rbt_freepair ( @@ -590,10 +590,10 @@ MOO_EXPORT void moo_rbt_freepair ( */ MOO_EXPORT int moo_rbt_dflcomp ( const moo_rbt_t* rbt, - const void* kptr1, - moo_oow_t klen1, - const void* kptr2, - moo_oow_t klen2 + const void* kptr1, + moo_oow_t klen1, + const void* kptr2, + moo_oow_t klen2 ); #if defined(__cplusplus) diff --git a/moo/lib/utf8.c b/moo/lib/utf8.c index f717acc..9a2e83f 100644 --- a/moo/lib/utf8.c +++ b/moo/lib/utf8.c @@ -45,7 +45,7 @@ struct __utf8_t moo_uint8_t fbyte; /* mask to the first utf8 byte */ moo_uint8_t mask; moo_uint8_t fmask; - int length; /* number of bytes */ + int length; /* number of bytes */ }; typedef struct __utf8_t __utf8_t; diff --git a/moo/mod/ffi.c b/moo/mod/ffi.c index 77003e7..bbec3be 100644 --- a/moo/mod/ffi.c +++ b/moo/mod/ffi.c @@ -122,12 +122,36 @@ reterr: 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) ffi_t* rcv; moo_oop_t fun, sig, args; + DCCallVM* dc = MOO_NULL; + moo_oow_t i, j; + void* f; + moo_oop_oop_t arr; + int ellipsis = 0; + struct bcstr_node_t* bcstr; if (nargs < 3) { @@ -146,192 +170,220 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_ooi_t nargs) goto reterr; } +#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; } +#endif + f = MOO_OOP_TO_SMPTR(fun); + arr = (moo_oop_oop_t)args; + + dc = dcNewCallVM (4096); /* TODO: right size? */ + if (!dc) { - moo_oow_t i; - DCCallVM* dc; - void* f; - moo_oop_oop_t arr; - int mode_set; + moo_seterrnum (moo, moo_syserrtoerrnum(errno)); + goto reterr; + } - f = MOO_OOP_TO_SMPTR(fun); - arr = (moo_oop_oop_t)args; + MOO_DEBUG2 (moo, " %p in %p\n", f, rcv->handle); - dc = dcNewCallVM (4096); - if (!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) { - moo_seterrnum (moo, moo_syserrtoerrnum(errno)); + /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ + moo_seterrnum (moo, MOO_ENOIMPL); + goto reterr; + } + dcReset (dc); + ellipsis = 1; + i++; + } + + for (j = 0; i < MOO_OBJ_GET_SIZE(sig); i++) + { + moo_ooch_t fmtc; + + fmtc = ((moo_oop_char_t)sig)->slot[i]; + + if (fmtc == ')') + { + i++; + break; + } + else if (fmtc == '|') + { + if (ellipsis) + { + 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; + } + } + continue; + } + + if (j >= MOO_OBJ_GET_SIZE(arr)) + { + moo_seterrnum (moo, MOO_EINVAL); goto reterr; } - MOO_DEBUG2 (moo, " %p in %p\n", f, rcv->handle); - - /*dcMode (dc, DC_CALL_C_DEFAULT); - dcReset (dc);*/ - - /*for (i = 1; i < MOO_OBJ_GET_SIZE(sig); i++) + switch (fmtc) { - if (((moo_oop_char_t)sig)->slot[i] == '|') - { - dcMode (dc, DC_CALL_C_ELLIPSIS); -MOO_DEBUG0 (moo, "CALL MODE 111 ERROR %d %d\n", dcGetError (dc), DC_ERROR_UNSUPPORTED_MODE); - mode_set = 1; - break; - } - } - if (!mode_set) */ dcMode (dc, DC_CALL_C_DEFAULT); - - for (i = 1; i < MOO_OBJ_GET_SIZE(sig); i++) - { -MOO_DEBUG1 (moo, "FFI: CALLING ARG %c\n", ((moo_oop_char_t)sig)->slot[i]); - switch (((moo_oop_char_t)sig)->slot[i]) - { - /* TODO: support more types... */ - /* - case '|': - dcMode (dc, DC_CALL_C_ELLIPSIS_VARARGS); -MOO_DEBUG2 (moo, "CALL MODE 222 ERROR %d %d\n", dcGetError (dc), DC_ERROR_UNSUPPORTED_MODE); - break; - */ - - case 'c': - /* TODO: sanity check on the argument type */ - dcArgChar (dc, MOO_OOP_TO_CHAR(arr->slot[i - 1])); - break; - - case 'i': -/* TODO: use moo_inttoooi () */ - dcArgInt (dc, MOO_OOP_TO_SMOOI(arr->slot[i - 1])); - break; - - case 'l': -/* TODO: use moo_inttoooi () */ - dcArgLong (dc, MOO_OOP_TO_SMOOI(arr->slot[i - 1])); - break; - - case 'L': -/* TODO: use moo_inttoooi () */ - dcArgLongLong (dc, MOO_OOP_TO_SMOOI(arr->slot[i - 1])); - break; - -#if 0 - case 'B': /* byte array */ -#endif - case 's': - { - moo_oow_t bcslen, ucslen; - moo_bch_t bcs[1024]; - - ucslen = MOO_OBJ_GET_SIZE(arr->slot[i - 1]); - moo_convootobchars (moo, ((moo_oop_char_t)arr->slot[i - 2])->slot, &ucslen, bcs, &bcslen); /* proper string conversion */ - - bcs[bcslen] = '\0'; - dcArgPointer (dc, bcs); - break; - } - - default: - /* TODO: ERROR HANDLING */ - break; - } - - } - - switch (((moo_oop_char_t)sig)->slot[0]) - { -/* TODO: support more types... */ -/* TODO: proper return value conversion */ + /* TODO: support more types... */ case 'c': - { - char r = dcCallChar (dc, f); - MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(r)); + /* TODO: sanity check on the argument type */ + dcArgChar (dc, MOO_OOP_TO_CHAR(arr->slot[j])); + j++; break; - } case 'i': - { - moo_oop_t r; - r = moo_ooitoint (moo, dcCallInt (dc, f)); - if (!r) return MOO_PF_HARD_FAILURE; - MOO_STACK_SETRET (moo, nargs, r); +/* TODO: use moo_inttoooi () */ + dcArgInt (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + j++; break; - } case 'l': - { - moo_oop_t r; - r = moo_ooitoint (moo, dcCallLong (dc, f)); - if (!r) return MOO_PF_HARD_FAILURE; - MOO_STACK_SETRET (moo, nargs, r); +/* TODO: use moo_inttoooi () */ + dcArgLong (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + j++; break; - } - #if (STIX_SIZEOF_LONG_LONG > 0) case 'L': - { - long long r = dcCallLongLong (dc, f); - mod_oop_t r; - - #if STIX_SIZEOF_LONG_LONG <= STIX_SIZEOF_LONG - r = moo_ooitoint (moo, dcCallLongLong (dc, f)); - #else - # error TODO:... - #endif - if (!rr) return MOD_PF_HARD_FAILURE; - - MOO_STACK_SETRET (moo, nargs, r); +/* TODO: use moo_inttoooi () */ + dcArgLongLong (dc, MOO_OOP_TO_SMOOI(arr->slot[j])); + j++; break; - } - #endif #if 0 - case 'b': /* byte array */ - { - } + case 'B': /* byte array */ #endif - - case 'B': + case 's': { moo_oow_t bcslen, ucslen; - moo_ooch_t ucs[1024]; - moo_oop_t s; - char* r = dcCallPointer (dc, f); + moo_bch_t bcs[1024]; /*TODO: dynamic length.... */ - bcslen = strlen(r); - moo_convbtooochars (moo, r, &bcslen, ucs, &ucslen); /* error check... */ + 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 */ - s = moo_makestring(moo, ucs, ucslen); - if (!s) - { - dcFree (dc); - return MOO_PF_HARD_FAILURE; /* TODO: proper error h andling */ - } - - MOO_STACK_SETRET (moo, nargs, s); + bcs[bcslen] = '\0'; + dcArgPointer (dc, bcs); + j++; break; } default: - - moo_seterrnum (moo, MOO_EINVAL); - goto reterr; + /* TODO: ERROR HANDLING */ break; } - - dcFree (dc); } + if (i >= MOO_OBJ_GET_SIZE(sig)) goto call_void; + + switch (((moo_oop_char_t)sig)->slot[i]) + { +/* TODO: support more types... */ +/* TODO: proper return value conversion */ + case 'c': + { + char r = dcCallChar (dc, f); + MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(r)); + break; + } + + case 'i': + { + moo_oop_t r; + + r = moo_ooitoint (moo, dcCallInt (dc, f)); + if (!r) goto oops; + MOO_STACK_SETRET (moo, nargs, r); + break; + } + + case 'l': + { + moo_oop_t r; + r = moo_ooitoint (moo, dcCallLong (dc, f)); + if (!r) goto oops; + MOO_STACK_SETRET (moo, nargs, r); + break; + } + + #if (STIX_SIZEOF_LONG_LONG > 0) + case 'L': + { + long long r = dcCallLongLong (dc, f); + mod_oop_t r; + + #if STIX_SIZEOF_LONG_LONG <= STIX_SIZEOF_LONG + r = moo_ooitoint (moo, dcCallLongLong (dc, f)); + #else + # error TODO:... + #endif + if (!rr) goto oops; + + MOO_STACK_SETRET (moo, nargs, r); + break; + } + #endif + +#if 0 + case 'B': /* byte array */ + { + } +#endif + + case 's': + { + moo_oow_t bcslen, ucslen; + moo_ooch_t ucs[1024]; /* TOOD: buffer size... */ + moo_oop_t s; + char* r = dcCallPointer (dc, f); + + bcslen = strlen(r); + moo_convbtooochars (moo, r, &bcslen, ucs, &ucslen); /* error check... */ + + s = moo_makestring(moo, ucs, ucslen); + if (!s) goto oops; + + MOO_STACK_SETRET (moo, nargs, s); + break; + } + + default: + call_void: + dcCallVoid (dc, f); + MOO_STACK_SETRETTORCV (moo, nargs); + break; + } + + dcFree (dc); return MOO_PF_SUCCESS; reterr: + if (dc) dcFree(dc); MOO_STACK_SETRETTOERROR (moo, nargs); return MOO_PF_SUCCESS; +oops: + if (dc) dcFree(dc); + return MOO_PF_HARD_FAILURE; + #else moo_seterrnum (moo, MOO_ENOIMPL); MOO_STACK_SETRETTOERROR (moo, nargs);