mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-23 07:59:37 +00:00
cst-federation: for-map statements
This commit is contained in:
parent
a100cf3418
commit
2ee9736407
4 changed files with 754 additions and 627 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
745
c/mapping/mlr_dsl_cst_for_map_statements.c
Normal file
745
c/mapping/mlr_dsl_cst_for_map_statements.c
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue