1 #include <stdlib.h>
2 #include "lib/mlr_globals.h"
3 #include "lib/mlrutil.h"
4 #include "keylist_evaluators.h"
5 #include "mlr_dsl_cst.h"
6 #include "context_flags.h"
7 
8 // ================================================================
9 typedef struct _full_srec_assignment_state_t {
10 	rxval_evaluator_t* prhs_xevaluator;
11 } full_srec_assignment_state_t;
12 
13 static mlr_dsl_cst_statement_handler_t handle_full_srec_assignment_nop;
14 static mlr_dsl_cst_statement_handler_t handle_full_srec_assignment;
15 static mlr_dsl_cst_statement_freer_t free_full_srec_assignment;
16 
17 // ----------------------------------------------------------------
alloc_full_srec_assignment(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)18 mlr_dsl_cst_statement_t* alloc_full_srec_assignment(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
19 	int type_inferencing, int context_flags)
20 {
21 	full_srec_assignment_state_t* pstate = mlr_malloc_or_die(sizeof(
22 		full_srec_assignment_state_t));
23 
24 	mlr_dsl_ast_node_t* plhs_node = pnode->pchildren->phead->pvvalue;
25 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
26 
27 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->type != MD_AST_NODE_TYPE_FULL_SREC);
28 
29 	mlr_dsl_cst_statement_handler_t* phandler = handle_full_srec_assignment;
30 	if (prhs_node->type == MD_AST_NODE_TYPE_FULL_SREC) {
31 		// '$* = $*' is a syntactically acceptable no-op
32 		pstate->prhs_xevaluator = NULL;
33 		phandler = handle_full_srec_assignment_nop;
34 	} else {
35 		pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
36 			prhs_node, pcst->pfmgr, type_inferencing, context_flags);
37 		phandler = handle_full_srec_assignment;
38 	}
39 
40 	return mlr_dsl_cst_statement_valloc(
41 		pnode,
42 		phandler,
43 		free_full_srec_assignment,
44 		pstate);
45 }
46 
47 // ----------------------------------------------------------------
free_full_srec_assignment(mlr_dsl_cst_statement_t * pstatement,context_t * _)48 static void free_full_srec_assignment(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
49 	full_srec_assignment_state_t* pstate = pstatement->pvstate;
50 
51 	if (pstate->prhs_xevaluator != NULL) {
52 		pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
53 	}
54 
55 	free(pstate);
56 }
57 
58 // ----------------------------------------------------------------
handle_full_srec_assignment_nop(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)59 static void handle_full_srec_assignment_nop(
60 	mlr_dsl_cst_statement_t* pstatement,
61 	variables_t*             pvars,
62 	cst_outputs_t*           pcst_outputs)
63 {
64 }
65 
66 // ----------------------------------------------------------------
handle_full_srec_assignment(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)67 static void handle_full_srec_assignment(
68 	mlr_dsl_cst_statement_t* pstatement,
69 	variables_t*             pvars,
70 	cst_outputs_t*           pcst_outputs)
71 {
72 	full_srec_assignment_state_t* pstate = pstatement->pvstate;
73 
74 	lrec_t* poutrec = lrec_unbacked_alloc(); // pinrec might be part of the RHS.
75 	lhmsmv_t* pout_typed_overlay = lhmsmv_alloc();
76 
77 	rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
78 	boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
79 
80 	if (!boxed_xval.xval.is_terminal) {
81 		for (mlhmmv_level_entry_t* pe = boxed_xval.xval.pnext_level->phead; pe != NULL; pe = pe->pnext) {
82 			mv_t* pkey = &pe->level_key;
83 			mlhmmv_xvalue_t* pval = &pe->level_xvalue;
84 
85 			if (pval->is_terminal) { // xxx else collapse-down using json separator?
86 				char* skey = mv_alloc_format_val(pkey);
87 				// xxx if we're going to transfer here *and* free below, this needs a nullptr poke
88 				// at the copy-from site
89 				//mv_t val = boxed_xval.is_ephemeral ? pval->terminal_mlrval : mv_copy(&pval->terminal_mlrval);
90 				mv_t val = mv_copy(&pval->terminal_mlrval);
91 
92 				// Write typed mlrval output to the typed overlay rather than into the lrec
93 				// (which holds only string values).
94 				//
95 				// The rval_evaluator reads the overlay in preference to the lrec. E.g. if the
96 				// input had "x"=>"abc","y"=>"def" but a previous statement had set "y"=>7.4 and
97 				// "z"=>"ghi", then an expression right-hand side referring to $y would get the
98 				// floating-point value 7.4. So we don't need to lrec_put the value here, and
99 				// moreover should not for two reasons: (1) there is a performance hit of doing
100 				// throwaway number-to-string formatting -- it's better to do it once at the
101 				// end; (2) having the string values doubly owned by the typed overlay and the
102 				// lrec would result in double frees, or awkward bookkeeping. However, the NR
103 				// variable evaluator reads prec->field_count, so we need to put something here.
104 				// And putting something statically allocated minimizes copying/freeing.
105 				lhmsmv_put(pout_typed_overlay, mlr_strdup_or_die(skey), &val,
106 					FREE_ENTRY_KEY | FREE_ENTRY_VALUE);
107 				lrec_put(poutrec, skey, "bug", FREE_ENTRY_KEY);
108 			}
109 		}
110 		if (boxed_xval.is_ephemeral) {
111 			mlhmmv_xvalue_free(&boxed_xval.xval);
112 		}
113 	} else {
114 		mlhmmv_xvalue_free(&boxed_xval.xval);
115 	}
116 	lrec_free(pvars->pinrec);
117 	lhmsmv_free(pvars->ptyped_overlay);
118 	pvars->pinrec = poutrec;
119 	pvars->ptyped_overlay = pout_typed_overlay;
120 }
121 
122 // ================================================================
123 typedef struct _local_variable_definition_state_t {
124 	char*              lhs_variable_name;
125 	int                lhs_frame_relative_index;
126 	int                lhs_type_mask;
127 	rxval_evaluator_t* prhs_xevaluator;
128 } local_variable_definition_state_t;
129 
130 static mlr_dsl_cst_statement_handler_t handle_local_variable_definition_from_xval;
131 static mlr_dsl_cst_statement_freer_t free_local_variable_definition;
132 
133 // ----------------------------------------------------------------
alloc_local_variable_definition(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags,int type_mask)134 mlr_dsl_cst_statement_t* alloc_local_variable_definition(
135 	mlr_dsl_cst_t*      pcst,
136 	mlr_dsl_ast_node_t* pnode,
137 	int                 type_inferencing,
138 	int                 context_flags,
139 	int                 type_mask)
140 {
141 	local_variable_definition_state_t* pstate = mlr_malloc_or_die(
142 		sizeof(local_variable_definition_state_t));
143 
144 	pstate->lhs_variable_name        = NULL;
145 	pstate->lhs_frame_relative_index = MD_UNUSED_INDEX;
146 	pstate->lhs_type_mask            = 0;
147 	pstate->prhs_xevaluator          = NULL;
148 
149 	mlr_dsl_ast_node_t* pname_node = pnode->pchildren->phead->pvvalue;
150 	pstate->lhs_variable_name = pname_node->text;
151 	MLR_INTERNAL_CODING_ERROR_IF(pname_node->vardef_frame_relative_index == MD_UNUSED_INDEX);
152 	pstate->lhs_frame_relative_index = pname_node->vardef_frame_relative_index;
153 	pstate->lhs_type_mask = type_mask;
154 
155 	mlr_dsl_cst_statement_handler_t* pstatement_handler = NULL;
156 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
157 	pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
158 		prhs_node, pcst->pfmgr, type_inferencing, context_flags);
159 	pstatement_handler = handle_local_variable_definition_from_xval;
160 
161 	return mlr_dsl_cst_statement_valloc(
162 		pnode,
163 		pstatement_handler,
164 		free_local_variable_definition,
165 		pstate);
166 }
167 
168 // ----------------------------------------------------------------
free_local_variable_definition(mlr_dsl_cst_statement_t * pstatement,context_t * _)169 static void free_local_variable_definition(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
170 	local_variable_definition_state_t* pstate = pstatement->pvstate;
171 
172 	pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
173 
174 	free(pstate);
175 }
176 
177 // ----------------------------------------------------------------
handle_local_variable_definition_from_xval(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)178 static void handle_local_variable_definition_from_xval(
179 	mlr_dsl_cst_statement_t* pstatement,
180 	variables_t*             pvars,
181 	cst_outputs_t*           pcst_outputs)
182 {
183 	local_variable_definition_state_t* pstate = pstatement->pvstate;
184 	rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
185 	boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
186 
187 	local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack);
188 	if (boxed_xval.is_ephemeral) {
189 		local_stack_frame_define_extended(pframe,
190 			pstate->lhs_variable_name, pstate->lhs_frame_relative_index, pstate->lhs_type_mask,
191 			boxed_xval.xval);
192 	} else {
193 		local_stack_frame_define_extended(pframe,
194 			pstate->lhs_variable_name, pstate->lhs_frame_relative_index, pstate->lhs_type_mask,
195 			mlhmmv_xvalue_copy(&boxed_xval.xval));
196 	}
197 }
198 
199 // ================================================================
200 typedef struct _nonindexed_local_variable_assignment_state_t {
201 	char*              lhs_variable_name; // For error messages only: stack-index is computed by stack-allocator:
202 	int                lhs_frame_relative_index;
203 	rxval_evaluator_t* prhs_xevaluator;
204 } nonindexed_local_variable_assignment_state_t;
205 
206 static mlr_dsl_cst_statement_handler_t handle_nonindexed_local_variable_assignment_from_xval;
207 static mlr_dsl_cst_statement_freer_t free_nonindexed_local_variable_assignment;
208 
209 // ----------------------------------------------------------------
alloc_nonindexed_local_variable_assignment(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)210 mlr_dsl_cst_statement_t* alloc_nonindexed_local_variable_assignment(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
211 	int type_inferencing, int context_flags)
212 {
213 	nonindexed_local_variable_assignment_state_t* pstate = mlr_malloc_or_die(sizeof(
214 		nonindexed_local_variable_assignment_state_t));
215 
216 	pstate->lhs_variable_name        = NULL;
217 	pstate->lhs_frame_relative_index = MD_UNUSED_INDEX;
218 	pstate->prhs_xevaluator          = NULL;
219 
220 	MLR_INTERNAL_CODING_ERROR_IF((pnode->pchildren == NULL) || (pnode->pchildren->length != 2));
221 
222 	mlr_dsl_ast_node_t* plhs_node = pnode->pchildren->phead->pvvalue;
223 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
224 
225 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->type != MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE);
226 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->pchildren != NULL);
227 
228 	pstate->lhs_variable_name = plhs_node->text;
229 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->vardef_frame_relative_index == MD_UNUSED_INDEX);
230 	pstate->lhs_frame_relative_index = plhs_node->vardef_frame_relative_index;
231 
232 	mlr_dsl_cst_statement_handler_t* pstatement_handler = NULL;
233 
234 	pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
235 		prhs_node, pcst->pfmgr, type_inferencing, context_flags);
236 	pstatement_handler = handle_nonindexed_local_variable_assignment_from_xval;
237 
238 	return mlr_dsl_cst_statement_valloc(
239 		pnode,
240 		pstatement_handler,
241 		free_nonindexed_local_variable_assignment,
242 		pstate);
243 }
244 
245 // ----------------------------------------------------------------
free_nonindexed_local_variable_assignment(mlr_dsl_cst_statement_t * pstatement,context_t * _)246 static void free_nonindexed_local_variable_assignment(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
247 	nonindexed_local_variable_assignment_state_t* pstate = pstatement->pvstate;
248 
249 	if (pstate->prhs_xevaluator != NULL) {
250 		pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
251 	}
252 
253 	free(pstate);
254 }
255 
256 // ----------------------------------------------------------------
handle_nonindexed_local_variable_assignment_from_xval(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)257 static void handle_nonindexed_local_variable_assignment_from_xval(
258 	mlr_dsl_cst_statement_t* pstatement,
259 	variables_t*             pvars,
260 	cst_outputs_t*           pcst_outputs)
261 {
262 	nonindexed_local_variable_assignment_state_t* pstate = pstatement->pvstate;
263 
264 	rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
265 	boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
266 
267 	if (!boxed_xval.xval.is_terminal || mv_is_present(&boxed_xval.xval.terminal_mlrval)) {
268 		local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack);
269 		if (boxed_xval.is_ephemeral) {
270 			local_stack_frame_assign_extended_nonindexed(pframe, pstate->lhs_frame_relative_index,
271 				boxed_xval.xval);
272 		} else {
273 			local_stack_frame_assign_extended_nonindexed(pframe, pstate->lhs_frame_relative_index,
274 				mlhmmv_xvalue_copy(&boxed_xval.xval));
275 		}
276 	}
277 }
278 
279 // ================================================================
280 typedef struct _indexed_local_variable_assignment_state_t {
281 	char*              lhs_variable_name; // For error messages only: stack-index is computed by stack-allocator:
282 	int                lhs_frame_relative_index;
283 	sllv_t*            plhs_keylist_evaluators;
284 	rxval_evaluator_t* prhs_xevaluator;
285 } indexed_local_variable_assignment_state_t;
286 
287 static mlr_dsl_cst_statement_handler_t handle_indexed_local_variable_assignment_from_xval;
288 static mlr_dsl_cst_statement_freer_t free_indexed_local_variable_assignment;
289 
290 // ----------------------------------------------------------------
alloc_indexed_local_variable_assignment(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)291 mlr_dsl_cst_statement_t* alloc_indexed_local_variable_assignment(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
292 	int type_inferencing, int context_flags)
293 {
294 	indexed_local_variable_assignment_state_t* pstate = mlr_malloc_or_die(sizeof(
295 		indexed_local_variable_assignment_state_t));
296 
297 	pstate->lhs_variable_name        = NULL;
298 	pstate->lhs_frame_relative_index = MD_UNUSED_INDEX;
299 	pstate->prhs_xevaluator          = NULL;
300 
301 	mlr_dsl_ast_node_t* plhs_node = pnode->pchildren->phead->pvvalue;
302 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
303 
304 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->type != MD_AST_NODE_TYPE_INDEXED_LOCAL_VARIABLE);
305 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->pchildren == NULL);
306 
307 	pstate->lhs_variable_name = plhs_node->text;
308 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->vardef_frame_relative_index == MD_UNUSED_INDEX);
309 	pstate->lhs_frame_relative_index = plhs_node->vardef_frame_relative_index;
310 
311 	pstate->plhs_keylist_evaluators = allocate_keylist_evaluators_from_ast_node(
312 		plhs_node, pcst->pfmgr, type_inferencing, context_flags);
313 
314 	mlr_dsl_cst_statement_handler_t* pstatement_handler = NULL;
315 
316 	pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
317 		prhs_node, pcst->pfmgr, type_inferencing, context_flags);
318 	pstatement_handler = handle_indexed_local_variable_assignment_from_xval;
319 
320 	return mlr_dsl_cst_statement_valloc(
321 		pnode,
322 		pstatement_handler,
323 		free_indexed_local_variable_assignment,
324 		pstate);
325 }
326 
327 // ----------------------------------------------------------------
free_indexed_local_variable_assignment(mlr_dsl_cst_statement_t * pstatement,context_t * _)328 static void free_indexed_local_variable_assignment(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
329 	indexed_local_variable_assignment_state_t* pstate = pstatement->pvstate;
330 
331 	for (sllve_t* pe = pstate->plhs_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) {
332 		rval_evaluator_t* pev = pe->pvvalue;
333 		pev->pfree_func(pev);
334 	}
335 	sllv_free(pstate->plhs_keylist_evaluators);
336 
337 	pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
338 
339 	free(pstate);
340 }
341 
342 // ----------------------------------------------------------------
handle_indexed_local_variable_assignment_from_xval(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)343 static void handle_indexed_local_variable_assignment_from_xval(
344 	mlr_dsl_cst_statement_t* pstatement,
345 	variables_t*             pvars,
346 	cst_outputs_t*           pcst_outputs)
347 {
348 	indexed_local_variable_assignment_state_t* pstate = pstatement->pvstate;
349 
350 	int lhs_keys_all_non_null_or_error;
351 	sllmv_t* pmvkeys = evaluate_list(pstate->plhs_keylist_evaluators, pvars, &lhs_keys_all_non_null_or_error);
352 	if (lhs_keys_all_non_null_or_error) {
353 
354 		rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
355 		boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
356 
357 		if (!boxed_xval.xval.is_terminal || mv_is_present(&boxed_xval.xval.terminal_mlrval)) {
358 			local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack);
359 			if (boxed_xval.is_ephemeral) {
360 				local_stack_frame_assign_extended_indexed(pframe, pstate->lhs_frame_relative_index,
361 					pmvkeys, boxed_xval.xval);
362 			} else {
363 				local_stack_frame_assign_extended_indexed(pframe, pstate->lhs_frame_relative_index,
364 					pmvkeys, mlhmmv_xvalue_copy(&boxed_xval.xval));
365 			}
366 		}
367 
368 	}
369 	sllmv_free(pmvkeys);
370 
371 }
372 
373 // ================================================================
374 typedef struct _oosvar_assignment_state_t {
375 	sllv_t*            plhs_keylist_evaluators;
376 	rxval_evaluator_t* prhs_xevaluator;
377 } oosvar_assignment_state_t;
378 
379 static mlr_dsl_cst_statement_handler_t handle_oosvar_assignment_from_xval;
380 static mlr_dsl_cst_statement_freer_t free_oosvar_assignment;
381 
382 // ----------------------------------------------------------------
alloc_oosvar_assignment(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)383 mlr_dsl_cst_statement_t* alloc_oosvar_assignment(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
384 	int type_inferencing, int context_flags)
385 {
386 	oosvar_assignment_state_t* pstate = mlr_malloc_or_die(sizeof(oosvar_assignment_state_t));
387 
388 	pstate->plhs_keylist_evaluators = NULL;
389 	pstate->prhs_xevaluator         = NULL;
390 
391 	mlr_dsl_ast_node_t* plhs_node = pnode->pchildren->phead->pvvalue;
392 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
393 
394 	MLR_INTERNAL_CODING_ERROR_IF(plhs_node->type != MD_AST_NODE_TYPE_OOSVAR_KEYLIST);
395 
396 	pstate->plhs_keylist_evaluators = allocate_keylist_evaluators_from_ast_node(
397 		plhs_node, pcst->pfmgr, type_inferencing, context_flags);
398 
399 	mlr_dsl_cst_statement_handler_t* pstatement_handler = NULL;
400 
401 	pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
402 		prhs_node, pcst->pfmgr, type_inferencing, context_flags);
403 	pstatement_handler = handle_oosvar_assignment_from_xval;
404 
405 	return mlr_dsl_cst_statement_valloc(
406 		pnode,
407 		pstatement_handler,
408 		free_oosvar_assignment,
409 		pstate);
410 }
411 
412 // ----------------------------------------------------------------
free_oosvar_assignment(mlr_dsl_cst_statement_t * pstatement,context_t * _)413 static void free_oosvar_assignment(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
414 	oosvar_assignment_state_t* pstate = pstatement->pvstate;
415 
416 	for (sllve_t* pe = pstate->plhs_keylist_evaluators->phead; pe != NULL; pe = pe->pnext) {
417 		rval_evaluator_t* pev = pe->pvvalue;
418 		pev->pfree_func(pev);
419 	}
420 	sllv_free(pstate->plhs_keylist_evaluators);
421 	if (pstate->prhs_xevaluator != NULL) {
422 		pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
423 	}
424 
425 	free(pstate);
426 }
427 
428 // ----------------------------------------------------------------
handle_oosvar_assignment_from_xval(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)429 static void handle_oosvar_assignment_from_xval(
430 	mlr_dsl_cst_statement_t* pstatement,
431 	variables_t*             pvars,
432 	cst_outputs_t*           pcst_outputs)
433 {
434 	oosvar_assignment_state_t* pstate = pstatement->pvstate;
435 
436 	int lhs_all_non_null_or_error = TRUE;
437 	sllmv_t* plhskeys = evaluate_list(pstate->plhs_keylist_evaluators, pvars,
438 		&lhs_all_non_null_or_error);
439 
440 	if (lhs_all_non_null_or_error) {
441 		rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
442 		boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
443 
444 		if (!boxed_xval.xval.is_terminal || mv_is_present(&boxed_xval.xval.terminal_mlrval)) {
445 			if (boxed_xval.is_ephemeral) {
446 				mlhmmv_level_put_xvalue(pvars->poosvars->root_xvalue.pnext_level, plhskeys->phead, &boxed_xval.xval);
447 			} else {
448 				mlhmmv_xvalue_t copy_xval = mlhmmv_xvalue_copy(&boxed_xval.xval);
449 				mlhmmv_level_put_xvalue(pvars->poosvars->root_xvalue.pnext_level, plhskeys->phead, &copy_xval);
450 			}
451 		}
452 	}
453 
454 	sllmv_free(plhskeys);
455 }
456 
457 // ================================================================
458 typedef struct _full_oosvar_assignment_state_t {
459 	rxval_evaluator_t* prhs_xevaluator;
460 } full_oosvar_assignment_state_t;
461 
462 static mlr_dsl_cst_statement_handler_t handle_full_oosvar_assignment_from_xval;
463 static mlr_dsl_cst_statement_handler_t handle_full_oosvar_assignment_nop;
464 static mlr_dsl_cst_statement_freer_t free_full_oosvar_assignment;
465 
466 // ----------------------------------------------------------------
alloc_full_oosvar_assignment(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)467 mlr_dsl_cst_statement_t* alloc_full_oosvar_assignment(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
468 	int type_inferencing, int context_flags)
469 {
470 	full_oosvar_assignment_state_t* pstate = mlr_malloc_or_die(sizeof(full_oosvar_assignment_state_t));
471 
472 	pstate->prhs_xevaluator = NULL;
473 
474 	mlr_dsl_ast_node_t* plhs_node = pnode->pchildren->phead->pvvalue;
475 	mlr_dsl_ast_node_t* prhs_node = pnode->pchildren->phead->pnext->pvvalue;
476 	MLR_INTERNAL_CODING_ERROR_UNLESS(plhs_node->type == MD_AST_NODE_TYPE_FULL_OOSVAR);
477 
478 	mlr_dsl_cst_statement_handler_t* pstatement_handler = NULL;
479 	if (prhs_node->type == MD_AST_NODE_TYPE_FULL_OOSVAR) {
480 		pstatement_handler = handle_full_oosvar_assignment_nop;
481 	} else {
482 		pstate->prhs_xevaluator = rxval_evaluator_alloc_from_ast(
483 			prhs_node, pcst->pfmgr, type_inferencing, context_flags);
484 		pstatement_handler = handle_full_oosvar_assignment_from_xval;
485 	}
486 
487 	return mlr_dsl_cst_statement_valloc(
488 		pnode,
489 		pstatement_handler,
490 		free_full_oosvar_assignment,
491 		pstate);
492 }
493 
494 // ----------------------------------------------------------------
free_full_oosvar_assignment(mlr_dsl_cst_statement_t * pstatement,context_t * _)495 static void free_full_oosvar_assignment(mlr_dsl_cst_statement_t* pstatement, context_t* _) {
496 	full_oosvar_assignment_state_t* pstate = pstatement->pvstate;
497 
498 	if (pstate->prhs_xevaluator != NULL) {
499 		pstate->prhs_xevaluator->pfree_func(pstate->prhs_xevaluator);
500 	}
501 
502 	free(pstate);
503 }
504 
505 // ----------------------------------------------------------------
handle_full_oosvar_assignment_from_xval(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)506 static void handle_full_oosvar_assignment_from_xval(
507 	mlr_dsl_cst_statement_t* pstatement,
508 	variables_t*             pvars,
509 	cst_outputs_t*           pcst_outputs)
510 {
511 	full_oosvar_assignment_state_t* pstate = pstatement->pvstate;
512 	rxval_evaluator_t* prhs_xevaluator = pstate->prhs_xevaluator;
513 	boxed_xval_t boxed_xval = prhs_xevaluator->pprocess_func(prhs_xevaluator->pvstate, pvars);
514 
515 	if (boxed_xval.xval.is_terminal) {
516 		mlhmmv_root_clear(pvars->poosvars);
517 		mlhmmv_xvalue_free(&boxed_xval.xval);
518 	} else {
519 		if (boxed_xval.is_ephemeral) {
520 			mlhmmv_level_free(pvars->poosvars->root_xvalue.pnext_level);
521 			pvars->poosvars->root_xvalue.pnext_level = boxed_xval.xval.pnext_level;
522 		} else {
523 			mlhmmv_xvalue_t copy = mlhmmv_xvalue_copy(&boxed_xval.xval);
524 			mlhmmv_root_clear(pvars->poosvars);
525 			for (mlhmmv_level_entry_t* pe = copy.pnext_level->phead; pe != NULL; pe = pe->pnext) {
526 				// xxx comment: value transfer not copy.
527 				mlhmmv_level_put_xvalue_singly_keyed(pvars->poosvars->root_xvalue.pnext_level, &pe->level_key, &pe->level_xvalue);
528 				pe->level_xvalue.terminal_mlrval = mv_absent();
529 				pe->level_xvalue.pnext_level = NULL;
530 				pe->level_xvalue.is_terminal = TRUE;
531 			}
532 			mlhmmv_xvalue_free(&copy);
533 		}
534 	}
535 }
536 
537 // ----------------------------------------------------------------
538 // @* = @*
handle_full_oosvar_assignment_nop(mlr_dsl_cst_statement_t * pstatement,variables_t * pvars,cst_outputs_t * pcst_outputs)539 static void handle_full_oosvar_assignment_nop(
540 	mlr_dsl_cst_statement_t* pstatement,
541 	variables_t*             pvars,
542 	cst_outputs_t*           pcst_outputs)
543 {
544 }
545