From 2ee9736407b49e0ea4f3be3ee3e323552e21008d Mon Sep 17 00:00:00 2001 From: John Kerl Date: Sun, 6 Nov 2016 11:10:55 -0500 Subject: [PATCH] cst-federation: for-map statements --- c/mapping/Makefile.am | 1 + c/mapping/mlr_dsl_cst.h | 20 +- c/mapping/mlr_dsl_cst_for_map_statements.c | 745 +++++++++++++++++++++ c/mapping/mlr_dsl_cst_statements.c | 615 ----------------- 4 files changed, 754 insertions(+), 627 deletions(-) create mode 100644 c/mapping/mlr_dsl_cst_for_map_statements.c diff --git a/c/mapping/Makefile.am b/c/mapping/Makefile.am index e973620ad..9868e47da 100644 --- a/c/mapping/Makefile.am +++ b/c/mapping/Makefile.am @@ -60,6 +60,7 @@ libmapping_la_SOURCES= \ mlr_dsl_cst_unset_statements.c \ mlr_dsl_cst_condish_statements.c \ mlr_dsl_cst_for_srec_statements.c \ + mlr_dsl_cst_for_map_statements.c \ mlr_dsl_cst_triple_for_statements.c \ mlr_dsl_cst_loop_control_statements.c \ mlr_dsl_cst_return_statements.c \ diff --git a/c/mapping/mlr_dsl_cst.h b/c/mapping/mlr_dsl_cst.h index 0d858c435..8a1719ba5 100644 --- a/c/mapping/mlr_dsl_cst.h +++ b/c/mapping/mlr_dsl_cst.h @@ -195,18 +195,7 @@ typedef struct _mlr_dsl_cst_statement_t { sllv_t* poosvar_rhs_keylist_evaluators; // Vararg stuff for emit and unset - sllv_t* pvarargs; - - char** for_map_k_variable_names; - int* for_map_k_frame_relative_indices; - int* for_map_k_type_masks; - int for_map_k_count; - - char* for_v_variable_name; - int for_v_frame_relative_index; - int for_v_type_mask; - - int for_map_target_frame_relative_index; + sllv_t* pvarargs; // factor out of emit as well, as i did for unset } mlr_dsl_cst_statement_t; @@ -411,6 +400,13 @@ mlr_dsl_cst_statement_allocator_t alloc_unset; // mapping/mlr_dsl_cst_for_srec_statements.c mlr_dsl_cst_statement_allocator_t alloc_for_srec; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// mapping/mlr_dsl_cst_for_map_statements.c +mlr_dsl_cst_statement_allocator_t alloc_for_oosvar; +mlr_dsl_cst_statement_allocator_t alloc_for_oosvar_key_only; +mlr_dsl_cst_statement_allocator_t alloc_for_local_map; +mlr_dsl_cst_statement_allocator_t alloc_for_local_map_key_only; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // mapping/mlr_dsl_cst_triple_for_statements.c mlr_dsl_cst_statement_allocator_t alloc_triple_for; diff --git a/c/mapping/mlr_dsl_cst_for_map_statements.c b/c/mapping/mlr_dsl_cst_for_map_statements.c new file mode 100644 index 000000000..370c1577a --- /dev/null +++ b/c/mapping/mlr_dsl_cst_for_map_statements.c @@ -0,0 +1,745 @@ +#include +#include "lib/mlr_globals.h" +#include "lib/mlrutil.h" +#include "mlr_dsl_cst.h" +#include "context_flags.h" + +static void handle_for_oosvar_aux( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs, + mlhmmv_value_t submap, + char** prest_for_k_variable_names, + int* prest_for_k_frame_relative_indices, + int* prest_for_k_frame_type_masks, + int prest_for_k_count); + +static void handle_for_local_map_aux( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs, + mlhmmv_value_t submap, + char** prest_for_k_variable_names, + int* prest_for_k_frame_relative_indices, + int* prest_for_k_frame_type_masks, + int prest_for_k_count); + +// ================================================================ +typedef struct _for_oosvar_state_t { + char** k_variable_names; + int* k_frame_relative_indices; + int* k_type_masks; + int k_count; + + char* v_variable_name; + int v_frame_relative_index; + int v_type_mask; + + sllv_t* ptarget_keylist_evaluators; +} for_oosvar_state_t; + +static mlr_dsl_cst_statement_handler_t handle_for_oosvar; +static mlr_dsl_cst_statement_freer_t free_for_oosvar; + +// ---------------------------------------------------------------- +// $ mlr -n put -v 'for((k1,k2,k3),v in @a["4"][$5]) { $6 = 7; $8 = 9}' +// AST ROOT: +// text="block", type=STATEMENT_BLOCK: +// text="for", type=FOR_OOSVAR: +// text="key_and_value_variables", type=FOR_VARIABLES: +// text="key_variables", type=FOR_VARIABLES: +// text="k1", type=UNTYPED_LOCAL_DEFINITION. +// text="k2", type=UNTYPED_LOCAL_DEFINITION. +// text="k3", type=UNTYPED_LOCAL_DEFINITION. +// text="v", type=UNTYPED_LOCAL_DEFINITION. +// text="oosvar_keylist", type=OOSVAR_KEYLIST: +// text="a", type=STRING_LITERAL. +// text="4", type=STRING_LITERAL. +// text="5", type=FIELD_NAME. +// text="for_loop_oosvar_block", type=STATEMENT_BLOCK: +// text="=", type=SREC_ASSIGNMENT: +// text="6", type=FIELD_NAME. +// text="7", type=NUMERIC_LITERAL. +// text="=", type=SREC_ASSIGNMENT: +// text="8", type=FIELD_NAME. +// text="9", type=NUMERIC_LITERAL. + +mlr_dsl_cst_statement_t* alloc_for_oosvar(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ + for_oosvar_state_t* pstate = mlr_malloc_or_die(sizeof(for_oosvar_state_t)); + + pstate->k_variable_names = NULL; + pstate->k_frame_relative_indices = NULL; + pstate->k_type_masks = NULL; + pstate->k_count = 0; + + pstate->v_variable_name = NULL; + pstate->v_frame_relative_index = MD_UNUSED_INDEX; + pstate->v_type_mask = 0; + + pstate->ptarget_keylist_evaluators = NULL; + + // Left child node is list of bound variables. + // - Left subnode is namelist for key boundvars. + // - Right subnode is name for value boundvar. + // Middle child node is keylist for basepoint in the oosvar mlhmmv. + // Right child node is the list of statements in the body. + mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* psubleft = pleft->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* psubright = pleft->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; + + pstate->k_variable_names = mlr_malloc_or_die(sizeof(char*) * psubleft->pchildren->length); + pstate->k_frame_relative_indices = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); + pstate->k_type_masks = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); + pstate->k_count = 0; + for (sllve_t* pe = psubleft->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pnamenode = pe->pvvalue; + MLR_INTERNAL_CODING_ERROR_IF(pnamenode->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->k_variable_names[pstate->k_count] = pnamenode->text; + pstate->k_frame_relative_indices[pstate->k_count] = pnamenode->vardef_frame_relative_index; + pstate->k_type_masks[pstate->k_count] = mlr_dsl_ast_node_type_to_type_mask(pnamenode->type); + pstate->k_count++; + } + pstate->v_variable_name = psubright->text; + MLR_INTERNAL_CODING_ERROR_IF(psubright->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->v_frame_relative_index = psubright->vardef_frame_relative_index; + pstate->v_type_mask = mlr_dsl_ast_node_type_to_type_mask(psubright->type); + + pstate->ptarget_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( + pcst, pmiddle, type_inferencing, context_flags); + + MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); + cst_statement_block_t* pblock = cst_statement_block_alloc(pnode->subframe_var_count); + + for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; + sllv_append(pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, + type_inferencing, context_flags)); + } + + return mlr_dsl_cst_statement_valloc_with_block( + pnode, + handle_for_oosvar, + pblock, + handle_statement_block_with_break_continue, + free_for_oosvar, + pstate); +} + +// ---------------------------------------------------------------- +static void free_for_oosvar(mlr_dsl_cst_statement_t* pstatement) { + for_oosvar_state_t* pstate = pstatement->pvstate; + + free(pstate->k_variable_names); + free(pstate->k_frame_relative_indices); + free(pstate->k_type_masks); + for (sllve_t* pe = pstate->ptarget_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) { + rval_evaluator_t* pev = pe->pvvalue; + pev->pfree_func(pev); + } + sllv_free(pstate->ptarget_keylist_evaluators); + + free(pstate); +} + +// ---------------------------------------------------------------- +static void handle_for_oosvar( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + for_oosvar_state_t* pstate = pstatement->pvstate; + + // Evaluate the keylist: e.g. in 'for ((k1, k2), v in @a[$3][x]) { ... }', find the values of $3 + // and x for the current record and stack frame. The keylist bindings are outside the scope + // of the for-loop, while the k1/k2/v are bound within the for-loop. + + int keys_all_non_null_or_error = FALSE; + sllmv_t* ptarget_keylist = evaluate_list(pstate->ptarget_keylist_evaluators, pvars, + &keys_all_non_null_or_error); + if (keys_all_non_null_or_error) { + + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); + loop_stack_push(pvars->ploop_stack); + + // Locate and copy the submap indexed by the keylist. E.g. in 'for ((k1, k2), v in @a[3][$4]) { ... }', the + // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the + // for-loop. + mlhmmv_value_t submap = mlhmmv_copy_submap_from_root(pvars->poosvars, ptarget_keylist); + + if (!submap.is_terminal && submap.u.pnext_level != NULL) { + // Recurse over the for-k-names, e.g. ["k1", "k2"], on each call descending one level + // deeper into the submap. Note there must be at least one k-name so we are assuming + // the for-loop within handle_for_oosvar_aux was gone through once & thus + // handle_statement_block_with_break_continue was called through there. + + handle_for_oosvar_aux(pstatement, pvars, pcst_outputs, submap, + pstate->k_variable_names, pstate->k_frame_relative_indices, + pstate->k_type_masks, pstate->k_count); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); + } + if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + } + + mlhmmv_free_submap(submap); + + loop_stack_pop(pvars->ploop_stack); + local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); + } + sllmv_free(ptarget_keylist); +} + +static void handle_for_oosvar_aux( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs, + mlhmmv_value_t submap, + char** prest_for_k_variable_names, + int* prest_for_k_frame_relative_indices, + int* prest_for_k_type_masks, + int prest_for_k_count) +{ + for_oosvar_state_t* pstate = pstatement->pvstate; + + if (prest_for_k_count > 0) { // Keep recursing over remaining k-names + + if (submap.is_terminal) { + // The submap was too shallow for the user-specified k-names; there are no terminals here. + } else { + // Loop over keys at this submap level: + for (mlhmmv_level_entry_t* pe = submap.u.pnext_level->phead; pe != NULL; pe = pe->pnext) { + // Bind the k-name to the entry-key mlrval: + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_frame_define(pframe, prest_for_k_variable_names[0], prest_for_k_frame_relative_indices[0], + prest_for_k_type_masks[0], mv_copy(&pe->level_key)); + // Recurse into the next-level submap: + handle_for_oosvar_aux(pstatement, pvars, pcst_outputs, pe->level_value, + &prest_for_k_variable_names[1], &prest_for_k_frame_relative_indices[1], &prest_for_k_type_masks[1], + prest_for_k_count - 1); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + // Bit cleared in recursive caller + return; + } else if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + + } + } + + } else { // End of recursion: k-names have all been used up + + if (!submap.is_terminal) { + // The submap was too deep for the user-specified k-names; there are no terminals here. + } else { + // Bind the v-name to the terminal mlrval: + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_frame_define(pframe, pstate->v_variable_name, pstate->v_frame_relative_index, + pstate->v_type_mask, mv_copy(&submap.u.mlrval)); + // Execute the loop-body statements: + pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); + } + + } +} + +// ================================================================ +typedef struct _for_oosvar_key_only_state_t { + char* k_variable_name; + int k_frame_relative_index; + int k_type_mask; + + char* v_variable_name; + int v_frame_relative_index; + int v_type_mask; + + sllv_t* ptarget_keylist_evaluators; +} for_oosvar_key_only_state_t; + +static mlr_dsl_cst_statement_handler_t handle_for_oosvar_key_only; +static mlr_dsl_cst_statement_freer_t free_for_oosvar_key_only; + +// ---------------------------------------------------------------- +mlr_dsl_cst_statement_t* alloc_for_oosvar_key_only(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ + for_oosvar_key_only_state_t* pstate = mlr_malloc_or_die(sizeof(for_oosvar_key_only_state_t)); + + pstate->k_variable_name = NULL; + pstate->k_frame_relative_index = MD_UNUSED_INDEX; + pstate->k_type_mask = 0; + + pstate->v_variable_name = NULL; + pstate->v_frame_relative_index = MD_UNUSED_INDEX; + pstate->v_type_mask = 0; + + pstate->ptarget_keylist_evaluators = NULL; + + // Left child node is single bound variable + // Middle child node is keylist for basepoint in the oosvar mlhmmv. + // Right child node is the list of statements in the body. + mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; + + MLR_INTERNAL_CODING_ERROR_IF(pleft->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->k_variable_name = pleft->text; + pstate->k_frame_relative_index = pleft->vardef_frame_relative_index; + pstate->k_type_mask = mlr_dsl_ast_node_type_to_type_mask(pleft->type); + + pstate->ptarget_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( + pcst, pmiddle, type_inferencing, context_flags); + + MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); + cst_statement_block_t* pblock = cst_statement_block_alloc(pnode->subframe_var_count); + + for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; + sllv_append(pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, + type_inferencing, context_flags)); + } + + return mlr_dsl_cst_statement_valloc_with_block( + pnode, + handle_for_oosvar_key_only, + pblock, + handle_statement_block_with_break_continue, + free_for_oosvar_key_only, + pstate); +} + +// ---------------------------------------------------------------- +static void free_for_oosvar_key_only(mlr_dsl_cst_statement_t* pstatement) { + for_oosvar_key_only_state_t* pstate = pstatement->pvstate; + + for (sllve_t* pe = pstate->ptarget_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) { + rval_evaluator_t* pev = pe->pvvalue; + pev->pfree_func(pev); + } + sllv_free(pstate->ptarget_keylist_evaluators); + + free(pstate); +} + +// ---------------------------------------------------------------- +static void handle_for_oosvar_key_only( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + for_oosvar_key_only_state_t* pstate = pstatement->pvstate; + + // Evaluate the keylist: e.g. in 'for (k in @a[$3][x]) { ... }', find the values of $3 + // and x for the current record and stack frame. The keylist bindings are outside the scope + // of the for-loop, while the k is bound within the for-loop. + + int keys_all_non_null_or_error = FALSE; + sllmv_t* ptarget_keylist = evaluate_list(pstate->ptarget_keylist_evaluators, pvars, + &keys_all_non_null_or_error); + if (keys_all_non_null_or_error) { + // Locate the submap indexed by the keylist and copy its keys. E.g. in 'for (k1 in @a[3][$4]) { ... }', the + // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the + // for-loop. + + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); + loop_stack_push(pvars->ploop_stack); + + sllv_t* pkeys = mlhmmv_copy_keys_from_submap(pvars->poosvars, ptarget_keylist); + + for (sllve_t* pe = pkeys->phead; pe != NULL; pe = pe->pnext) { + // Bind the v-name to the terminal mlrval: + local_stack_frame_define(pframe, + pstate->k_variable_name, pstate->k_frame_relative_index, + pstate->k_type_mask, mv_copy(pe->pvvalue)); + + // Execute the loop-body statements: + pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); + } + if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + + mv_free(pe->pvvalue); + free(pe->pvvalue); + } + + loop_stack_pop(pvars->ploop_stack); + local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); + + sllv_free(pkeys); + } + sllmv_free(ptarget_keylist); +} + +// ================================================================ +typedef struct _for_local_map_state_t { + char** k_variable_names; + int* k_frame_relative_indices; + int* k_type_masks; + int k_count; + + char* v_variable_name; + int v_frame_relative_index; + int v_type_mask; + + int target_frame_relative_index; + sllv_t* ptarget_keylist_evaluators; +} for_local_map_state_t; + +static mlr_dsl_cst_statement_handler_t handle_for_local_map; +static mlr_dsl_cst_statement_freer_t free_for_local_map; + +// ---------------------------------------------------------------- +mlr_dsl_cst_statement_t* alloc_for_local_map(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ + for_local_map_state_t* pstate = mlr_malloc_or_die(sizeof(for_local_map_state_t)); + + pstate->k_variable_names = NULL; + pstate->k_frame_relative_indices = NULL; + pstate->k_type_masks = NULL; + pstate->k_count = 0; + + pstate->v_variable_name = NULL; + pstate->v_frame_relative_index = MD_UNUSED_INDEX; + pstate->v_type_mask = 0; + + pstate->target_frame_relative_index = MD_UNUSED_INDEX; + pstate->ptarget_keylist_evaluators = NULL; + + // Left child node is list of bound variables. + // Left subnode is namelist for key boundvars. + // Right subnode is name for value boundvar. + // Middle child node is keylist for basepoint in the local mlhmmv. + // Right child node is the list of statements in the body. + mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* psubleft = pleft->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* psubright = pleft->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; + + pstate->k_variable_names = mlr_malloc_or_die(sizeof(char*) * psubleft->pchildren->length); + pstate->k_frame_relative_indices = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); + pstate->k_type_masks = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); + pstate->k_count = 0; + for (sllve_t* pe = psubleft->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pnamenode = pe->pvvalue; + MLR_INTERNAL_CODING_ERROR_IF(pnamenode->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->k_variable_names[pstate->k_count] = pnamenode->text; + pstate->k_frame_relative_indices[pstate->k_count] = pnamenode->vardef_frame_relative_index; + pstate->k_type_masks[pstate->k_count] = mlr_dsl_ast_node_type_to_type_mask(pnamenode->type); + pstate->k_count++; + } + pstate->v_variable_name = psubright->text; + MLR_INTERNAL_CODING_ERROR_IF(psubright->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->v_frame_relative_index = psubright->vardef_frame_relative_index; + pstate->v_type_mask = mlr_dsl_ast_node_type_to_type_mask(psubright->type); + + // xxx comment liberally + MLR_INTERNAL_CODING_ERROR_IF(pmiddle->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->target_frame_relative_index = pmiddle->vardef_frame_relative_index; + pstate->ptarget_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( // xxx rename x 2 + pcst, pmiddle, type_inferencing, context_flags); + + MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); + cst_statement_block_t* pblock = cst_statement_block_alloc(pnode->subframe_var_count); + + for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; + sllv_append(pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, + type_inferencing, context_flags)); + } + + return mlr_dsl_cst_statement_valloc_with_block( + pnode, + handle_for_local_map, + pblock, + handle_statement_block_with_break_continue, + free_for_local_map, + pstate); +} + +// ---------------------------------------------------------------- +static void free_for_local_map(mlr_dsl_cst_statement_t* pstatement) { + for_local_map_state_t* pstate = pstatement->pvstate; + + free(pstate->k_variable_names); + free(pstate->k_frame_relative_indices); + free(pstate->k_type_masks); + for (sllve_t* pe = pstate->ptarget_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) { + rval_evaluator_t* pev = pe->pvvalue; + pev->pfree_func(pev); + } + sllv_free(pstate->ptarget_keylist_evaluators); + + free(pstate); +} + +// ---------------------------------------------------------------- +static void handle_for_local_map( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + for_local_map_state_t* pstate = pstatement->pvstate; + + // Evaluate the keylist: e.g. in 'for ((k1, k2), v in @a[$3][x]) { ... }', find the values of $3 + // and x for the current record and stack frame. The keylist bindings are outside the scope + // of the for-loop, while the k1/k2/v are bound within the for-loop. + + int keys_all_non_null_or_error = FALSE; + sllmv_t* ptarget_keylist = evaluate_list(pstate->ptarget_keylist_evaluators, pvars, + &keys_all_non_null_or_error); + if (keys_all_non_null_or_error) { + + // In '(for a, b in c) { ... }' the 'c' is evaluated in the outer scope and + // the a, b are bound within the inner scope. + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + + // Locate and copy the submap indexed by the keylist. E.g. in 'for ((k1, k2), v in a[3][$4]) + // { ... }', the submap is first indexed by the stack-frame slot for "a", then further + // indexed by [3, $4]. Copy it for the very likely case that it is being updated inside the + // for-loop. + + mlhmmv_value_t *psubmap = local_stack_frame_get_map_value(pframe, + pstate->target_frame_relative_index, ptarget_keylist); + + if (psubmap != NULL) { + mlhmmv_value_t submap = mlhmmv_copy_aux(psubmap); + + local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); + loop_stack_push(pvars->ploop_stack); + + if (!submap.is_terminal && submap.u.pnext_level != NULL) { + // Recurse over the for-k-names, e.g. ["k1", "k2"], on each call descending one level + // deeper into the submap. Note there must be at least one k-name so we are assuming + // the for-loop within handle_for_local_map_aux was gone through once & thus + // handle_statement_block_with_break_continue was called through there. + + handle_for_local_map_aux(pstatement, pvars, pcst_outputs, submap, + pstate->k_variable_names, pstate->k_frame_relative_indices, + pstate->k_type_masks, pstate->k_count); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); + } + if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + } + + mlhmmv_free_submap(submap); + + loop_stack_pop(pvars->ploop_stack); + local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); + } + } + sllmv_free(ptarget_keylist); +} + +static void handle_for_local_map_aux( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs, + mlhmmv_value_t submap, + char** prest_for_k_variable_names, + int* prest_for_k_frame_relative_indices, + int* prest_for_k_type_masks, + int prest_for_k_count) +{ + for_local_map_state_t* pstate = pstatement->pvstate; + + if (prest_for_k_count > 0) { // Keep recursing over remaining k-names + + if (submap.is_terminal) { + // The submap was too shallow for the user-specified k-names; there are no terminals here. + } else { + // Loop over keys at this submap level: + for (mlhmmv_level_entry_t* pe = submap.u.pnext_level->phead; pe != NULL; pe = pe->pnext) { + // Bind the k-name to the entry-key mlrval: + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_frame_define(pframe, prest_for_k_variable_names[0], prest_for_k_frame_relative_indices[0], + prest_for_k_type_masks[0], mv_copy(&pe->level_key)); + // Recurse into the next-level submap: + handle_for_local_map_aux(pstatement, pvars, pcst_outputs, pe->level_value, + &prest_for_k_variable_names[1], &prest_for_k_frame_relative_indices[1], &prest_for_k_type_masks[1], + prest_for_k_count - 1); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + // Bit cleared in recursive caller + return; + } else if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + + } + } + + } else { // End of recursion: k-names have all been used up + + if (!submap.is_terminal) { + // The submap was too deep for the user-specified k-names; there are no terminals here. + } else { + // Bind the v-name to the terminal mlrval: + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + local_stack_frame_define(pframe, pstate->v_variable_name, pstate->v_frame_relative_index, + pstate->v_type_mask, mv_copy(&submap.u.mlrval)); + // Execute the loop-body statements: + pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); + } + + } +} + +// ================================================================ +typedef struct _for_local_map_key_only_state_t { + char* k_variable_name; + int k_frame_relative_index; + int k_type_mask; + + char* v_variable_name; + int v_frame_relative_index; + int v_type_mask; + + int target_frame_relative_index; + sllv_t* ptarget_keylist_evaluators; +} for_local_map_key_only_state_t; + +static mlr_dsl_cst_statement_handler_t handle_for_local_map_key_only; +static mlr_dsl_cst_statement_freer_t free_for_local_map_key_only; + +// ---------------------------------------------------------------- +mlr_dsl_cst_statement_t* alloc_for_local_map_key_only(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ + for_local_map_key_only_state_t* pstate = mlr_malloc_or_die(sizeof(for_local_map_key_only_state_t)); + + pstate->k_variable_name = NULL; + pstate->k_frame_relative_index = MD_UNUSED_INDEX; + pstate->k_type_mask = 0; + + pstate->v_variable_name = NULL; + pstate->v_frame_relative_index = MD_UNUSED_INDEX; + pstate->v_type_mask = 0; + + pstate->target_frame_relative_index = MD_UNUSED_INDEX; + pstate->ptarget_keylist_evaluators = NULL; + + // Left child node is single bound variable + // Middle child node is keylist for basepoint in the oosvar mlhmmv. + // Right child node is the list of statements in the body. + mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; + + MLR_INTERNAL_CODING_ERROR_IF(pleft->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->k_variable_name = pleft->text; + pstate->k_frame_relative_index = pleft->vardef_frame_relative_index; + pstate->k_type_mask = mlr_dsl_ast_node_type_to_type_mask(pleft->type); + + // xxx comment liberally + MLR_INTERNAL_CODING_ERROR_IF(pmiddle->vardef_frame_relative_index == MD_UNUSED_INDEX); + pstate->target_frame_relative_index = pmiddle->vardef_frame_relative_index; + pstate->ptarget_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( // xxx rename x 2 + pcst, pmiddle, type_inferencing, context_flags); + + MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); + cst_statement_block_t* pblock = cst_statement_block_alloc(pnode->subframe_var_count); + + for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; + sllv_append(pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, + type_inferencing, context_flags)); + } + + return mlr_dsl_cst_statement_valloc_with_block( + pnode, + handle_for_local_map_key_only, + pblock, + handle_statement_block_with_break_continue, + free_for_local_map_key_only, + pstate); +} + + +// ---------------------------------------------------------------- +static void free_for_local_map_key_only(mlr_dsl_cst_statement_t* pstatement) { + for_local_map_key_only_state_t* pstate = pstatement->pvstate; + + for (sllve_t* pe = pstate->ptarget_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) { + rval_evaluator_t* pev = pe->pvvalue; + pev->pfree_func(pev); + } + sllv_free(pstate->ptarget_keylist_evaluators); + + free(pstate); +} + +// ---------------------------------------------------------------- +static void handle_for_local_map_key_only( + mlr_dsl_cst_statement_t* pstatement, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + for_local_map_key_only_state_t* pstate = pstatement->pvstate; + + // Evaluate the keylist: e.g. in 'for (k in @a[$3][x]) { ... }', find the values of $3 + // and x for the current record and stack frame. The keylist bindings are outside the scope + // of the for-loop, while the k is bound within the for-loop. + + int keys_all_non_null_or_error = FALSE; + sllmv_t* ptarget_keylist = evaluate_list(pstate->ptarget_keylist_evaluators, pvars, + &keys_all_non_null_or_error); + if (keys_all_non_null_or_error) { + // Locate the submap indexed by the keylist and copy its keys. E.g. in 'for (k1 in @a[3][$4]) { ... }', the + // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the + // for-loop. + + local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); + + mlhmmv_value_t *psubmap = local_stack_frame_get_map_value(pframe, + pstate->target_frame_relative_index, ptarget_keylist); + sllv_t* pkeys = mlhmmv_copy_keys_from_submap_xxx_rename(psubmap, NULL); // xxx refactor w/o null + + local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); + loop_stack_push(pvars->ploop_stack); + + for (sllve_t* pe = pkeys->phead; pe != NULL; pe = pe->pnext) { + // Bind the v-name to the terminal mlrval: + local_stack_frame_define(pframe, + pstate->k_variable_name, pstate->k_frame_relative_index, + pstate->k_type_mask, mv_copy(pe->pvvalue)); + + // Execute the loop-body statements: + pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); + + if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { + loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); + } + if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { + loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); + } + + mv_free(pe->pvvalue); + free(pe->pvvalue); + } + + loop_stack_pop(pvars->ploop_stack); + local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); + + sllv_free(pkeys); + } + sllmv_free(ptarget_keylist); +} diff --git a/c/mapping/mlr_dsl_cst_statements.c b/c/mapping/mlr_dsl_cst_statements.c index b770b7e6f..32a6fc3eb 100644 --- a/c/mapping/mlr_dsl_cst_statements.c +++ b/c/mapping/mlr_dsl_cst_statements.c @@ -14,42 +14,6 @@ // * Do "mlr -n put -v 'your expression goes here'" // ================================================================ -// ---------------------------------------------------------------- -static mlr_dsl_cst_statement_t* alloc_blank(mlr_dsl_ast_node_t* past_node); -void mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t* pstatement); - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static mlr_dsl_cst_statement_allocator_t alloc_for_oosvar; -static mlr_dsl_cst_statement_allocator_t alloc_for_oosvar_key_only; -static mlr_dsl_cst_statement_allocator_t alloc_for_local_map; -static mlr_dsl_cst_statement_allocator_t alloc_for_local_map_key_only; - -// ---------------------------------------------------------------- -static mlr_dsl_cst_statement_handler_t handle_for_oosvar; -static mlr_dsl_cst_statement_handler_t handle_for_oosvar_key_only; -static mlr_dsl_cst_statement_handler_t handle_for_local_map; -static mlr_dsl_cst_statement_handler_t handle_for_local_map_key_only; - -static void handle_for_oosvar_aux( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs, - mlhmmv_value_t submap, - char** prest_for_k_variable_names, - int* prest_for_k_frame_relative_indices, - int* prest_for_k_frame_type_masks, - int prest_for_k_count); - -static void handle_for_local_map_aux( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs, - mlhmmv_value_t submap, - char** prest_for_k_variable_names, - int* prest_for_k_frame_relative_indices, - int* prest_for_k_frame_type_masks, - int prest_for_k_count); - // ================================================================ cst_statement_block_t* cst_statement_block_alloc(int subframe_var_count) { cst_statement_block_t* pblock = mlr_malloc_or_die(sizeof(cst_statement_block_t)); @@ -467,41 +431,6 @@ mlr_dsl_cst_statement_t* mlr_dsl_cst_alloc_final_filter_statement(mlr_dsl_cst_t* } } -// ---------------------------------------------------------------- -static mlr_dsl_cst_statement_t* alloc_blank(mlr_dsl_ast_node_t* past_node) { - mlr_dsl_cst_statement_t* pstatement = mlr_malloc_or_die(sizeof(mlr_dsl_cst_statement_t)); - - // xxx post-federation - pstatement->past_node = past_node; - pstatement->pstatement_handler = NULL; - pstatement->pstatement_freer = NULL; - pstatement->pblock_handler = NULL; - pstatement->pvstate = FALSE; - - // xxx pre-federation - - pstatement->poosvar_target_keylist_evaluators = NULL; - pstatement->local_lhs_variable_name = 0; - pstatement->local_lhs_frame_relative_index = 0; - pstatement->local_lhs_type_mask = TYPE_MASK_ANY; - pstatement->psrec_lhs_evaluator = NULL; - pstatement->prhs_evaluator = NULL; - pstatement->poosvar_rhs_keylist_evaluators = NULL; - pstatement->pvarargs = NULL; - pstatement->pblock = NULL; - - pstatement->for_map_k_variable_names = NULL; - pstatement->for_map_k_frame_relative_indices = NULL; - pstatement->for_map_k_type_masks = NULL; - pstatement->for_map_k_count = 0; - pstatement->for_v_variable_name = NULL; - pstatement->for_v_frame_relative_index = 0; - pstatement->for_v_type_mask = TYPE_MASK_ANY; - pstatement->for_map_target_frame_relative_index = 0; - - return pstatement; -} - // ---------------------------------------------------------------- // xxx post-federation @@ -541,216 +470,6 @@ mlr_dsl_cst_statement_t* mlr_dsl_cst_statement_valloc_with_block( return pstatement; } -// ---------------------------------------------------------------- -// $ mlr -n put -v 'for((k1,k2,k3),v in @a["4"][$5]) { $6 = 7; $8 = 9}' -// AST ROOT: -// text="list", type=statement_list: -// text="for", type=for_oosvar: -// text="key_and_value_variables", type=for_variables: -// text="key_variables", type=for_variables: -// text="k1", type=non_sigil_name. -// text="k2", type=non_sigil_name. -// text="k3", type=non_sigil_name. -// text="v", type=non_sigil_name. -// text="oosvar_keylist", type=oosvar_keylist: -// text="a", type=string_literal. -// text="4", type=numeric_literal. -// text="5", type=field_name. -// text="list", type=statement_list: -// text="=", type=srec_assignment: -// text="6", type=field_name. -// text="7", type=numeric_literal. -// text="=", type=srec_assignment: -// text="8", type=field_name. -// text="9", type=numeric_literal. - -static mlr_dsl_cst_statement_t* alloc_for_oosvar(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, - int type_inferencing, int context_flags) -{ - mlr_dsl_cst_statement_t* pstatement = alloc_blank(pnode); - - // Left child node is list of bound variables. - // Left subnode is namelist for key boundvars. - // Right subnode is name for value boundvar. - // Middle child node is keylist for basepoint in the oosvar mlhmmv. - // Right child node is the list of statements in the body. - mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* psubleft = pleft->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* psubright = pleft->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; - - pstatement->for_map_k_variable_names = mlr_malloc_or_die(sizeof(char*) * psubleft->pchildren->length); - pstatement->for_map_k_frame_relative_indices = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); - pstatement->for_map_k_type_masks = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); - pstatement->for_map_k_count = 0; - for (sllve_t* pe = psubleft->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pnamenode = pe->pvvalue; - MLR_INTERNAL_CODING_ERROR_IF(pnamenode->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_k_variable_names[pstatement->for_map_k_count] = - mlr_strdup_or_die(pnamenode->text); - pstatement->for_map_k_frame_relative_indices[pstatement->for_map_k_count] = - pnamenode->vardef_frame_relative_index; - pstatement->for_map_k_type_masks[pstatement->for_map_k_count] = - mlr_dsl_ast_node_type_to_type_mask(pnamenode->type); - pstatement->for_map_k_count++; - } - pstatement->for_v_variable_name = mlr_strdup_or_die(psubright->text); - MLR_INTERNAL_CODING_ERROR_IF(psubright->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_v_frame_relative_index = psubright->vardef_frame_relative_index; - pstatement->for_v_type_mask = mlr_dsl_ast_node_type_to_type_mask(psubright->type); - - pstatement->poosvar_target_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( - pcst, pmiddle, type_inferencing, context_flags); - - MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); - pstatement->pblock = cst_statement_block_alloc(pnode->subframe_var_count); - - for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; - sllv_append(pstatement->pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, - type_inferencing, context_flags)); - } - pstatement->pstatement_handler = handle_for_oosvar; - pstatement->pblock_handler = handle_statement_block_with_break_continue; - - return pstatement; -} - -static mlr_dsl_cst_statement_t* alloc_for_oosvar_key_only(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, - int type_inferencing, int context_flags) -{ - mlr_dsl_cst_statement_t* pstatement = alloc_blank(pnode); - - // Left child node is single bound variable - // Middle child node is keylist for basepoint in the oosvar mlhmmv. - // Right child node is the list of statements in the body. - mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; - - pstatement->for_map_k_variable_names = mlr_malloc_or_die(sizeof(char*)); - pstatement->for_map_k_frame_relative_indices = mlr_malloc_or_die(sizeof(int)); - pstatement->for_map_k_type_masks = mlr_malloc_or_die(sizeof(int)); - MLR_INTERNAL_CODING_ERROR_IF(pleft->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_k_variable_names[0] = mlr_strdup_or_die(pleft->text); - pstatement->for_map_k_frame_relative_indices[0] = pleft->vardef_frame_relative_index; - pstatement->for_map_k_type_masks[0] = mlr_dsl_ast_node_type_to_type_mask(pleft->type); - - pstatement->poosvar_target_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( - pcst, pmiddle, type_inferencing, context_flags); - - MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); - pstatement->pblock = cst_statement_block_alloc(pnode->subframe_var_count); - - for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; - sllv_append(pstatement->pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, - type_inferencing, context_flags)); - } - pstatement->pstatement_handler = handle_for_oosvar_key_only; - pstatement->pblock_handler = handle_statement_block_with_break_continue; - - return pstatement; -} - -// ---------------------------------------------------------------- -static mlr_dsl_cst_statement_t* alloc_for_local_map(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, - int type_inferencing, int context_flags) -{ - mlr_dsl_cst_statement_t* pstatement = alloc_blank(pnode); - - // Left child node is list of bound variables. - // Left subnode is namelist for key boundvars. - // Right subnode is name for value boundvar. - // Middle child node is keylist for basepoint in the local mlhmmv. - // Right child node is the list of statements in the body. - mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* psubleft = pleft->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* psubright = pleft->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; - - pstatement->for_map_k_variable_names = mlr_malloc_or_die(sizeof(char*) * psubleft->pchildren->length); - pstatement->for_map_k_frame_relative_indices = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); - pstatement->for_map_k_type_masks = mlr_malloc_or_die(sizeof(int) * psubleft->pchildren->length); - pstatement->for_map_k_count = 0; - for (sllve_t* pe = psubleft->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pnamenode = pe->pvvalue; - MLR_INTERNAL_CODING_ERROR_IF(pnamenode->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_k_variable_names[pstatement->for_map_k_count] = - mlr_strdup_or_die(pnamenode->text); - pstatement->for_map_k_frame_relative_indices[pstatement->for_map_k_count] = - pnamenode->vardef_frame_relative_index; - pstatement->for_map_k_type_masks[pstatement->for_map_k_count] = - mlr_dsl_ast_node_type_to_type_mask(pnamenode->type); - pstatement->for_map_k_count++; - } - pstatement->for_v_variable_name = mlr_strdup_or_die(psubright->text); - MLR_INTERNAL_CODING_ERROR_IF(psubright->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_v_frame_relative_index = psubright->vardef_frame_relative_index; - pstatement->for_v_type_mask = mlr_dsl_ast_node_type_to_type_mask(psubright->type); - - // xxx comment liberally - MLR_INTERNAL_CODING_ERROR_IF(pmiddle->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_target_frame_relative_index = pmiddle->vardef_frame_relative_index; - pstatement->poosvar_target_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( // xxx rename x 2 - pcst, pmiddle, type_inferencing, context_flags); - - MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); - pstatement->pblock = cst_statement_block_alloc(pnode->subframe_var_count); - - for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; - sllv_append(pstatement->pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, - type_inferencing, context_flags)); - } - pstatement->pstatement_handler = handle_for_local_map; - pstatement->pblock_handler = handle_statement_block_with_break_continue; - - return pstatement; -} - -static mlr_dsl_cst_statement_t* alloc_for_local_map_key_only(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode, - int type_inferencing, int context_flags) -{ - mlr_dsl_cst_statement_t* pstatement = alloc_blank(pnode); - - // Left child node is single bound variable - // Middle child node is keylist for basepoint in the oosvar mlhmmv. - // Right child node is the list of statements in the body. - mlr_dsl_ast_node_t* pleft = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* pmiddle = pnode->pchildren->phead->pnext->pvvalue; - mlr_dsl_ast_node_t* pright = pnode->pchildren->phead->pnext->pnext->pvvalue; - - pstatement->for_map_k_variable_names = mlr_malloc_or_die(sizeof(char*)); - pstatement->for_map_k_frame_relative_indices = mlr_malloc_or_die(sizeof(int)); - pstatement->for_map_k_type_masks = mlr_malloc_or_die(sizeof(int)); - MLR_INTERNAL_CODING_ERROR_IF(pleft->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_k_variable_names[0] = mlr_strdup_or_die(pleft->text); - pstatement->for_map_k_frame_relative_indices[0] = pleft->vardef_frame_relative_index; - pstatement->for_map_k_type_masks[0] = mlr_dsl_ast_node_type_to_type_mask(pleft->type); - - // xxx comment liberally - MLR_INTERNAL_CODING_ERROR_IF(pmiddle->vardef_frame_relative_index == MD_UNUSED_INDEX); - pstatement->for_map_target_frame_relative_index = pmiddle->vardef_frame_relative_index; - pstatement->poosvar_target_keylist_evaluators = allocate_keylist_evaluators_from_oosvar_node( // xxx rename x 2 - pcst, pmiddle, type_inferencing, context_flags); - - MLR_INTERNAL_CODING_ERROR_IF(pnode->subframe_var_count == MD_UNUSED_INDEX); - pstatement->pblock = cst_statement_block_alloc(pnode->subframe_var_count); - - for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { - mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; - sllv_append(pstatement->pblock->pstatements, mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, - type_inferencing, context_flags)); - } - pstatement->pstatement_handler = handle_for_local_map_key_only; - pstatement->pblock_handler = handle_statement_block_with_break_continue; - - return pstatement; -} - // ---------------------------------------------------------------- // Example ASTs, with and without indexing on the left-hand-side oosvar name: @@ -867,15 +586,6 @@ void mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t* pstatement) { cst_statement_block_free(pstatement->pblock); - if (pstatement->for_map_k_variable_names != NULL) { - for (int i = 0; i < pstatement->for_map_k_count; i++) - free(pstatement->for_map_k_variable_names[i]); - free(pstatement->for_map_k_variable_names); - } - free(pstatement->for_map_k_frame_relative_indices); - free(pstatement->for_map_k_type_masks); - free(pstatement->for_v_variable_name); - free(pstatement); } @@ -1052,328 +762,3 @@ void mlr_dsl_cst_handle_statement_list( } } } - -// ---------------------------------------------------------------- -static void handle_for_oosvar( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs) -{ - // Evaluate the keylist: e.g. in 'for ((k1, k2), v in @a[$3][x]) { ... }', find the values of $3 - // and x for the current record and stack frame. The keylist bindings are outside the scope - // of the for-loop, while the k1/k2/v are bound within the for-loop. - - int keys_all_non_null_or_error = FALSE; - sllmv_t* plhskeylist = evaluate_list(pstatement->poosvar_target_keylist_evaluators, pvars, - &keys_all_non_null_or_error); - if (keys_all_non_null_or_error) { - - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); - loop_stack_push(pvars->ploop_stack); - - // Locate and copy the submap indexed by the keylist. E.g. in 'for ((k1, k2), v in @a[3][$4]) { ... }', the - // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the - // for-loop. - mlhmmv_value_t submap = mlhmmv_copy_submap_from_root(pvars->poosvars, plhskeylist); - - if (!submap.is_terminal && submap.u.pnext_level != NULL) { - // Recurse over the for-k-names, e.g. ["k1", "k2"], on each call descending one level - // deeper into the submap. Note there must be at least one k-name so we are assuming - // the for-loop within handle_for_oosvar_aux was gone through once & thus - // handle_statement_block_with_break_continue was called through there. - - handle_for_oosvar_aux(pstatement, pvars, pcst_outputs, submap, - pstatement->for_map_k_variable_names, pstatement->for_map_k_frame_relative_indices, - pstatement->for_map_k_type_masks, pstatement->for_map_k_count); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); - } - if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - } - - mlhmmv_free_submap(submap); - - loop_stack_pop(pvars->ploop_stack); - local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); - } - sllmv_free(plhskeylist); -} - -static void handle_for_oosvar_aux( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs, - mlhmmv_value_t submap, - char** prest_for_k_variable_names, - int* prest_for_k_frame_relative_indices, - int* prest_for_k_type_masks, - int prest_for_k_count) -{ - if (prest_for_k_count > 0) { // Keep recursing over remaining k-names - - if (submap.is_terminal) { - // The submap was too shallow for the user-specified k-names; there are no terminals here. - } else { - // Loop over keys at this submap level: - for (mlhmmv_level_entry_t* pe = submap.u.pnext_level->phead; pe != NULL; pe = pe->pnext) { - // Bind the k-name to the entry-key mlrval: - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_frame_define(pframe, prest_for_k_variable_names[0], prest_for_k_frame_relative_indices[0], - prest_for_k_type_masks[0], mv_copy(&pe->level_key)); - // Recurse into the next-level submap: - handle_for_oosvar_aux(pstatement, pvars, pcst_outputs, pe->level_value, - &prest_for_k_variable_names[1], &prest_for_k_frame_relative_indices[1], &prest_for_k_type_masks[1], - prest_for_k_count - 1); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - // Bit cleared in recursive caller - return; - } else if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - - } - } - - } else { // End of recursion: k-names have all been used up - - if (!submap.is_terminal) { - // The submap was too deep for the user-specified k-names; there are no terminals here. - } else { - // Bind the v-name to the terminal mlrval: - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_frame_define(pframe, pstatement->for_v_variable_name, pstatement->for_v_frame_relative_index, - pstatement->for_v_type_mask, mv_copy(&submap.u.mlrval)); - // Execute the loop-body statements: - pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); - } - - } -} - -// ---------------------------------------------------------------- -static void handle_for_oosvar_key_only( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs) -{ - // Evaluate the keylist: e.g. in 'for (k in @a[$3][x]) { ... }', find the values of $3 - // and x for the current record and stack frame. The keylist bindings are outside the scope - // of the for-loop, while the k is bound within the for-loop. - - int keys_all_non_null_or_error = FALSE; - sllmv_t* plhskeylist = evaluate_list(pstatement->poosvar_target_keylist_evaluators, pvars, - &keys_all_non_null_or_error); - if (keys_all_non_null_or_error) { - // Locate the submap indexed by the keylist and copy its keys. E.g. in 'for (k1 in @a[3][$4]) { ... }', the - // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the - // for-loop. - - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); - loop_stack_push(pvars->ploop_stack); - - sllv_t* pkeys = mlhmmv_copy_keys_from_submap(pvars->poosvars, plhskeylist); - - for (sllve_t* pe = pkeys->phead; pe != NULL; pe = pe->pnext) { - // Bind the v-name to the terminal mlrval: - local_stack_frame_define(pframe, - pstatement->for_map_k_variable_names[0], pstatement->for_map_k_frame_relative_indices[0], - pstatement->for_map_k_type_masks[0], mv_copy(pe->pvvalue)); - - // Execute the loop-body statements: - pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); - } - if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - - mv_free(pe->pvvalue); - free(pe->pvvalue); - } - - loop_stack_pop(pvars->ploop_stack); - local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); - - sllv_free(pkeys); - } - sllmv_free(plhskeylist); -} - -// ---------------------------------------------------------------- -static void handle_for_local_map( // xxx vardef_frame_relative_index - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs) -{ - // Evaluate the keylist: e.g. in 'for ((k1, k2), v in @a[$3][x]) { ... }', find the values of $3 - // and x for the current record and stack frame. The keylist bindings are outside the scope - // of the for-loop, while the k1/k2/v are bound within the for-loop. - - int keys_all_non_null_or_error = FALSE; - // xxx confusing 'oosvar' name ... clean up please. - // xxx confusing 'keylist' name ... clean up please. - sllmv_t* plhskeylist = evaluate_list(pstatement->poosvar_target_keylist_evaluators, pvars, - &keys_all_non_null_or_error); - if (keys_all_non_null_or_error) { - - // In '(for a, b in c) { ... }' the 'c' is evaluated in the outer scope and - // the a, b are bound within the inner scope. - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - - // Locate and copy the submap indexed by the keylist. E.g. in 'for ((k1, k2), v in a[3][$4]) - // { ... }', the submap is first indexed by the stack-frame slot for "a", then further - // indexed by [3, $4]. Copy it for the very likely case that it is being updated inside the - // for-loop. - - mlhmmv_value_t *psubmap = local_stack_frame_get_map_value(pframe, - pstatement->for_map_target_frame_relative_index, plhskeylist); - - if (psubmap != NULL) { - mlhmmv_value_t submap = mlhmmv_copy_aux(psubmap); - - local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); - loop_stack_push(pvars->ploop_stack); - - if (!submap.is_terminal && submap.u.pnext_level != NULL) { - // Recurse over the for-k-names, e.g. ["k1", "k2"], on each call descending one level - // deeper into the submap. Note there must be at least one k-name so we are assuming - // the for-loop within handle_for_local_map_aux was gone through once & thus - // handle_statement_block_with_break_continue was called through there. - - handle_for_local_map_aux(pstatement, pvars, pcst_outputs, submap, - pstatement->for_map_k_variable_names, pstatement->for_map_k_frame_relative_indices, - pstatement->for_map_k_type_masks, pstatement->for_map_k_count); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); - } - if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - } - - mlhmmv_free_submap(submap); - - loop_stack_pop(pvars->ploop_stack); - local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); - } - } - sllmv_free(plhskeylist); -} - -static void handle_for_local_map_aux( - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs, - mlhmmv_value_t submap, - char** prest_for_k_variable_names, - int* prest_for_k_frame_relative_indices, - int* prest_for_k_type_masks, - int prest_for_k_count) -{ - if (prest_for_k_count > 0) { // Keep recursing over remaining k-names - - if (submap.is_terminal) { - // The submap was too shallow for the user-specified k-names; there are no terminals here. - } else { - // Loop over keys at this submap level: - for (mlhmmv_level_entry_t* pe = submap.u.pnext_level->phead; pe != NULL; pe = pe->pnext) { - // Bind the k-name to the entry-key mlrval: - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_frame_define(pframe, prest_for_k_variable_names[0], prest_for_k_frame_relative_indices[0], - prest_for_k_type_masks[0], mv_copy(&pe->level_key)); - // Recurse into the next-level submap: - handle_for_local_map_aux(pstatement, pvars, pcst_outputs, pe->level_value, - &prest_for_k_variable_names[1], &prest_for_k_frame_relative_indices[1], &prest_for_k_type_masks[1], - prest_for_k_count - 1); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - // Bit cleared in recursive caller - return; - } else if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - - } - } - - } else { // End of recursion: k-names have all been used up - - if (!submap.is_terminal) { - // The submap was too deep for the user-specified k-names; there are no terminals here. - } else { - // Bind the v-name to the terminal mlrval: - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - local_stack_frame_define(pframe, pstatement->for_v_variable_name, pstatement->for_v_frame_relative_index, - pstatement->for_v_type_mask, mv_copy(&submap.u.mlrval)); - // Execute the loop-body statements: - pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); - } - - } -} - -// ---------------------------------------------------------------- -static void handle_for_local_map_key_only( // xxx vardef_frame_relative_index - mlr_dsl_cst_statement_t* pstatement, - variables_t* pvars, - cst_outputs_t* pcst_outputs) -{ - // Evaluate the keylist: e.g. in 'for (k in @a[$3][x]) { ... }', find the values of $3 - // and x for the current record and stack frame. The keylist bindings are outside the scope - // of the for-loop, while the k is bound within the for-loop. - - int keys_all_non_null_or_error = FALSE; - // xxx rename plhskeylist to ptarget_keylist - sllmv_t* plhskeylist = evaluate_list(pstatement->poosvar_target_keylist_evaluators, pvars, - &keys_all_non_null_or_error); - if (keys_all_non_null_or_error) { - // Locate the submap indexed by the keylist and copy its keys. E.g. in 'for (k1 in @a[3][$4]) { ... }', the - // submap is indexed by ["a", 3, $4]. Copy it for the very likely case that it is being updated inside the - // for-loop. - - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - - // xxx this is wrong. each of these two statements is subscripting. only one or the other should. - mlhmmv_value_t *psubmap = local_stack_frame_get_map_value(pframe, - pstatement->for_map_target_frame_relative_index, plhskeylist); - sllv_t* pkeys = mlhmmv_copy_keys_from_submap_xxx_rename(psubmap, NULL); // xxx refactor w/o null - - local_stack_subframe_enter(pframe, pstatement->pblock->subframe_var_count); - loop_stack_push(pvars->ploop_stack); - - for (sllve_t* pe = pkeys->phead; pe != NULL; pe = pe->pnext) { - // Bind the v-name to the terminal mlrval: - local_stack_frame_define(pframe, - pstatement->for_map_k_variable_names[0], pstatement->for_map_k_frame_relative_indices[0], - pstatement->for_map_k_type_masks[0], mv_copy(pe->pvvalue)); - - // Execute the loop-body statements: - pstatement->pblock_handler(pstatement->pblock, pvars, pcst_outputs); - - if (loop_stack_get(pvars->ploop_stack) & LOOP_BROKEN) { - loop_stack_clear(pvars->ploop_stack, LOOP_BROKEN); - } - if (loop_stack_get(pvars->ploop_stack) & LOOP_CONTINUED) { - loop_stack_clear(pvars->ploop_stack, LOOP_CONTINUED); - } - - mv_free(pe->pvvalue); - free(pe->pvvalue); - } - - loop_stack_pop(pvars->ploop_stack); - local_stack_subframe_exit(pframe, pstatement->pblock->subframe_var_count); - - sllv_free(pkeys); - } - sllmv_free(plhskeylist); -}