+added variable arguments support.

This commit is contained in:
paladin-t 2016-01-18 15:21:07 +08:00
parent 138866904f
commit 4792ac7a93
4 changed files with 192 additions and 16 deletions

View File

@ -1,4 +1,5 @@
Jan. 18 2016
Added variable arguments support
Added a NOW statement to the shell
Polished shell implementation code

View File

@ -132,6 +132,8 @@ extern "C" {
#define DON(__o) ((__o) ? ((_object_t*)((__o)->data)) : 0)
#define TON(__t) (((__t) && *(__t)) ? ((_object_t*)(((_tuple3_t*)(*(__t)))->e1)) : 0)
#define _IS_VAR_ARGS(__v) ((__v) == &_VAR_ARGS)
#define _IS_EOS(__o) (__o && ((_object_t*)(__o))->type == _DT_EOS)
#define _IS_SEP(__o, __c) (((_object_t*)(__o))->type == _DT_SEP && ((_object_t*)(__o))->data.separator == __c)
#define _IS_FUNC(__o, __f) (((_object_t*)(__o))->type == _DT_FUNC && ((_object_t*)(__o))->data.func->pointer == __f)
@ -599,6 +601,12 @@ static const _object_t _OBJ_INT_ZERO = { _DT_INT, (mb_data_e)0, false, 0 };
static _object_t* _OBJ_BOOL_TRUE = 0;
static _object_t* _OBJ_BOOL_FALSE = 0;
#ifdef MB_ENABLE_CLASS
static const _var_t _VAR_ARGS = { "...", 0, 0 };
#else /* MB_ENABLE_CLASS */
static const _var_t _VAR_ARGS = { "...", 0 };
#endif /* MB_ENABLE_CLASS */
/* Parsing context */
#define _CLASS_STATE_NONE 0
#define _CLASS_STATE_PROC 1
@ -677,6 +685,7 @@ typedef struct mb_interpreter_t {
_ls_node_t* ast;
_parsing_context_t* parsing_context;
_running_context_t* running_context;
_ls_node_t* var_args;
unsigned char jump_set;
#ifdef MB_ENABLE_CLASS
_class_t* last_instance;
@ -978,6 +987,8 @@ static _ls_node_t* _ls_find(_ls_node_t* list, void* data, _ls_compare cmp);
static _ls_node_t* _ls_back(_ls_node_t* node);
static _ls_node_t* _ls_pushback(_ls_node_t* list, void* data);
static void* _ls_popback(_ls_node_t* list);
static _ls_node_t* _ls_front(_ls_node_t* node);
static void* _ls_popfront(_ls_node_t* list);
static _ls_node_t* _ls_insert_at(_ls_node_t* list, int index, void* data);
static unsigned int _ls_remove(_ls_node_t* list, _ls_node_t* node, _ls_operation op);
static unsigned int _ls_try_remove(_ls_node_t* list, void* info, _ls_compare cmp, _ls_operation op);
@ -1091,7 +1102,10 @@ static int _get_priority_index(mb_func_t op);
static _object_t* _operate_operand(mb_interpreter_t* s, _object_t* optr, _object_t* opnd1, _object_t* opnd2, int* status);
static bool_t _is_expression_terminal(mb_interpreter_t* s, _object_t* obj);
static int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val);
static int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg, bool_t proc_ref);
static _ls_node_t* _push_var_args(mb_interpreter_t* s);
static void _pop_var_args(mb_interpreter_t* s, _ls_node_t* last_var_args);
static int _pop_arg(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned ca, unsigned* ia, _routine_t* r, mb_pop_routine_arg_func_t pop_arg, _ls_node_t* args, mb_value_t* arg);
static int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg, bool_t proc_ref, _ls_node_t* args);
static int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg);
static int _eval_script_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg);
#ifdef MB_ENABLE_LAMBDA
@ -1646,6 +1660,7 @@ static int _core_return(mb_interpreter_t* s, void** l);
static int _core_call(mb_interpreter_t* s, void** l);
static int _core_def(mb_interpreter_t* s, void** l);
static int _core_enddef(mb_interpreter_t* s, void** l);
static int _core_args(mb_interpreter_t* s, void** l);
#ifdef MB_ENABLE_CLASS
static int _core_class(mb_interpreter_t* s, void** l);
static int _core_endclass(mb_interpreter_t* s, void** l);
@ -1763,6 +1778,7 @@ static const _func_t _core_libs[] = {
{ "CALL", _core_call },
{ "DEF", _core_def },
{ "ENDDEF", _core_enddef },
{ "...", _core_args },
#ifdef MB_ENABLE_CLASS
{ "CLASS", _core_class },
@ -1964,6 +1980,35 @@ void* _ls_popback(_ls_node_t* list) {
return result;
}
_ls_node_t* _ls_front(_ls_node_t* node) {
_ls_node_t* result = node;
result = result->next;
return result;
}
void* _ls_popfront(_ls_node_t* list) {
void* result = 0;
_ls_node_t* tmp = 0;
mb_assert(list);
tmp = _ls_front(list);
if(tmp) {
result = tmp->data;
list->next = tmp->next;
if(tmp->next)
tmp->next->prev = list;
if(!list->next)
list->prev = 0;
tmp->prev = tmp->next = 0;
safe_free(tmp);
}
return result;
}
_ls_node_t* _ls_insert_at(_ls_node_t* list, int index, void* data) {
_ls_node_t* result = 0;
_ls_node_t* tmp = 0;
@ -3248,7 +3293,46 @@ _exit:
return result;
}
int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg, bool_t proc_ref) {
_ls_node_t* _push_var_args(mb_interpreter_t* s) {
/* Push current variable arguments list */
_ls_node_t* result = s->var_args;
s->var_args = 0;
return result;
}
void _pop_var_args(mb_interpreter_t* s, _ls_node_t* last_var_args) {
/* Pop current variable arguments list */
_ls_node_t* var_args = s->var_args;
s->var_args = last_var_args;
if(var_args) {
_ls_foreach(var_args, _destroy_object_capsule_only);
_ls_destroy(var_args);
}
}
int _pop_arg(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, unsigned ca, unsigned* ia, _routine_t* r, mb_pop_routine_arg_func_t pop_arg, _ls_node_t* args, mb_value_t* arg) {
/* Pop an argument from the caller or a variable argument list */
int result = MB_FUNC_OK;
_ls_node_t* ast = *l;
mb_make_nil(*arg);
if(ast && _IS_FUNC(ast->data, _core_args)) {
if(args) {
_object_t* obj = (_object_t*)_ls_popfront(args);
if(obj) {
_internal_object_to_public_value(obj, arg);
_destroy_object_capsule_only(obj, 0);
}
}
} else {
result = pop_arg(s, (void**)l, va, ca, ia, r, arg);
}
return result;
}
int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running, mb_value_t* va, unsigned ca, _routine_t* r, mb_has_routine_arg_func_t has_arg, mb_pop_routine_arg_func_t pop_arg, bool_t proc_ref, _ls_node_t* args) {
/* Process arguments of a routine */
int result = MB_FUNC_OK;
_ls_node_t* parameters = 0;
@ -3257,6 +3341,7 @@ int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running,
_var_t* var = 0;
_ls_node_t* rnode = 0;
unsigned ia = 0;
_ls_node_t* var_args = 0;
parameters = r->func.basic.parameters;
#ifdef MB_ENABLE_LAMBDA
@ -3269,16 +3354,17 @@ int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running,
pars = parameters;
pars = pars->next;
while(pars && (!has_arg || (has_arg && has_arg(s, (void**)l, va, ca, &ia, r)))) {
_object_t* obj = 0;
if(pop_arg) {
mb_make_nil(arg);
mb_check(pop_arg(s, (void**)l, va, ca, &ia, r, &arg));
}
var = (_var_t*)pars->data;
pars = pars->next;
if(_IS_VAR_ARGS(var))
break;
if(pop_arg) {
mb_check(_pop_arg(s, l, va, ca, &ia, r, pop_arg, args, &arg));
}
if(running->meta == _SCOPE_META_REF) {
obj = (_object_t*)(_ht_find(running->var_dict, var->name)->data);
_object_t* obj = (_object_t*)(_ht_find(running->var_dict, var->name)->data);
var = obj->data.variable;
if(proc_ref)
@ -3293,8 +3379,38 @@ int _proc_args(mb_interpreter_t* s, _ls_node_t** l, _running_context_t* running,
}
result = _public_value_to_internal_object(&arg, var->data);
if(result != MB_FUNC_OK)
break;
if(args && _ls_empty(args))
break;
}
if(_IS_VAR_ARGS(var)) {
if(has_arg && !var_args && _IS_VAR_ARGS(var))
var_args = s->var_args = _ls_create();
while(has_arg && has_arg(s, (void**)l, va, ca, &ia, r)) {
if(pop_arg) {
mb_check(_pop_arg(s, l, va, ca, &ia, r, pop_arg, args, &arg));
}
if(var_args) {
_object_t* obj = _create_object();
result = _public_value_to_internal_object(&arg, obj);
_ls_pushback(var_args, obj);
}
if(args && _ls_empty(args))
break;
}
}
if(_IS_VAR_ARGS(var)) {
if(args) {
_ls_node_t* ast = *l;
if(ast) ast = ast->next;
*l = ast;
}
}
}
@ -3336,6 +3452,7 @@ int _eval_script_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
_running_context_t* running = 0;
_routine_t* lastr = 0;
mb_value_t inte;
_ls_node_t* lastv = 0;
mb_assert(s && l && r);
@ -3356,12 +3473,14 @@ int _eval_script_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
lastr = s->last_routine;
s->last_routine = r;
lastv = _push_var_args(s);
if(!va) {
mb_check(mb_attempt_open_bracket(s, (void**)l));
}
running = _push_weak_scope_by_routine(s, r->func.basic.scope, r);
result = _proc_args(s, l, running, va, ca, r, has_arg, pop_arg, true);
result = _proc_args(s, l, running, va, ca, r, has_arg, pop_arg, true, lastv);
if(result != MB_FUNC_OK) {
if(running->meta == _SCOPE_META_REF)
_destroy_scope(s, running);
@ -3373,7 +3492,7 @@ int _eval_script_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
running = _pop_weak_scope(s, running);
if(!va) {
mb_check(mb_attempt_close_bracket(s, (void**)l));
_mb_check_mark(mb_attempt_close_bracket(s, (void**)l), result, _error);
}
ast = (_ls_node_t*)*l;
@ -3414,7 +3533,7 @@ int _eval_script_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
_out_of_scope(s, running, 0, true);
#endif /* MB_ENABLE_CLASS */
result = _proc_args(s, l, running, 0, 0, r, 0, 0, false);
result = _proc_args(s, l, running, 0, 0, r, 0, 0, false, 0);
if(result != MB_FUNC_OK)
goto _exit;
@ -3430,8 +3549,11 @@ _exit:
if(result != MB_FUNC_OK)
_pop_scope(s, true);
_error:
s->last_routine = lastr;
_pop_var_args(s, lastv);
_tail:
return result;
}
@ -3444,18 +3566,21 @@ int _eval_lambda_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
_running_context_t* running = 0;
_routine_t* lastr = 0;
mb_value_t inte;
_ls_node_t* lastv = 0;
mb_assert(s && l && r);
lastr = s->last_routine;
s->last_routine = r;
lastv = _push_var_args(s);
if(!va) {
mb_check(mb_attempt_open_bracket(s, (void**)l));
}
running = _link_lambda_scope_chain(s, &r->func.lambda, true);
result = _proc_args(s, l, running, va, ca, r, has_arg, pop_arg, true);
result = _proc_args(s, l, running, va, ca, r, has_arg, pop_arg, true, lastv);
if(result != MB_FUNC_OK) {
_unlink_lambda_scope_chain(s, &r->func.lambda, true);
@ -3464,7 +3589,7 @@ int _eval_lambda_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
running = _unlink_lambda_scope_chain(s, &r->func.lambda, true);
if(!va) {
mb_check(mb_attempt_close_bracket(s, (void**)l));
_mb_check_mark(mb_attempt_close_bracket(s, (void**)l), result, _error);
}
ast = (_ls_node_t*)*l;
@ -3501,7 +3626,7 @@ int _eval_lambda_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
_out_of_scope(s, running, 0, true);
result = _proc_args(s, l, running, 0, 0, r, 0, 0, false);
result = _proc_args(s, l, running, 0, 0, r, 0, 0, false, 0);
if(result != MB_FUNC_OK)
goto _exit;
@ -3517,8 +3642,11 @@ _exit:
if(result != MB_FUNC_OK)
_unlink_lambda_scope_chain(s, &r->func.lambda, false);
_error:
s->last_routine = lastr;
_pop_var_args(s, lastv);
*l = ast;
return result;
@ -3530,12 +3658,15 @@ int _eval_native_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
int result = MB_FUNC_OK;
_routine_t* lastr = 0;
mb_routine_func_t entry = 0;
_ls_node_t* lastv = 0;
mb_assert(s && l && r);
lastr = s->last_routine;
s->last_routine = r;
lastv = _push_var_args(s);
entry = r->func.native.entry;
if(!entry) {
_handle_error_on_obj(s, SE_RN_INVALID_ROUTINE, s->source_file, TON(l), MB_FUNC_ERR, _exit, result);
@ -3546,6 +3677,8 @@ int _eval_native_routine(mb_interpreter_t* s, _ls_node_t** l, mb_value_t* va, un
_exit:
s->last_routine = lastr;
_pop_var_args(s, lastv);
return result;
}
@ -10357,6 +10490,8 @@ int mb_run(struct mb_interpreter_t* s) {
_destroy_parsing_context(&s->parsing_context);
s->source_file = 0;
s->handled_error = false;
if(s->suspent_point) {
@ -12175,6 +12310,10 @@ int _core_def(mb_interpreter_t* s, void** l) {
if(!routine->func.basic.parameters)
routine->func.basic.parameters = _ls_create();
_ls_pushback(routine->func.basic.parameters, var);
} else if(_IS_FUNC(obj, _core_args)) {
if(!routine->func.basic.parameters)
routine->func.basic.parameters = _ls_create();
_ls_pushback(routine->func.basic.parameters, (void*)&_VAR_ARGS);
}
ast = ast->next;
@ -12213,6 +12352,42 @@ _exit:
return result;
}
int _core_args(mb_interpreter_t* s, void** l) {
/* ... (variable argument list) statement */
int result = MB_FUNC_OK;
_ls_node_t* ast = 0;
_ls_node_t* var_args = 0;
bool_t pushed = false;
mb_assert(s && l);
ast = (_ls_node_t*)*l;
if(ast) ast = ast->next;
*l = ast;
var_args = s->var_args;
if(var_args) {
_object_t* obj = (_object_t*)_ls_popfront(var_args);
if(obj) {
mb_value_t arg;
mb_make_nil(arg);
_internal_object_to_public_value(obj, &arg);
mb_check(mb_push_value(s, l, arg));
pushed = true;
_destroy_object_capsule_only(obj, 0);
}
}
if(!pushed) {
mb_value_t arg;
mb_make_nil(arg);
arg.type = MB_DT_UNKNOWN;
mb_check(mb_push_value(s, l, arg));
}
return result;
}
#ifdef MB_ENABLE_CLASS
int _core_class(mb_interpreter_t* s, void** l) {
/* CLASS statement */

Binary file not shown.

View File

@ -870,7 +870,7 @@ static int _do_line(void) {
result = _new_program();
} else if(_str_eq(line, "RUN")) {
int i = 0;
mb_assert(_get_code());
mb_assert(_code());
result = mb_reset(&bas, false);
for(i = 0; i < _code()->count; ++i) {
if(result)