+added garbage collection for referenced objects.
This commit is contained in:
parent
d33b032b2b
commit
245c68bb39
303
core/my_basic.c
303
core/my_basic.c
@ -79,7 +79,7 @@ extern "C" {
|
||||
/** Macros */
|
||||
#define _VER_MAJOR 1
|
||||
#define _VER_MINOR 1
|
||||
#define _VER_REVISION 85
|
||||
#define _VER_REVISION 86
|
||||
#define _VER_SUFFIX
|
||||
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
|
||||
#define _STRINGIZE(A) _MAKE_STRINGIZE(A)
|
||||
@ -281,10 +281,19 @@ typedef unsigned int _ref_count_t;
|
||||
typedef struct _ref_t {
|
||||
_ref_count_t* count;
|
||||
_unref_func_t on_unref;
|
||||
_data_e type;
|
||||
struct mb_interpreter_t* s;
|
||||
} _ref_t;
|
||||
|
||||
typedef short _lock_t;
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
typedef struct _gc_t {
|
||||
_ht_node_t* table;
|
||||
int_t collecting;
|
||||
} _gc_t;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
typedef struct _array_t {
|
||||
_ref_t ref;
|
||||
char* name;
|
||||
@ -497,6 +506,9 @@ typedef struct mb_interpreter_t {
|
||||
int schedule_suspend_tag;
|
||||
_ls_node_t* temp_values;
|
||||
_ls_node_t* lazy_destroy_objects;
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_t gc;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
int_t no_eat_comma_mark;
|
||||
_ls_node_t* skip_to_eoi;
|
||||
_ls_node_t* in_neg_expr;
|
||||
@ -816,10 +828,16 @@ static int _ls_free_extra(void* data, void* extra);
|
||||
static unsigned int _ht_hash_object(void* ht, void* d);
|
||||
static unsigned int _ht_hash_string(void* ht, void* d);
|
||||
static unsigned int _ht_hash_int(void* ht, void* d);
|
||||
#ifdef MB_ENABLE_GC
|
||||
static unsigned int _ht_hash_ref(void* ht, void* d);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
static int _ht_cmp_object(void* d1, void* d2);
|
||||
static int _ht_cmp_string(void* d1, void* d2);
|
||||
static int _ht_cmp_int(void* d1, void* d2);
|
||||
#ifdef MB_ENABLE_GC
|
||||
static int _ht_cmp_ref(void* d1, void* d2);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
static _ht_node_t* _ht_create(unsigned int size, _ht_compare cmp, _ht_hash hs, _ls_operation freeextra);
|
||||
static _ls_node_t* _ht_find(_ht_node_t* ht, void* key);
|
||||
@ -829,6 +847,7 @@ static unsigned int _ht_foreach(_ht_node_t* ht, _ht_operation op);
|
||||
static unsigned int _ht_count(_ht_node_t* ht);
|
||||
static void _ht_clear(_ht_node_t* ht);
|
||||
static void _ht_destroy(_ht_node_t* ht);
|
||||
static int _ht_remove_exist(void* data, void* extra, _ht_node_t* ht);
|
||||
#define _HT_FOREACH(H, O, P, E) \
|
||||
do { \
|
||||
_ls_node_t* __bucket = 0; \
|
||||
@ -948,7 +967,7 @@ 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);
|
||||
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);
|
||||
@ -963,10 +982,20 @@ static bool_t _is_number(void* obj);
|
||||
static bool_t _is_string(void* obj);
|
||||
static char* _extract_string(_object_t* obj);
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
static void _gc_add(_ref_t* ref, void* data);
|
||||
static void _gc_remove(_ref_t* ref, void* data);
|
||||
static int _gc_add_reachable(void* data, void* extra, _ht_node_t* gc);
|
||||
static void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht);
|
||||
static int _gc_destroy_garbage(void* data, void* extra);
|
||||
static void _gc_try_trigger(mb_interpreter_t* s);
|
||||
static void _gc_collect_garbage(mb_interpreter_t* s);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
static _list_t* _create_list(void);
|
||||
static _list_t* _create_list(mb_interpreter_t* s);
|
||||
static void _destroy_list(_list_t* c);
|
||||
static _dict_t* _create_dict(void);
|
||||
static _dict_t* _create_dict(mb_interpreter_t* s);
|
||||
static void _destroy_dict(_dict_t* c);
|
||||
static _list_it_t* _create_list_it(_list_t* coll, bool_t lock);
|
||||
static bool_t _destroy_list_it(_list_it_t* it);
|
||||
@ -1021,7 +1050,7 @@ static bool_t _write_on_ref_object(_lock_t* lk, _ref_t* ref, void* obj);
|
||||
|
||||
static unsigned _ref(_ref_t* ref, void* data);
|
||||
static unsigned _unref(_ref_t* ref, void* data);
|
||||
static void _create_ref(_ref_t* ref, _unref_func_t dtor);
|
||||
static void _create_ref(_ref_t* ref, _unref_func_t dtor, _data_e t, mb_interpreter_t* s);
|
||||
static void _destroy_ref(_ref_t* ref);
|
||||
|
||||
static void _init_class(mb_interpreter_t* s, _class_t* instance, char* n);
|
||||
@ -1051,6 +1080,7 @@ static int _destroy_object(void* data, void* extra);
|
||||
static int _destroy_object_with_extra(void* data, void* extra);
|
||||
static int _destroy_object_not_compile_time(void* data, void* extra);
|
||||
static int _destroy_object_capsule_only(void* data, void* extra);
|
||||
static int _destroy_object_capsule_only_with_extra(void* data, void* extra);
|
||||
static int _do_nothing_on_object(void* data, void* extra);
|
||||
static int _remove_source_object(void* data, void* extra);
|
||||
static int _destroy_memory(void* data, void* extra);
|
||||
@ -1697,6 +1727,21 @@ unsigned int _ht_hash_int(void* ht, void* d) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
unsigned int _ht_hash_ref(void* ht, void* d) {
|
||||
unsigned int result = 0;
|
||||
_ht_node_t* self = (_ht_node_t*)ht;
|
||||
_ref_t* ref = *(_ref_t**)d;
|
||||
|
||||
mb_assert(ht);
|
||||
|
||||
result = (unsigned int)(intptr_t)ref;
|
||||
result %= self->array_size;
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
int _ht_cmp_object(void* d1, void* d2) {
|
||||
_object_t* o1 = (_object_t*)d1;
|
||||
_object_t* o2 = (_object_t*)d2;
|
||||
@ -1743,6 +1788,21 @@ int _ht_cmp_int(void* d1, void* d2) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
int _ht_cmp_ref(void* d1, void* d2) {
|
||||
_ref_t* r1 = *(_ref_t**)d1;
|
||||
_ref_t* r2 = *(_ref_t**)d2;
|
||||
int_t i = (intptr_t)r1 - (intptr_t)r2;
|
||||
int result = 0;
|
||||
if(i < 0)
|
||||
result = -1;
|
||||
else if(i > 0)
|
||||
result = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
_ht_node_t* _ht_create(unsigned int size, _ht_compare cmp, _ht_hash hs, _ls_operation freeextra) {
|
||||
const unsigned int array_size = size ? size : _HT_ARRAY_SIZE_DEFAULT;
|
||||
_ht_node_t* result = 0;
|
||||
@ -1876,6 +1936,16 @@ void _ht_destroy(_ht_node_t* ht) {
|
||||
safe_free(ht);
|
||||
}
|
||||
|
||||
int _ht_remove_exist(void* data, void* extra, _ht_node_t* ht) {
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
mb_unrefvar(data);
|
||||
|
||||
if(_ht_find(ht, extra))
|
||||
_ht_remove(ht, extra, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Memory manipulations */
|
||||
void* mb_malloc(size_t s) {
|
||||
char* ret = NULL;
|
||||
@ -3024,7 +3094,7 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
(*obj)->ref = true;
|
||||
*delsym = true;
|
||||
} else {
|
||||
tmp.array = _create_array(sym, _DT_ANY);
|
||||
tmp.array = _create_array(sym, _DT_ANY, s);
|
||||
memcpy(&tmp.array->type, value, sizeof(tmp.array->type));
|
||||
(*obj)->data.array = tmp.array;
|
||||
|
||||
@ -3583,13 +3653,13 @@ bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected) {
|
||||
return result;
|
||||
}
|
||||
|
||||
_array_t* _create_array(const char* n, _data_e t) {
|
||||
_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));
|
||||
memset(result, 0, sizeof(_array_t));
|
||||
result->type = t;
|
||||
result->name = (char*)n;
|
||||
_create_ref(&result->ref, _unref_array);
|
||||
_create_ref(&result->ref, _unref_array, _DT_ARRAY, s);
|
||||
_ref(&result->ref, result);
|
||||
|
||||
return result;
|
||||
@ -3966,13 +4036,167 @@ char* _extract_string(_object_t* obj) {
|
||||
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->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
|
||||
_list_t* _create_list(void) {
|
||||
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 */
|
||||
_list_t* result = (_list_t*)mb_malloc(sizeof(_list_t));
|
||||
memset(result, 0, sizeof(_list_t));
|
||||
result->list = _ls_create();
|
||||
_create_ref(&result->ref, _unref_list);
|
||||
_create_ref(&result->ref, _unref_list, _DT_LIST, s);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -3985,12 +4209,12 @@ void _destroy_list(_list_t* c) {
|
||||
safe_free(c);
|
||||
}
|
||||
|
||||
_dict_t* _create_dict(void) {
|
||||
_dict_t* _create_dict(mb_interpreter_t* s) {
|
||||
/* Create a dictionary */
|
||||
_dict_t* result = (_dict_t*)mb_malloc(sizeof(_dict_t));
|
||||
memset(result, 0, sizeof(_dict_t));
|
||||
result->dict = _ht_create(0, _ht_cmp_object, _ht_hash_object, _destroy_object_with_extra);
|
||||
_create_ref(&result->ref, _unref_dict);
|
||||
_create_ref(&result->ref, _unref_dict, _DT_DICT, s);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -4591,12 +4815,19 @@ unsigned _unref(_ref_t* ref, void* data) {
|
||||
unsigned result = 0;
|
||||
|
||||
result = --(*(ref->count));
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_add(ref, data);
|
||||
ref->on_unref(ref, data);
|
||||
if(!ref->count)
|
||||
_gc_remove(ref, data);
|
||||
#else /* MB_ENABLE_GC */
|
||||
ref->on_unref(ref, data);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void _create_ref(_ref_t* ref, _unref_func_t dtor) {
|
||||
void _create_ref(_ref_t* ref, _unref_func_t dtor, _data_e t, mb_interpreter_t* s) {
|
||||
/* Create a reference stub */
|
||||
if(ref->count)
|
||||
return;
|
||||
@ -4604,6 +4835,8 @@ void _create_ref(_ref_t* ref, _unref_func_t dtor) {
|
||||
ref->count = (unsigned*)mb_malloc(sizeof(unsigned));
|
||||
*(ref->count) = 0;
|
||||
ref->on_unref = dtor;
|
||||
ref->type = t;
|
||||
ref->s = s;
|
||||
}
|
||||
|
||||
void _destroy_ref(_ref_t* ref) {
|
||||
@ -4948,7 +5181,7 @@ int _clone_object(_object_t* obj, _object_t* tgt) {
|
||||
break;
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
case _DT_LIST:
|
||||
tgt->data.list = _create_list();
|
||||
tgt->data.list = _create_list(obj->data.list->ref.s);
|
||||
_LS_FOREACH(obj->data.list->list, _do_nothing_on_object, _clone_to_list, tgt->data.list);
|
||||
|
||||
break;
|
||||
@ -4957,7 +5190,7 @@ int _clone_object(_object_t* obj, _object_t* tgt) {
|
||||
|
||||
break;
|
||||
case _DT_DICT:
|
||||
tgt->data.dict = _create_dict();
|
||||
tgt->data.dict = _create_dict(obj->data.dict->ref.s);
|
||||
_HT_FOREACH(obj->data.dict->dict, _do_nothing_on_object, _clone_to_dict, tgt->data.dict);
|
||||
|
||||
break;
|
||||
@ -5195,6 +5428,25 @@ int _destroy_object_capsule_only(void* data, void* extra) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int _destroy_object_capsule_only_with_extra(void* data, void* extra) {
|
||||
/* Destroy only the capsule (wrapper) of an object, leave the data behind, deal with extra as well */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_object_t* obj = 0;
|
||||
mb_unrefvar(extra);
|
||||
|
||||
mb_assert(data);
|
||||
|
||||
obj = (_object_t*)data;
|
||||
safe_free(obj);
|
||||
|
||||
obj = (_object_t*)extra;
|
||||
safe_free(obj);
|
||||
|
||||
result = _OP_RESULT_DEL_NODE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _do_nothing_on_object(void* data, void* extra) {
|
||||
/* Do nothing with an object, this is a helper function */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
@ -5614,6 +5866,7 @@ int _dispose_scope_chain(mb_interpreter_t* s) {
|
||||
prev = running->prev;
|
||||
|
||||
global_scope = running->var_dict;
|
||||
running->var_dict = 0;
|
||||
_ht_foreach(global_scope, _destroy_object);
|
||||
_ht_clear(global_scope);
|
||||
_ht_destroy(global_scope);
|
||||
@ -6145,6 +6398,10 @@ int mb_open(struct mb_interpreter_t** s) {
|
||||
*s = (mb_interpreter_t*)mb_malloc(sizeof(mb_interpreter_t));
|
||||
memset(*s, 0, sizeof(mb_interpreter_t));
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
(*s)->gc.table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
(*s)->in_neg_expr = _ls_create();
|
||||
|
||||
local_scope = _ht_create(0, _ht_cmp_string, _ht_hash_string, _ls_free_extra);
|
||||
@ -6223,6 +6480,12 @@ int mb_close(struct mb_interpreter_t** s) {
|
||||
|
||||
_close_constant(*s);
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_collect_garbage(*s);
|
||||
_ht_destroy((*s)->gc.table);
|
||||
(*s)->gc.table = 0;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
safe_free(*s);
|
||||
*s = 0;
|
||||
|
||||
@ -6623,6 +6886,10 @@ int mb_push_value(struct mb_interpreter_t* s, void** l, mb_value_t val) {
|
||||
running = s->running_context;
|
||||
_assign_public_value(&running->intermediate_value, &val);
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_try_trigger(s);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6717,7 +6984,7 @@ int mb_init_array(struct mb_interpreter_t* s, void** l, mb_data_e t, int* d, int
|
||||
type = _DT_REAL;
|
||||
#endif /* MB_SIMPLE_ARRAY */
|
||||
|
||||
arr = _create_array(0, type);
|
||||
arr = _create_array(0, type, s);
|
||||
for(j = 0; j < c; j++) {
|
||||
n = d[j];
|
||||
arr->dimensions[arr->dimension_count++] = n;
|
||||
@ -9548,7 +9815,7 @@ int _coll_list(mb_interpreter_t* s, void** l) {
|
||||
|
||||
mb_check(mb_attempt_open_bracket(s, l));
|
||||
|
||||
coll = _create_list();
|
||||
coll = _create_list(s);
|
||||
|
||||
while(mb_has_arg(s, l)) {
|
||||
mb_check(mb_pop_value(s, l, &arg));
|
||||
@ -9575,7 +9842,7 @@ int _coll_dict(mb_interpreter_t* s, void** l) {
|
||||
|
||||
mb_check(mb_attempt_open_bracket(s, l));
|
||||
|
||||
coll = _create_dict();
|
||||
coll = _create_dict(s);
|
||||
|
||||
while(mb_has_arg(s, l)) {
|
||||
mb_check(mb_pop_value(s, l, &arg));
|
||||
|
Loading…
x
Reference in New Issue
Block a user