diff --git a/c/containers/mlhmmv.c b/c/containers/mlhmmv.c index 9c1ffa2a0..b93411a27 100644 --- a/c/containers/mlhmmv.c +++ b/c/containers/mlhmmv.c @@ -1126,30 +1126,20 @@ static void mlhmmv_to_lrecs_aux_within_record( } // ---------------------------------------------------------------- -void mlhmmv_to_lrecs_lashed(mlhmmv_value_t** ptop_values, int num_submaps, sllmv_t** ppkeys, sllmv_t* pnames, +void mlhmmv_to_lrecs_lashed(mlhmmv_value_t** ptop_values, int num_submaps, mv_t* pbasenames, sllmv_t* pnames, sllv_t* poutrecs, int do_full_prefixing, char* flatten_separator) { -// xxx remove -// printf("BGN\n"); -// for (int i = 0; i < num_submaps; i++) { -// printf("KEYS %d:\n", i); -// sllmv_print(ppkeys[i]); -// } -// printf("NAMES:\n"); -// sllmv_print(pnames); -// printf("END\n"); - // First is primary and rest are lashed to it (lookups with same keys as primary). if (ptop_values[0] == NULL) { // No such entry in the mlhmmv results in no output records - } else if (ptop_values[0]->is_terminal) { + } else if (ptop_values[0]->is_terminal && mv_is_present(&ptop_values[0]->mlrval)) { lrec_t* poutrec = lrec_unbacked_alloc(); for (int i = 0; i < num_submaps; i++) { // E.g. '@v = 3' at the top level of the mlhmmv. - if (ptop_values[i]->is_terminal) { + if (ptop_values[i]->is_terminal && mv_is_present(&ptop_values[i]->mlrval)) { lrec_put(poutrec, - mv_alloc_format_val(&ppkeys[i]->phead->value), + mv_alloc_format_val(&pbasenames[i]), mv_alloc_format_val(&ptop_values[i]->mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); } } @@ -1174,7 +1164,7 @@ void mlhmmv_to_lrecs_lashed(mlhmmv_value_t** ptop_values, int num_submaps, sllmv oosvar_names[i] = NULL; } else { ppnext_levels[i] = ptop_values[i]->pnext_level; - oosvar_names[i] = mv_alloc_format_val(&ppkeys[i]->phead->value); + oosvar_names[i] = mv_alloc_format_val(&pbasenames[i]); } } @@ -1204,39 +1194,41 @@ static void mlhmmv_to_lrecs_aux_across_records_lashed( if (prestnames != NULL) { // If there is a namelist entry, pull it out to its own field on the output lrecs. // First is iterated over and the rest are lashed (lookups with same keys as primary). - for (mlhmmv_level_entry_t* pe = pplevels[0]->phead; pe != NULL; pe = pe->pnext) { - mlhmmv_value_t* pfirst_level_value = &pe->level_value; - lrec_t* pnextrec = lrec_copy(ptemplate); - lrec_put(pnextrec, - mv_alloc_format_val(&prestnames->value), - mv_alloc_format_val(&pe->level_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); + if (pplevels[0] != NULL) { + for (mlhmmv_level_entry_t* pe = pplevels[0]->phead; pe != NULL; pe = pe->pnext) { + mlhmmv_value_t* pfirst_level_value = &pe->level_value; + lrec_t* pnextrec = lrec_copy(ptemplate); + lrec_put(pnextrec, + mv_alloc_format_val(&prestnames->value), + mv_alloc_format_val(&pe->level_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); - if (pfirst_level_value->is_terminal) { - for (int i = 0; i < num_levels; i++) { - mlhmmv_value_t* plevel_value = mlhmmv_get_next_level_entry_value(pplevels[i], &pe->level_key); - if (plevel_value != NULL && plevel_value->is_terminal) { - lrec_put(pnextrec, - mlr_strdup_or_die(prefixes[i]), - mv_alloc_format_val(&plevel_value->mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); + if (pfirst_level_value->is_terminal) { + for (int i = 0; i < num_levels; i++) { + mlhmmv_value_t* plevel_value = mlhmmv_get_next_level_entry_value(pplevels[i], &pe->level_key); + if (plevel_value != NULL && plevel_value->is_terminal) { + lrec_put(pnextrec, + mlr_strdup_or_die(prefixes[i]), + mv_alloc_format_val(&plevel_value->mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE); + } } - } - sllv_append(poutrecs, pnextrec); - } else { - mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*)); - for (int i = 0; i < num_levels; i++) { - mlhmmv_value_t* plevel_value = mlhmmv_get_next_level_entry_value(pplevels[i], &pe->level_key); - if (plevel_value == NULL || plevel_value->is_terminal) { - ppnext_levels[i] = NULL; - } else { - ppnext_levels[i] = plevel_value->pnext_level; + sllv_append(poutrecs, pnextrec); + } else { + mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*)); + for (int i = 0; i < num_levels; i++) { + mlhmmv_value_t* plevel_value = mlhmmv_get_next_level_entry_value(pplevels[i], &pe->level_key); + if (plevel_value == NULL || plevel_value->is_terminal) { + ppnext_levels[i] = NULL; + } else { + ppnext_levels[i] = plevel_value->pnext_level; + } } + + mlhmmv_to_lrecs_aux_across_records_lashed(ppnext_levels, prefixes, num_levels, + prestnames->pnext, pnextrec, poutrecs, do_full_prefixing, flatten_separator); + + free(ppnext_levels); + lrec_free(pnextrec); } - - mlhmmv_to_lrecs_aux_across_records_lashed(ppnext_levels, prefixes, num_levels, - prestnames->pnext, pnextrec, poutrecs, do_full_prefixing, flatten_separator); - - free(ppnext_levels); - lrec_free(pnextrec); } } diff --git a/c/containers/mlhmmv.h b/c/containers/mlhmmv.h index d0188f997..013ded4e2 100644 --- a/c/containers/mlhmmv.h +++ b/c/containers/mlhmmv.h @@ -224,7 +224,7 @@ void mlhmmv_clear_level(mlhmmv_level_t* plevel); void mlhmmv_to_lrecs(mlhmmv_t* pmap, sllmv_t* pkeys, sllmv_t* pnames, sllv_t* poutrecs, int do_full_prefixing, char* flatten_separator); -void mlhmmv_to_lrecs_lashed(mlhmmv_value_t** ptop_values, int num_submaps, sllmv_t** ppkeys, sllmv_t* pnames, +void mlhmmv_to_lrecs_lashed(mlhmmv_value_t** ptop_values, int num_submaps, mv_t* pbasenames, sllmv_t* pnames, sllv_t* poutrecs, int do_full_prefixing, char* flatten_separator); // xxx rm? diff --git a/c/mapping/mlr_dsl_cst_output_statements.c b/c/mapping/mlr_dsl_cst_output_statements.c index 6ef5dfc1e..2f2c31466 100644 --- a/c/mapping/mlr_dsl_cst_output_statements.c +++ b/c/mapping/mlr_dsl_cst_output_statements.c @@ -189,7 +189,7 @@ mlr_dsl_cst_statement_t* alloc_tee(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnod } // ---------------------------------------------------------------- -static void free_tee(mlr_dsl_cst_statement_t* pstatement) { // xxx from mlr_dsl_cst_statement_free +static void free_tee(mlr_dsl_cst_statement_t* pstatement) { tee_state_t* pstate = pstatement->pvstate; if (pstate->poutput_filename_evaluator != NULL) { @@ -1023,119 +1023,42 @@ static void handle_emit_all_to_file( // ================================================================ struct _emit_lashed_item_t; // Forward reference -typedef mlhmmv_value_t* emit_lashed_item_getter_t( - struct _emit_lashed_item_t* pitem, variables_t* pvars, sllmv_t* pmvkeys); -// Ooosvars/localvars don't need freeing; ephemeral map-literals do. -typedef void emit_lashed_item_freer_t(struct _emit_lashed_item_t* pitem); typedef struct _emit_lashed_item_t { - // For map literals - rxval_evaluator_xxx_deprecated_t* prhs_xevaluator; - mlhmmv_value_t ephemeral_xvalue; // xxx rm - - // For local variables - int localvar_frame_relative_index; - - // Oosvar/localvar indices ["a", 1, $2] in - // 'for (k,v in @a[1][$2]) {...}' or - // 'for (k,v in a[1][$2]) {...}'. - sllv_t* pemit_keylist_evaluators; - - emit_lashed_item_getter_t* pemit_lashed_item_getter; - emit_lashed_item_freer_t* pemit_lashed_item_freer; + rval_evaluator_t* pbasename_evaluator; + rxval_evaluator_t* pitem_xevaluator; } emit_lashed_item_t; -static emit_lashed_item_t* emit_lashed_item_alloc() { +static emit_lashed_item_t* emit_lashed_item_alloc( + rval_evaluator_t* pbasename_evaluator, + rxval_evaluator_t* pitem_xevaluator) +{ emit_lashed_item_t* pitem = mlr_malloc_or_die(sizeof(emit_lashed_item_t)); - pitem->prhs_xevaluator = NULL; - pitem->localvar_frame_relative_index = MD_UNUSED_INDEX; - pitem->pemit_keylist_evaluators = NULL; - pitem->pemit_lashed_item_getter = NULL; - pitem->pemit_lashed_item_freer = NULL; + pitem->pbasename_evaluator = pbasename_evaluator; + pitem->pitem_xevaluator = pitem_xevaluator; return pitem; } static void emit_lashed_item_free(emit_lashed_item_t* pitem) { - if (pitem->prhs_xevaluator != NULL) { - pitem->prhs_xevaluator->pfree_func(pitem->prhs_xevaluator); - } - if (pitem->pemit_keylist_evaluators != NULL) { - for (sllve_t* pe = pitem->pemit_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) { - rval_evaluator_t* phandler = pe->pvvalue; - phandler->pfree_func(phandler); - } - sllv_free(pitem->pemit_keylist_evaluators); - } + pitem->pbasename_evaluator->pfree_func(pitem->pbasename_evaluator); + pitem->pitem_xevaluator->pfree_func(pitem->pitem_xevaluator); free(pitem); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static mlhmmv_value_t* oosvar_emit_lashed_item_get( - emit_lashed_item_t* pitem, variables_t* pvars, sllmv_t* pmvkeys) -{ - int error = 0; - // xxx check copy or not ... also encode that into all such names. - return mlhmmv_get_value_from_level(pvars->poosvars->proot_level, pmvkeys, &error); -} -static void oosvar_emit_lashed_item_free(emit_lashed_item_t* pitem) { - // Nothing to free for oosvars: we pointed to data within the oosvar and printed it, without allocating - // anything extra. -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static mlhmmv_value_t* nonindexed_local_variable_emit_lashed_item_get( - emit_lashed_item_t* pitem, variables_t* pvars, sllmv_t* pmvkeys) -{ - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - // xxx check for copy/reference; and annotate the method names to make that clear at a glance. - return local_stack_frame_get_extended_from_indexed(pframe, pitem->localvar_frame_relative_index, NULL); -} -static void nonindexed_local_variable_emit_lashed_item_free(emit_lashed_item_t* pitem) { - // Nothing to free for localvars: we pointed to data within the localvar and printed it, without allocating - // anything extra. -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static mlhmmv_value_t* indexed_local_variable_emit_lashed_item_get( - emit_lashed_item_t* pitem, variables_t* pvars, sllmv_t* pmvkeys) -{ - local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack); - // xxx check for copy/reference; and annotate the method names to make that clear at a glance. - // xxx need to index but skip the variable name at list head ... - return local_stack_frame_get_extended_from_indexed(pframe, pitem->localvar_frame_relative_index, NULL); -} -static void indexed_local_variable_emit_lashed_item_free(emit_lashed_item_t* pitem) { - // Nothing to free for localvars: we pointed to data within the localvar and printed it, without allocating - // anything extra. -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static mlhmmv_value_t* map_literal_emit_lashed_item_get( - emit_lashed_item_t* pitem, variables_t* pvars, sllmv_t* pmvkeys) -{ - rxval_evaluator_xxx_deprecated_t* prhs_xevaluator = pitem->prhs_xevaluator; - pitem->ephemeral_xvalue = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars); - return &pitem->ephemeral_xvalue; -} -static void map_literal_emit_lashed_item_free(emit_lashed_item_t* pitem) { - mlhmmv_free_submap(pitem->ephemeral_xvalue); -} - // ---------------------------------------------------------------- typedef struct _emit_lashed_state_t { + int num_emit_lashed_items; + emit_lashed_item_t** ppitems; + sllv_t* pemit_namelist_evaluators; + rval_evaluator_t* poutput_filename_evaluator; FILE* stdfp; file_output_mode_t file_output_mode; - sllv_t* pemit_namelist_evaluators; - int do_full_prefixing; - - int num_emit_lashed_items; - emit_lashed_item_t** ppitems; - lrec_writer_t* psingle_lrec_writer; // emit/tee to stdout/stderr multi_lrec_writer_t* pmulti_lrec_writer; // emit-to-file - int flush_every_record; + int do_full_prefixing; + int flush_every_record; } emit_lashed_state_t; static mlr_dsl_cst_statement_handler_t handle_emit_lashed; @@ -1154,67 +1077,44 @@ mlr_dsl_cst_statement_t* alloc_emit_lashed(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node { emit_lashed_state_t* pstate = mlr_malloc_or_die(sizeof(emit_lashed_state_t)); - mlr_dsl_ast_node_t* pemit_node = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* poutput_node = pnode->pchildren->phead->pnext->pvvalue; - - mlr_dsl_ast_node_t* pkeylists_node = pemit_node->pchildren->phead->pvvalue; + pstate->num_emit_lashed_items = 0; + pstate->ppitems = NULL; + pstate->pemit_namelist_evaluators = NULL; pstate->poutput_filename_evaluator = NULL; pstate->stdfp = NULL; - pstate->pemit_namelist_evaluators = NULL; - pstate->num_emit_lashed_items = 0; - pstate->ppitems = NULL; pstate->psingle_lrec_writer = NULL; pstate->pmulti_lrec_writer = NULL; + mlr_dsl_ast_node_t* pemit_node = pnode->pchildren->phead->pvvalue; + mlr_dsl_ast_node_t* poutput_node = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pkeylists_node = pemit_node->pchildren->phead->pvvalue; + pstate->num_emit_lashed_items = pkeylists_node->pchildren->length; pstate->ppitems = mlr_malloc_or_die(pstate->num_emit_lashed_items * sizeof(emit_lashed_item_t*)); int i = 0; for (sllve_t* pe = pkeylists_node->pchildren->phead; pe != NULL; pe = pe->pnext, i++) { mlr_dsl_ast_node_t* pkeylist_node = pe->pvvalue; - emit_lashed_item_t* pitem = emit_lashed_item_alloc(); + rval_evaluator_t* pbasename_evaluator = NULL; switch (pkeylist_node->type) { - case MD_AST_NODE_TYPE_OOSVAR_KEYLIST: - pitem->pemit_lashed_item_getter = oosvar_emit_lashed_item_get; - pitem->pemit_lashed_item_freer = oosvar_emit_lashed_item_free; - pitem->pemit_keylist_evaluators = allocate_keylist_evaluators_from_ast_node( - pkeylist_node, pcst->pfmgr, type_inferencing, context_flags); - break; - case MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE: - pitem->pemit_lashed_item_getter = nonindexed_local_variable_emit_lashed_item_get; - pitem->pemit_lashed_item_freer = nonindexed_local_variable_emit_lashed_item_free; - pitem->pemit_keylist_evaluators = sllv_alloc(); - // xxx comment; also, this is awkward. - sllv_push(pitem->pemit_keylist_evaluators, rval_evaluator_alloc_from_string(pkeylist_node->text)); - MLR_INTERNAL_CODING_ERROR_IF(pkeylist_node->vardef_frame_relative_index == MD_UNUSED_INDEX); - pitem->localvar_frame_relative_index = pkeylist_node->vardef_frame_relative_index; - break; - case MD_AST_NODE_TYPE_INDEXED_LOCAL_VARIABLE: - pitem->pemit_lashed_item_getter = indexed_local_variable_emit_lashed_item_get; - pitem->pemit_lashed_item_freer = indexed_local_variable_emit_lashed_item_free; - pitem->pemit_keylist_evaluators = allocate_keylist_evaluators_from_ast_node( - pkeylist_node, pcst->pfmgr, type_inferencing, context_flags); - MLR_INTERNAL_CODING_ERROR_IF(pkeylist_node->vardef_frame_relative_index == MD_UNUSED_INDEX); - pitem->localvar_frame_relative_index = pkeylist_node->vardef_frame_relative_index; + pbasename_evaluator = rval_evaluator_alloc_from_string(pkeylist_node->text); break; - - case MD_AST_NODE_TYPE_MAP_LITERAL: - pitem->pemit_lashed_item_getter = map_literal_emit_lashed_item_get; - pitem->pemit_lashed_item_freer = map_literal_emit_lashed_item_free; - pitem->pemit_keylist_evaluators = sllv_alloc(); - sllv_push(pitem->pemit_keylist_evaluators, rval_evaluator_alloc_from_string("_")); - pitem->prhs_xevaluator = rxval_evaluator_alloc_from_ast_xxx_deprecated( - pkeylist_node, pcst->pfmgr, type_inferencing, context_flags); + case MD_AST_NODE_TYPE_OOSVAR_KEYLIST: + pbasename_evaluator = rval_evaluator_alloc_from_string( + ((mlr_dsl_ast_node_t*)pkeylist_node->pchildren->phead->pvvalue)->text); break; - default: - MLR_INTERNAL_CODING_ERROR(); + pbasename_evaluator = rval_evaluator_alloc_from_string("_"); + break; } - pstate->ppitems[i] = pitem; + rxval_evaluator_t* pitem_xevaluator = rxval_evaluator_alloc_from_ast( + pkeylist_node, pcst->pfmgr, type_inferencing, context_flags); + + pstate->ppitems[i] = emit_lashed_item_alloc(pbasename_evaluator, pitem_xevaluator); } sllv_t* pemit_namelist_evaluators = sllv_alloc(); @@ -1260,6 +1160,13 @@ mlr_dsl_cst_statement_t* alloc_emit_lashed(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node static void free_emit_lashed(mlr_dsl_cst_statement_t* pstatement) { emit_lashed_state_t* pstate = pstatement->pvstate; + if (pstate->ppitems != NULL) { + for (int i = 0; i < pstate->num_emit_lashed_items; i++) { + emit_lashed_item_free(pstate->ppitems[i]); + } + free(pstate->ppitems); + } + if (pstate->poutput_filename_evaluator != NULL) { pstate->poutput_filename_evaluator->pfree_func(pstate->poutput_filename_evaluator); } @@ -1272,13 +1179,6 @@ static void free_emit_lashed(mlr_dsl_cst_statement_t* pstatement) { sllv_free(pstate->pemit_namelist_evaluators); } - if (pstate->ppitems != NULL) { - for (int i = 0; i < pstate->num_emit_lashed_items; i++) { - emit_lashed_item_free(pstate->ppitems[i]); - } - free(pstate->ppitems); - } - if (pstate->psingle_lrec_writer != NULL) { pstate->psingle_lrec_writer->pfree_func(pstate->psingle_lrec_writer); } @@ -1361,45 +1261,48 @@ static void handle_emit_lashed_common( sllv_t* poutrecs, char* oosvar_flatten_separator) { - int keys_all_non_null_or_error = TRUE; - - sllmv_t** ppmvkeys = mlr_malloc_or_die(pstate->num_emit_lashed_items * sizeof(sllmv_t*)); + // xxx alloc array in ctor, free in dtor, reuse here + mv_t* pbasenames = mlr_malloc_or_die(pstate->num_emit_lashed_items * sizeof(mv_t)); for (int i = 0; i < pstate->num_emit_lashed_items; i++) { - ppmvkeys[i] = evaluate_list(pstate->ppitems[i]->pemit_keylist_evaluators, pvars, - &keys_all_non_null_or_error); + rval_evaluator_t* pev = pstate->ppitems[i]->pbasename_evaluator; + pbasenames[i] = pev->pprocess_func(pev->pvstate, pvars); } - if (keys_all_non_null_or_error) { - int names_all_non_null_or_error = TRUE; - sllmv_t* pmvnames = evaluate_list(pstate->pemit_namelist_evaluators, pvars, - &names_all_non_null_or_error); - if (names_all_non_null_or_error) { + int names_all_non_null_or_error = TRUE; + sllmv_t* pmvnames = evaluate_list(pstate->pemit_namelist_evaluators, pvars, + &names_all_non_null_or_error); + if (names_all_non_null_or_error) { - mlhmmv_value_t** ptop_values = mlr_malloc_or_die( - pstate->num_emit_lashed_items * sizeof(mlhmmv_level_entry_t*)); - for (int i = 0; i < pstate->num_emit_lashed_items; i++) { - emit_lashed_item_t* pitem = pstate->ppitems[i]; - ptop_values[i] = pitem->pemit_lashed_item_getter(pitem, pvars, ppmvkeys[i]); - } - - mlhmmv_to_lrecs_lashed(ptop_values, pstate->num_emit_lashed_items, ppmvkeys, pmvnames, - poutrecs, pstate->do_full_prefixing, oosvar_flatten_separator); - - for (int i = 0; i < pstate->num_emit_lashed_items; i++) { - emit_lashed_item_t* pitem = pstate->ppitems[i]; - if (pitem->pemit_lashed_item_freer != NULL) { - pitem->pemit_lashed_item_freer(pitem); - } - } - - free(ptop_values); + // xxx alloc array in ctor, free in dtor, reuse here + boxed_xval_t* pboxed_xvals = mlr_malloc_or_die( + pstate->num_emit_lashed_items * sizeof(boxed_xval_t)); + // xxx comment + mlhmmv_value_t** ptop_values = mlr_malloc_or_die( + pstate->num_emit_lashed_items * sizeof(mlhmmv_level_entry_t*)); + for (int i = 0; i < pstate->num_emit_lashed_items; i++) { + emit_lashed_item_t* pitem = pstate->ppitems[i]; + pboxed_xvals[i] = pitem->pitem_xevaluator->pprocess_func( + pitem->pitem_xevaluator->pvstate, pvars); + ptop_values[i] = &pboxed_xvals[i].xval; } - sllmv_free(pmvnames); + + mlhmmv_to_lrecs_lashed(ptop_values, pstate->num_emit_lashed_items, pbasenames, pmvnames, + poutrecs, pstate->do_full_prefixing, oosvar_flatten_separator); + + for (int i = 0; i < pstate->num_emit_lashed_items; i++) { + if (pboxed_xvals[i].map_is_ephemeral) { + mlhmmv_free_submap(pboxed_xvals[i].xval); + } + } + + free(ptop_values); + free(pboxed_xvals); } + sllmv_free(pmvnames); + for (int i = 0; i < pstate->num_emit_lashed_items; i++) { - sllmv_free(ppmvkeys[i]); + mv_free(&pbasenames[i]); } - free(ppmvkeys); } // ================================================================