diff --git a/src/apfl.h b/src/apfl.h index f6f1468..9cb449d 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -155,6 +155,7 @@ enum apfl_error_type { APFL_ERR_UNEXPECTED_EXPRESSION, APFL_ERR_INVALID_ASSIGNMENT_LHS, APFL_ERR_EMPTY_ASSIGNMENT, + APFL_ERR_ONLY_ONE_EXPAND_ALLOWED, }; const char *apfl_error_type_name(enum apfl_error_type); @@ -252,12 +253,11 @@ enum apfl_expr_param_type { APFL_EXPR_PARAM_VAR, APFL_EXPR_PARAM_CONSTANT, APFL_EXPR_PARAM_PREDICATE, - APFL_EXPR_PARAM_EXPAND, APFL_EXPR_PARAM_LIST, }; struct apfl_expr_params { - struct apfl_expr_param *params; + struct apfl_expr_params_item *params; size_t len; }; @@ -268,11 +268,15 @@ struct apfl_expr_param { struct apfl_string var; struct apfl_expr_const constant; struct apfl_expr_param_predicate predicate; - struct apfl_expr_param *expand; struct apfl_expr_params list; }; }; +struct apfl_expr_params_item { + bool expand; + struct apfl_expr_param param; +}; + struct apfl_expr_subfunc { struct apfl_expr_params params; struct apfl_expr_body body; @@ -287,7 +291,6 @@ enum apfl_expr_assignable_type { APFL_EXPR_ASSIGNABLE_VAR, APFL_EXPR_ASSIGNABLE_CONSTANT, APFL_EXPR_ASSIGNABLE_PREDICATE, - APFL_EXPR_ASSIGNABLE_EXPAND, APFL_EXPR_ASSIGNABLE_DOT, APFL_EXPR_ASSIGNABLE_AT, APFL_EXPR_ASSIGNABLE_LIST, @@ -306,7 +309,7 @@ struct apfl_expr_assignable_at { struct apfl_expr *rhs; }; struct apfl_expr_assignable_list { - struct apfl_expr_assignable *children; + struct apfl_expr_assignable_list_item *items; size_t len; }; @@ -317,13 +320,17 @@ struct apfl_expr_assignable { struct apfl_string var; struct apfl_expr_const constant; struct apfl_expr_assignable_predicate predicate; - struct apfl_expr_assignable *expand; struct apfl_expr_assignable_dot dot; struct apfl_expr_assignable_at at; struct apfl_expr_assignable_list list; }; }; +struct apfl_expr_assignable_list_item { + struct apfl_expr_assignable assignable; + bool expand; +}; + struct apfl_expr_assignment { bool local; struct apfl_expr_assignable lhs; @@ -376,12 +383,14 @@ void apfl_expr_const_deinit(struct apfl_expr_const *); void apfl_expr_param_predicate_deinit(struct apfl_expr_param_predicate *); void apfl_expr_param_list_deinit(struct apfl_expr_param_list *); void apfl_expr_params_deinit(struct apfl_expr_params *); +void apfl_expr_params_item_deinit(struct apfl_expr_params_item *); void apfl_expr_param_deinit(struct apfl_expr_param *); void apfl_expr_subfunc_deinit(struct apfl_expr_subfunc *); void apfl_expr_complex_func_deinit(struct apfl_expr_complex_func *); void apfl_expr_assignable_predicate_deinit(struct apfl_expr_assignable_predicate *); void apfl_expr_assignable_dot_deinit(struct apfl_expr_assignable_dot *); void apfl_expr_assignable_at_deinit(struct apfl_expr_assignable_at *); +void apfl_expr_assignable_list_item_deinit(struct apfl_expr_assignable_list_item *); void apfl_expr_assignable_list_deinit(struct apfl_expr_assignable_list *); void apfl_expr_assignable_deinit(struct apfl_expr_assignable *); void apfl_expr_assignment_deinit(struct apfl_expr_assignment *); diff --git a/src/error.c b/src/error.c index c288f7d..0c92c37 100644 --- a/src/error.c +++ b/src/error.c @@ -44,6 +44,8 @@ apfl_error_type_name(enum apfl_error_type type) return "APFL_ERR_INVALID_ASSIGNMENT_LHS"; case APFL_ERR_EMPTY_ASSIGNMENT: return "APFL_ERR_EMPTY_ASSIGNMENT"; + case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED: + return "APFL_ERR_ONLY_ONE_EXPAND_ALLOWED"; } return ""; @@ -136,6 +138,12 @@ apfl_error_print(struct apfl_error error, FILE *file) POSARGS ); return; + case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED: + fprintf( + file, + "Only one expansion (~) is allowed per level, near " POSFMT "\n", + POSARGS + ); } fprintf(file, "Unknown error %d\n", (int)error.type); diff --git a/src/expr.c b/src/expr.c index 240bf47..b0799a9 100644 --- a/src/expr.c +++ b/src/expr.c @@ -118,7 +118,13 @@ apfl_expr_param_list_deinit(struct apfl_expr_param_list *list) void apfl_expr_params_deinit(struct apfl_expr_params *params) { - DEINIT_LIST(params->params, params->len, apfl_expr_param_deinit); + DEINIT_LIST(params->params, params->len, apfl_expr_params_item_deinit); +} + +void +apfl_expr_params_item_deinit(struct apfl_expr_params_item *item) +{ + apfl_expr_param_deinit(&item->param); } void @@ -134,9 +140,6 @@ apfl_expr_param_deinit(struct apfl_expr_param *param) case APFL_EXPR_PARAM_PREDICATE: apfl_expr_param_predicate_deinit(¶m->predicate); break; - case APFL_EXPR_PARAM_EXPAND: - DESTROY(param->expand, apfl_expr_param_deinit); - break; case APFL_EXPR_PARAM_LIST: apfl_expr_params_deinit(¶m->list); break; @@ -180,10 +183,16 @@ apfl_expr_assignable_at_deinit(struct apfl_expr_assignable_at *at) DEINIT_GENERIC_LHS_RHS_EXPR(at, apfl_expr_assignable_deinit); } +void +apfl_expr_assignable_list_item_deinit(struct apfl_expr_assignable_list_item *item) +{ + apfl_expr_assignable_deinit(&item->assignable); +} + void apfl_expr_assignable_list_deinit(struct apfl_expr_assignable_list *list) { - DEINIT_LIST(list->children, list->len, apfl_expr_assignable_deinit); + DEINIT_LIST(list->items, list->len, apfl_expr_assignable_list_item_deinit); } void @@ -199,9 +208,6 @@ apfl_expr_assignable_deinit(struct apfl_expr_assignable *a) case APFL_EXPR_ASSIGNABLE_PREDICATE: apfl_expr_assignable_predicate_deinit(&a->predicate); break; - case APFL_EXPR_ASSIGNABLE_EXPAND: - DESTROY(a->expand, apfl_expr_assignable_deinit); - break; case APFL_EXPR_ASSIGNABLE_DOT: apfl_expr_assignable_dot_deinit(&a->dot); break; @@ -395,9 +401,6 @@ apfl_expr_param_move(struct apfl_expr_param *in) case APFL_EXPR_PARAM_PREDICATE: out.predicate = apfl_expr_param_predicate_move(&in->predicate); break; - case APFL_EXPR_PARAM_EXPAND: - MOVEPTR(out.expand, in->expand); - break; case APFL_EXPR_PARAM_LIST: out.list = apfl_expr_params_move(&in->list); break; @@ -456,7 +459,7 @@ struct apfl_expr_assignable_list apfl_expr_assignable_list_move(struct apfl_expr_assignable_list *in) { struct apfl_expr_assignable_list out; - MOVE_LIST(out, in, children, len); + MOVE_LIST(out, in, items, len); return out; } @@ -474,9 +477,6 @@ apfl_expr_assignable_move(struct apfl_expr_assignable *in) case APFL_EXPR_ASSIGNABLE_PREDICATE: out.predicate = apfl_expr_assignable_predicate_move(&in->predicate); break; - case APFL_EXPR_ASSIGNABLE_EXPAND: - MOVEPTR(out.expand, in->expand); - break; case APFL_EXPR_ASSIGNABLE_DOT: out.dot = apfl_expr_assignable_dot_move(&in->dot); break; @@ -579,6 +579,18 @@ print_constant(struct apfl_expr_const constant, unsigned indent, FILE *f) } } +static void print_param(struct apfl_expr_param *, unsigned, FILE *); + +static void +print_params_item(struct apfl_expr_params_item *item, unsigned indent, FILE *f) +{ + if (item->expand) { + apfl_print_indented(indent, f, "Expand\n"); + indent++; + } + print_param(&item->param, indent, f); +} + static void print_param(struct apfl_expr_param *param, unsigned indent, FILE *f) { @@ -596,14 +608,10 @@ print_param(struct apfl_expr_param *param, unsigned indent, FILE *f) apfl_print_indented(indent+1, f, "RHS\n"); print_expr(param->predicate.rhs, indent+2, f); break; - case APFL_EXPR_PARAM_EXPAND: - apfl_print_indented(indent, f, "Expand\n"); - print_param(param->expand, indent+1, f); - break; case APFL_EXPR_PARAM_LIST: apfl_print_indented(indent, f, "List\n"); for (size_t i = 0; i < param->list.len; i++) { - print_param(¶m->list.params[i], indent+1, f); + print_params_item(¶m->list.params[i], indent+1, f); } break; } @@ -626,10 +634,6 @@ print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE * apfl_print_indented(indent+1, f, "RHS\n"); print_expr(assignable.predicate.rhs, indent+2, f); break; - case APFL_EXPR_ASSIGNABLE_EXPAND: - apfl_print_indented(indent, f, "Expand\n"); - print_assignable(*assignable.expand, indent+1, f); - break; case APFL_EXPR_ASSIGNABLE_DOT: apfl_print_indented(indent, f, "Dot (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(assignable.dot.rhs)); print_assignable(*assignable.dot.lhs, indent+1, f); @@ -644,7 +648,13 @@ print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE * case APFL_EXPR_ASSIGNABLE_LIST: apfl_print_indented(indent, f, "List\n"); for (size_t i = 0; i < assignable.list.len; i++) { - print_assignable(assignable.list.children[i], indent+1, f); + struct apfl_expr_assignable_list_item *item = &assignable.list.items[i]; + unsigned indent_item = indent+1; + if (item->expand) { + apfl_print_indented(indent_item, f, "Expand\n"); + indent_item++; + } + print_assignable(item->assignable, indent_item, f); } break; } @@ -686,7 +696,7 @@ print_expr(struct apfl_expr *expr, unsigned indent, FILE *f) struct apfl_expr_subfunc *sub = &expr->complex_func.subfuncs[i]; apfl_print_indented(indent+2, f, "Parameters\n"); for (size_t j = 0; j < sub->params.len; j++) { - print_param(&sub->params.params[j], indent+3, f); + print_params_item(&sub->params.params[j], indent+3, f); } apfl_print_indented(indent+2, f, "Body\n"); print_body(&sub->body, indent+3, f); @@ -769,7 +779,10 @@ params_eq(struct apfl_expr_params a, struct apfl_expr_params b) return false; } for (size_t i = 0; i < a.len; i++) { - if (!param_eq(a.params[i], b.params[i])) { + if ( + a.params[i].expand != b.params[i].expand + || !param_eq(a.params[i].param, b.params[i].param) + ) { return false; } } @@ -813,8 +826,6 @@ param_eq(struct apfl_expr_param a, struct apfl_expr_param b) case APFL_EXPR_PARAM_PREDICATE: return param_eq(*a.predicate.lhs, *b.predicate.lhs) && apfl_expr_eq(*a.predicate.rhs, *b.predicate.rhs); - case APFL_EXPR_PARAM_EXPAND: - return param_eq(*a.expand, *b.expand); case APFL_EXPR_PARAM_LIST: return params_eq(a.list, b.list); } @@ -838,8 +849,6 @@ assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b) case APFL_EXPR_ASSIGNABLE_PREDICATE: return assignable_eq(*a.predicate.lhs, *b.predicate.lhs) && apfl_expr_eq(*a.predicate.rhs, *b.predicate.rhs); - case APFL_EXPR_ASSIGNABLE_EXPAND: - return assignable_eq(*a.expand, *b.expand); case APFL_EXPR_ASSIGNABLE_DOT: return assignable_eq(*a.dot.lhs, *b.dot.lhs) && apfl_string_eq(a.dot.rhs, b.dot.rhs); @@ -851,7 +860,10 @@ assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b) return false; } for (size_t i = 0; i < a.list.len; i++) { - if (!assignable_eq(a.list.children[i], b.list.children[i])) { + if ( + a.list.items[i].expand != b.list.items[i].expand + || !assignable_eq(a.list.items[i].assignable, b.list.items[i].assignable) + ) { return false; } } diff --git a/src/parser.c b/src/parser.c index 9f95199..c77d1b7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -972,7 +972,18 @@ parse_stringify(apfl_parser_ptr p, struct fragment *fragment, struct apfl_positi return true; } -static bool fragment_to_param_recursive(apfl_parser_ptr, struct fragment *, struct apfl_expr_param *); +static struct fragment +fragment_unwrap_expand(struct fragment fragment) +{ + assert(fragment.type == FRAG_EXPAND); + struct fragment tmp = fragment_move(fragment.expand); + free(fragment.expand); + fragment.expand = NULL; + fragment_deinit(&fragment); + return tmp; +} + +static bool fragment_to_param(apfl_parser_ptr, struct fragment, struct apfl_expr_param *); static bool fragments_to_params(apfl_parser_ptr, struct fragment_list, struct apfl_expr_params *); @@ -990,7 +1001,7 @@ predicate_fragment_to_param( goto error; } - if (!fragment_to_param_recursive(p, lhs_rhs->lhs, out->predicate.lhs)) { + if (!fragment_to_param(p, fragment_move(lhs_rhs->lhs), out->predicate.lhs)) { free(out->predicate.lhs); out->predicate.lhs = NULL; goto error; @@ -1009,7 +1020,7 @@ error: } static bool -fragment_to_param_recursive( +fragment_to_param_inner( apfl_parser_ptr p, struct fragment *fragment, struct apfl_expr_param *out @@ -1051,23 +1062,71 @@ fragment_to_param_recursive( static bool fragment_to_param( apfl_parser_ptr p, - struct fragment *fragment, - struct apfl_expr_param *out, - bool *seen_expand + struct fragment fragment, + struct apfl_expr_param *out ) { - if (fragment->type == FRAG_EXPAND && !*seen_expand) { - *seen_expand = true; // This prevents a param list with more than one ~ + bool ok = fragment_to_param_inner(p, &fragment, out); + fragment_deinit(&fragment); + return ok; +} - out->type = APFL_EXPR_PARAM_EXPAND; - if ((out->expand = malloc(sizeof(struct apfl_expr_param))) == NULL) { - p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); - return false; - } - - return fragment_to_param_recursive(p, fragment->expand, out->expand); +static bool +fragments_to_params_inner( + apfl_parser_ptr p, + /*borrowed*/ struct fragment_list fragments, + struct apfl_expr_params *out +) { + if (fragments.len == 0) { + out->len = 0; + out->params = NULL; + return true; } - return fragment_to_param_recursive(p, fragment, out); + out->params = ALLOC_LIST(struct apfl_expr_params_item, fragments.len); + out->len = 0; + if (out->params == NULL) { + goto error; + } + + bool seen_expand = false; + for (size_t i = 0; i < fragments.len; i++) { + struct apfl_expr_params_item *out_item = &out->params[i]; + struct fragment item_fragment = fragment_move(&fragments.children[i]); + + if (item_fragment.type == FRAG_EXPAND) { + if (seen_expand) { + p->error = (struct apfl_error) { + .type = APFL_ERR_ONLY_ONE_EXPAND_ALLOWED, + .position = item_fragment.position, + }; + fragment_deinit(&item_fragment); + goto error; + } + + out_item->expand = true; + seen_expand = true; + + item_fragment = fragment_unwrap_expand(item_fragment); + } else { + out_item->expand = false; + } + + if (!fragment_to_param( + p, + fragment_move(&item_fragment), + &out_item->param + )) { + goto error; + } + + out->len++; + } + + return true; + +error: + apfl_expr_params_deinit(out); + return false; } static bool @@ -1076,48 +1135,14 @@ fragments_to_params( struct fragment_list fragments, struct apfl_expr_params *out ) { - bool result = true; - - if (fragments.len == 0) { - out->len = 0; - out->params = NULL; - goto ok; - } - - out->params = ALLOC_LIST(struct apfl_expr_param, fragments.len); - out->len = 0; - if (out->params == NULL) { - goto error; - } - - bool seen_expand = false; - for (size_t i = 0; i < fragments.len; i++) { - if (!fragment_to_param( - p, - &fragments.children[i], - &out->params[i], - &seen_expand - )) { - goto error; - } - - out->len++; - } - - goto ok; - -error: - result = false; - apfl_expr_params_deinit(out); -ok: + bool ok = fragments_to_params_inner(p, fragments, out); fragment_list_deinit(&fragments); - return result; + return ok; } static bool fragment_to_assignable( apfl_parser_ptr p, - bool expand_ok, struct fragment fragment, struct apfl_expr_assignable *out ); @@ -1125,36 +1150,13 @@ fragment_to_assignable( static bool fragment_to_assignable_inner( apfl_parser_ptr p, - bool expand_ok, struct fragment *fragment, struct apfl_expr_assignable *out ) { switch (fragment->type) { case FRAG_EXPAND: - if (!expand_ok) { - p->error = (struct apfl_error) { - .type = APFL_ERR_INVALID_ASSIGNMENT_LHS, - .position = fragment->position, - }; - goto error; - } - - out->type = APFL_EXPR_ASSIGNABLE_EXPAND; - if ((out->expand = malloc(sizeof(struct apfl_expr_assignable))) == NULL) { - p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); - goto error; - } - - if (!fragment_to_assignable( - p, - false, - fragment_move(fragment->expand), - out->expand - )) { - goto error; - } - - return true; + p->error = err_unexpected_token(APFL_TOK_EXPAND, fragment->position); + goto error; case FRAG_CONSTANT: out->type = APFL_EXPR_ASSIGNABLE_CONSTANT; out->constant = apfl_expr_const_move(&fragment->constant); @@ -1175,7 +1177,6 @@ fragment_to_assignable_inner( if (!fragment_to_assignable( p, - expand_ok, fragment_move(fragment->dot.lhs), out->dot.lhs )) { @@ -1196,7 +1197,6 @@ fragment_to_assignable_inner( if (!fragment_to_assignable( p, - expand_ok, fragment_move(fragment->at.lhs), out->at.lhs )) { @@ -1227,7 +1227,6 @@ fragment_to_assignable_inner( if (!fragment_to_assignable( p, - expand_ok, fragment_move(fragment->at.lhs), out->predicate.lhs )) { @@ -1254,23 +1253,39 @@ fragment_to_assignable_inner( case FRAG_LIST: out->type = APFL_EXPR_ASSIGNABLE_LIST; out->list.len = 0; - out->list.children = malloc(sizeof(struct apfl_expr_assignable) * fragment->list.len); + out->list.items = ALLOC_LIST(struct apfl_expr_assignable_list_item, fragment->list.len); - expand_ok = true; + bool expand_ok = true; for (size_t i = 0; i < fragment->list.len; i++) { - struct apfl_expr_assignable *cur = &out->list.children[i]; + struct apfl_expr_assignable_list_item *out_item = &out->list.items[i]; + struct fragment item_fragment = fragment_move(&fragment->list.children[i]); + + if (item_fragment.type == FRAG_EXPAND) { + if (!expand_ok) { + p->error = (struct apfl_error) { + .type = APFL_ERR_ONLY_ONE_EXPAND_ALLOWED, + .position = item_fragment.position, + }; + fragment_deinit(&item_fragment); + goto error; + } + + out_item->expand = true; + expand_ok = false; + + item_fragment = fragment_unwrap_expand(item_fragment); + } else { + out_item->expand = false; + } if (!fragment_to_assignable( p, - expand_ok, - fragment_move(&fragment->list.children[i]), - cur + fragment_move(&item_fragment), + &out_item->assignable )) { goto error; } - expand_ok = expand_ok && cur->type != APFL_EXPR_ASSIGNABLE_EXPAND; - out->list.len++; } @@ -1286,16 +1301,17 @@ error: static bool fragment_to_assignable( apfl_parser_ptr p, - bool expand_ok, struct fragment fragment, struct apfl_expr_assignable *outptr ) { struct apfl_expr_assignable out = { // Just a value that can be safely deinited - .type = APFL_EXPR_ASSIGNABLE_EXPAND, - .expand = NULL, + .type = APFL_EXPR_ASSIGNABLE_CONSTANT, + .constant = { + .type = APFL_EXPR_CONST_NIL, + }, }; - bool result = fragment_to_assignable_inner(p, expand_ok, &fragment, &out); + bool result = fragment_to_assignable_inner(p, &fragment, &out); fragment_deinit(&fragment); if (result) { *outptr = out; @@ -1556,7 +1572,7 @@ break_inner: struct fragment fragment = fragment_move(&fragments->children[0]); fragment_list_deinit(fragments); // Reset fragment list - if (!fragment_to_assignable(p, false, fragment, &cur_partial->lhs)) { + if (!fragment_to_assignable(p, fragment, &cur_partial->lhs)) { goto error; } diff --git a/src/parser_test.c b/src/parser_test.c index dec2ad5..a81f6a2 100644 --- a/src/parser_test.c +++ b/src/parser_test.c @@ -135,6 +135,24 @@ list_item(bool expand, struct apfl_expr *expr) }; } +static struct apfl_expr_assignable_list_item +assignable_list_item(bool expand, struct apfl_expr_assignable assignable) +{ + return (struct apfl_expr_assignable_list_item) { + .expand = expand, + .assignable = assignable, + }; +} + +static struct apfl_expr_params_item +params_item(bool expand, struct apfl_expr_param param) +{ + return (struct apfl_expr_params_item) { + .expand = expand, + .param = param, + }; +} + // Fugly macros to make it a bit easier to create a heap allocated struct value #define BEGIN_NEW(pt, T) ((T *)new_helper(pt, sizeof(T), &((T) #define END_NEW ))) @@ -186,8 +204,8 @@ MKLISTBUILDER(list, struct apfl_expr_list, struct apfl_expr_list_item, items, le MKLISTBUILDER(body, struct apfl_expr_body, struct apfl_expr, items, len) MKLISTBUILDER(dict, struct apfl_expr_dict, struct apfl_expr_dict_pair, items, len) MKLISTBUILDER(complex_func, struct apfl_expr_complex_func, struct apfl_expr_subfunc, subfuncs, len) -MKLISTBUILDER(params, struct apfl_expr_params, struct apfl_expr_param, params, len) -MKLISTBUILDER(assignable_list, struct apfl_expr_assignable_list, struct apfl_expr_assignable, children, len) +MKLISTBUILDER(params, struct apfl_expr_params, struct apfl_expr_params_item, params, len) +MKLISTBUILDER(assignable_list, struct apfl_expr_assignable_list, struct apfl_expr_assignable_list_item, items, len) #define POS(l, c) (struct apfl_position) { .line = l, .col = c } @@ -508,10 +526,10 @@ TEST(factorial, t) { .complex_func = LIST_BEGIN(pt, complex_func) LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) - LIST_ADD (struct apfl_expr_param) { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_CONSTANT, .constant = num_const(0), - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD const_expr(2, 10, num_const(1)), @@ -519,10 +537,10 @@ TEST(factorial, t) { }, LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) - LIST_ADD (struct apfl_expr_param) { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "n"), - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { @@ -602,15 +620,15 @@ TEST(map, t) { .complex_func = LIST_BEGIN(pt, complex_func) LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) - LIST_ADD (struct apfl_expr_param) { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "_"), - }, - LIST_ADD (struct apfl_expr_param) { + }), + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_LIST, .list = LIST_BEGIN(pt, params) LIST_END, - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { @@ -623,26 +641,23 @@ TEST(map, t) { }, LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) - LIST_ADD (struct apfl_expr_param) { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "f"), - }, - LIST_ADD (struct apfl_expr_param) { + }), + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_LIST, .list = LIST_BEGIN(pt, params) - LIST_ADD (struct apfl_expr_param) { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "x"), - }, - LIST_ADD (struct apfl_expr_param) { - .type = APFL_EXPR_PARAM_EXPAND, - .expand = BEGIN_NEW(pt, struct apfl_expr_param) { - .type = APFL_EXPR_PARAM_VAR, - .var = new_string(pt, "xs"), - } END_NEW - }, + }), + LIST_ADD params_item(true, (struct apfl_expr_param) { + .type = APFL_EXPR_PARAM_VAR, + .var = new_string(pt, "xs"), + }), LIST_END, - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { @@ -876,26 +891,23 @@ TEST(assignment, t) { .lhs = (struct apfl_expr_assignable) { .type = APFL_EXPR_ASSIGNABLE_LIST, .list = LIST_BEGIN(pt, assignable_list) - LIST_ADD (struct apfl_expr_assignable) { + LIST_ADD assignable_list_item(false, (struct apfl_expr_assignable) { .type = APFL_EXPR_ASSIGNABLE_LIST, .list = LIST_BEGIN(pt, assignable_list) - LIST_ADD (struct apfl_expr_assignable) { + LIST_ADD assignable_list_item(false, (struct apfl_expr_assignable) { .type = APFL_EXPR_ASSIGNABLE_CONSTANT, .constant = num_const(1), - }, - LIST_ADD (struct apfl_expr_assignable) { + }), + LIST_ADD assignable_list_item(false, (struct apfl_expr_assignable) { .type = APFL_EXPR_ASSIGNABLE_CONSTANT, .constant = num_const(2), - }, + }), LIST_END, - }, - LIST_ADD (struct apfl_expr_assignable) { - .type = APFL_EXPR_ASSIGNABLE_EXPAND, - .expand = BEGIN_NEW(pt, struct apfl_expr_assignable) { - .type = APFL_EXPR_ASSIGNABLE_VAR, - .var = new_string(pt, "xs"), - } END_NEW, - }, + }), + LIST_ADD assignable_list_item(true, (struct apfl_expr_assignable) { + .type = APFL_EXPR_ASSIGNABLE_VAR, + .var = new_string(pt, "xs"), + }), LIST_END, }, .rhs = BEGIN_NEW(pt, struct apfl_expr) { @@ -1017,18 +1029,15 @@ TEST(complex_function, t) { .complex_func = LIST_BEGIN(pt, complex_func) LIST_ADD { .params = LIST_BEGIN(pt, params) - LIST_ADD { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "a"), - }, - LIST_ADD { - .type = APFL_EXPR_PARAM_EXPAND, - .expand = BEGIN_NEW(pt, struct apfl_expr_param) { - .type = APFL_EXPR_PARAM_VAR, - .var = new_string(pt, "b"), - } END_NEW - }, - LIST_ADD { + }), + LIST_ADD params_item(true, (struct apfl_expr_param) { + .type = APFL_EXPR_PARAM_VAR, + .var = new_string(pt, "b"), + }), + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_PREDICATE, .predicate = { .lhs = BEGIN_NEW(pt, struct apfl_expr_param) { @@ -1052,7 +1061,7 @@ TEST(complex_function, t) { }, } END_NEW, }, - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD var(pt, 1, 21, "foo"), @@ -1062,29 +1071,29 @@ TEST(complex_function, t) { }, LIST_ADD { .params = LIST_BEGIN(pt, params) - LIST_ADD { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_CONSTANT, .constant = num_const(1), - }, - LIST_ADD { + }), + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_LIST, .list = LIST_BEGIN(pt, params) LIST_END, - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_END, }, LIST_ADD { .params = LIST_BEGIN(pt, params) - LIST_ADD { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "x"), - }, - LIST_ADD { + }), + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_LIST, .list = LIST_BEGIN(pt, params) - LIST_ADD { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_PREDICATE, .predicate = { .lhs = BEGIN_NEW(pt, struct apfl_expr_param) { @@ -1093,16 +1102,13 @@ TEST(complex_function, t) { } END_NEW, .rhs = new_var(pt, 3, 15, "x"), }, - }, - LIST_ADD { - .type = APFL_EXPR_PARAM_EXPAND, - .expand = BEGIN_NEW(pt, struct apfl_expr_param) { - .type = APFL_EXPR_PARAM_VAR, - .var = new_string(pt, "ys"), - } END_NEW, - }, + }), + LIST_ADD params_item(true, (struct apfl_expr_param) { + .type = APFL_EXPR_PARAM_VAR, + .var = new_string(pt, "ys"), + }), LIST_END - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD var(pt, 4, 5, "a"), @@ -1119,10 +1125,10 @@ TEST(complex_function, t) { .complex_func = LIST_BEGIN(pt, complex_func) LIST_ADD { .params = LIST_BEGIN(pt, params) - LIST_ADD { + LIST_ADD params_item(false, (struct apfl_expr_param) { .type = APFL_EXPR_PARAM_VAR, .var = new_string(pt, "x"), - }, + }), LIST_END, .body = LIST_BEGIN(pt, body) LIST_ADD var(pt, 6, 14, "y"), @@ -1300,6 +1306,29 @@ TEST(err_dict_mapsto_too_early, t) { destroy_parser_test(pt); } +TEST(err_assign_multiple_expands_per_level, t) { + struct parser_test *pt = new_parser_test(t, "[~foo ~bar] = baz"); + expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED); + destroy_parser_test(pt); +} +TEST(err_assign_multiple_expands_per_level_nested, t) { + struct parser_test *pt = new_parser_test(t, "[1 [~foo ~bar]] = baz"); + expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED); + destroy_parser_test(pt); +} + +TEST(err_params_multiple_expands, t) { + struct parser_test *pt = new_parser_test(t, "{ ~foo ~bar -> baz }"); + expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED); + destroy_parser_test(pt); +} + +TEST(err_params_multiple_expands_nested, t) { + struct parser_test *pt = new_parser_test(t, "{ 1 [~foo ~bar] -> baz }"); + expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED); + destroy_parser_test(pt); +} + TESTS_BEGIN ADDTEST(empty), ADDTEST(hello_world), @@ -1333,4 +1362,8 @@ TESTS_BEGIN ADDTEST(err_statements_before_params), ADDTEST(err_dict_mapsto_missing), ADDTEST(err_dict_mapsto_too_early), + ADDTEST(err_assign_multiple_expands_per_level), + ADDTEST(err_assign_multiple_expands_per_level_nested), + ADDTEST(err_params_multiple_expands), + ADDTEST(err_params_multiple_expands_nested), TESTS_END