Improve AST representation of expansion in assignables / parameters

The previous representation didn't properly model the fact that an
assignable / parameter can only be expanded, if it's a list element. This
now better models this. Other than being more correct, this should also
make evaluating these a bit easier.

While I was at it, I also improved the error message for multiple
expansions on the same level and added tests for these.
This commit is contained in:
Laria 2022-01-07 23:08:25 +01:00
parent e928f40da4
commit 4eea93ff97
5 changed files with 275 additions and 197 deletions

View file

@ -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 *);

View file

@ -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 "<unknown error>";
@ -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);

View file

@ -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(&param->predicate);
break;
case APFL_EXPR_PARAM_EXPAND:
DESTROY(param->expand, apfl_expr_param_deinit);
break;
case APFL_EXPR_PARAM_LIST:
apfl_expr_params_deinit(&param->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(&param->list.params[i], indent+1, f);
print_params_item(&param->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;
}
}

View file

@ -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;
}

View file

@ -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