From e0bf2bf54e39c74e415ee33880735faddcf0ddf1 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Tue, 24 May 2016 18:07:52 -0400 Subject: [PATCH] scope-validation iterate --- c/dsls/mlr_dsl_parse.y | 2 +- c/mapping/mapper_filter.c | 3 +- c/mapping/mlr_dsl_cst.c | 141 +++++++++++++++++++---------- c/mapping/rval_evaluators.h | 11 ++- c/mapping/rval_expr_evaluators.c | 84 ++++++++++++----- c/todo.txt | 2 + c/unit_test/test_rval_evaluators.c | 2 +- 7 files changed, 165 insertions(+), 80 deletions(-) diff --git a/c/dsls/mlr_dsl_parse.y b/c/dsls/mlr_dsl_parse.y index 1ca2d5b13..ee6a6d179 100644 --- a/c/dsls/mlr_dsl_parse.y +++ b/c/dsls/mlr_dsl_parse.y @@ -134,7 +134,7 @@ md_unbraced_statement(A) ::= MD_TOKEN_BREAK(O). { A = mlr_dsl_ast_node_alloc(O->text, MD_AST_NODE_TYPE_BREAK); } md_unbraced_statement(A) ::= MD_TOKEN_CONTINUE(O). { - A = mlr_dsl_ast_node_alloc(O->text, MD_AST_NODE_TYPE_BREAK); + A = mlr_dsl_ast_node_alloc(O->text, MD_AST_NODE_TYPE_CONTINUE); } // ================================================================ diff --git a/c/mapping/mapper_filter.c b/c/mapping/mapper_filter.c index 73a1f8dd5..990d40756 100644 --- a/c/mapping/mapper_filter.c +++ b/c/mapping/mapper_filter.c @@ -133,13 +133,14 @@ static mapper_t* mapper_filter_alloc(ap_state_t* pargp, char* mlr_dsl_expression mlr_dsl_ast_node_t* past, int type_inferencing, int do_exclude) { mapper_filter_state_t* pstate = mlr_malloc_or_die(sizeof(mapper_filter_state_t)); + int context_flags = 0; // xxx pstate->pargp = pargp; // Retain the string contents along with any in-pointers from the AST/CST pstate->mlr_dsl_expression = mlr_dsl_expression; pstate->comment_stripped_mlr_dsl_expression = comment_stripped_mlr_dsl_expression; pstate->past = past; - pstate->pevaluator = rval_evaluator_alloc_from_ast(past, type_inferencing); + pstate->pevaluator = rval_evaluator_alloc_from_ast(past, type_inferencing, context_flags); pstate->poosvars = mlhmmv_alloc(); pstate->do_exclude = do_exclude; diff --git a/c/mapping/mlr_dsl_cst.c b/c/mapping/mlr_dsl_cst.c index 129a7bb8f..77a053af6 100644 --- a/c/mapping/mlr_dsl_cst.c +++ b/c/mapping/mlr_dsl_cst.c @@ -1,14 +1,7 @@ #include "lib/mlr_globals.h" #include "lib/mlrutil.h" #include "mlr_dsl_cst.h" - -// The grammar permits certain statements which are syntactically invalid, (a) because it's awkward to handle -// there, and (b) because we get far better control over error messages here (vs. 'syntax error'). -// The following flags are used as the CST is built from the AST for CST-build-time validation. -// xxx move to header file for use by rval expr evaluators -#define IN_BINDABLE 0x0100 // boundvars are only OK inside a bindable, e.g. (recursively) inside a for-loop -#define IN_BREAKABLE 0x0200 // break/continue are only OK (recursively) inside for/while/do-while -#define IN_BEGIN_OR_END 0x0400 // $stuff is not OK (recursively) inside begin/end +#include "context_flags.h" static mlr_dsl_ast_node_t* get_list_for_block(mlr_dsl_ast_node_t* pnode); @@ -31,6 +24,8 @@ static mlr_dsl_cst_statement_t* alloc_while(mlr_dsl_a static mlr_dsl_cst_statement_t* alloc_do_while(mlr_dsl_ast_node_t* past, int ti, int cf); static mlr_dsl_cst_statement_t* alloc_for_srec(mlr_dsl_ast_node_t* past, int ti, int cf); static mlr_dsl_cst_statement_t* alloc_for_oosvar(mlr_dsl_ast_node_t* past, int ti, int cf); +static mlr_dsl_cst_statement_t* alloc_break(mlr_dsl_ast_node_t* past, int ti, int cf); +static mlr_dsl_cst_statement_t* alloc_continue(mlr_dsl_ast_node_t* past, int ti, int cf); static mlr_dsl_cst_statement_t* alloc_conditional_block(mlr_dsl_ast_node_t* past, int ti, int cf); static mlr_dsl_cst_statement_t* alloc_if_head(mlr_dsl_ast_node_t* past, int ti, int cf); static mlr_dsl_cst_statement_t* alloc_filter(mlr_dsl_ast_node_t* past, int ti, int cf); @@ -73,6 +68,8 @@ static void handle_do_while(mlr_dsl_cst_statement_t* s, static void handle_do_while(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); static void handle_for_srec(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); static void handle_for_oosvar(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); +static void handle_break(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); +static void handle_continue(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); static void handle_if_head(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); static void handle_bare_boolean(mlr_dsl_cst_statement_t* s, variables_t* v, cst_outputs_t* o); @@ -267,6 +264,7 @@ static mlr_dsl_cst_statement_t* alloc_cst_statement(mlr_dsl_ast_node_t* pnode, i switch(pnode->type) { // xxx invalidates based on context flags + // xxx comment we only invalidate LHS here (and RHS for full-srec stuff). the rest in rval_expr_evaluators. // IN_BINDABLE // IN_BREAKABLE // IN_BEGIN_OR_END @@ -294,14 +292,20 @@ static mlr_dsl_cst_statement_t* alloc_cst_statement(mlr_dsl_ast_node_t* pnode, i break; case MD_AST_NODE_TYPE_BREAK: - // xxx not OK unless IN_BREAKABLE - printf("break alloc stub!\n"); - return NULL; + if (!(context_flags & IN_BREAKABLE)) { + fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n", + MLR_GLOBALS.argv0); + exit(1); + } + return alloc_break(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_CONTINUE: - printf("continue alloc stub!\n"); - // xxx not OK unless IN_BREAKABLE - return NULL; + if (!(context_flags & IN_BREAKABLE)) { + fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n", + MLR_GLOBALS.argv0); + exit(1); + } + return alloc_continue(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_CONDITIONAL_BLOCK: @@ -312,26 +316,42 @@ static mlr_dsl_cst_statement_t* alloc_cst_statement(mlr_dsl_ast_node_t* pnode, i break; case MD_AST_NODE_TYPE_SREC_ASSIGNMENT: - // xxx not OK IN_BEGIN_OR_END + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } return alloc_srec_assignment(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT: - // xxx not OK IN_BEGIN_OR_END + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } return alloc_indirect_srec_assignment(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT: return alloc_oosvar_assignment(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT: - // xxx not OK IN_BEGIN_OR_END + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: assignments from $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } return alloc_oosvar_from_full_srec_assignment(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_FULL_SREC_FROM_OOSVAR_ASSIGNMENT: - // xxx not OK IN_BEGIN_OR_END + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } return alloc_full_srec_from_oosvar_assignment(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_UNSET: - // xxx not OK to unset srec IN_BEGIN_OR_END + // xxx not OK to unset srec IN_BEGIN_OR_END. pass this through. return alloc_unset(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_EMITF: @@ -344,14 +364,14 @@ static mlr_dsl_cst_statement_t* alloc_cst_statement(mlr_dsl_ast_node_t* pnode, i return alloc_emit_or_emitp(pnode, type_inferencing, FALSE, context_flags); break; case MD_AST_NODE_TYPE_FILTER: - // xxx not OK to test on srec IN_BEGIN_OR_END + // xxx not OK to test on srec IN_BEGIN_OR_END. pass this through. return alloc_filter(pnode, type_inferencing, context_flags); break; case MD_AST_NODE_TYPE_DUMP: return alloc_dump(pnode, type_inferencing, context_flags); break; default: - // xxx not OK to test on srec IN_BEGIN_OR_END + // xxx not OK to test on srec IN_BEGIN_OR_END. pass this through. return alloc_bare_boolean(pnode, type_inferencing, context_flags); break; } @@ -406,7 +426,7 @@ static mlr_dsl_cst_statement_t* alloc_srec_assignment(mlr_dsl_ast_node_t* past, pstatement->phandler = handle_srec_assignment; pstatement->srec_lhs_field_name = pleft->text; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing, context_flags); return pstatement; } @@ -432,8 +452,8 @@ static mlr_dsl_cst_statement_t* alloc_indirect_srec_assignment(mlr_dsl_ast_node_ mlr_dsl_ast_node_t* pright = past->pchildren->phead->pnext->pvvalue; pstatement->phandler = handle_indirect_srec_assignment; - pstatement->psrec_lhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing); - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing); + pstatement->psrec_lhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing, context_flags); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing, context_flags); return pstatement; } @@ -465,7 +485,7 @@ static mlr_dsl_cst_statement_t* alloc_oosvar_assignment(mlr_dsl_ast_node_t* past } pstatement->poosvar_lhs_keylist_evaluators = poosvar_lhs_keylist_evaluators; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing, context_flags); return pstatement; } @@ -549,7 +569,7 @@ static mlr_dsl_cst_statement_t* alloc_unset(mlr_dsl_ast_node_t* past, int type_i } else if (pnode->type == MD_AST_NODE_TYPE_INDIRECT_FIELD_NAME) { sllv_append(pstatement->pvarargs, mlr_dsl_cst_statement_vararg_alloc( NULL, - rval_evaluator_alloc_from_ast(pnode->pchildren->phead->pvvalue, type_inferencing), + rval_evaluator_alloc_from_ast(pnode->pchildren->phead->pvvalue, type_inferencing, context_flags), NULL, NULL)); @@ -609,7 +629,7 @@ static mlr_dsl_cst_statement_t* alloc_emitf(mlr_dsl_ast_node_t* pnode, int type_ sllv_append(pstatement->pvarargs, mlr_dsl_cst_statement_vararg_alloc( pchild->text, NULL, - rval_evaluator_alloc_from_ast(pwalker, type_inferencing), + rval_evaluator_alloc_from_ast(pwalker, type_inferencing, context_flags), NULL)); } @@ -652,7 +672,7 @@ static mlr_dsl_cst_statement_t* alloc_emit_or_emitp(mlr_dsl_ast_node_t* pnode, i for (sllve_t* pe = pnode->pchildren->phead->pnext; pe != NULL; pe = pe->pnext) { mlr_dsl_ast_node_t* pkeynode = pe->pvvalue; sllv_append(pemit_oosvar_namelist_evaluators, - rval_evaluator_alloc_from_ast(pkeynode, type_inferencing)); + rval_evaluator_alloc_from_ast(pkeynode, type_inferencing, context_flags)); } pstatement->phandler = do_full_prefixing @@ -666,7 +686,7 @@ static mlr_dsl_cst_statement_t* alloc_emit_or_emitp(mlr_dsl_ast_node_t* pnode, i for (sllve_t* pe = pnode->pchildren->phead->pnext; pe != NULL; pe = pe->pnext) { mlr_dsl_ast_node_t* pkeynode = pe->pvvalue; sllv_append(pemit_oosvar_namelist_evaluators, - rval_evaluator_alloc_from_ast(pkeynode, type_inferencing)); + rval_evaluator_alloc_from_ast(pkeynode, type_inferencing, context_flags)); } pstatement->phandler = do_full_prefixing @@ -703,7 +723,7 @@ static mlr_dsl_cst_statement_t* alloc_while(mlr_dsl_ast_node_t* past, int type_i } pstatement->phandler = handle_while; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing, context_flags); pstatement->pblock_statements = pblock_statements; return pstatement; } @@ -726,7 +746,7 @@ static mlr_dsl_cst_statement_t* alloc_do_while(mlr_dsl_ast_node_t* past, int typ } pstatement->phandler = handle_do_while; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pright, type_inferencing, context_flags); pstatement->pblock_statements = pblock_statements; return pstatement; } @@ -827,17 +847,7 @@ static mlr_dsl_cst_statement_t* alloc_for_oosvar(mlr_dsl_ast_node_t* past, int t sllv_t* pblock_statements = sllv_alloc(); for (sllve_t* pe = pright->pchildren->phead; pe != NULL; pe = pe->pnext) { mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; - // xxx also elsewhere, invalidate. cmt there this is done at the CST - // rather than AST-parse level since we can give better error messages - // (and, a simpler Lemon grammar). - if (pbody_ast_node->type == MD_AST_NODE_TYPE_CONTINUE) { - printf("continue alloc stub!\n"); - } else if (pbody_ast_node->type == MD_AST_NODE_TYPE_BREAK) { - printf("break alloc stub!\n"); - } else { - // xxx stub 3rd arg - sllv_append(pblock_statements, alloc_cst_statement(pbody_ast_node, type_inferencing, context_flags)); - } + sllv_append(pblock_statements, alloc_cst_statement(pbody_ast_node, type_inferencing, context_flags)); } pstatement->pblock_statements = pblock_statements; pstatement->pbound_variables = lhmsmv_alloc(); @@ -847,6 +857,23 @@ static mlr_dsl_cst_statement_t* alloc_for_oosvar(mlr_dsl_ast_node_t* past, int t return pstatement; } +static mlr_dsl_cst_statement_t* alloc_break(mlr_dsl_ast_node_t* past, int type_inferencing, + int context_flags) +{ + mlr_dsl_cst_statement_t* pstatement = alloc_blank(); + pstatement->phandler = handle_break; + return pstatement; +} + +static mlr_dsl_cst_statement_t* alloc_continue(mlr_dsl_ast_node_t* past, int type_inferencing, + int context_flags) +{ + mlr_dsl_cst_statement_t* pstatement = alloc_blank(); + pstatement->phandler = handle_continue; + return pstatement; +} + +// ---------------------------------------------------------------- static mlr_dsl_cst_statement_t* alloc_conditional_block(mlr_dsl_ast_node_t* pnode, int type_inferencing, int context_flags) { @@ -865,7 +892,7 @@ static mlr_dsl_cst_statement_t* alloc_conditional_block(mlr_dsl_ast_node_t* pnod } pstatement->phandler = handle_conditional_block; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pleft, type_inferencing, context_flags); pstatement->pblock_statements = pblock_statements; return pstatement; } @@ -966,7 +993,7 @@ static mlr_dsl_cst_statement_t* alloc_if_item(mlr_dsl_ast_node_t* pexprnode, pstatement->phandler = NULL; // handled by the containing if-head evaluator pstatement->prhs_evaluator = pexprnode != NULL - ? rval_evaluator_alloc_from_ast(pexprnode, type_inferencing) // if-statement or elif-statement + ? rval_evaluator_alloc_from_ast(pexprnode, type_inferencing, context_flags) // if-statement or elif-statement : rval_evaluator_alloc_from_boolean(TRUE); // else-statement pstatement->pblock_statements = pblock_statements; return pstatement; @@ -981,7 +1008,7 @@ static mlr_dsl_cst_statement_t* alloc_filter(mlr_dsl_ast_node_t* past, int type_ mlr_dsl_ast_node_t* pnode = past->pchildren->phead->pvvalue; pstatement->phandler = handle_filter; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pnode, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(pnode, type_inferencing, context_flags); return pstatement; } @@ -1000,7 +1027,7 @@ static mlr_dsl_cst_statement_t* alloc_bare_boolean(mlr_dsl_ast_node_t* past, int mlr_dsl_cst_statement_t* pstatement = alloc_blank(); pstatement->phandler = handle_bare_boolean; - pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(past, type_inferencing); + pstatement->prhs_evaluator = rval_evaluator_alloc_from_ast(past, type_inferencing, context_flags); return pstatement; } @@ -1575,7 +1602,7 @@ static void handle_for_srec( mlr_dsl_cst_handle(pnode->pblock_statements, pvars, pcst_outputs); } - // xxx break/continue-handling (needs to be in rval evaluators w/ stack of brk/ctu flags @ context + // xxx break/continue-handling (needs to be in rval evaluators w/ stack of brk/ctu flags @ context) lrec_free(pcopy); bind_stack_pop(pvars->pbind_stack); } @@ -1649,6 +1676,24 @@ static void handle_for_oosvar_aux( } } +// ---------------------------------------------------------------- +static void handle_break( + mlr_dsl_cst_statement_t* pnode, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + // xxx stub +} + +// ---------------------------------------------------------------- +static void handle_continue( + mlr_dsl_cst_statement_t* pnode, + variables_t* pvars, + cst_outputs_t* pcst_outputs) +{ + // xxx stub +} + // ---------------------------------------------------------------- static void handle_if_head( mlr_dsl_cst_statement_t* pnode, @@ -1737,7 +1782,7 @@ static sllv_t* allocate_keylist_evaluators_from_oosvar_node(mlr_dsl_ast_node_t* if (pkeynode->type == MD_AST_NODE_TYPE_STRING_LITERAL) { sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_string(pkeynode->text)); } else { - sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_ast(pkeynode, type_inferencing)); + sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_ast(pkeynode, type_inferencing, context_flags)); } } return pkeylist_evaluators; diff --git a/c/mapping/rval_evaluators.h b/c/mapping/rval_evaluators.h index a44d0aa21..677680517 100644 --- a/c/mapping/rval_evaluators.h +++ b/c/mapping/rval_evaluators.h @@ -61,12 +61,14 @@ extern function_lookup_t FUNCTION_LOOKUP_TABLE[]; // rval_expr_evaluators.c // Topmost function: -rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* past, int type_inferencing); +rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* past, int type_inferencing, int context_flags); // Next level: rval_evaluator_t* rval_evaluator_alloc_from_field_name(char* field_name, int type_inferencing); -rval_evaluator_t* rval_evaluator_alloc_from_indirect_field_name(mlr_dsl_ast_node_t* pnode, int type_inferencing); -rval_evaluator_t* rval_evaluator_alloc_from_oosvar_keylist(mlr_dsl_ast_node_t* pnode, int type_inferencing); +rval_evaluator_t* rval_evaluator_alloc_from_indirect_field_name(mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags); +rval_evaluator_t* rval_evaluator_alloc_from_oosvar_keylist(mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags); // This is used for evaluating strings and numbers in literal expressions, e.g. '$x = "abc"' // or '$x = "left_\1". The values are subject to replacement with regex captures. See comments @@ -82,7 +84,8 @@ rval_evaluator_t* rval_evaluator_alloc_from_string(char* string); rval_evaluator_t* rval_evaluator_alloc_from_boolean_literal(char* string); rval_evaluator_t* rval_evaluator_alloc_from_boolean(int boolval); -rval_evaluator_t* rval_evaluator_alloc_from_environment(mlr_dsl_ast_node_t* pnode, int type_inferencing); +rval_evaluator_t* rval_evaluator_alloc_from_environment(mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags); rval_evaluator_t* rval_evaluator_alloc_from_NF(); rval_evaluator_t* rval_evaluator_alloc_from_NR(); rval_evaluator_t* rval_evaluator_alloc_from_FNR(); diff --git a/c/mapping/rval_expr_evaluators.c b/c/mapping/rval_expr_evaluators.c index 4b1d930ff..dc18d91cd 100644 --- a/c/mapping/rval_expr_evaluators.c +++ b/c/mapping/rval_expr_evaluators.c @@ -8,24 +8,40 @@ #include "lib/mtrand.h" #include "mapping/mapper.h" #include "mapping/rval_evaluators.h" +#include "mapping/context_flags.h" // ================================================================ // See comments in rval_evaluators.h // ================================================================ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* pnode, - int type_inferencing, function_lookup_t* fcn_lookup_table); + int type_inferencing, int context_flags, function_lookup_t* fcn_lookup_table); // ================================================================ -rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* pnode, int type_inferencing) { - return rval_evaluator_alloc_from_ast_aux(pnode, type_inferencing, FUNCTION_LOOKUP_TABLE); +// The grammar permits certain statements which are syntactically invalid, (a) because it's awkward to handle +// there, and (b) because we get far better control over error messages here (vs. 'syntax error'). +// The context flags are used as the CST is built from the AST, for CST-build-time validation. + +rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* pnode, int type_inferencing, int context_flags) { + return rval_evaluator_alloc_from_ast_aux(pnode, type_inferencing, context_flags, FUNCTION_LOOKUP_TABLE); } static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* pnode, - int type_inferencing, function_lookup_t* fcn_lookup_table) + int type_inferencing, int context_flags, function_lookup_t* fcn_lookup_table) { + +// IN_BINDABLE +// IN_BREAKABLE +// IN_BEGIN_OR_END + if (pnode->pchildren == NULL) { // leaf node if (pnode->type == MD_AST_NODE_TYPE_FIELD_NAME) { + // xxx functionize + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } return rval_evaluator_alloc_from_field_name(pnode->text, type_inferencing); } else if (pnode->type == MD_AST_NODE_TYPE_STRNUM_LITERAL) { return rval_evaluator_alloc_from_strnum_literal(pnode->text, type_inferencing); @@ -36,6 +52,11 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p } else if (pnode->type == MD_AST_NODE_TYPE_CONTEXT_VARIABLE) { return rval_evaluator_alloc_from_context_variable(pnode->text); } else if (pnode->type == MD_AST_NODE_TYPE_BOUND_VARIABLE) { + if (!(context_flags & IN_BINDABLE)) { + fprintf(stderr, "%s: statements involving bound variables are not valid outside for-loops.\n", + MLR_GLOBALS.argv0); + exit(1); + } return rval_evaluator_alloc_from_bound_variable(pnode->text); } else { fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", @@ -44,13 +65,19 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p } } else if (pnode->type == MD_AST_NODE_TYPE_INDIRECT_FIELD_NAME) { - return rval_evaluator_alloc_from_indirect_field_name(pnode->pchildren->phead->pvvalue, type_inferencing); + if ((context_flags & IN_BEGIN_OR_END)) { + fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n", + MLR_GLOBALS.argv0); + exit(1); + } + return rval_evaluator_alloc_from_indirect_field_name(pnode->pchildren->phead->pvvalue, + type_inferencing, context_flags); } else if (pnode->type == MD_AST_NODE_TYPE_OOSVAR_KEYLIST) { - return rval_evaluator_alloc_from_oosvar_keylist(pnode, type_inferencing); + return rval_evaluator_alloc_from_oosvar_keylist(pnode, type_inferencing, context_flags); } else if (pnode->type == MD_AST_NODE_TYPE_ENV) { - return rval_evaluator_alloc_from_environment(pnode, type_inferencing); + return rval_evaluator_alloc_from_environment(pnode, type_inferencing, context_flags); } else { // operator/function if ((pnode->type != MD_AST_NODE_TYPE_NON_SIGIL_NAME) @@ -70,7 +97,8 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p pevaluator = rval_evaluator_alloc_from_zary_func_name(func_name); } else if (user_provided_arity == 1) { mlr_dsl_ast_node_t* parg1_node = pnode->pchildren->phead->pvvalue; - rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, fcn_lookup_table); + rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_unary_func_name(func_name, parg1); } else if (user_provided_arity == 2) { mlr_dsl_ast_node_t* parg1_node = pnode->pchildren->phead->pvvalue; @@ -79,12 +107,12 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p if ((streq(func_name, "=~") || streq(func_name, "!=~")) && type2 == MD_AST_NODE_TYPE_STRNUM_LITERAL) { rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_binary_regex_arg2_func_name(func_name, parg1, parg2_node->text, FALSE); } else if ((streq(func_name, "=~") || streq(func_name, "!=~")) && type2 == MD_AST_NODE_TYPE_REGEXI) { rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_binary_regex_arg2_func_name(func_name, parg1, parg2_node->text, TYPE_INFER_STRING_FLOAT_INT); } else { @@ -92,9 +120,9 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p // the regexes will be compiled record-by-record rather than once at alloc time, which will // be slower. rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); rval_evaluator_t* parg2 = rval_evaluator_alloc_from_ast_aux(parg2_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_binary_func_name(func_name, parg1, parg2); } @@ -107,18 +135,18 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p if ((streq(func_name, "sub") || streq(func_name, "gsub")) && type2 == MD_AST_NODE_TYPE_STRNUM_LITERAL) { // sub/gsub-regex special case: rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); rval_evaluator_t* parg3 = rval_evaluator_alloc_from_ast_aux(parg3_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_ternary_regex_arg2_func_name(func_name, parg1, parg2_node->text, FALSE, parg3); } else if ((streq(func_name, "sub") || streq(func_name, "gsub")) && type2 == MD_AST_NODE_TYPE_REGEXI) { // sub/gsub-regex special case: rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); rval_evaluator_t* parg3 = rval_evaluator_alloc_from_ast_aux(parg3_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_ternary_regex_arg2_func_name(func_name, parg1, parg2_node->text, TYPE_INFER_STRING_FLOAT_INT, parg3); @@ -127,11 +155,11 @@ static rval_evaluator_t* rval_evaluator_alloc_from_ast_aux(mlr_dsl_ast_node_t* p // the regexes will be compiled record-by-record rather than once at alloc time, which will // be slower. rval_evaluator_t* parg1 = rval_evaluator_alloc_from_ast_aux(parg1_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); rval_evaluator_t* parg2 = rval_evaluator_alloc_from_ast_aux(parg2_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); rval_evaluator_t* parg3 = rval_evaluator_alloc_from_ast_aux(parg3_node, type_inferencing, - fcn_lookup_table); + context_flags, fcn_lookup_table); pevaluator = rval_evaluator_alloc_from_ternary_func_name(func_name, parg1, parg2, parg3); } } else { @@ -397,11 +425,13 @@ static void rval_evaluator_indirect_field_name_free(rval_evaluator_t* pevaluator free(pevaluator); } -rval_evaluator_t* rval_evaluator_alloc_from_indirect_field_name(mlr_dsl_ast_node_t* pnamenode, int type_inferencing) { +rval_evaluator_t* rval_evaluator_alloc_from_indirect_field_name(mlr_dsl_ast_node_t* pnamenode, + int type_inferencing, int context_flags) +{ rval_evaluator_indirect_field_name_state_t* pstate = mlr_malloc_or_die( sizeof(rval_evaluator_indirect_field_name_state_t)); - pstate->pname_evaluator = rval_evaluator_alloc_from_ast(pnamenode, type_inferencing); + pstate->pname_evaluator = rval_evaluator_alloc_from_ast(pnamenode, type_inferencing, context_flags); rval_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(rval_evaluator_t)); pevaluator->pvstate = pstate; @@ -481,7 +511,9 @@ static void rval_evaluator_oosvar_keylist_free(rval_evaluator_t* pevaluator) { // oosvar_keylist (oosvar_keylist): // 5 (string_literal). -rval_evaluator_t* rval_evaluator_alloc_from_oosvar_keylist(mlr_dsl_ast_node_t* pnode, int type_inferencing) { +rval_evaluator_t* rval_evaluator_alloc_from_oosvar_keylist(mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ rval_evaluator_oosvar_keylist_state_t* pstate = mlr_malloc_or_die( sizeof(rval_evaluator_oosvar_keylist_state_t)); @@ -492,7 +524,7 @@ rval_evaluator_t* rval_evaluator_alloc_from_oosvar_keylist(mlr_dsl_ast_node_t* p if (pkeynode->type == MD_AST_NODE_TYPE_STRING_LITERAL) { sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_string(pkeynode->text)); } else { - sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_ast(pkeynode, type_inferencing)); + sllv_append(pkeylist_evaluators, rval_evaluator_alloc_from_ast(pkeynode, type_inferencing, context_flags)); } } pstate->poosvar_rhs_keylist_evaluators = pkeylist_evaluators; @@ -725,13 +757,15 @@ static void rval_evaluator_environment_free(rval_evaluator_t* pevaluator) { free(pevaluator); } -rval_evaluator_t* rval_evaluator_alloc_from_environment(mlr_dsl_ast_node_t* pnode, int type_inferencing) { +rval_evaluator_t* rval_evaluator_alloc_from_environment(mlr_dsl_ast_node_t* pnode, + int type_inferencing, int context_flags) +{ rval_evaluator_environment_state_t* pstate = mlr_malloc_or_die(sizeof(rval_evaluator_environment_state_t)); rval_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(rval_evaluator_t)); mlr_dsl_ast_node_t* pnamenode = pnode->pchildren->phead->pnext->pvvalue; - pstate->pname_evaluator = rval_evaluator_alloc_from_ast(pnamenode, type_inferencing); + pstate->pname_evaluator = rval_evaluator_alloc_from_ast(pnamenode, type_inferencing, context_flags); pevaluator->pprocess_func = rval_evaluator_environment_func; pevaluator->pfree_func = rval_evaluator_environment_free; diff --git a/c/todo.txt b/c/todo.txt index f6b37036a..1fb4b5f98 100644 --- a/c/todo.txt +++ b/c/todo.txt @@ -10,6 +10,8 @@ TOP-OF-LIST SUMMARY -> find a more elegant way to do this but don't block 4.1.0 ! CST-build-time invalidations: + ! propagate-back to caller + ! filter is oosless - $stuff inside begin/end - break/continue outside for/while/do-while - boundvars outside for diff --git a/c/unit_test/test_rval_evaluators.c b/c/unit_test/test_rval_evaluators.c index a55e1ed3d..140816dc6 100644 --- a/c/unit_test/test_rval_evaluators.c +++ b/c/unit_test/test_rval_evaluators.c @@ -144,7 +144,7 @@ static char * test_numbers() { mlr_dsl_ast_node_t* p2logxnode = mlr_dsl_ast_node_alloc_binary("*", MD_AST_NODE_TYPE_OPERATOR, p2node, plogxnode); - rval_evaluator_t* pastr = rval_evaluator_alloc_from_ast(p2logxnode, TYPE_INFER_STRING_FLOAT_INT); + rval_evaluator_t* pastr = rval_evaluator_alloc_from_ast(p2logxnode, TYPE_INFER_STRING_FLOAT_INT, 0); lrec_t* prec = lrec_unbacked_alloc(); lhmsv_t* ptyped_overlay = lhmsv_alloc();