+added referenced usertype support.
This commit is contained in:
parent
43904234c8
commit
12fef457d3
575
core/my_basic.c
575
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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user