1 #include <stdlib.h>
2 #include "lib/mlr_globals.h"
3 #include "lib/mlrutil.h"
4 #include "mlr_dsl_cst.h"
5 #include "context_flags.h"
6 
7 // ================================================================
8 // The Lemon parser in parsing/mlr_dsl_parse.y builds up an abstract syntax tree
9 // specifically for the CST builder here.
10 //
11 // For clearer visuals on what the ASTs look like:
12 // * See parsing/mlr_dsl_parse.y
13 // * See reg_test/run's filter -v and put -v outputs, e.g. in reg_test/expected/out
14 // * Do "mlr -n put -v 'your expression goes here'"
15 // ================================================================
16 
17 // ================================================================
cst_statement_block_alloc(int subframe_var_count)18 cst_statement_block_t* cst_statement_block_alloc(int subframe_var_count) {
19 	cst_statement_block_t* pblock = mlr_malloc_or_die(sizeof(cst_statement_block_t));
20 
21 	pblock->subframe_var_count = subframe_var_count;
22 	pblock->pstatements     = sllv_alloc();
23 
24 	return pblock;
25 }
26 
27 // ----------------------------------------------------------------
cst_statement_block_free(cst_statement_block_t * pblock,context_t * pctx)28 void cst_statement_block_free(cst_statement_block_t* pblock, context_t* pctx) {
29 	if (pblock == NULL)
30 		return;
31 	for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
32 		mlr_dsl_cst_statement_free(pe->pvvalue, pctx);
33 	}
34 	sllv_free(pblock->pstatements);
35 	free(pblock);
36 }
37 
38 // ================================================================
39 // ALLOCATORS
40 // ================================================================
cst_top_level_statement_block_alloc(int max_var_depth,int subframe_var_count)41 cst_top_level_statement_block_t* cst_top_level_statement_block_alloc(int max_var_depth, int subframe_var_count) {
42 	cst_top_level_statement_block_t* ptop_level_block = mlr_malloc_or_die(sizeof(cst_top_level_statement_block_t));
43 
44 	ptop_level_block->max_var_depth = max_var_depth;
45 	ptop_level_block->pframe        = local_stack_frame_alloc(max_var_depth);
46 	ptop_level_block->pblock        = cst_statement_block_alloc(subframe_var_count);
47 
48 	return ptop_level_block;
49 }
50 
51 // ----------------------------------------------------------------
cst_top_level_statement_block_free(cst_top_level_statement_block_t * ptop_level_block,context_t * pctx)52 void cst_top_level_statement_block_free(cst_top_level_statement_block_t* ptop_level_block, context_t* pctx) {
53 	if (ptop_level_block == NULL)
54 		return;
55 	local_stack_frame_free(ptop_level_block->pframe);
56 	cst_statement_block_free(ptop_level_block->pblock, pctx);
57 	free(ptop_level_block);
58 }
59 
60 // ================================================================
61 // The parser accepts many things that are invalid, e.g.
62 // * begin{end{}} -- begin/end not at top level
63 // * begin{$x=1} -- references to stream records at begin/end
64 // * break/continue outside of for/while/do-while
65 // * $x=x -- boundvars outside of for-loop variable bindings
66 //
67 // All of the above are enforced here by the CST builder, which takes the parser's output AST as
68 // input.  This is done (a) to keep the parser from being overly complex, and (b) so we can get much
69 // more informative error messages in C than in Lemon ('syntax error').
70 //
71 // In this file we set up left-hand sides for assignments, as well as right-hand sides for emit and
72 // unset.  Most right-hand sides are set up in rval_expr_evaluators.c so the context_flags are
73 // passed through to there as well.
74 
mlr_dsl_cst_alloc_statement(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)75 mlr_dsl_cst_statement_t* mlr_dsl_cst_alloc_statement(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
76 	int type_inferencing, int context_flags)
77 {
78 	switch(pnode->type) {
79 
80 	case MD_AST_NODE_TYPE_FUNC_DEF:
81 		fprintf(stderr, "%s: func statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
82 		exit(1);
83 		break;
84 
85 	case MD_AST_NODE_TYPE_SUBR_DEF:
86 		fprintf(stderr, "%s: subr statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
87 		exit(1);
88 		break;
89 
90 	case MD_AST_NODE_TYPE_BEGIN:
91 		fprintf(stderr, "%s: begin statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
92 		exit(1);
93 		break;
94 
95 	case MD_AST_NODE_TYPE_END:
96 		fprintf(stderr, "%s: end statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
97 		exit(1);
98 		break;
99 
100 	case MD_AST_NODE_TYPE_RETURN_VALUE:
101 		if (!(context_flags & IN_FUNC_DEF)) {
102 			fprintf(stderr, "%s: return-value statements are only valid within func blocks.\n",
103 				MLR_GLOBALS.bargv0);
104 			exit(1);
105 		}
106 		return alloc_return_value(pcst, pnode, type_inferencing, context_flags);
107 		break;
108 
109 	case MD_AST_NODE_TYPE_RETURN_VOID:
110 		if (!(context_flags & IN_SUBR_DEF)) {
111 			fprintf(stderr, "%s: return-void statements are only valid within subr blocks.\n",
112 				MLR_GLOBALS.bargv0);
113 			exit(1);
114 		}
115 		return alloc_return_void(pcst, pnode, type_inferencing, context_flags);
116 		break;
117 
118 	case MD_AST_NODE_TYPE_SUBR_CALLSITE:
119 		if (context_flags & IN_FUNC_DEF) {
120 			fprintf(stderr, "%s: subroutine calls are not valid within func blocks.\n",
121 				MLR_GLOBALS.bargv0);
122 			exit(1);
123 		}
124 		return alloc_subr_callsite_statement(pcst, pnode, type_inferencing, context_flags);
125 		break;
126 
127 	case MD_AST_NODE_TYPE_CONDITIONAL_BLOCK:
128 		return alloc_conditional_block(pcst, pnode, type_inferencing, context_flags);
129 		break;
130 	case MD_AST_NODE_TYPE_IF_HEAD:
131 		return alloc_if_head(pcst, pnode, type_inferencing, context_flags);
132 		break;
133 
134 	case MD_AST_NODE_TYPE_WHILE:
135 		return alloc_while(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
136 		break;
137 	case MD_AST_NODE_TYPE_DO_WHILE:
138 		return alloc_do_while(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
139 		break;
140 
141 	case MD_AST_NODE_TYPE_FOR_SREC:
142 		if (context_flags & IN_BEGIN_OR_END) {
143 			fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n",
144 				MLR_GLOBALS.bargv0);
145 			exit(1);
146 		}
147 		return alloc_for_srec(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
148 		break;
149 
150 	case MD_AST_NODE_TYPE_FOR_SREC_KEY_ONLY:
151 		if (context_flags & IN_BEGIN_OR_END) {
152 			fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n",
153 				MLR_GLOBALS.bargv0);
154 			exit(1);
155 		}
156 		return alloc_for_srec_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
157 		break;
158 
159 	case MD_AST_NODE_TYPE_FOR_OOSVAR:
160 		return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
161 		break;
162 	case MD_AST_NODE_TYPE_FOR_OOSVAR_KEY_ONLY:
163 		return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
164 		break;
165 
166 	case MD_AST_NODE_TYPE_FOR_LOCAL_MAP:
167 		return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
168 		break;
169 	case MD_AST_NODE_TYPE_FOR_LOCAL_MAP_KEY_ONLY:
170 		return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
171 		break;
172 
173 	case MD_AST_NODE_TYPE_FOR_MAP_LITERAL:
174 		return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
175 		break;
176 	case MD_AST_NODE_TYPE_FOR_MAP_LITERAL_KEY_ONLY:
177 		return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
178 		break;
179 
180 	case MD_AST_NODE_TYPE_FOR_FUNC_RETVAL:
181 		return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
182 		break;
183 	case MD_AST_NODE_TYPE_FOR_FUNC_RETVAL_KEY_ONLY:
184 		return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
185 		break;
186 
187 	case MD_AST_NODE_TYPE_TRIPLE_FOR:
188 		return alloc_triple_for(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
189 		break;
190 
191 	case MD_AST_NODE_TYPE_BREAK:
192 		if (!(context_flags & IN_BREAKABLE)) {
193 			fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n",
194 				MLR_GLOBALS.bargv0);
195 			exit(1);
196 		}
197 		return alloc_break(pcst, pnode, type_inferencing, context_flags);
198 		break;
199 	case MD_AST_NODE_TYPE_CONTINUE:
200 		if (!(context_flags & IN_BREAKABLE)) {
201 			fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n",
202 				MLR_GLOBALS.bargv0);
203 			exit(1);
204 		}
205 		return alloc_continue(pcst, pnode, type_inferencing, context_flags);
206 		break;
207 
208 	case MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION:
209 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_ANY);
210 
211 	case MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION:
212 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_NUMERIC);
213 		break;
214 
215 	case MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION:
216 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_INT);
217 		break;
218 
219 	case MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION:
220 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_FLOAT);
221 		break;
222 
223 	case MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION:
224 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_BOOLEAN);
225 		break;
226 
227 	case MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION:
228 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_STRING);
229 		break;
230 
231 	case MD_AST_NODE_TYPE_MAP_LOCAL_DEFINITION:
232 		return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_MAP);
233 		break;
234 
235 	case MD_AST_NODE_TYPE_NONINDEXED_LOCAL_ASSIGNMENT:
236 		return alloc_nonindexed_local_variable_assignment(pcst, pnode, type_inferencing, context_flags);
237 		break;
238 
239 	case MD_AST_NODE_TYPE_INDEXED_LOCAL_ASSIGNMENT:
240 		return alloc_indexed_local_variable_assignment(pcst, pnode, type_inferencing, context_flags);
241 		break;
242 
243 	case MD_AST_NODE_TYPE_SREC_ASSIGNMENT:
244 		if (context_flags & IN_BEGIN_OR_END) {
245 			fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
246 				MLR_GLOBALS.bargv0);
247 			exit(1);
248 		}
249 		if (context_flags & IN_FUNC_DEF) {
250 			fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
251 				MLR_GLOBALS.bargv0);
252 			exit(1);
253 		}
254 		return alloc_srec_assignment(pcst, pnode, type_inferencing, context_flags);
255 		break;
256 
257 	case MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT:
258 		if (context_flags & IN_BEGIN_OR_END) {
259 			fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
260 				MLR_GLOBALS.bargv0);
261 			exit(1);
262 		}
263 		if (context_flags & IN_FUNC_DEF) {
264 			fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
265 				MLR_GLOBALS.bargv0);
266 			exit(1);
267 		}
268 		return alloc_indirect_srec_assignment(pcst, pnode, type_inferencing, context_flags);
269 		break;
270 
271 	case MD_AST_NODE_TYPE_POSITIONAL_SREC_NAME_ASSIGNMENT:
272 		if (context_flags & IN_BEGIN_OR_END) {
273 			fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
274 				MLR_GLOBALS.bargv0);
275 			exit(1);
276 		}
277 		if (context_flags & IN_FUNC_DEF) {
278 			fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
279 				MLR_GLOBALS.bargv0);
280 			exit(1);
281 		}
282 		return alloc_positional_srec_name_assignment(pcst, pnode, type_inferencing, context_flags);
283 		break;
284 
285 	case MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT:
286 		return alloc_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
287 		break;
288 
289 	case MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
290 		if (context_flags & IN_BEGIN_OR_END) {
291 			fprintf(stderr, "%s: assignments from $-variables are not valid within begin or end blocks.\n",
292 				MLR_GLOBALS.bargv0);
293 			exit(1);
294 		}
295 		return alloc_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
296 		break;
297 
298 	case MD_AST_NODE_TYPE_FULL_OOSVAR_ASSIGNMENT:
299 		return alloc_full_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
300 		break;
301 
302 	case MD_AST_NODE_TYPE_FULL_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
303 		if (context_flags & IN_BEGIN_OR_END) {
304 			fprintf(stderr, "%s: assignments from $-variables are not valid within begin or end blocks.\n",
305 				MLR_GLOBALS.bargv0);
306 			exit(1);
307 		}
308 		return alloc_full_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
309 		break;
310 
311 	case MD_AST_NODE_TYPE_FULL_SREC_ASSIGNMENT:
312 		if (context_flags & IN_BEGIN_OR_END) {
313 			fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
314 				MLR_GLOBALS.bargv0);
315 			exit(1);
316 		}
317 		if (context_flags & IN_FUNC_DEF) {
318 			fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
319 				MLR_GLOBALS.bargv0);
320 			exit(1);
321 		}
322 		return alloc_full_srec_assignment(pcst, pnode, type_inferencing, context_flags);
323 		break;
324 
325 	case MD_AST_NODE_TYPE_ENV_ASSIGNMENT:
326 		return alloc_env_assignment(pcst, pnode, type_inferencing, context_flags);
327 		break;
328 
329 	case MD_AST_NODE_TYPE_UNSET:
330 		return alloc_unset(pcst, pnode, type_inferencing, context_flags);
331 		break;
332 
333 	case MD_AST_NODE_TYPE_TEE:
334 		if (context_flags & IN_FUNC_DEF) {
335 			fprintf(stderr, "%s: tee statements are not valid within func blocks.\n",
336 				MLR_GLOBALS.bargv0);
337 			exit(1);
338 		}
339 		return alloc_tee(pcst, pnode, type_inferencing, context_flags);
340 		break;
341 
342 	case MD_AST_NODE_TYPE_EMITF:
343 		if (context_flags & IN_FUNC_DEF) {
344 			fprintf(stderr, "%s: emitf statements are not valid within func blocks.\n",
345 				MLR_GLOBALS.bargv0);
346 			exit(1);
347 		}
348 		return alloc_emitf(pcst, pnode, type_inferencing, context_flags);
349 		break;
350 	case MD_AST_NODE_TYPE_EMITP:
351 		if (context_flags & IN_FUNC_DEF) {
352 			fprintf(stderr, "%s: emitp statements are not valid within func blocks.\n",
353 				MLR_GLOBALS.bargv0);
354 			exit(1);
355 		}
356 		return alloc_emit(pcst, pnode, type_inferencing, context_flags, TRUE);
357 		break;
358 	case MD_AST_NODE_TYPE_EMIT:
359 		if (context_flags & IN_FUNC_DEF) {
360 			fprintf(stderr, "%s: emit statements are not valid within func blocks.\n",
361 				MLR_GLOBALS.bargv0);
362 			exit(1);
363 		}
364 		return alloc_emit(pcst, pnode, type_inferencing, context_flags, FALSE);
365 		break;
366 
367 	case MD_AST_NODE_TYPE_EMITP_LASHED:
368 		if (context_flags & IN_FUNC_DEF) {
369 			fprintf(stderr, "%s: emitp statements are not valid within func blocks.\n",
370 				MLR_GLOBALS.bargv0);
371 			exit(1);
372 		}
373 		return alloc_emit_lashed(pcst, pnode, type_inferencing, context_flags, TRUE);
374 		break;
375 	case MD_AST_NODE_TYPE_EMIT_LASHED:
376 		if (context_flags & IN_FUNC_DEF) {
377 			fprintf(stderr, "%s: emit statements are not valid within func blocks.\n",
378 				MLR_GLOBALS.bargv0);
379 			exit(1);
380 		}
381 		return alloc_emit_lashed(pcst, pnode, type_inferencing, context_flags, FALSE);
382 		break;
383 
384 	case MD_AST_NODE_TYPE_FILTER:
385 		if (context_flags & IN_FUNC_DEF) {
386 			fprintf(stderr, "%s: filter statements are not valid within func blocks.\n",
387 				MLR_GLOBALS.bargv0);
388 			exit(1);
389 		}
390 		if (context_flags & IN_MLR_FILTER) {
391 			fprintf(stderr, "%s filter: expressions must not also contain the \"filter\" keyword.\n",
392 				MLR_GLOBALS.bargv0);
393 			exit(1);
394 		}
395 		return alloc_filter(pcst, pnode, type_inferencing, context_flags);
396 		break;
397 
398 	case MD_AST_NODE_TYPE_DUMP:
399 		return alloc_dump(pcst, pnode, type_inferencing, context_flags);
400 		break;
401 
402 	case MD_AST_NODE_TYPE_PRINT:
403 		return alloc_print(pcst, pnode, type_inferencing, context_flags, "\n");
404 		break;
405 
406 	case MD_AST_NODE_TYPE_PRINTN:
407 		return alloc_print(pcst, pnode, type_inferencing, context_flags, "");
408 		break;
409 
410 	default:
411 		return alloc_bare_boolean(pcst, pnode, type_inferencing, context_flags);
412 		break;
413 	}
414 }
415 
416 // ----------------------------------------------------------------
417 // mlr put and mlr filter are almost entirely the same code. The key difference is that the final
418 // statement for the latter must be a bare boolean expression.
419 
mlr_dsl_cst_alloc_final_filter_statement(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int negate_final_filter,int type_inferencing,int context_flags)420 mlr_dsl_cst_statement_t* mlr_dsl_cst_alloc_final_filter_statement(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
421 	int negate_final_filter, int type_inferencing, int context_flags)
422 {
423 	switch(pnode->type) {
424 
425 	case MD_AST_NODE_TYPE_FILTER:
426 		fprintf(stderr, "%s filter: expressions must not also contain the \"filter\" keyword.\n",
427 			MLR_GLOBALS.bargv0);
428 		exit(1);
429 		break;
430 
431 	case MD_AST_NODE_TYPE_FUNC_DEF:
432 	case MD_AST_NODE_TYPE_SUBR_DEF:
433 	case MD_AST_NODE_TYPE_BEGIN:
434 	case MD_AST_NODE_TYPE_END:
435 	case MD_AST_NODE_TYPE_RETURN_VALUE:
436 	case MD_AST_NODE_TYPE_RETURN_VOID:
437 	case MD_AST_NODE_TYPE_SUBR_CALLSITE:
438 	case MD_AST_NODE_TYPE_CONDITIONAL_BLOCK:
439 	case MD_AST_NODE_TYPE_IF_HEAD:
440 	case MD_AST_NODE_TYPE_WHILE:
441 	case MD_AST_NODE_TYPE_DO_WHILE:
442 	case MD_AST_NODE_TYPE_FOR_SREC:
443 	case MD_AST_NODE_TYPE_FOR_SREC_KEY_ONLY:
444 	case MD_AST_NODE_TYPE_FOR_OOSVAR:
445 	case MD_AST_NODE_TYPE_TRIPLE_FOR:
446 	case MD_AST_NODE_TYPE_BREAK:
447 	case MD_AST_NODE_TYPE_CONTINUE:
448 	case MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION:
449 	case MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION:
450 	case MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION:
451 	case MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION:
452 	case MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION:
453 	case MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION:
454 	case MD_AST_NODE_TYPE_NONINDEXED_LOCAL_ASSIGNMENT:
455 	case MD_AST_NODE_TYPE_SREC_ASSIGNMENT:
456 	case MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT:
457 	case MD_AST_NODE_TYPE_POSITIONAL_SREC_NAME_ASSIGNMENT:
458 	case MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT:
459 	case MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
460 	case MD_AST_NODE_TYPE_FULL_OOSVAR_ASSIGNMENT:
461 	case MD_AST_NODE_TYPE_FULL_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
462 	case MD_AST_NODE_TYPE_FULL_SREC_ASSIGNMENT:
463 	case MD_AST_NODE_TYPE_UNSET:
464 	case MD_AST_NODE_TYPE_TEE:
465 	case MD_AST_NODE_TYPE_EMITF:
466 	case MD_AST_NODE_TYPE_EMITP:
467 	case MD_AST_NODE_TYPE_EMIT:
468 	case MD_AST_NODE_TYPE_EMITP_LASHED:
469 	case MD_AST_NODE_TYPE_EMIT_LASHED:
470 	case MD_AST_NODE_TYPE_DUMP:
471 	case MD_AST_NODE_TYPE_PRINT:
472 	case MD_AST_NODE_TYPE_PRINTN:
473 		fprintf(stderr, "%s: filter expressions must end in a final boolean statement.\n", MLR_GLOBALS.bargv0);
474 		exit(1);
475 		break;
476 
477 	default:
478 		return alloc_final_filter(pcst, pnode, negate_final_filter, type_inferencing, context_flags);
479 		break;
480 	}
481 }
482 
483 // ----------------------------------------------------------------
484 // For used by constructors of subclasses of mlr_dsl_cst_statement_t.
485 
mlr_dsl_cst_statement_valloc(mlr_dsl_ast_node_t * past_node,mlr_dsl_cst_statement_handler_t * pstatement_handler,mlr_dsl_cst_statement_freer_t * pstatement_freer,void * pvstate)486 mlr_dsl_cst_statement_t* mlr_dsl_cst_statement_valloc(
487 	mlr_dsl_ast_node_t*              past_node,
488 	mlr_dsl_cst_statement_handler_t* pstatement_handler,
489 	mlr_dsl_cst_statement_freer_t*   pstatement_freer,
490 	void*                            pvstate)
491 {
492 	mlr_dsl_cst_statement_t* pstatement = mlr_malloc_or_die(sizeof(mlr_dsl_cst_statement_t));
493 	pstatement->past_node           = past_node;
494 	pstatement->pstatement_handler  = pstatement_handler;
495 	pstatement->pblock              = NULL;
496 	pstatement->pblock_handler      = NULL;
497 	pstatement->pstatement_freer    = pstatement_freer;
498 	pstatement->pvstate             = pvstate;
499 	return pstatement;
500 }
501 
mlr_dsl_cst_statement_valloc_with_block(mlr_dsl_ast_node_t * past_node,mlr_dsl_cst_statement_handler_t * pstatement_handler,cst_statement_block_t * pblock,mlr_dsl_cst_block_handler_t * pblock_handler,mlr_dsl_cst_statement_freer_t * pstatement_freer,void * pvstate)502 mlr_dsl_cst_statement_t* mlr_dsl_cst_statement_valloc_with_block(
503 	mlr_dsl_ast_node_t*              past_node,
504 	mlr_dsl_cst_statement_handler_t* pstatement_handler,
505 	cst_statement_block_t*           pblock,
506 	mlr_dsl_cst_block_handler_t*     pblock_handler,
507 	mlr_dsl_cst_statement_freer_t*   pstatement_freer,
508 	void*                            pvstate)
509 {
510 	mlr_dsl_cst_statement_t* pstatement = mlr_malloc_or_die(sizeof(mlr_dsl_cst_statement_t));
511 	pstatement->past_node           = past_node;
512 	pstatement->pstatement_handler  = pstatement_handler;
513 	pstatement->pblock              = pblock;
514 	pstatement->pblock_handler      = pblock_handler;
515 	pstatement->pstatement_freer    = pstatement_freer;
516 	pstatement->pvstate             = pvstate;
517 	return pstatement;
518 }
519 
520 // ----------------------------------------------------------------
mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t * pstatement,context_t * pctx)521 void mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t* pstatement, context_t* pctx) {
522 
523 	if (pstatement->pstatement_freer != NULL) {
524 		pstatement->pstatement_freer(pstatement, pctx);
525 	}
526 
527 	cst_statement_block_free(pstatement->pblock, pctx);
528 
529 	free(pstatement);
530 }
531 
532 // ================================================================
533 // Top-level entry point for statement-handling, e.g. from mapper_put.
534 
mlr_dsl_cst_handle_top_level_statement_blocks(sllv_t * ptop_level_blocks,variables_t * pvars,cst_outputs_t * pcst_outputs)535 void mlr_dsl_cst_handle_top_level_statement_blocks(
536 	sllv_t*      ptop_level_blocks, // block bodies for begins, main, ends
537 	variables_t* pvars,
538 	cst_outputs_t* pcst_outputs)
539 {
540 	for (sllve_t* pe = ptop_level_blocks->phead; pe != NULL; pe = pe->pnext) {
541 		mlr_dsl_cst_handle_top_level_statement_block(pe->pvvalue, pvars, pcst_outputs);
542 	}
543 }
544 
mlr_dsl_cst_handle_top_level_statement_block(cst_top_level_statement_block_t * ptop_level_block,variables_t * pvars,cst_outputs_t * pcst_outputs)545 void mlr_dsl_cst_handle_top_level_statement_block(
546 	cst_top_level_statement_block_t* ptop_level_block,
547 	variables_t* pvars,
548 	cst_outputs_t* pcst_outputs)
549 {
550 	local_stack_push(pvars->plocal_stack, local_stack_frame_enter(ptop_level_block->pframe));
551 	local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack);
552 	local_stack_subframe_enter(pframe, ptop_level_block->pblock->subframe_var_count);
553 
554 	mlr_dsl_cst_handle_statement_block(ptop_level_block->pblock, pvars, pcst_outputs);
555 
556 	local_stack_subframe_exit(pframe, ptop_level_block->pblock->subframe_var_count);
557 	local_stack_frame_exit(local_stack_pop(pvars->plocal_stack));
558 }
559 
560 // ================================================================
561 // HANDLERS
562 // ================================================================
563 // This is for statement lists not recursively contained within a loop body -- including the
564 // main/begin/end statements.  Since there is no containing loop body, there is no need to check
565 // for break or continue flags after each statement.
mlr_dsl_cst_handle_statement_block(cst_statement_block_t * pblock,variables_t * pvars,cst_outputs_t * pcst_outputs)566 void mlr_dsl_cst_handle_statement_block(
567 	cst_statement_block_t* pblock,
568 	variables_t*           pvars,
569 	cst_outputs_t*         pcst_outputs)
570 {
571 	if (pvars->trace_execution) {
572 		for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
573 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
574 			fprintf(stdout, "TRACE ");
575 			mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
576 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
577 			// The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
578 			if (pvars->return_state.returned) {
579 				break;
580 			}
581 		}
582 	} else {
583 		for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
584 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
585 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
586 			// The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
587 			if (pvars->return_state.returned) {
588 				break;
589 			}
590 		}
591 	}
592 }
593 
594 // This is for statement lists recursively contained within a loop body.
595 // It checks for break or continue flags after each statement.
mlr_dsl_cst_handle_statement_block_with_break_continue(cst_statement_block_t * pblock,variables_t * pvars,cst_outputs_t * pcst_outputs)596 void mlr_dsl_cst_handle_statement_block_with_break_continue(
597 	cst_statement_block_t* pblock,
598 	variables_t*   pvars,
599 	cst_outputs_t* pcst_outputs)
600 {
601 	if (pvars->trace_execution) {
602 		for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
603 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
604 			fprintf(stdout, "TRACE ");
605 			mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
606 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
607 			if (loop_stack_get(pvars->ploop_stack) != 0) {
608 				break;
609 			}
610 			// The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
611 			if (pvars->return_state.returned) {
612 				break;
613 			}
614 		}
615 	} else {
616 		for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
617 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
618 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
619 			if (loop_stack_get(pvars->ploop_stack) != 0) {
620 				break;
621 			}
622 			// The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
623 			if (pvars->return_state.returned) {
624 				break;
625 			}
626 		}
627 	}
628 }
629 
630 // Triple-for start/continuation/update statement lists
mlr_dsl_cst_handle_statement_list(sllv_t * pstatements,variables_t * pvars,cst_outputs_t * pcst_outputs)631 void mlr_dsl_cst_handle_statement_list(
632 	sllv_t*        pstatements,
633 	variables_t*   pvars,
634 	cst_outputs_t* pcst_outputs)
635 {
636 	if (pvars->trace_execution) {
637 		for (sllve_t* pe = pstatements->phead; pe != NULL; pe = pe->pnext) {
638 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
639 			fprintf(stdout, "TRACE ");
640 			mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
641 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
642 		}
643 	} else {
644 		for (sllve_t* pe = pstatements->phead; pe != NULL; pe = pe->pnext) {
645 			mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
646 			pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
647 		}
648 	}
649 }
650