*polished sample script; *fixed a memory leak with gc caused by reference cycle; *finished internal class development.
This commit is contained in:
parent
a426e150ae
commit
ef79101296
2
HISTORY
2
HISTORY
@ -1,6 +1,8 @@
|
||||
Dec. 11 2015
|
||||
Added an IS statement to detect type equality of a value
|
||||
Added support to store a routine in a variable by CALL statement
|
||||
Fixed a memory leak with GC caused by reference cycle
|
||||
Finished internal class development
|
||||
|
||||
Dec. 10 2015
|
||||
Developing class, added a NEW statement to duplicate a class instance
|
||||
|
193
core/my_basic.c
193
core/my_basic.c
@ -82,7 +82,7 @@ extern "C" {
|
||||
/** Macros */
|
||||
#define _VER_MAJOR 1
|
||||
#define _VER_MINOR 1
|
||||
#define _VER_REVISION 105
|
||||
#define _VER_REVISION 106
|
||||
#define _VER_SUFFIX
|
||||
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
|
||||
#define _STRINGIZE(A) _MAKE_STRINGIZE(A)
|
||||
@ -312,6 +312,8 @@ typedef short _lock_t;
|
||||
#ifdef MB_ENABLE_GC
|
||||
typedef struct _gc_t {
|
||||
_ht_node_t* table;
|
||||
_ht_node_t* recursive_table;
|
||||
_ht_node_t* collected_table;
|
||||
int_t collecting;
|
||||
} _gc_t;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
@ -1072,6 +1074,10 @@ static char* _extract_string(_object_t* obj);
|
||||
case _DT_USERTYPE_REF: \
|
||||
_unref(&(__o)->data.usertype_ref->ref, (__o)->data.usertype_ref); \
|
||||
break;
|
||||
#define _ADDGC_USERTYPE_REF(__o, __g) \
|
||||
case _DT_USERTYPE_REF: \
|
||||
_gc_add(&(__o)->data.usertype_ref->ref, (__o)->data.usertype_ref, (__g)); \
|
||||
break;
|
||||
#define _REF_ARRAY(__o) \
|
||||
case _DT_ARRAY: \
|
||||
if(!(__o)->ref) \
|
||||
@ -1082,6 +1088,11 @@ static char* _extract_string(_object_t* obj);
|
||||
if(!(__o)->ref) \
|
||||
_unref(&(__o)->data.array->ref, (__o)->data.array); \
|
||||
break;
|
||||
#define _ADDGC_ARRAY(__o, __g) \
|
||||
case _DT_ARRAY: \
|
||||
if(!(__o)->ref) \
|
||||
_gc_add(&(__o)->data.array->ref, (__o)->data.array, (__g)); \
|
||||
break;
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
# define _REF_COLL(__o) \
|
||||
case _DT_LIST: \
|
||||
@ -1097,6 +1108,13 @@ static char* _extract_string(_object_t* obj);
|
||||
case _DT_DICT: \
|
||||
_unref(&(__o)->data.dict->ref, (__o)->data.dict); \
|
||||
break;
|
||||
# define _ADDGC_COLL(__o, __g) \
|
||||
case _DT_LIST: \
|
||||
_gc_add(&(__o)->data.list->ref, (__o)->data.list, (__g)); \
|
||||
break; \
|
||||
case _DT_DICT: \
|
||||
_gc_add(&(__o)->data.dict->ref, (__o)->data.dict, (__g)); \
|
||||
break;
|
||||
#else /* MB_ENABLE_COLLECTION_LIB */
|
||||
# define _REF_COLL(__o) ((void)(__o));
|
||||
# define _UNREF_COLL(__o) ((void)(__o));
|
||||
@ -1111,9 +1129,15 @@ static char* _extract_string(_object_t* obj);
|
||||
if(!(__o)->ref) \
|
||||
_unref(&(__o)->data.instance->ref, (__o)->data.instance); \
|
||||
break;
|
||||
# define _ADDGC_CLASS(__o, __g) \
|
||||
case _DT_CLASS: \
|
||||
if(!(__o)->ref) \
|
||||
_gc_add(&(__o)->data.instance->ref, (__o)->data.instance, (__g)); \
|
||||
break;
|
||||
#else /* MB_ENABLE_CLASS */
|
||||
# define _REF_CLASS(__o) ((void)(__o));
|
||||
# define _UNREF_CLASS(__o) ((void)(__o));
|
||||
# define _ADDGC_CLASS(__o, __g) ((void)(__o)); ((void)(__g));
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
#define _REF(__o) \
|
||||
switch((__o)->type) { \
|
||||
@ -1131,6 +1155,14 @@ static char* _extract_string(_object_t* obj);
|
||||
_UNREF_CLASS(__o) \
|
||||
default: break; \
|
||||
}
|
||||
#define _ADDGC(__o, __g) \
|
||||
switch((__o)->type) { \
|
||||
_ADDGC_USERTYPE_REF(__o, __g) \
|
||||
_ADDGC_ARRAY(__o, __g) \
|
||||
_ADDGC_COLL(__o, __g) \
|
||||
_ADDGC_CLASS(__o, __g) \
|
||||
default: break; \
|
||||
}
|
||||
|
||||
static bool_t _lock_ref_object(_lock_t* lk, _ref_t* ref, void* obj);
|
||||
static bool_t _unlock_ref_object(_lock_t* lk, _ref_t* ref, void* obj);
|
||||
@ -1142,10 +1174,12 @@ static void _create_ref(_ref_t* ref, _unref_func_t dtor, _data_e t, mb_interpret
|
||||
static void _destroy_ref(_ref_t* ref);
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
static void _gc_add(_ref_t* ref, void* data);
|
||||
static void _gc_add(_ref_t* ref, void* data, _gc_t* gc);
|
||||
static void _gc_remove(_ref_t* ref, void* data);
|
||||
static int _gc_add_reachable(void* data, void* extra, void* ht);
|
||||
static void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht);
|
||||
static int _gc_destroy_garbage_in_list(void* data, void* extra, _gc_t* gc);
|
||||
static int _gc_destroy_garbage_in_dict(void* data, void* extra, _gc_t* gc);
|
||||
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);
|
||||
@ -1265,6 +1299,7 @@ static void _swap_public_value(mb_value_t* tgt, mb_value_t* src);
|
||||
static int _clear_scope_chain(mb_interpreter_t* s);
|
||||
static int _dispose_scope_chain(mb_interpreter_t* s);
|
||||
static void _tidy_scope_chain(mb_interpreter_t* s);
|
||||
static void _tidy_intermediate_value(_ref_t* ref, void* data);
|
||||
|
||||
static void _stepped(mb_interpreter_t* s, _ls_node_t* ast);
|
||||
static int _execute_statement(mb_interpreter_t* s, _ls_node_t** l);
|
||||
@ -4115,7 +4150,9 @@ unsigned _unref(_ref_t* ref, void* data) {
|
||||
|
||||
result = --(*(ref->count));
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_add(ref, data);
|
||||
_gc_add(ref, data, 0);
|
||||
if(ref->count && !(*ref->count))
|
||||
_tidy_intermediate_value(ref, data);
|
||||
ref->on_unref(ref, data);
|
||||
if(!ref->count)
|
||||
_gc_remove(ref, data);
|
||||
@ -4148,23 +4185,33 @@ void _destroy_ref(_ref_t* ref) {
|
||||
}
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
void _gc_add(_ref_t* ref, void* data) {
|
||||
void _gc_add(_ref_t* ref, void* data, _gc_t* gc) {
|
||||
/* Add a referenced object to GC */
|
||||
_ht_node_t* table = 0;
|
||||
|
||||
mb_assert(ref && data);
|
||||
|
||||
if(gc && _ht_find(gc->collected_table, ref))
|
||||
return;
|
||||
|
||||
if(ref->type == _DT_ARRAY)
|
||||
return;
|
||||
|
||||
if(!ref->s->gc.table)
|
||||
return;
|
||||
|
||||
if(ref->s->gc.collecting)
|
||||
if(ref->s->gc.collecting > 1)
|
||||
return;
|
||||
|
||||
if(ref->count && *ref->count)
|
||||
_ht_set_or_insert(ref->s->gc.table, ref, data);
|
||||
if(ref->s->gc.collecting)
|
||||
table = ref->s->gc.recursive_table;
|
||||
else
|
||||
_ht_remove(ref->s->gc.table, ref, 0);
|
||||
table = ref->s->gc.table;
|
||||
|
||||
if(ref->count && *ref->count)
|
||||
_ht_set_or_insert(table, ref, data);
|
||||
else
|
||||
_ht_remove(table, ref, 0);
|
||||
}
|
||||
|
||||
void _gc_remove(_ref_t* ref, void* data) {
|
||||
@ -4251,27 +4298,9 @@ 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;
|
||||
_object_t tmp;
|
||||
|
||||
mb_assert(s && ht);
|
||||
|
||||
_MAKE_NIL(&tmp);
|
||||
_public_value_to_internal_object(&s->running_context->intermediate_value, &tmp);
|
||||
switch(tmp.type) {
|
||||
case _DT_ARRAY: /* Fall through */
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
case _DT_LIST: /* Fall through */
|
||||
case _DT_DICT: /* Fall through */
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
#ifdef MB_ENABLE_CLASS
|
||||
case _DT_CLASS: /* Fall through */
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
case _DT_USERTYPE_REF:
|
||||
_gc_add_reachable(&tmp, 0, ht);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
running = s->running_context;
|
||||
while(running) {
|
||||
global_scope = running->var_dict;
|
||||
@ -4283,10 +4312,50 @@ void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht) {
|
||||
}
|
||||
}
|
||||
|
||||
int _gc_destroy_garbage_in_list(void* data, void* extra, _gc_t* gc) {
|
||||
/* Destroy only the capsule (wrapper) of an object, leave the data behind, and add it to GC if possible */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_object_t* obj = 0;
|
||||
mb_unrefvar(extra);
|
||||
|
||||
mb_assert(data);
|
||||
|
||||
obj = (_object_t*)data;
|
||||
_ADDGC(obj, gc);
|
||||
safe_free(obj);
|
||||
|
||||
result = _OP_RESULT_DEL_NODE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _gc_destroy_garbage_in_dict(void* data, void* extra, _gc_t* gc) {
|
||||
/* Destroy only the capsule (wrapper) of an object, leave the data behind, deal with extra as well, and add it to GC if possible */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_object_t* obj = 0;
|
||||
mb_unrefvar(extra);
|
||||
|
||||
mb_assert(data);
|
||||
|
||||
obj = (_object_t*)data;
|
||||
_ADDGC(obj, gc);
|
||||
safe_free(obj);
|
||||
|
||||
obj = (_object_t*)extra;
|
||||
_ADDGC(obj, gc);
|
||||
safe_free(obj);
|
||||
|
||||
result = _OP_RESULT_DEL_NODE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _gc_destroy_garbage(void* data, void* extra) {
|
||||
/* Destroy a garbage */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_gc_t* gc = 0;
|
||||
_ref_t* ref = 0;
|
||||
bool_t cld = false;
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
_list_t* lst = 0;
|
||||
_dict_t* dct = 0;
|
||||
@ -4295,18 +4364,27 @@ int _gc_destroy_garbage(void* data, void* extra) {
|
||||
mb_assert(data && extra);
|
||||
|
||||
ref = (_ref_t*)extra;
|
||||
gc = &ref->s->gc;
|
||||
switch(ref->type) {
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
case _DT_LIST:
|
||||
lst = (_list_t*)data;
|
||||
_ls_foreach(lst->list, _destroy_object_capsule_only);
|
||||
if(gc->collecting <= 1 && !_ht_find(gc->recursive_table, ref)) {
|
||||
_LS_FOREACH(lst->list, _do_nothing_on_object, _gc_destroy_garbage_in_list, gc);
|
||||
} else {
|
||||
_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);
|
||||
if(gc->collecting <= 1 && !_ht_find(gc->recursive_table, ref)) {
|
||||
_HT_FOREACH(dct->dict, _do_nothing_on_object, _gc_destroy_garbage_in_dict, gc);
|
||||
} else {
|
||||
_ht_foreach(dct->dict, _destroy_object_capsule_only_with_extra);
|
||||
}
|
||||
_ht_clear(dct->dict);
|
||||
|
||||
break;
|
||||
@ -4314,7 +4392,12 @@ int _gc_destroy_garbage(void* data, void* extra) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_unref(ref, data);
|
||||
if(ref->count) {
|
||||
cld = (*(ref->count)) == 1;
|
||||
_unref(ref, data);
|
||||
if(cld)
|
||||
_ht_set_or_insert(gc->collected_table, ref, data);
|
||||
}
|
||||
|
||||
result = _OP_RESULT_DEL_NODE;
|
||||
|
||||
@ -4345,8 +4428,14 @@ void _gc_collect_garbage(mb_interpreter_t* s) {
|
||||
_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);
|
||||
if(s->gc.recursive_table->count) {
|
||||
s->gc.collecting++;
|
||||
_ht_foreach(s->gc.recursive_table, _gc_destroy_garbage);
|
||||
_ht_clear(s->gc.recursive_table);
|
||||
s->gc.collecting--;
|
||||
}
|
||||
/* Tidy */
|
||||
_ht_clear(valid);
|
||||
_ht_destroy(valid);
|
||||
s->gc.collecting--;
|
||||
@ -6629,6 +6718,7 @@ int _dispose_scope_chain(mb_interpreter_t* s) {
|
||||
result++;
|
||||
running = prev;
|
||||
}
|
||||
s->running_context = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -6654,6 +6744,35 @@ void _tidy_scope_chain(mb_interpreter_t* s) {
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
}
|
||||
|
||||
void _tidy_intermediate_value(_ref_t* ref, void* data) {
|
||||
/* Tidy the intermediate value */
|
||||
_object_t tmp;
|
||||
|
||||
mb_assert(ref && data);
|
||||
|
||||
if(!ref->s->running_context)
|
||||
return;
|
||||
|
||||
_MAKE_NIL(&tmp);
|
||||
_public_value_to_internal_object(&ref->s->running_context->intermediate_value, &tmp);
|
||||
if(tmp.data.usertype == data) {
|
||||
switch(tmp.type) {
|
||||
case _DT_ARRAY: /* Fall through */
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
case _DT_LIST: /* Fall through */
|
||||
case _DT_DICT: /* Fall through */
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
#ifdef MB_ENABLE_CLASS
|
||||
case _DT_CLASS: /* Fall through */
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
case _DT_USERTYPE_REF:
|
||||
mb_make_nil(ref->s->running_context->intermediate_value);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _stepped(mb_interpreter_t* s, _ls_node_t* ast) {
|
||||
/* Called each step */
|
||||
_object_t* obj = 0;
|
||||
@ -7405,6 +7524,8 @@ int mb_open(struct mb_interpreter_t** s) {
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
(*s)->gc.table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
|
||||
(*s)->gc.recursive_table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
|
||||
(*s)->gc.collected_table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
(*s)->sub_stack = _ls_create();
|
||||
@ -7446,13 +7567,21 @@ int mb_close(struct mb_interpreter_t** s) {
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_collect_garbage(*s);
|
||||
_ht_destroy((*s)->gc.table);
|
||||
(*s)->gc.table = 0;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
_tidy_scope_chain(*s);
|
||||
_dispose_scope_chain(*s);
|
||||
|
||||
#ifdef MB_ENABLE_GC
|
||||
_gc_collect_garbage(*s);
|
||||
_ht_destroy((*s)->gc.table);
|
||||
_ht_destroy((*s)->gc.recursive_table);
|
||||
_ht_destroy((*s)->gc.collected_table);
|
||||
(*s)->gc.table = 0;
|
||||
(*s)->gc.recursive_table = 0;
|
||||
(*s)->gc.collected_table = 0;
|
||||
#endif /* MB_ENABLE_GC */
|
||||
|
||||
_ls_foreach((*s)->temp_values, _destroy_object);
|
||||
_ls_destroy((*s)->temp_values);
|
||||
_ls_foreach((*s)->lazy_destroy_objects, _destroy_object);
|
||||
|
@ -4,4 +4,4 @@
|
||||
|
||||
s$ = "hello "
|
||||
s$ = s$ + "world"
|
||||
PRINT s$ + "!"
|
||||
print s$ + "!"
|
@ -4,14 +4,14 @@
|
||||
|
||||
e = 50
|
||||
|
||||
PRINT "Primes in ", e, ": ", 2, ", "
|
||||
print "Primes in ", e, ": ", 2, ", "
|
||||
|
||||
FOR n = 3 TO e
|
||||
m = 2
|
||||
is = 1
|
||||
WHILE m < n
|
||||
IF n MOD m = 0 THEN is = 0 ELSE m = m + 1
|
||||
IF is = 0 THEN EXIT
|
||||
WEND
|
||||
IF is = 1 THEN PRINT n, ", "
|
||||
NEXT n
|
||||
for n = 3 to e
|
||||
m = 2
|
||||
isp = 1
|
||||
while m < n
|
||||
if n mod m = 0 then isp = 0 else m = m + 1
|
||||
if isp = 0 then exit
|
||||
wend
|
||||
if isp = 1 then print n, ", "
|
||||
next n
|
@ -2,21 +2,21 @@
|
||||
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
|
||||
' For more information, see https://github.com/paladin-t/my_basic/
|
||||
|
||||
PRINT "Input: "
|
||||
INPUT ns$
|
||||
n = VAL(ns$)
|
||||
print "Input: "
|
||||
input ns$
|
||||
n = val(ns$)
|
||||
|
||||
x = n * 2 - 1
|
||||
a = 1 - 1 / 3
|
||||
w = (x - 5) / 2 + 1
|
||||
v = 100 / w
|
||||
|
||||
FOR y = 5 TO x STEP 2
|
||||
for y = 5 to x step 2
|
||||
iy = (y - 1) / 4
|
||||
iy = FLOOR(iy)
|
||||
IF iy = (y - 1) / 4 THEN a = a + 1 / y ELSE a = a - 1 / y
|
||||
iy = floor(iy)
|
||||
if iy = (y - 1) / 4 then a = a + 1 / y else a = a - 1 / y
|
||||
u = u + v
|
||||
NEXT
|
||||
next
|
||||
a = a * 4
|
||||
|
||||
PRINT "PI = ", a
|
||||
print "Pi = ", a
|
@ -2,22 +2,22 @@
|
||||
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
|
||||
' For more information, see https://github.com/paladin-t/my_basic/
|
||||
|
||||
BEGIN:
|
||||
begin:
|
||||
n = 10
|
||||
DIM arr(n)
|
||||
GOSUB CALC
|
||||
GOSUB SHOW
|
||||
END
|
||||
dim arr(n)
|
||||
gosub calc
|
||||
gosub show
|
||||
end
|
||||
|
||||
CALC:
|
||||
calc:
|
||||
arr(0) = 1
|
||||
FOR i = 1 TO n - 1
|
||||
IF i = 1 THEN arr(i) = 1 ELSE arr(i) = arr(i - 1) + arr(i - 2)
|
||||
NEXT
|
||||
RETURN
|
||||
for i = 1 to n - 1
|
||||
if i = 1 then arr(i) = 1 else arr(i) = arr(i - 1) + arr(i - 2)
|
||||
next
|
||||
return
|
||||
|
||||
SHOW:
|
||||
FOR i = 0 TO n - 1
|
||||
PRINT arr(i), ", "
|
||||
NEXT
|
||||
RETURN
|
||||
show:
|
||||
for i = 0 to n - 1
|
||||
print arr(i), ", "
|
||||
next
|
||||
return
|
@ -2,14 +2,14 @@
|
||||
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
|
||||
' For more information, see https://github.com/paladin-t/my_basic/
|
||||
|
||||
DEF AREA(a, b)
|
||||
RETURN CALL MUL(a, b)
|
||||
ENDDEF
|
||||
def area(a, b)
|
||||
return call mul(a, b)
|
||||
enddef
|
||||
|
||||
DEF MUL(a, b)
|
||||
def mul(a, b)
|
||||
return a * b
|
||||
ENDDEF
|
||||
enddef
|
||||
|
||||
a = 3
|
||||
b = 4
|
||||
PRINT a; b; AREA(a, b);
|
||||
print a; b; area(a, b);
|
Loading…
x
Reference in New Issue
Block a user