diff --git a/c/containers/mlr_dsl_ast.c b/c/containers/mlr_dsl_ast.c index e15c2bb08..2e8f8244f 100644 --- a/c/containers/mlr_dsl_ast.c +++ b/c/containers/mlr_dsl_ast.c @@ -119,6 +119,25 @@ mlr_dsl_ast_node_t* mlr_dsl_ast_node_set_function_name( return pa; } +// ---------------------------------------------------------------- +int mlr_dsl_ast_node_cannot_be_bare_boolean(mlr_dsl_ast_node_t* pnode) { + switch (pnode->type) { + case MD_AST_NODE_TYPE_BOOLEAN_LITERAL: + case MD_AST_NODE_TYPE_FIELD_NAME: + case MD_AST_NODE_TYPE_INDIRECT_FIELD_NAME: + case MD_AST_NODE_TYPE_OOSVAR_KEYLIST: + case MD_AST_NODE_TYPE_NON_SIGIL_NAME: + case MD_AST_NODE_TYPE_OPERATOR: + case MD_AST_NODE_TYPE_ENV: + case MD_AST_NODE_TYPE_BOUND_VARIABLE: + return FALSE; + break; + default: + return TRUE; + break; + } +} + // ---------------------------------------------------------------- void mlr_dsl_ast_print(mlr_dsl_ast_t* past) { printf("AST ROOT:\n"); diff --git a/c/containers/mlr_dsl_ast.h b/c/containers/mlr_dsl_ast.h index 6312a14d4..52e758ea1 100644 --- a/c/containers/mlr_dsl_ast.h +++ b/c/containers/mlr_dsl_ast.h @@ -114,6 +114,8 @@ mlr_dsl_ast_node_t* mlr_dsl_ast_node_prepend_arg(mlr_dsl_ast_node_t* pa, mlr_dsl mlr_dsl_ast_node_t* mlr_dsl_ast_node_append_arg(mlr_dsl_ast_node_t* pa, mlr_dsl_ast_node_t* pb); mlr_dsl_ast_node_t* mlr_dsl_ast_node_set_function_name(mlr_dsl_ast_node_t* pa, char* name); +int mlr_dsl_ast_node_cannot_be_bare_boolean(mlr_dsl_ast_node_t* pnode); + void mlr_dsl_ast_print(mlr_dsl_ast_t* past); void mlr_dsl_ast_node_print(mlr_dsl_ast_node_t* pnode); void mlr_dsl_ast_node_fprint(mlr_dsl_ast_node_t* pnode, FILE* o); diff --git a/c/dsls/mlr_dsl_parse.y b/c/dsls/mlr_dsl_parse.y index 4902d8f50..fe1532522 100644 --- a/c/dsls/mlr_dsl_parse.y +++ b/c/dsls/mlr_dsl_parse.y @@ -429,7 +429,7 @@ md_triple_for(A) ::= MD_TOKEN_FOR(F) MD_TOKEN_LPAREN md_triple_for_start(S) MD_TOKEN_SEMICOLON - md_rhs(C) + md_triple_for_continuation(C) MD_TOKEN_SEMICOLON md_triple_for_update(U) MD_TOKEN_RPAREN @@ -440,24 +440,6 @@ md_triple_for(A) ::= A = mlr_dsl_ast_node_alloc_quaternary(F->text, MD_AST_NODE_TYPE_TRIPLE_FOR, S, C, U, L); } -md_triple_for(A) ::= - MD_TOKEN_FOR(F) MD_TOKEN_LPAREN - md_triple_for_start(S) - MD_TOKEN_SEMICOLON - MD_TOKEN_SEMICOLON - md_triple_for_update(U) - MD_TOKEN_RPAREN - MD_TOKEN_LBRACE - md_statement_list(L) - MD_TOKEN_RBRACE. -{ - A = mlr_dsl_ast_node_alloc_quaternary(F->text, MD_AST_NODE_TYPE_TRIPLE_FOR, - S, - mlr_dsl_ast_node_alloc("true", MD_AST_NODE_TYPE_BOOLEAN_LITERAL), - U, - L); -} - md_triple_for_start(A) ::= md_statement_not_braced_end(B). { if (B->type == MD_AST_NODE_TYPE_NOP) { A = mlr_dsl_ast_node_alloc_zary("triple_for_start_statements", MD_AST_NODE_TYPE_STATEMENT_LIST); @@ -473,6 +455,21 @@ md_triple_for_start(A) ::= md_triple_for_start(B) MD_TOKEN_COMMA md_statement_no } } +md_triple_for_continuation(A) ::= md_statement_not_braced_end(B). { + if (B->type == MD_AST_NODE_TYPE_NOP) { + A = mlr_dsl_ast_node_alloc_zary("triple_for_continuation_statements", MD_AST_NODE_TYPE_STATEMENT_LIST); + } else { + A = mlr_dsl_ast_node_alloc_unary("triple_for_continuation_statements", MD_AST_NODE_TYPE_STATEMENT_LIST, B); + } +} +md_triple_for_continuation(A) ::= md_triple_for_continuation(B) MD_TOKEN_COMMA md_statement_not_braced_end(C). { + if (B->type == MD_AST_NODE_TYPE_NOP) { + A = C; + } else { + A = mlr_dsl_ast_node_append_arg(B, C); + } +} + md_triple_for_update(A) ::= md_statement_not_braced_end(B). { if (B->type == MD_AST_NODE_TYPE_NOP) { A = mlr_dsl_ast_node_alloc_zary("triple_for_update_statements", MD_AST_NODE_TYPE_STATEMENT_LIST); diff --git a/c/mapping/context_flags.h b/c/mapping/context_flags.h index 7a3b48166..ff79ee9dd 100644 --- a/c/mapping/context_flags.h +++ b/c/mapping/context_flags.h @@ -5,11 +5,12 @@ // 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. -#define IN_BREAKABLE 0x00000200 // break/continue are only OK (recursively) inside for/while/do-while -#define IN_BEGIN_OR_END 0x00000400 // $stuff is not OK (recursively) inside begin/end -#define IN_FUNC_DEF 0x00000800 // local only valid in func/subr; no srec assignments in functions -#define IN_SUBR_DEF 0x00001000 // local only valid in func/subr -#define IN_MLR_FILTER 0x00002000 // Anywhere within mlr filter, the 'filter' keyword is invalid -#define IN_MLR_FINAL_FILTER 0x00004000 // mlr filter's final statement must be a bare boolean +#define IN_BREAKABLE 0x00000200 // break/continue are only OK (recursively) inside for/while/do-while +#define IN_BEGIN_OR_END 0x00000400 // $stuff is not OK (recursively) inside begin/end +#define IN_FUNC_DEF 0x00000800 // local only valid in func/subr; no srec assignments in functions +#define IN_SUBR_DEF 0x00001000 // local only valid in func/subr +#define IN_MLR_FILTER 0x00002000 // Anywhere within mlr filter, the 'filter' keyword is invalid +#define IN_MLR_FINAL_FILTER 0x00004000 // mlr filter's final statement must be a bare boolean +#define IN_TRIPLE_FOR_CONTINUE 0x00004000 // Final statement of triple-for continuation statements must be a bare boolean #endif // CONTEXT_FLAGS_H diff --git a/c/mapping/mlr_dsl_cst.c b/c/mapping/mlr_dsl_cst.c index 502c49a37..aa65520b7 100644 --- a/c/mapping/mlr_dsl_cst.c +++ b/c/mapping/mlr_dsl_cst.c @@ -1385,7 +1385,7 @@ static mlr_dsl_cst_statement_t* alloc_triple_for(mlr_dsl_cst_t* pcst, mlr_dsl_as mlr_dsl_cst_statement_t* pstatement = alloc_blank(); mlr_dsl_ast_node_t* pstart_statements_node = pnode->pchildren->phead->pvvalue; - mlr_dsl_ast_node_t* pcontinuation_statement_node = pnode->pchildren->phead->pnext->pvvalue; + mlr_dsl_ast_node_t* pcontinuation_statements_node = pnode->pchildren->phead->pnext->pvvalue; mlr_dsl_ast_node_t* pupdate_statements_node = pnode->pchildren->phead->pnext->pnext->pvvalue; mlr_dsl_ast_node_t* pbody_statements_node = pnode->pchildren->phead->pnext->pnext->pnext->pvvalue; @@ -1396,9 +1396,28 @@ static mlr_dsl_cst_statement_t* alloc_triple_for(mlr_dsl_cst_t* pcst, mlr_dsl_as type_inferencing, context_flags & ~IN_BREAKABLE)); } - // xxx assert length 1 - pstatement->ptriple_for_continuation_evaluator = rval_evaluator_alloc_from_ast(pcontinuation_statement_node, - pcst->pfmgr, type_inferencing, context_flags & ~IN_BREAKABLE); + // Continuation statements are split into the final boolean, and the statements before (if any). + pstatement->ptriple_for_pre_continuation_statements = sllv_alloc(); + // Empty continuation for triple-for is an implicit TRUE. + if (pcontinuation_statements_node->pchildren->length == 0) { + pstatement->ptriple_for_continuation_evaluator = rval_evaluator_alloc_from_boolean(TRUE); + } else { + for (sllve_t* pe = pcontinuation_statements_node->pchildren->phead; pe != NULL && pe->pnext != NULL; pe = pe->pnext) { + mlr_dsl_ast_node_t* pbody_ast_node = pe->pvvalue; + sllv_append(pstatement->ptriple_for_pre_continuation_statements, + mlr_dsl_cst_alloc_statement(pcst, pbody_ast_node, + type_inferencing, context_flags & ~IN_BREAKABLE)); + } + mlr_dsl_ast_node_t* pfinal_continuation_statement_node = pcontinuation_statements_node->pchildren->ptail->pvvalue; + if (mlr_dsl_ast_node_cannot_be_bare_boolean(pfinal_continuation_statement_node)) { + fprintf(stderr, + "%s: the final triple-for continutation statement must be a bare boolean.\n", + MLR_GLOBALS.bargv0); + exit(1); + } + pstatement->ptriple_for_continuation_evaluator = rval_evaluator_alloc_from_ast(pfinal_continuation_statement_node, + pcst->pfmgr, type_inferencing, (context_flags & ~IN_BREAKABLE) | IN_TRIPLE_FOR_CONTINUE); + } pstatement->ptriple_for_update_statements = sllv_alloc(); for (sllve_t* pe = pupdate_statements_node->pchildren->phead; pe != NULL; pe = pe->pnext) { diff --git a/c/mapping/rval_expr_evaluators.c b/c/mapping/rval_expr_evaluators.c index 9dabbbcf9..55df1fcd5 100644 --- a/c/mapping/rval_expr_evaluators.c +++ b/c/mapping/rval_expr_evaluators.c @@ -58,16 +58,9 @@ rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* pnode, fmgr_ break; default: - if (context_flags & IN_MLR_FINAL_FILTER) { - fprintf(stderr, - "%s: expressions for mlr filter must be single statements, evaluating to boolean.\n", - MLR_GLOBALS.bargv0); - exit(1); - } else { - fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", - MLR_GLOBALS.bargv0, __FILE__, __LINE__); - exit(1); - } + fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", + MLR_GLOBALS.bargv0, __FILE__, __LINE__); + exit(1); break; } @@ -94,6 +87,9 @@ rval_evaluator_t* rval_evaluator_alloc_from_ast(mlr_dsl_ast_node_t* pnode, fmgr_ if ((pnode->type != MD_AST_NODE_TYPE_NON_SIGIL_NAME) && (pnode->type != MD_AST_NODE_TYPE_OPERATOR)) { fprintf(stderr, "%s: internal coding error detected in file %s at line %d (node type %s).\n", MLR_GLOBALS.bargv0, __FILE__, __LINE__, mlr_dsl_ast_node_describe_type(pnode->type)); + printf("XXX\n"); + mlr_dsl_ast_node_print(pnode); + printf("XXX\n"); exit(1); }