expr+parser: Restrict what an assignable can be
If you assign into a member access (`foo.bar = baz` or `foo@bar = baz`), it is no longer permitted that the LHS of the at/dot is an arbitrary assignable. It now must be a variable, at or dot. This disallows some silly constructs (e.g. `[foo]@bar = baz`), increases the similarity to function parameters and should make writing the evaluation code for these more easy.
This commit is contained in:
parent
ac3af0baf1
commit
50cd2c18d2
6 changed files with 391 additions and 212 deletions
89
src/apfl.h
89
src/apfl.h
|
|
@ -157,6 +157,8 @@ enum apfl_error_type {
|
|||
APFL_ERR_INVALID_ASSIGNMENT_LHS,
|
||||
APFL_ERR_EMPTY_ASSIGNMENT,
|
||||
APFL_ERR_ONLY_ONE_EXPAND_ALLOWED,
|
||||
APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS,
|
||||
APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS,
|
||||
};
|
||||
|
||||
const char *apfl_error_type_name(enum apfl_error_type);
|
||||
|
|
@ -289,23 +291,38 @@ struct apfl_expr_complex_func {
|
|||
};
|
||||
|
||||
enum apfl_expr_assignable_type {
|
||||
APFL_EXPR_ASSIGNABLE_VAR,
|
||||
APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
|
||||
APFL_EXPR_ASSIGNABLE_CONSTANT,
|
||||
APFL_EXPR_ASSIGNABLE_PREDICATE,
|
||||
APFL_EXPR_ASSIGNABLE_DOT,
|
||||
APFL_EXPR_ASSIGNABLE_AT,
|
||||
APFL_EXPR_ASSIGNABLE_LIST,
|
||||
};
|
||||
|
||||
struct apfl_expr_assignable_predicate {
|
||||
struct apfl_expr_assignable *lhs;
|
||||
struct apfl_expr *rhs;
|
||||
enum apfl_expr_assignable_var_or_member_type {
|
||||
APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT,
|
||||
APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT,
|
||||
};
|
||||
struct apfl_expr_assignable_dot {
|
||||
struct apfl_expr_assignable *lhs;
|
||||
|
||||
struct apfl_expr_assignable_var_or_member_dot {
|
||||
struct apfl_expr_assignable_var_or_member *lhs;
|
||||
struct apfl_string rhs;
|
||||
};
|
||||
struct apfl_expr_assignable_at {
|
||||
struct apfl_expr_assignable_var_or_member_at {
|
||||
struct apfl_expr_assignable_var_or_member *lhs;
|
||||
struct apfl_expr *rhs;
|
||||
};
|
||||
|
||||
struct apfl_expr_assignable_var_or_member {
|
||||
enum apfl_expr_assignable_var_or_member_type type;
|
||||
|
||||
union {
|
||||
struct apfl_string var;
|
||||
struct apfl_expr_assignable_var_or_member_dot dot;
|
||||
struct apfl_expr_assignable_var_or_member_at at;
|
||||
};
|
||||
};
|
||||
|
||||
struct apfl_expr_assignable_predicate {
|
||||
struct apfl_expr_assignable *lhs;
|
||||
struct apfl_expr *rhs;
|
||||
};
|
||||
|
|
@ -318,11 +335,9 @@ struct apfl_expr_assignable {
|
|||
enum apfl_expr_assignable_type type;
|
||||
|
||||
union {
|
||||
struct apfl_string var;
|
||||
struct apfl_expr_assignable_var_or_member var_or_member;
|
||||
struct apfl_expr_const constant;
|
||||
struct apfl_expr_assignable_predicate predicate;
|
||||
struct apfl_expr_assignable_dot dot;
|
||||
struct apfl_expr_assignable_at at;
|
||||
struct apfl_expr_assignable_list list;
|
||||
};
|
||||
};
|
||||
|
|
@ -389,10 +404,11 @@ 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_var_or_member_dot_deinit(struct apfl_expr_assignable_var_or_member_dot *);
|
||||
void apfl_expr_assignable_var_or_member_at_deinit(struct apfl_expr_assignable_var_or_member_at *);
|
||||
void apfl_expr_assignable_var_or_member_deinit(struct apfl_expr_assignable_var_or_member *);
|
||||
void apfl_expr_assignable_deinit(struct apfl_expr_assignable *);
|
||||
void apfl_expr_assignment_deinit(struct apfl_expr_assignment *);
|
||||
void apfl_expr_dot_deinit(struct apfl_expr_dot *);
|
||||
|
|
@ -402,28 +418,29 @@ void apfl_expr_at_deinit(struct apfl_expr_at *);
|
|||
|
||||
// Begin move functions
|
||||
|
||||
struct apfl_expr apfl_expr_move(struct apfl_expr *);
|
||||
struct apfl_expr_list apfl_expr_list_move(struct apfl_expr_list *);
|
||||
struct apfl_expr_list_item apfl_expr_list_item_move(struct apfl_expr_list_item *);
|
||||
struct apfl_expr_dict_pair apfl_expr_dict_pair_move(struct apfl_expr_dict_pair *);
|
||||
struct apfl_expr_dict apfl_expr_dict_move(struct apfl_expr_dict *);
|
||||
struct apfl_expr_call apfl_expr_call_move(struct apfl_expr_call *);
|
||||
struct apfl_expr_body apfl_expr_body_move(struct apfl_expr_body *);
|
||||
struct apfl_expr_const apfl_expr_const_move(struct apfl_expr_const *);
|
||||
struct apfl_expr_param_predicate apfl_expr_param_predicate_move(struct apfl_expr_param_predicate *);
|
||||
struct apfl_expr_param_list apfl_expr_param_list_move(struct apfl_expr_param_list *);
|
||||
struct apfl_expr_params apfl_expr_params_move(struct apfl_expr_params *);
|
||||
struct apfl_expr_param apfl_expr_param_move(struct apfl_expr_param *);
|
||||
struct apfl_expr_subfunc apfl_expr_subfunc_move(struct apfl_expr_subfunc *);
|
||||
struct apfl_expr_complex_func apfl_expr_complex_func_move(struct apfl_expr_complex_func *);
|
||||
struct apfl_expr_assignable_predicate apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *);
|
||||
struct apfl_expr_assignable_dot apfl_expr_assignable_dot_move(struct apfl_expr_assignable_dot *);
|
||||
struct apfl_expr_assignable_at apfl_expr_assignable_at_move(struct apfl_expr_assignable_at *);
|
||||
struct apfl_expr_assignable_list apfl_expr_assignable_list_move(struct apfl_expr_assignable_list *);
|
||||
struct apfl_expr_assignable apfl_expr_assignable_move(struct apfl_expr_assignable *);
|
||||
struct apfl_expr_assignment apfl_expr_assignment_move(struct apfl_expr_assignment *);
|
||||
struct apfl_expr_dot apfl_expr_dot_move(struct apfl_expr_dot *);
|
||||
struct apfl_expr_at apfl_expr_at_move(struct apfl_expr_at *);
|
||||
struct apfl_expr apfl_expr_move(struct apfl_expr *);
|
||||
struct apfl_expr_list apfl_expr_list_move(struct apfl_expr_list *);
|
||||
struct apfl_expr_list_item apfl_expr_list_item_move(struct apfl_expr_list_item *);
|
||||
struct apfl_expr_dict_pair apfl_expr_dict_pair_move(struct apfl_expr_dict_pair *);
|
||||
struct apfl_expr_dict apfl_expr_dict_move(struct apfl_expr_dict *);
|
||||
struct apfl_expr_call apfl_expr_call_move(struct apfl_expr_call *);
|
||||
struct apfl_expr_body apfl_expr_body_move(struct apfl_expr_body *);
|
||||
struct apfl_expr_const apfl_expr_const_move(struct apfl_expr_const *);
|
||||
struct apfl_expr_param_predicate apfl_expr_param_predicate_move(struct apfl_expr_param_predicate *);
|
||||
struct apfl_expr_param_list apfl_expr_param_list_move(struct apfl_expr_param_list *);
|
||||
struct apfl_expr_params apfl_expr_params_move(struct apfl_expr_params *);
|
||||
struct apfl_expr_param apfl_expr_param_move(struct apfl_expr_param *);
|
||||
struct apfl_expr_subfunc apfl_expr_subfunc_move(struct apfl_expr_subfunc *);
|
||||
struct apfl_expr_complex_func apfl_expr_complex_func_move(struct apfl_expr_complex_func *);
|
||||
struct apfl_expr_assignable_var_or_member apfl_expr_assignable_var_or_member_move(struct apfl_expr_assignable_var_or_member *);
|
||||
struct apfl_expr_assignable_predicate apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *);
|
||||
struct apfl_expr_assignable_dot apfl_expr_assignable_dot_move(struct apfl_expr_assignable_dot *);
|
||||
struct apfl_expr_assignable_at apfl_expr_assignable_at_move(struct apfl_expr_assignable_at *);
|
||||
struct apfl_expr_assignable_list apfl_expr_assignable_list_move(struct apfl_expr_assignable_list *);
|
||||
struct apfl_expr_assignable apfl_expr_assignable_move(struct apfl_expr_assignable *);
|
||||
struct apfl_expr_assignment apfl_expr_assignment_move(struct apfl_expr_assignment *);
|
||||
struct apfl_expr_dot apfl_expr_dot_move(struct apfl_expr_dot *);
|
||||
struct apfl_expr_at apfl_expr_at_move(struct apfl_expr_at *);
|
||||
|
||||
// End move functions
|
||||
|
||||
|
|
|
|||
19
src/error.c
19
src/error.c
|
|
@ -48,6 +48,10 @@ apfl_error_type_name(enum apfl_error_type type)
|
|||
return "APFL_ERR_EMPTY_ASSIGNMENT";
|
||||
case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED:
|
||||
return "APFL_ERR_ONLY_ONE_EXPAND_ALLOWED";
|
||||
case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS:
|
||||
return "APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS";
|
||||
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
|
||||
return "APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS";
|
||||
}
|
||||
|
||||
return "<unknown error>";
|
||||
|
|
@ -149,6 +153,21 @@ apfl_error_print(struct apfl_error error, FILE *file)
|
|||
"Only one expansion (~) is allowed per level, near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected constant in member access near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected expression in member access near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(file, "Unknown error %d\n", (int)error.type);
|
||||
|
|
|
|||
|
|
@ -439,11 +439,14 @@ evaluate_assignment(apfl_ctx ctx, struct apfl_expr_assignment *assignment)
|
|||
// TODO: Use assignment->local flag. Sonce we don't hev functions yet, it's not yet relevant.
|
||||
// TODO: Handle special variable _. Maybe the parser should already generate a different assignment type for it?
|
||||
|
||||
if (assignment->lhs.type != APFL_EXPR_ASSIGNABLE_VAR) {
|
||||
if (
|
||||
assignment->lhs.type != APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER
|
||||
|| assignment->lhs.var_or_member.type != APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR
|
||||
) {
|
||||
return (struct apfl_result) { .type = APFL_RESULT_ERR }; // TODO: Implement other assignable types
|
||||
}
|
||||
|
||||
apfl_refcounted_string varname = apfl_string_move_into_new_refcounted(&assignment->lhs.var);
|
||||
apfl_refcounted_string varname = apfl_string_move_into_new_refcounted(&assignment->lhs.var_or_member.var);
|
||||
if (varname == NULL) {
|
||||
return fatal();
|
||||
}
|
||||
|
|
|
|||
186
src/expr.c
186
src/expr.c
|
|
@ -165,24 +165,6 @@ apfl_expr_assignable_predicate_deinit(struct apfl_expr_assignable_predicate *pre
|
|||
DEINIT_GENERIC_LHS_RHS_EXPR(pred, apfl_expr_assignable_deinit);
|
||||
}
|
||||
|
||||
#define GENERIC_DOT_DEINIT(dot, lhs_deiniter) \
|
||||
do { \
|
||||
DESTROY(dot->lhs, lhs_deiniter); \
|
||||
apfl_string_deinit(&dot->rhs); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
apfl_expr_assignable_dot_deinit(struct apfl_expr_assignable_dot *dot)
|
||||
{
|
||||
GENERIC_DOT_DEINIT(dot, apfl_expr_assignable_deinit);
|
||||
}
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
|
|
@ -195,12 +177,43 @@ apfl_expr_assignable_list_deinit(struct apfl_expr_assignable_list *list)
|
|||
DEINIT_LIST(list->items, list->len, apfl_expr_assignable_list_item_deinit);
|
||||
}
|
||||
|
||||
void
|
||||
apfl_expr_assignable_var_or_member_dot_deinit(struct apfl_expr_assignable_var_or_member_dot *dot)
|
||||
{
|
||||
DESTROY(dot->lhs, apfl_expr_assignable_var_or_member_deinit);
|
||||
apfl_string_deinit(&dot->rhs);
|
||||
}
|
||||
|
||||
void
|
||||
apfl_expr_assignable_var_or_member_at_deinit(struct apfl_expr_assignable_var_or_member_at *at)
|
||||
{
|
||||
DESTROY(at->lhs, apfl_expr_assignable_var_or_member_deinit);
|
||||
DESTROY(at->rhs, apfl_expr_deinit);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
apfl_expr_assignable_var_or_member_deinit(struct apfl_expr_assignable_var_or_member *var_or_member)
|
||||
{
|
||||
switch (var_or_member->type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR:
|
||||
apfl_string_deinit(&var_or_member->var);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT:
|
||||
apfl_expr_assignable_var_or_member_dot_deinit(&var_or_member->dot);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT:
|
||||
apfl_expr_assignable_var_or_member_at_deinit(&var_or_member->at);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
apfl_expr_assignable_deinit(struct apfl_expr_assignable *a)
|
||||
{
|
||||
switch (a->type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR:
|
||||
apfl_string_deinit(&a->var);
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER:
|
||||
apfl_expr_assignable_var_or_member_deinit(&a->var_or_member);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_CONSTANT:
|
||||
apfl_expr_const_deinit(&a->constant);
|
||||
|
|
@ -208,12 +221,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_DOT:
|
||||
apfl_expr_assignable_dot_deinit(&a->dot);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_AT:
|
||||
apfl_expr_assignable_at_deinit(&a->at);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_LIST:
|
||||
apfl_expr_assignable_list_deinit(&a->list);
|
||||
break;
|
||||
|
|
@ -230,7 +237,8 @@ apfl_expr_assignment_deinit(struct apfl_expr_assignment *a)
|
|||
void
|
||||
apfl_expr_dot_deinit(struct apfl_expr_dot *dot)
|
||||
{
|
||||
GENERIC_DOT_DEINIT(dot, apfl_expr_deinit);
|
||||
DESTROY(dot->lhs, apfl_expr_deinit);
|
||||
apfl_string_deinit(&dot->rhs);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -425,6 +433,27 @@ apfl_expr_complex_func_move(struct apfl_expr_complex_func *in)
|
|||
return out;
|
||||
}
|
||||
|
||||
struct apfl_expr_assignable_var_or_member
|
||||
apfl_expr_assignable_var_or_member_move(struct apfl_expr_assignable_var_or_member *in)
|
||||
{
|
||||
struct apfl_expr_assignable_var_or_member out = *in;
|
||||
switch (in->type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR:
|
||||
out.var = apfl_string_move(&in->var);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT:
|
||||
MOVEPTR(out.dot.lhs, in->dot.lhs);
|
||||
out.dot.rhs = apfl_string_move(&in->dot.rhs);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT:
|
||||
MOVEPTR(out.at.lhs, in->at.lhs);
|
||||
MOVEPTR(out.at.rhs, in->at.rhs);
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct apfl_expr_assignable_predicate
|
||||
apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *in)
|
||||
{
|
||||
|
|
@ -433,28 +462,6 @@ apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *in)
|
|||
return out;
|
||||
}
|
||||
|
||||
#define GENERIC_DOT_MOVE(out, in) \
|
||||
do { \
|
||||
MOVEPTR(out.lhs, in->lhs); \
|
||||
out.rhs = apfl_string_move(&in->rhs); \
|
||||
} while (0)
|
||||
|
||||
struct apfl_expr_assignable_dot
|
||||
apfl_expr_assignable_dot_move(struct apfl_expr_assignable_dot *in)
|
||||
{
|
||||
struct apfl_expr_assignable_dot out;
|
||||
GENERIC_DOT_MOVE(out, in);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct apfl_expr_assignable_at
|
||||
apfl_expr_assignable_at_move(struct apfl_expr_assignable_at *in)
|
||||
{
|
||||
struct apfl_expr_assignable_at out;
|
||||
GENERIC_LHS_RHS_PTRS_MOVE(out, in);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct apfl_expr_assignable_list
|
||||
apfl_expr_assignable_list_move(struct apfl_expr_assignable_list *in)
|
||||
{
|
||||
|
|
@ -468,8 +475,8 @@ apfl_expr_assignable_move(struct apfl_expr_assignable *in)
|
|||
{
|
||||
struct apfl_expr_assignable out = *in;
|
||||
switch (in->type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR:
|
||||
out.var = apfl_string_move(&in->var);
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER:
|
||||
out.var_or_member = apfl_expr_assignable_var_or_member_move(&in->var_or_member);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_CONSTANT:
|
||||
out.constant = apfl_expr_const_move(&in->constant);
|
||||
|
|
@ -477,12 +484,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_DOT:
|
||||
out.dot = apfl_expr_assignable_dot_move(&in->dot);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_AT:
|
||||
out.at = apfl_expr_assignable_at_move(&in->at);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_LIST:
|
||||
out.list = apfl_expr_assignable_list_move(&in->list);
|
||||
break;
|
||||
|
|
@ -503,7 +504,8 @@ struct apfl_expr_dot
|
|||
apfl_expr_dot_move(struct apfl_expr_dot *in)
|
||||
{
|
||||
struct apfl_expr_dot out;
|
||||
GENERIC_DOT_MOVE(out, in);
|
||||
MOVEPTR(out.lhs, in->lhs);
|
||||
out.rhs = apfl_string_move(&in->rhs);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -617,12 +619,33 @@ print_param(struct apfl_expr_param *param, unsigned indent, FILE *f)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_assignable_var_or_member(struct apfl_expr_assignable_var_or_member var_or_member, unsigned indent, FILE *f)
|
||||
{
|
||||
switch (var_or_member.type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR:
|
||||
apfl_print_indented(indent, f, "Variable (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(var_or_member.var));
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT:
|
||||
apfl_print_indented(indent, f, "Dot (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(var_or_member.dot.rhs));
|
||||
print_assignable_var_or_member(*var_or_member.dot.lhs, indent+1, f);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT:
|
||||
apfl_print_indented(indent, f, "At\n");
|
||||
apfl_print_indented(indent+1, f, "LHS\n");
|
||||
print_assignable_var_or_member(*var_or_member.at.lhs, indent+2, f);
|
||||
apfl_print_indented(indent+1, f, "RHS\n");
|
||||
print_expr(var_or_member.at.rhs, indent+2, f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE *f)
|
||||
{
|
||||
switch(assignable.type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR:
|
||||
apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(assignable.var));
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER:
|
||||
print_assignable_var_or_member(assignable.var_or_member, indent, f);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_CONSTANT:
|
||||
print_constant(assignable.constant, indent, f);
|
||||
|
|
@ -634,17 +657,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_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);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_AT:
|
||||
apfl_print_indented(indent, f, "At\n");
|
||||
apfl_print_indented(indent+1, f, "LHS\n");
|
||||
print_assignable(*assignable.at.lhs, indent+2, f);
|
||||
apfl_print_indented(indent+1, f, "RHS\n");
|
||||
print_expr(assignable.at.rhs, indent+2, f);
|
||||
break;
|
||||
case APFL_EXPR_ASSIGNABLE_LIST:
|
||||
apfl_print_indented(indent, f, "List\n");
|
||||
for (size_t i = 0; i < assignable.list.len; i++) {
|
||||
|
|
@ -834,6 +846,28 @@ param_eq(struct apfl_expr_param a, struct apfl_expr_param b)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
assignable_var_or_member_eq(struct apfl_expr_assignable_var_or_member a, struct apfl_expr_assignable_var_or_member b)
|
||||
{
|
||||
if (a.type != b.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (a.type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR:
|
||||
return apfl_string_eq(a.var, b.var);
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT:
|
||||
return assignable_var_or_member_eq(*a.dot.lhs, *b.dot.lhs)
|
||||
&& apfl_string_eq(a.dot.rhs, b.dot.rhs);
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT:
|
||||
return assignable_var_or_member_eq(*a.at.lhs, *b.at.lhs)
|
||||
&& apfl_expr_eq(*a.at.rhs, *b.at.rhs);
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b)
|
||||
{
|
||||
|
|
@ -842,19 +876,13 @@ assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b)
|
|||
}
|
||||
|
||||
switch (a.type) {
|
||||
case APFL_EXPR_ASSIGNABLE_VAR:
|
||||
return apfl_string_eq(a.var, b.var);
|
||||
case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER:
|
||||
return assignable_var_or_member_eq(a.var_or_member, b.var_or_member);
|
||||
case APFL_EXPR_ASSIGNABLE_CONSTANT:
|
||||
return const_eq(a.constant, b.constant);
|
||||
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_DOT:
|
||||
return assignable_eq(*a.dot.lhs, *b.dot.lhs)
|
||||
&& apfl_string_eq(a.dot.rhs, b.dot.rhs);
|
||||
case APFL_EXPR_ASSIGNABLE_AT:
|
||||
return assignable_eq(*a.at.lhs, *b.at.lhs)
|
||||
&& apfl_expr_eq(*a.at.rhs, *b.at.rhs);
|
||||
case APFL_EXPR_ASSIGNABLE_LIST:
|
||||
if (a.list.len != b.list.len) {
|
||||
return false;
|
||||
|
|
|
|||
132
src/parser.c
132
src/parser.c
|
|
@ -1140,6 +1140,86 @@ fragments_to_params(
|
|||
return ok;
|
||||
}
|
||||
|
||||
static bool fragment_to_assignable_var_or_member(
|
||||
apfl_parser_ptr p,
|
||||
struct fragment *fragment,
|
||||
struct apfl_expr_assignable_var_or_member *out
|
||||
) {
|
||||
struct apfl_expr_assignable_var_or_member *lhs;
|
||||
struct apfl_expr *rhs;
|
||||
|
||||
switch (fragment->type) {
|
||||
case FRAG_EXPAND:
|
||||
p->error = err_unexpected_token(APFL_TOK_EXPAND, fragment->position);
|
||||
return false;
|
||||
case FRAG_CONSTANT:
|
||||
p->error = (struct apfl_error) {
|
||||
.type = APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS,
|
||||
.position = fragment->position,
|
||||
};
|
||||
return false;
|
||||
case FRAG_NAME:
|
||||
out->type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
out->var = apfl_string_move(&fragment->name);
|
||||
return true;
|
||||
case FRAG_DOT:
|
||||
lhs = ALLOC(struct apfl_expr_assignable_var_or_member);
|
||||
if (lhs == NULL) {
|
||||
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
|
||||
return false;
|
||||
}
|
||||
if (!fragment_to_assignable_var_or_member(p, fragment->dot.lhs, lhs)) {
|
||||
free(lhs);
|
||||
return false;
|
||||
}
|
||||
out->type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT;
|
||||
out->dot = (struct apfl_expr_assignable_var_or_member_dot) {
|
||||
.lhs = lhs,
|
||||
.rhs = apfl_string_move(&fragment->dot.rhs),
|
||||
};
|
||||
return true;
|
||||
case FRAG_AT:
|
||||
lhs = ALLOC(struct apfl_expr_assignable_var_or_member);
|
||||
rhs = ALLOC(struct apfl_expr);
|
||||
if (lhs == NULL || rhs == NULL) {
|
||||
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
|
||||
return false;
|
||||
}
|
||||
if (!fragment_to_assignable_var_or_member(p, fragment->at.lhs, lhs)) {
|
||||
free(lhs);
|
||||
free(rhs);
|
||||
return false;
|
||||
}
|
||||
if (!fragment_to_expr(p, fragment_move(fragment->at.rhs), rhs)) {
|
||||
DESTROY(lhs, apfl_expr_assignable_var_or_member_deinit);
|
||||
free(rhs);
|
||||
return false;
|
||||
}
|
||||
out->type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT;
|
||||
out->at = (struct apfl_expr_assignable_var_or_member_at) {
|
||||
.lhs = lhs,
|
||||
.rhs = rhs,
|
||||
};
|
||||
return true;
|
||||
case FRAG_PREDICATE:
|
||||
p->error = err_unexpected_token(APFL_TOK_QUESTION_MARK, fragment->position);
|
||||
return false;
|
||||
case FRAG_EXPR:
|
||||
p->error = (struct apfl_error) {
|
||||
.type = APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS,
|
||||
.position = fragment->position,
|
||||
};
|
||||
return false;
|
||||
case FRAG_LIST:
|
||||
p->error = err_unexpected_token(APFL_TOK_LBRACKET, fragment->position);
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
fragment_to_assignable(
|
||||
apfl_parser_ptr p,
|
||||
|
|
@ -1153,6 +1233,8 @@ fragment_to_assignable_inner(
|
|||
struct fragment *fragment,
|
||||
struct apfl_expr_assignable *out
|
||||
) {
|
||||
struct apfl_expr_assignable_var_or_member var_or_member;
|
||||
|
||||
switch (fragment->type) {
|
||||
case FRAG_EXPAND:
|
||||
p->error = err_unexpected_token(APFL_TOK_EXPAND, fragment->position);
|
||||
|
|
@ -1162,57 +1244,13 @@ fragment_to_assignable_inner(
|
|||
out->constant = apfl_expr_const_move(&fragment->constant);
|
||||
return true;
|
||||
case FRAG_NAME:
|
||||
out->type = APFL_EXPR_ASSIGNABLE_VAR;
|
||||
out->var = apfl_string_move(&fragment->name);
|
||||
return true;
|
||||
case FRAG_DOT:
|
||||
out->type = APFL_EXPR_ASSIGNABLE_DOT;
|
||||
|
||||
out->dot.rhs = apfl_string_move(&fragment->dot.rhs);
|
||||
|
||||
if ((out->dot.lhs = malloc(sizeof(struct apfl_expr_assignable))) == NULL) {
|
||||
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!fragment_to_assignable(
|
||||
p,
|
||||
fragment_move(fragment->dot.lhs),
|
||||
out->dot.lhs
|
||||
)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return true;
|
||||
case FRAG_AT:
|
||||
out->type = APFL_EXPR_ASSIGNABLE_AT;
|
||||
|
||||
out->at.lhs = malloc(sizeof(struct apfl_expr_assignable));
|
||||
out->at.rhs = malloc(sizeof(struct apfl_expr));
|
||||
|
||||
if (out->at.lhs == NULL || out->at.rhs == NULL) {
|
||||
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
|
||||
if (!fragment_to_assignable_var_or_member(p, fragment, &var_or_member)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!fragment_to_assignable(
|
||||
p,
|
||||
fragment_move(fragment->at.lhs),
|
||||
out->at.lhs
|
||||
)) {
|
||||
free(out->at.rhs);
|
||||
out->at.rhs = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!fragment_to_expr(
|
||||
p,
|
||||
fragment_move(fragment->at.rhs),
|
||||
out->at.rhs
|
||||
)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
out->type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER;
|
||||
out->var_or_member = var_or_member;
|
||||
return true;
|
||||
case FRAG_PREDICATE:
|
||||
out->type = APFL_EXPR_ASSIGNABLE_PREDICATE;
|
||||
|
|
|
|||
|
|
@ -289,6 +289,26 @@ new_const_expr(struct parser_test *pt, int line, int col, struct apfl_expr_const
|
|||
return new_helper(pt, sizeof(struct apfl_expr), &expr);
|
||||
}
|
||||
|
||||
static struct apfl_expr_assignable
|
||||
assignable_var(struct parser_test *pt, const char *name)
|
||||
{
|
||||
return (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
|
||||
.var_or_member = {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
.var = new_string(pt, name),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static struct apfl_expr_assignable *
|
||||
new_assignable_var(struct parser_test *pt, const char *name)
|
||||
{
|
||||
struct apfl_expr_assignable assignable = assignable_var(pt, name);
|
||||
return new_helper(pt, sizeof(struct apfl_expr_assignable), &assignable);
|
||||
}
|
||||
|
||||
|
||||
TEST(empty, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "");
|
||||
expect_eof(pt);
|
||||
|
|
@ -516,10 +536,7 @@ TEST(factorial, t) {
|
|||
.type = APFL_EXPR_ASSIGNMENT,
|
||||
.position = POS(1, 11),
|
||||
.assignment = (struct apfl_expr_assignment) {
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "factorial"),
|
||||
},
|
||||
.lhs = assignable_var(pt, "factorial"),
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
.type = APFL_EXPR_COMPLEX_FUNC,
|
||||
.position = POS(1, 14),
|
||||
|
|
@ -610,10 +627,7 @@ TEST(map, t) {
|
|||
.type = APFL_EXPR_ASSIGNMENT,
|
||||
.position = POS(1, 5),
|
||||
.assignment = (struct apfl_expr_assignment) {
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "map"),
|
||||
},
|
||||
.lhs = assignable_var(pt, "map"),
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
.type = APFL_EXPR_COMPLEX_FUNC,
|
||||
.position = POS(1, 8),
|
||||
|
|
@ -841,10 +855,7 @@ TEST(assignment, t) {
|
|||
.position = POS(1, 3),
|
||||
.assignment = (struct apfl_expr_assignment) {
|
||||
.local = false,
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "a"),
|
||||
},
|
||||
.lhs = assignable_var(pt, "a"),
|
||||
.rhs = new_var(pt, 1, 5, "b"),
|
||||
},
|
||||
});
|
||||
|
|
@ -854,13 +865,16 @@ TEST(assignment, t) {
|
|||
.assignment = (struct apfl_expr_assignment) {
|
||||
.local = true,
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_DOT,
|
||||
.dot = (struct apfl_expr_assignable_dot) {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "foo"),
|
||||
} END_NEW,
|
||||
.rhs = new_string(pt, "bar"),
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
|
||||
.var_or_member = {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT,
|
||||
.dot = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
.var = new_string(pt, "foo"),
|
||||
} END_NEW,
|
||||
.rhs = new_string(pt, "bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
|
|
@ -871,10 +885,7 @@ TEST(assignment, t) {
|
|||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
|
||||
.predicate = (struct apfl_expr_assignable_predicate) {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "bar"),
|
||||
} END_NEW,
|
||||
.lhs = new_assignable_var(pt, "bar"),
|
||||
.rhs = new_var(pt, 2, 16, "pred"),
|
||||
},
|
||||
},
|
||||
|
|
@ -904,10 +915,7 @@ TEST(assignment, t) {
|
|||
}),
|
||||
LIST_END,
|
||||
}),
|
||||
LIST_ADD assignable_list_item(true, (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "xs"),
|
||||
}),
|
||||
LIST_ADD assignable_list_item(true, assignable_var(pt, "xs")),
|
||||
LIST_END,
|
||||
},
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
|
|
@ -916,23 +924,26 @@ TEST(assignment, t) {
|
|||
.assignment = (struct apfl_expr_assignment) {
|
||||
.local = true,
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_AT,
|
||||
.at = (struct apfl_expr_assignable_at) {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "bla"),
|
||||
} END_NEW,
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
.type = APFL_EXPR_CALL,
|
||||
.position = POS(3, 19),
|
||||
.call = (struct apfl_expr_call) {
|
||||
.callee = new_var(pt, 3, 20, "a"),
|
||||
.arguments = LIST_BEGIN(pt, list)
|
||||
LIST_ADD list_item(false, new_var(pt, 3, 22, "b")),
|
||||
LIST_END,
|
||||
},
|
||||
} END_NEW,
|
||||
},
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
|
||||
.var_or_member = {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT,
|
||||
.at = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
.var = new_string(pt, "bla"),
|
||||
} END_NEW,
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
.type = APFL_EXPR_CALL,
|
||||
.position = POS(3, 19),
|
||||
.call = (struct apfl_expr_call) {
|
||||
.callee = new_var(pt, 3, 20, "a"),
|
||||
.arguments = LIST_BEGIN(pt, list)
|
||||
LIST_ADD list_item(false, new_var(pt, 3, 22, "b")),
|
||||
LIST_END,
|
||||
},
|
||||
} END_NEW,
|
||||
},
|
||||
}
|
||||
},
|
||||
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
|
||||
.type = APFL_EXPR_CALL,
|
||||
|
|
@ -990,10 +1001,7 @@ TEST(simple_function, t) {
|
|||
.position = POS(4, 9),
|
||||
.assignment = (struct apfl_expr_assignment) {
|
||||
.local = false,
|
||||
.lhs = (struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR,
|
||||
.var = new_string(pt, "baz"),
|
||||
},
|
||||
.lhs = assignable_var(pt, "baz"),
|
||||
.rhs = new_const_expr(pt, 4, 11, num_const(10)),
|
||||
},
|
||||
},
|
||||
|
|
@ -1223,6 +1231,50 @@ TEST(function_calls, t) {
|
|||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TEST(member_assignment_with_predicate, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "a.b@c?d?e = f");
|
||||
expect_expr(pt, (struct apfl_expr) {
|
||||
.type = APFL_EXPR_ASSIGNMENT,
|
||||
.position = POS(1, 11),
|
||||
.assignment = {
|
||||
.lhs = {
|
||||
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
|
||||
.predicate = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
|
||||
.predicate = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
|
||||
.var_or_member = {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT,
|
||||
.at = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT,
|
||||
.dot = {
|
||||
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
|
||||
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
|
||||
.var = new_string(pt, "a"),
|
||||
} END_NEW,
|
||||
.rhs = new_string(pt, "b"),
|
||||
},
|
||||
} END_NEW,
|
||||
.rhs = new_var(pt, 1, 5, "c"),
|
||||
},
|
||||
},
|
||||
} END_NEW,
|
||||
.rhs = new_var(pt, 1, 7, "d"),
|
||||
}
|
||||
} END_NEW,
|
||||
.rhs = new_var(pt, 1, 9, "e"),
|
||||
},
|
||||
},
|
||||
.rhs = new_var(pt, 1, 13, "f")
|
||||
}
|
||||
});
|
||||
expect_eof(pt);
|
||||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TEST(err_empty_assignment, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "= foo bar");
|
||||
expect_error_of_type(pt, APFL_ERR_EMPTY_ASSIGNMENT);
|
||||
|
|
@ -1329,6 +1381,24 @@ TEST(err_params_multiple_expands_nested, t) {
|
|||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TEST(err_unexpected_expression_in_member_assignable, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "(foo).bar = 123");
|
||||
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS);
|
||||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TEST(err_unexpected_constant_in_member_assignable, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "nil.bar = 456");
|
||||
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS);
|
||||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TEST(err_unexpected_assignment_member_access, t) {
|
||||
struct parser_test *pt = new_parser_test(t, "[1 2 3]@bar = 456");
|
||||
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
|
||||
destroy_parser_test(pt);
|
||||
}
|
||||
|
||||
TESTS_BEGIN
|
||||
ADDTEST(empty),
|
||||
ADDTEST(hello_world),
|
||||
|
|
@ -1349,6 +1419,7 @@ TESTS_BEGIN
|
|||
ADDTEST(simple_function),
|
||||
ADDTEST(complex_function),
|
||||
ADDTEST(function_calls),
|
||||
ADDTEST(member_assignment_with_predicate),
|
||||
ADDTEST(err_empty_assignment),
|
||||
ADDTEST(err_mismatching_parens),
|
||||
ADDTEST(err_unclosed_func),
|
||||
|
|
@ -1366,4 +1437,7 @@ TESTS_BEGIN
|
|||
ADDTEST(err_assign_multiple_expands_per_level_nested),
|
||||
ADDTEST(err_params_multiple_expands),
|
||||
ADDTEST(err_params_multiple_expands_nested),
|
||||
ADDTEST(err_unexpected_expression_in_member_assignable),
|
||||
ADDTEST(err_unexpected_constant_in_member_assignable),
|
||||
ADDTEST(err_unexpected_assignment_member_access),
|
||||
TESTS_END
|
||||
|
|
|
|||
Loading…
Reference in a new issue