diff --git a/core/my_basic.c b/core/my_basic.c index 6b4a9f6..c356c24 100755 --- a/core/my_basic.c +++ b/core/my_basic.c @@ -79,7 +79,7 @@ extern "C" { /** Macros */ #define _VER_MAJOR 1 #define _VER_MINOR 1 -#define _VER_REVISION 86 +#define _VER_REVISION 87 #define _VER_SUFFIX #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) #define _STRINGIZE(A) _MAKE_STRINGIZE(A) @@ -246,6 +246,7 @@ typedef enum _data_e { _DT_REAL, _DT_STRING, _DT_USERTYPE, + _DT_USERTYPE_REF, _DT_FUNC, _DT_VAR, _DT_ARRAY, @@ -294,6 +295,13 @@ typedef struct _gc_t { } _gc_t; #endif /* MB_ENABLE_GC */ +typedef struct _usertype_ref_t { + _ref_t ref; + void* usertype; + mb_unref_func_t unref; + mb_clone_func_t clone; +} _usertype_ref_t; + typedef struct _array_t { _ref_t ref; char* name; @@ -367,6 +375,7 @@ typedef struct _object_t { real_t float_point; char* string; void* usertype; + _usertype_ref_t* usertype_ref; _func_t* func; _var_t* variable; _array_t* array; @@ -967,17 +976,6 @@ static void _set_error_pos(mb_interpreter_t* s, int pos, unsigned short row, uns static int_t _get_size_of(_data_e type); static bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected); -static _array_t* _create_array(const char* n, _data_e t, mb_interpreter_t* s); -static void _destroy_array(_array_t* arr); -static void _init_array(_array_t* arr); -static int _get_array_pos(struct mb_interpreter_t* s, _array_t* arr, int* d, int c); -static int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index, bool_t* literally); -static bool_t _get_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); -static int _set_array_elem(mb_interpreter_t* s, _ls_node_t* ast, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); -static void _clear_array(_array_t* arr); -static bool_t _is_array(void* obj); -static void _unref_array(_ref_t* ref, void* data); - static bool_t _is_number(void* obj); static bool_t _is_string(void* obj); static char* _extract_string(_object_t* obj); @@ -992,6 +990,31 @@ static void _gc_try_trigger(mb_interpreter_t* s); static void _gc_collect_garbage(mb_interpreter_t* s); #endif /* MB_ENABLE_GC */ +static _usertype_ref_t* _create_usertype_ref(mb_interpreter_t* s, void* val, mb_unref_func_t un, mb_clone_func_t cl); +static void _destroy_usertype_ref(_usertype_ref_t* c); +static void _unref_usertype_ref(_ref_t* ref, void* data); + +static _array_t* _create_array(const char* n, _data_e t, mb_interpreter_t* s); +static void _destroy_array(_array_t* arr); +static void _init_array(_array_t* arr); +static int _get_array_pos(struct mb_interpreter_t* s, _array_t* arr, int* d, int c); +static int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index, bool_t* literally); +static bool_t _get_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); +static int _set_array_elem(mb_interpreter_t* s, _ls_node_t* ast, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); +static void _clear_array(_array_t* arr); +static bool_t _is_array(void* obj); +static void _unref_array(_ref_t* ref, void* data); + +#define _UNREF_USERTYPE_REF(__o) \ + case _DT_USERTYPE_REF: \ + _unref(&(__o)->data.usertype_ref->ref, (__o)->data.usertype_ref); \ + break; +#define _UNREF_ARRAY(__o) \ + case _DT_ARRAY: \ + if(!(__o)->ref) \ + _unref(&(__o)->data.array->ref, (__o)->data.array); \ + break; + #ifdef MB_ENABLE_COLLECTION_LIB static _list_t* _create_list(mb_interpreter_t* s); static void _destroy_list(_list_t* c); @@ -1032,15 +1055,11 @@ static int _clone_to_dict(void* data, void* extra, _dict_t* coll); case _DT_DICT: \ _unref(&(__o)->data.dict->ref, (__o)->data.dict); \ break; -#define _UNREF_ARRAY(__o) \ - case _DT_ARRAY: \ - if(!(__o)->ref) \ - _unref(&(__o)->data.array->ref, (__o)->data.array); \ - break; #define _UNREF_IF_IS_COLL(__o) \ switch((__o)->type) { \ - _UNREF_COLL(__o) \ + _UNREF_USERTYPE_REF(__o) \ _UNREF_ARRAY(__o) \ + _UNREF_COLL(__o) \ default: break; \ } #endif /* MB_ENABLE_COLLECTION_LIB */ @@ -2593,7 +2612,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { #ifdef MB_ENABLE_COLLECTION_LIB c->type == _DT_LIST || c->type == _DT_LIST_IT || c->type == _DT_DICT || c->type == _DT_DICT_IT || #endif /* MB_ENABLE_COLLECTION_LIB */ - c->type == _DT_VAR || c->type == _DT_USERTYPE || c->type == _DT_ARRAY)) { + c->type == _DT_VAR || c->type == _DT_USERTYPE || c->type == _DT_USERTYPE_REF || c->type == _DT_ARRAY)) { _set_current_error(s, SE_RN_INVALID_DATA_TYPE, 0); result = MB_FUNC_ERR; @@ -2623,12 +2642,12 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { _try_clear_intermediate_value(c, 0, s); #ifdef MB_ENABLE_COLLECTION_LIB - if(c->type == _DT_ARRAY || c->type == _DT_LIST || c->type == _DT_DICT || c->type == _DT_LIST_IT || c->type == _DT_DICT_IT) + if(c->type == _DT_USERTYPE_REF || c->type == _DT_ARRAY || c->type == _DT_LIST || c->type == _DT_DICT || c->type == _DT_LIST_IT || c->type == _DT_DICT_IT) _destroy_object_capsule_only(c, 0); else _destroy_object(c, 0); #else /* MB_ENABLE_COLLECTION_LIB */ - if(c->type == _DT_ARRAY) + if(c->type == _DT_USERTYPE_REF || c->type == _DT_ARRAY) _destroy_object_capsule_only(c, 0); else _destroy_object(c, 0); @@ -3653,6 +3672,245 @@ bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected) { return result; } +bool_t _is_number(void* obj) { + /* Determine if an object is a number */ + bool_t result = false; + _object_t* o = 0; + + mb_assert(obj); + + o = (_object_t*)obj; + if(o->type == _DT_INT || o->type == _DT_REAL) + result = true; + else if(o->type == _DT_VAR) + result = o->data.variable->data->type == _DT_INT || o->data.variable->data->type == _DT_REAL; + + return result; +} + +bool_t _is_string(void* obj) { + /* Determine if an object is a string value or a string variable */ + bool_t result = false; + _object_t* o = 0; + + mb_assert(obj); + + o = (_object_t*)obj; + if(o->type == _DT_STRING) + result = true; + else if(o->type == _DT_VAR) + result = o->data.variable->data->type == _DT_STRING; + + return result; +} + +char* _extract_string(_object_t* obj) { + /* Extract a string from an object */ + char* result = 0; + + mb_assert(obj); + + if(obj->type == _DT_STRING) + result = obj->data.string; + else if(obj->type == _DT_VAR && obj->data.variable->data->type == _DT_STRING) + result = obj->data.variable->data->data.string; + + if(!result) + result = MB_NULL_STRING; + + return result; +} + +#ifdef MB_ENABLE_GC +void _gc_add(_ref_t* ref, void* data) { + /* Add a referenced object to GC */ + mb_assert(ref && data); + + if(ref->type == _DT_ARRAY) + return; + + if(!ref->s->gc.table) + return; + + if(ref->s->gc.collecting) + return; + + if(ref->count && *ref->count) + _ht_set_or_insert(ref->s->gc.table, ref, data); + else + _ht_remove(ref->s->gc.table, ref, 0); +} + +void _gc_remove(_ref_t* ref, void* data) { + /* Remove a referenced object from GC */ + mb_unrefvar(data); + + mb_assert(ref && data); + + _ht_remove(ref->s->gc.table, ref, 0); +} + +int _gc_add_reachable(void* data, void* extra, _ht_node_t* ht) { + /* Get reachable objects */ + int result = _OP_RESULT_NORMAL; + _object_t* obj = 0; + _var_t* var = 0; + mb_unrefvar(extra); + + mb_assert(data && ht); + + obj = (_object_t*)data; + if(_is_internal_object(obj)) + goto _exit; + switch(obj->type) { + case _DT_VAR: + var = (_var_t*)(obj->data.variable); + _gc_add_reachable(var->data, extra, ht); + + break; + case _DT_USERTYPE_REF: + if(!_ht_find(ht, &obj->data.usertype_ref->ref)) + _ht_set_or_insert(ht, &obj->data.usertype_ref->ref, obj->data.usertype_ref); + + break; +#ifdef MB_ENABLE_COLLECTION_LIB + case _DT_LIST: + if(!_ht_find(ht, &obj->data.list->ref)) { + _ht_set_or_insert(ht, &obj->data.list->ref, obj->data.list); + _LS_FOREACH(obj->data.list->list, _do_nothing_on_object, _gc_add_reachable, ht); + } + + break; + case _DT_DICT: + if(!_ht_find(ht, &obj->data.dict->ref)) { + _ht_set_or_insert(ht, &obj->data.dict->ref, obj->data.dict); + _HT_FOREACH(obj->data.dict->dict, _do_nothing_on_object, _gc_add_reachable, ht); + } + + break; +#endif /* MB_ENABLE_COLLECTION_LIB */ + default: /* Do nothing */ + break; + } + +_exit: + return result; +} + +void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht) { + /* Get all reachable referenced objects */ + _running_context_t* running = 0; + _ht_node_t* global_scope = 0; + + mb_assert(s && ht); + + running = s->running_context; + while(running) { + global_scope = running->var_dict; + if(global_scope) { + _HT_FOREACH(global_scope, _do_nothing_on_object, _gc_add_reachable, ht); + } + + running = running->prev; + } +} + +int _gc_destroy_garbage(void* data, void* extra) { + /* Destroy a garbage */ + int result = _OP_RESULT_NORMAL; + _ref_t* ref = 0; +#ifdef MB_ENABLE_COLLECTION_LIB + _list_t* lst = 0; + _dict_t* dct = 0; +#endif /* #ifdef MB_ENABLE_COLLECTION_LIB */ + + mb_assert(data && extra); + + ref = (_ref_t*)extra; + switch(ref->type) { +#ifdef MB_ENABLE_COLLECTION_LIB + case _DT_LIST: + lst = (_list_t*)data; + _ls_foreach(lst->list, _destroy_object_capsule_only); + _ls_clear(lst->list); + lst->count = 0; + + break; + case _DT_DICT: + dct = (_dict_t*)data; + _ht_foreach(dct->dict, _destroy_object_capsule_only_with_extra); + _ht_clear(dct->dict); + + break; +#endif /* #ifdef MB_ENABLE_COLLECTION_LIB */ + default: + break; + } + _unref(ref, data); + + result = _OP_RESULT_DEL_NODE; + + return result; +} + +void _gc_try_trigger(mb_interpreter_t* s) { + /* Try trigger garbage collection */ + mb_assert(s); + + if(s->gc.table->count >= MB_GC_GARBAGE_THRESHOLD) + _gc_collect_garbage(s); +} + +void _gc_collect_garbage(mb_interpreter_t* s) { + /* Collect all garbage */ + _ht_node_t* valid = 0; + + mb_assert(s); + + /* Avoid infinity loop */ + if(s->gc.collecting) return; + s->gc.collecting++; + /* Get reachable information */ + valid = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object); + _gc_get_reachable(s, valid); + /* Get unreachable information */ + _HT_FOREACH(valid, _do_nothing_on_object, _ht_remove_exist, s->gc.table); + /* Collect garbage */ + _ht_foreach(s->gc.table, _gc_destroy_garbage); + /* Tidy */ + _ht_clear(s->gc.table); + _ht_clear(valid); + _ht_destroy(valid); + s->gc.collecting--; +} +#endif /* MB_ENABLE_GC */ + +_usertype_ref_t* _create_usertype_ref(mb_interpreter_t* s, void* val, mb_unref_func_t un, mb_clone_func_t cl) { + /* Create a referenced usertype */ + _usertype_ref_t* result = (_usertype_ref_t*)mb_malloc(sizeof(_usertype_ref_t)); + memset(result, 0, sizeof(_usertype_ref_t)); + result->usertype = val; + result->unref = un; + result->clone = cl; + _create_ref(&result->ref, _unref_usertype_ref, _DT_USERTYPE_REF, s); + + return result; +} + +void _destroy_usertype_ref(_usertype_ref_t* c) { + /* Destroy a referenced usertype */ + if(c->unref) + c->unref(c->ref.s, c->usertype); + _destroy_ref(&c->ref); + safe_free(c); +} + +void _unref_usertype_ref(_ref_t* ref, void* data) { + /* Unreference a referenced usertype */ + if(!(*(ref->count))) + _destroy_usertype_ref((_usertype_ref_t*)data); +} + _array_t* _create_array(const char* n, _data_e t, mb_interpreter_t* s) { /* Create an array */ _array_t* result = (_array_t*)mb_malloc(sizeof(_array_t)); @@ -3987,212 +4245,6 @@ void _unref_array(_ref_t* ref, void* data) { _destroy_array((_array_t*)data); } -bool_t _is_number(void* obj) { - /* Determine if an object is a number */ - bool_t result = false; - _object_t* o = 0; - - mb_assert(obj); - - o = (_object_t*)obj; - if(o->type == _DT_INT || o->type == _DT_REAL) - result = true; - else if(o->type == _DT_VAR) - result = o->data.variable->data->type == _DT_INT || o->data.variable->data->type == _DT_REAL; - - return result; -} - -bool_t _is_string(void* obj) { - /* Determine if an object is a string value or a string variable */ - bool_t result = false; - _object_t* o = 0; - - mb_assert(obj); - - o = (_object_t*)obj; - if(o->type == _DT_STRING) - result = true; - else if(o->type == _DT_VAR) - result = o->data.variable->data->type == _DT_STRING; - - return result; -} - -char* _extract_string(_object_t* obj) { - /* Extract a string from an object */ - char* result = 0; - - mb_assert(obj); - - if(obj->type == _DT_STRING) - result = obj->data.string; - else if(obj->type == _DT_VAR && obj->data.variable->data->type == _DT_STRING) - result = obj->data.variable->data->data.string; - - if(!result) - result = MB_NULL_STRING; - - return result; -} - -#ifdef MB_ENABLE_GC -void _gc_add(_ref_t* ref, void* data) { - /* Add a referenced object to GC */ - mb_assert(ref && data); - - if(ref->type == _DT_ARRAY) - return; - - if(!ref->s->gc.table) - return; - - if(ref->s->gc.collecting) - return; - - if(ref->count) - _ht_set_or_insert(ref->s->gc.table, ref, data); -} - -void _gc_remove(_ref_t* ref, void* data) { - /* Remove a referenced object from GC */ - mb_unrefvar(data); - - mb_assert(ref && data); - - _ht_remove(ref->s->gc.table, ref, 0); -} - -int _gc_add_reachable(void* data, void* extra, _ht_node_t* ht) { - /* Get reachable objects */ - int result = _OP_RESULT_NORMAL; - _object_t* obj = 0; - _var_t* var = 0; - mb_unrefvar(extra); - - mb_assert(data && ht); - - obj = (_object_t*)data; - if(_is_internal_object(obj)) - goto _exit; - switch(obj->type) { - case _DT_VAR: - var = (_var_t*)(obj->data.variable); - _gc_add_reachable(var->data, extra, ht); - - break; -#ifdef MB_ENABLE_COLLECTION_LIB - case _DT_LIST: - if(!_ht_find(ht, &obj->data.list->ref)) { - _ht_set_or_insert(ht, &obj->data.list->ref, obj->data.list); - _LS_FOREACH(obj->data.list->list, _do_nothing_on_object, _gc_add_reachable, ht); - } - - break; - case _DT_DICT: - if(!_ht_find(ht, &obj->data.dict->ref)) { - _ht_set_or_insert(ht, &obj->data.dict->ref, obj->data.dict); - _HT_FOREACH(obj->data.dict->dict, _do_nothing_on_object, _gc_add_reachable, ht); - } - - break; -#endif /* MB_ENABLE_COLLECTION_LIB */ - default: /* Do nothing */ - break; - } - -_exit: - return result; -} - -void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht) { - /* Get all reachable referenced objects */ - _running_context_t* running = 0; - _ht_node_t* global_scope = 0; - - mb_assert(s && ht); - - running = s->running_context; - while(running) { - global_scope = running->var_dict; - if(global_scope) { - _HT_FOREACH(global_scope, _do_nothing_on_object, _gc_add_reachable, ht); - } - - running = running->prev; - } -} - -int _gc_destroy_garbage(void* data, void* extra) { - /* Destroy a garbage */ - int result = _OP_RESULT_NORMAL; - _ref_t* ref = 0; -#ifdef MB_ENABLE_COLLECTION_LIB - _list_t* lst = 0; - _dict_t* dct = 0; -#endif /* #ifdef MB_ENABLE_COLLECTION_LIB */ - - mb_assert(data && extra); - - ref = (_ref_t*)extra; - switch(ref->type) { -#ifdef MB_ENABLE_COLLECTION_LIB - case _DT_LIST: - lst = (_list_t*)data; - _ls_foreach(lst->list, _destroy_object_capsule_only); - _ls_clear(lst->list); - lst->count = 0; - - break; - case _DT_DICT: - dct = (_dict_t*)data; - _ht_foreach(dct->dict, _destroy_object_capsule_only_with_extra); - _ht_clear(dct->dict); - - break; -#endif /* #ifdef MB_ENABLE_COLLECTION_LIB */ - default: - break; - } - _unref(ref, data); - - result = _OP_RESULT_DEL_NODE; - - return result; -} - -void _gc_try_trigger(mb_interpreter_t* s) { - /* Try trigger garbage collection */ - mb_assert(s); - - if(s->gc.table->count >= MB_GC_GARBAGE_THRESHOLD) - _gc_collect_garbage(s); -} - -void _gc_collect_garbage(mb_interpreter_t* s) { - /* Collect all garbage */ - _ht_node_t* valid = 0; - - mb_assert(s); - - /* Avoid infinity loop */ - if(s->gc.collecting) return; - s->gc.collecting++; - /* Get reachable information */ - valid = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object); - _gc_get_reachable(s, valid); - /* Get unreachable information */ - _HT_FOREACH(valid, _do_nothing_on_object, _ht_remove_exist, s->gc.table); - /* Collect garbage */ - _ht_foreach(s->gc.table, _gc_destroy_garbage); - /* Tidy */ - _ht_clear(s->gc.table); - _ht_clear(valid); - _ht_destroy(valid); - s->gc.collecting--; -} -#endif /* MB_ENABLE_GC */ - #ifdef MB_ENABLE_COLLECTION_LIB _list_t* _create_list(mb_interpreter_t* s) { /* Create a list */ @@ -4687,6 +4739,10 @@ int _clone_to_list(void* data, void* extra, _list_t* coll) { _clone_object(obj, tgt); _push_list(coll, 0, tgt); switch(tgt->type) { + case _DT_USERTYPE_REF: + _ref(&tgt->data.usertype_ref->ref, tgt->data.usertype_ref); + + break; case _DT_ARRAY: _ref(&tgt->data.array->ref, tgt->data.array); @@ -4725,6 +4781,10 @@ int _clone_to_dict(void* data, void* extra, _dict_t* coll) { _set_dict(coll, 0, 0, ktgt, vtgt); switch(ktgt->type) { + case _DT_USERTYPE_REF: + _ref(&ktgt->data.usertype_ref->ref, ktgt->data.usertype_ref); + + break; case _DT_ARRAY: _ref(&ktgt->data.array->ref, ktgt->data.array); @@ -4741,6 +4801,10 @@ int _clone_to_dict(void* data, void* extra, _dict_t* coll) { break; } switch(vtgt->type) { + case _DT_USERTYPE_REF: + _ref(&vtgt->data.usertype_ref->ref, vtgt->data.usertype_ref); + + break; case _DT_ARRAY: _ref(&vtgt->data.array->ref, vtgt->data.array); @@ -5171,6 +5235,14 @@ int _clone_object(_object_t* obj, _object_t* tgt) { case _DT_STRING: tgt->data.string = mb_memdup(obj->data.string, (unsigned)strlen(obj->data.string) + 1); + break; + case _DT_USERTYPE_REF: + tgt->data.usertype_ref = _create_usertype_ref( + obj->data.usertype_ref->ref.s, + obj->data.usertype_ref->clone(obj->data.usertype_ref->ref.s, obj->data.usertype_ref->usertype), + obj->data.usertype_ref->unref, obj->data.usertype_ref->clone + ); + break; case _DT_FUNC: tgt->data.func->name = mb_memdup(obj->data.func->name, (unsigned)strlen(obj->data.func->name) + 1); @@ -5273,6 +5345,7 @@ int _dispose_object(_object_t* obj) { } break; + _UNREF_USERTYPE_REF(obj) case _DT_FUNC: safe_free(obj->data.func->name); safe_free(obj->data.func); @@ -5536,6 +5609,8 @@ _data_e _public_type_to_internal_type(mb_data_e t) { return _DT_STRING; case MB_DT_USERTYPE: return _DT_USERTYPE; + case MB_DT_USERTYPE_REF: + return _DT_USERTYPE_REF; case MB_DT_ARRAY: return _DT_ARRAY; #ifdef MB_ENABLE_COLLECTION_LIB @@ -5568,6 +5643,8 @@ mb_data_e _internal_type_to_public_type(_data_e t) { return MB_DT_STRING; case _DT_USERTYPE: return MB_DT_USERTYPE; + case _DT_USERTYPE_REF: + return MB_DT_USERTYPE_REF; case _DT_ARRAY: return MB_DT_ARRAY; #ifdef MB_ENABLE_COLLECTION_LIB @@ -5621,6 +5698,11 @@ int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn) { itn->type = _DT_USERTYPE; itn->data.usertype = pbl->value.usertype; + break; + case MB_DT_USERTYPE_REF: + itn->type = _DT_USERTYPE_REF; + itn->data.usertype_ref = pbl->value.usertype_ref; + break; case MB_DT_ARRAY: itn->type = _DT_ARRAY; @@ -5695,6 +5777,11 @@ int _internal_object_to_public_value(_object_t* itn, mb_value_t* pbl) { pbl->type = MB_DT_USERTYPE; pbl->value.usertype = itn->data.usertype; + break; + case _DT_USERTYPE_REF: + pbl->type = MB_DT_USERTYPE_REF; + pbl->value.usertype_ref = itn->data.usertype_ref; + break; case _DT_ARRAY: pbl->type = MB_DT_ARRAY; @@ -5791,6 +5878,10 @@ void _assign_public_value(mb_value_t* tgt, mb_value_t* src) { if(src) { _public_value_to_internal_object(src, &obj); switch(obj.type) { + case _DT_USERTYPE_REF: + _ref(&obj.data.usertype_ref->ref, obj.data.usertype_ref); + + break; case _DT_ARRAY: _ref(&obj.data.array->ref, obj.data.array); @@ -5812,10 +5903,8 @@ void _assign_public_value(mb_value_t* tgt, mb_value_t* src) { _public_value_to_internal_object(tgt, &obj); switch(obj.type) { - case _DT_ARRAY: - _unref(&obj.data.array->ref, obj.data.array); - - break; + _UNREF_USERTYPE_REF(&obj) + _UNREF_ARRAY(&obj) #ifdef MB_ENABLE_COLLECTION_LIB _UNREF_COLL(&obj) #endif /* MB_ENABLE_COLLECTION_LIB */ @@ -6797,6 +6886,8 @@ int mb_pop_value(struct mb_interpreter_t* s, void** l, mb_value_t* val) { val_ptr = (_object_t*)mb_malloc(sizeof(_object_t)); memcpy(val_ptr, &val_obj, sizeof(_object_t)); _ls_pushback(s->temp_values, val_ptr); + } else if(val_ptr->type == _DT_USERTYPE_REF) { + _ref(&val_ptr->data.usertype_ref->ref, val_ptr->data.usertype_ref); } else if(val_ptr->type == _DT_ARRAY) { _ref(&val_ptr->data.array->ref, val_ptr->data.array); #ifdef MB_ENABLE_COLLECTION_LIB @@ -7092,6 +7183,22 @@ _exit: return result; } +int mb_ref_value(struct mb_interpreter_t* s, void* val, mb_unref_func_t un, mb_clone_func_t cl, mb_value_t* out) { + /* Create a referenced usertype value */ + int result = MB_FUNC_OK; + _usertype_ref_t* ref = 0; + + mb_assert(s && out); + + if(out) { + ref = _create_usertype_ref(s, val, un, cl); + out->type = MB_DT_USERTYPE_REF; + out->value.usertype_ref = ref; + } + + return result; +} + int mb_dispose_value(struct mb_interpreter_t* s, mb_value_t val) { /* Dispose a value */ int result = MB_FUNC_OK; @@ -7358,6 +7465,8 @@ const char* mb_get_type_string(mb_data_e t) { return "STRING"; case MB_DT_USERTYPE: return "USERTYPE"; + case MB_DT_USERTYPE_REF: + return "USERTYPE_REF"; case MB_DT_ARRAY: return "ARRAY"; #ifdef MB_ENABLE_COLLECTION_LIB @@ -7996,6 +8105,10 @@ int _core_let(mb_interpreter_t* s, void** l) { } } switch(val->type) { + case _DT_USERTYPE_REF: + _ref(&val->data.usertype_ref->ref, val->data.usertype_ref); + + break; case _DT_ARRAY: _ref(&val->data.array->ref, val->data.array);