diff --git a/c/mapping/mapper_filter.c b/c/mapping/mapper_filter.c index b41a8810c..91ce73f0c 100644 --- a/c/mapping/mapper_filter.c +++ b/c/mapping/mapper_filter.c @@ -212,6 +212,10 @@ static sllv_t* mapper_filter_process(lrec_t* pinrec, context_t* pctx, void* pvst .pctx = pctx, .pbind_stack = NULL, .ploop_stack = NULL, + .return_state = { + .returned = FALSE, + .retval = mv_absent(), + } }; mv_t val = pstate->pevaluator->pprocess_func(pstate->pevaluator->pvstate, &variables); diff --git a/c/mapping/mapper_put.c b/c/mapping/mapper_put.c index ec1b4c0a4..6b115c67c 100644 --- a/c/mapping/mapper_put.c +++ b/c/mapping/mapper_put.c @@ -350,6 +350,10 @@ static sllv_t* mapper_put_process(lrec_t* pinrec, context_t* pctx, void* pvstate .pctx = pctx, .pbind_stack = pstate->pbind_stack, .ploop_stack = pstate->ploop_stack, + .return_state = { + .returned = FALSE, + .retval = mv_absent(), + } }; cst_outputs_t cst_outputs = (cst_outputs_t) { .pshould_emit_rec = &should_emit_rec, @@ -372,6 +376,10 @@ static sllv_t* mapper_put_process(lrec_t* pinrec, context_t* pctx, void* pvstate .pctx = pctx, .pbind_stack = pstate->pbind_stack, .ploop_stack = pstate->ploop_stack, + .return_state = { + .returned = FALSE, + .retval = mv_absent(), + } }; cst_outputs_t cst_outputs = (cst_outputs_t) { .pshould_emit_rec = &should_emit_rec, @@ -400,6 +408,10 @@ static sllv_t* mapper_put_process(lrec_t* pinrec, context_t* pctx, void* pvstate .pctx = pctx, .pbind_stack = pstate->pbind_stack, .ploop_stack = pstate->ploop_stack, + .return_state = { + .returned = FALSE, + .retval = mv_absent(), + } }; cst_outputs_t cst_outputs = (cst_outputs_t) { .pshould_emit_rec = &should_emit_rec, diff --git a/c/mapping/mlr_dsl_cst.c b/c/mapping/mlr_dsl_cst.c index 0b8034f0a..16e4829eb 100644 --- a/c/mapping/mlr_dsl_cst.c +++ b/c/mapping/mlr_dsl_cst.c @@ -116,6 +116,8 @@ static void handle_statement_list_with_break_continue( cst_outputs_t* pcst_outputs); static cst_statement_handler_t handle_subr_callsite; +static cst_statement_handler_t handle_return_void; +static cst_statement_handler_t handle_return_value; static cst_statement_handler_t handle_local_variable_assignment; static cst_statement_handler_t handle_srec_assignment; @@ -724,7 +726,6 @@ static mlr_dsl_cst_statement_t* alloc_blank() { pstatement->psubr_defsite = NULL; pstatement->local_variable_name = NULL; pstatement->preturn_evaluator = NULL; - pstatement->is_return_void = FALSE; pstatement->pblock_handler = NULL; pstatement->poosvar_lhs_keylist_evaluators = NULL; pstatement->pemit_keylist_evaluators = NULL; @@ -776,6 +777,7 @@ static mlr_dsl_cst_statement_t* alloc_return_value(mlr_dsl_cst_t* pcst, mlr_dsl_ mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pvvalue; pstatement->preturn_evaluator = rval_evaluator_alloc_from_ast(prhs_node, pcst->pfmgr, type_inferencing, context_flags); + pstatement->pnode_handler = handle_return_value; return pstatement; } @@ -783,7 +785,7 @@ static mlr_dsl_cst_statement_t* alloc_return_void(mlr_dsl_cst_t* pcst, mlr_dsl_a int type_inferencing, int context_flags) { mlr_dsl_cst_statement_t* pstatement = alloc_blank(); - pstatement->is_return_void = TRUE; + pstatement->pnode_handler = handle_return_void; return pstatement; } @@ -1996,6 +1998,10 @@ void mlr_dsl_cst_handle_statement_list( for (sllve_t* pe = pcst_statements->phead; pe != NULL; pe = pe->pnext) { mlr_dsl_cst_statement_t* pstatement = pe->pvvalue; pstatement->pnode_handler(pstatement, pvars, pcst_outputs); + // The UDF/subroutine executor will clear the flag, and consume the retval if there is one. + if (pvars->return_state.returned) { + break; + } } } @@ -2012,6 +2018,10 @@ static void handle_statement_list_with_break_continue( if (loop_stack_get(pvars->ploop_stack) != 0) { break; } + // The UDF/subroutine executor will clear the flag, and consume the retval if there is one. + if (pvars->return_state.returned) { + break; + } } } @@ -2030,6 +2040,25 @@ static void handle_subr_callsite( pstatement->subr_callsite_arguments); } +// ---------------------------------------------------------------- +static void handle_return_void( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + pvars->return_state.returned = TRUE; +} + +// ---------------------------------------------------------------- +static void handle_return_value( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + pvars->return_state.returned = TRUE; + pvars->return_state.retval = pstatement->preturn_evaluator->pprocess_func(pstatement->preturn_evaluator->pvstate, pvars); +} + // ---------------------------------------------------------------- static void handle_local_variable_assignment( mlr_dsl_cst_statement_t* pstatement, diff --git a/c/mapping/mlr_dsl_cst.h b/c/mapping/mlr_dsl_cst.h index 5aa9e89ab..50a7a9ca0 100644 --- a/c/mapping/mlr_dsl_cst.h +++ b/c/mapping/mlr_dsl_cst.h @@ -118,8 +118,6 @@ typedef struct _mlr_dsl_cst_statement_t { // Return statement within user-defined function rval_evaluator_t* preturn_evaluator; - // Return statement within user-defined subroutine - int is_return_void; // There are two variants of statement-list handlers: one for inside loop bodies which has to check break/continue // flags after each statement, and another for outside loop bodies which doesn't need to check those. (This is a diff --git a/c/mapping/mlr_dsl_cst_func_subr.c b/c/mapping/mlr_dsl_cst_func_subr.c index 938ca888f..29cfb0ce4 100644 --- a/c/mapping/mlr_dsl_cst_func_subr.c +++ b/c/mapping/mlr_dsl_cst_func_subr.c @@ -144,16 +144,15 @@ static mv_t cst_udf_process_callback(void* pvstate, int arity, mv_t* args, varia for (sllve_t* pe = pstate->pblock_statements->phead; pe != NULL; pe = pe->pnext) { mlr_dsl_cst_statement_t* pstatement = pe->pvvalue; - if (pstatement->preturn_evaluator != NULL) { - // return statement - retval = pstatement->preturn_evaluator->pprocess_func(pstatement->preturn_evaluator->pvstate, pvars); + pstatement->pnode_handler(pstatement, pvars, pcst_outputs); + if (loop_stack_get(pvars->ploop_stack) != 0) { + break; + } + if (pvars->return_state.returned) { + pvars->return_state.returned = FALSE; + retval = pvars->return_state.retval; + pvars->return_state.retval = mv_absent(); break; - } else { - // anything else - pstatement->pnode_handler(pstatement, pvars, pcst_outputs); - if (loop_stack_get(pvars->ploop_stack) != 0) { - break; - } } } @@ -270,15 +269,13 @@ void mlr_dsl_cst_execute_subroutine(subr_defsite_t* pstate, variables_t* pvars, for (sllve_t* pe = pstate->pblock_statements->phead; pe != NULL; pe = pe->pnext) { mlr_dsl_cst_statement_t* pstatement = pe->pvvalue; - if (pstatement->is_return_void) { - // return statement + pstatement->pnode_handler(pstatement, pvars, pcst_outputs); + if (loop_stack_get(pvars->ploop_stack) != 0) { + break; + } + if (pvars->return_state.returned) { + pvars->return_state.returned = FALSE; break; - } else { - // anything else - pstatement->pnode_handler(pstatement, pvars, pcst_outputs); - if (loop_stack_get(pvars->ploop_stack) != 0) { - break; - } } } diff --git a/c/mapping/rval_evaluator.h b/c/mapping/rval_evaluator.h index e88d6422e..00982ab26 100644 --- a/c/mapping/rval_evaluator.h +++ b/c/mapping/rval_evaluator.h @@ -39,6 +39,11 @@ struct _rval_evaluator_t; // forward reference for method declarations +typedef struct _return_state_t { + int returned; + mv_t retval; +} return_state_t; + typedef struct _variables_t { lrec_t* pinrec; lhmsmv_t* ptyped_overlay; @@ -47,6 +52,7 @@ typedef struct _variables_t { context_t* pctx; bind_stack_t* pbind_stack; loop_stack_t* ploop_stack; + return_state_t return_state; } variables_t; typedef mv_t rval_evaluator_process_func_t(void* pvstate, variables_t* pvars);