cst-federation: for-map statements

This commit is contained in:
John Kerl 2016-11-06 11:10:55 -05:00
parent a100cf3418
commit 2ee9736407
4 changed files with 754 additions and 627 deletions

View file

@ -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 \

View file

@ -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;

View 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);
}

View file

@ -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);
}