diff --git a/HISTORY b/HISTORY index 54b381f..8696ce4 100755 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,6 @@ Jan. 4 2016 +Added stack tracing +Added an mb_debug_get_stack_trace function and an MB_ENABLE_STACK_TRACE macro Added support to duplicate a class instance by NEW statement with an identifier string Fixed a string value copy issue in mb_pop_value diff --git a/MY-BASIC Quick Reference.pdf b/MY-BASIC Quick Reference.pdf index 60a2133..c044b4b 100644 Binary files a/MY-BASIC Quick Reference.pdf and b/MY-BASIC Quick Reference.pdf differ diff --git a/core/my_basic.c b/core/my_basic.c index 0459672..1c4aea1 100755 --- a/core/my_basic.c +++ b/core/my_basic.c @@ -264,6 +264,7 @@ static const char* _ERR_DESC[] = { "Invalid iterator", "Empty collection", "Referenced type expected", + "Stack trace disabled", /** Extended abort */ "Extended abort" }; @@ -619,6 +620,9 @@ typedef struct mb_interpreter_t { int last_error_pos; unsigned short last_error_row; unsigned short last_error_col; +#ifdef MB_ENABLE_STACK_TRACE + _ls_node_t* stack_frames; +#endif /* MB_ENABLE_STACK_TRACE */ mb_debug_stepped_handler_t debug_stepped_handler; mb_error_handler_t error_handler; mb_print_func_t printer; @@ -2761,7 +2765,13 @@ _array: } else if(c->type == _DT_FUNC) { ast = ast->prev; if(_IS_UNARY_FUNC(c)) { +#ifdef MB_ENABLE_STACK_TRACE + _ls_pushback(s->stack_frames, c->data.func->name); +#endif /* MB_ENABLE_STACK_TRACE */ result = (c->data.func->pointer)(s, (void**)&ast); +#ifdef MB_ENABLE_STACK_TRACE + _ls_popback(s->stack_frames); +#endif /* MB_ENABLE_STACK_TRACE */ } else { int calc_depth = running->calc_depth; running->calc_depth = _INFINITY_CALC_DEPTH; @@ -3089,6 +3099,10 @@ int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned /* Evaluate a routine */ int result = MB_FUNC_OK; +#ifdef MB_ENABLE_STACK_TRACE + _ls_pushback(s->stack_frames, r->name); +#endif /* MB_ENABLE_STACK_TRACE */ + if(r->is_basic && r->func.basic.entry) { result = _eval_script_routine(s, l, va, ca, r, has_arg, pop_arg); } else if(!r->is_basic && r->func.native.entry) { @@ -3098,6 +3112,10 @@ int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned } _exit: +#ifdef MB_ENABLE_STACK_TRACE + _ls_popback(s->stack_frames); +#endif /* MB_ENABLE_STACK_TRACE */ + return result; } @@ -7138,7 +7156,13 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { _retry: switch(obj->type) { case _DT_FUNC: +#ifdef MB_ENABLE_STACK_TRACE + _ls_pushback(s->stack_frames, obj->data.func->name); +#endif /* MB_ENABLE_STACK_TRACE */ result = (obj->data.func->pointer)(s, (void**)&ast); +#ifdef MB_ENABLE_STACK_TRACE + _ls_popback(s->stack_frames); +#endif /* MB_ENABLE_STACK_TRACE */ if(result == MB_FUNC_IGNORE) { result = MB_FUNC_OK; obj = (_object_t*)ast->data; @@ -7843,17 +7867,21 @@ int mb_open(struct mb_interpreter_t** s) { (*s)->temp_values = _ls_create(); (*s)->lazy_destroy_objects = _ls_create(); +#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 */ + running = _create_running_context(); running->meta = _SCOPE_META_ROOT; (*s)->running_context = running; global_scope = _ht_create(0, _ht_cmp_string, _ht_hash_string, 0); running->var_dict = global_scope; -#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 */ +#ifdef MB_ENABLE_STACK_TRACE + (*s)->stack_frames = _ls_create(); +#endif /* MB_ENABLE_STACK_TRACE */ (*s)->sub_stack = _ls_create(); @@ -7892,6 +7920,10 @@ int mb_close(struct mb_interpreter_t** s) { _ls_destroy((*s)->sub_stack); +#ifdef MB_ENABLE_STACK_TRACE + _ls_destroy((*s)->stack_frames); +#endif /* MB_ENABLE_STACK_TRACE */ + _tidy_scope_chain(*s); _dispose_scope_chain(*s); @@ -7965,6 +7997,10 @@ int mb_reset(struct mb_interpreter_t** s, bool_t clrf/* = false*/) { _ls_foreach(ast, _destroy_object); _ls_clear(ast); +#ifdef MB_ENABLE_STACK_TRACE + _ls_clear((*s)->stack_frames); +#endif /* MB_ENABLE_STACK_TRACE */ + _clear_scope_chain(*s); if(clrf) { @@ -9398,6 +9434,39 @@ int mb_debug_set(struct mb_interpreter_t* s, const char* n, mb_value_t val) { return result; } +int mb_debug_get_stack_trace(struct mb_interpreter_t* s, void** l, char** fs, unsigned fc) { + /* Get stack frame names of an interpreter instance */ +#ifdef MB_ENABLE_STACK_TRACE + int result = MB_FUNC_OK; + _ls_node_t* f = 0; + unsigned i = 0; + mb_unrefvar(l); + + mb_assert(s); + + if(fs && fc) { + f = s->stack_frames->prev; + while(f && f->data && i < fc) { + fs[i++] = (char*)f->data; + f = f->prev; + } + } + while(i < fc) + fs[i++] = 0; + + return result; +#else /* MB_ENABLE_STACK_TRACE */ + int result = MB_FUNC_OK; + mb_unrefvar(fs); + mb_unrefvar(fc); + + _handle_error_on_obj(s, SE_RN_STACK_TRACE_DISABLED, 0, TON(l), MB_FUNC_ERR, _exit, result); + +_exit: + return result; +#endif /* MB_ENABLE_STACK_TRACE */ +} + int mb_debug_set_stepped_handler(struct mb_interpreter_t* s, mb_debug_stepped_handler_t h) { /* Set a stepped handler to an interpreter instance */ int result = MB_FUNC_OK; diff --git a/core/my_basic.h b/core/my_basic.h index fa3829d..7568bc3 100755 --- a/core/my_basic.h +++ b/core/my_basic.h @@ -62,6 +62,10 @@ extern "C" { # define MB_ENABLE_SOURCE_TRACE #endif /* MB_ENABLE_SOURCE_TRACE */ +#ifndef MB_ENABLE_STACK_TRACE +# define MB_ENABLE_STACK_TRACE +#endif /* MB_ENABLE_STACK_TRACE */ + #ifndef MB_ENABLE_UNICODE # define MB_ENABLE_UNICODE #endif /* MB_ENABLE_UNICODE */ @@ -327,6 +331,7 @@ typedef enum mb_error_e { SE_RN_INVALID_ITERATOR, SE_RN_EMPTY_COLLECTION, SE_RN_REFERENCED_EXPECTED, + SE_RN_STACK_TRACE_DISABLED, /** Extended abort */ SE_EA_EXTENDED_ABORT, /** Extra */ @@ -472,6 +477,7 @@ MBAPI int mb_schedule_suspend(struct mb_interpreter_t* s, int t); MBAPI int mb_debug_get(struct mb_interpreter_t* s, const char* n, mb_value_t* val); MBAPI int mb_debug_set(struct mb_interpreter_t* s, const char* n, mb_value_t val); +MBAPI int mb_debug_get_stack_trace(struct mb_interpreter_t* s, void** l, char** fs, unsigned fc); MBAPI int mb_debug_set_stepped_handler(struct mb_interpreter_t* s, mb_debug_stepped_handler_t h); MBAPI const char* mb_get_type_string(mb_data_e t);