#include #include #include #include "apfl.h" #include "common.h" #include "internal.h" void apfl_expr_deinit(struct apfl_expr *expr) { switch (expr->type) { case APFL_EXPR_LIST: apfl_expr_list_deinit(&expr->list); break; case APFL_EXPR_DICT: apfl_expr_dict_deinit(&expr->dict); break; case APFL_EXPR_CALL: apfl_expr_call_deinit(&expr->call); break; case APFL_EXPR_SIMPLE_FUNC: apfl_expr_body_deinit(&expr->simple_func); break; case APFL_EXPR_COMPLEX_FUNC: apfl_expr_complex_func_deinit(&expr->complex_func); break; case APFL_EXPR_ASSIGNMENT: apfl_expr_assignment_deinit(&expr->assignment); break; case APFL_EXPR_DOT: apfl_expr_dot_deinit(&expr->dot); break; case APFL_EXPR_AT: apfl_expr_at_deinit(&expr->at); break; case APFL_EXPR_CONSTANT: apfl_expr_const_deinit(&expr->constant); break; case APFL_EXPR_VAR: apfl_string_deinit(&expr->var); break; } } void apfl_expr_list_deinit(struct apfl_expr_list *list) { DEINIT_LIST(list->items, list->len, apfl_expr_list_item_deinit); } void apfl_expr_list_item_deinit(struct apfl_expr_list_item *item) { DESTROY(item->expr, apfl_expr_deinit); } void apfl_expr_dict_pair_deinit(struct apfl_expr_dict_pair *pair) { DESTROY(pair->k, apfl_expr_deinit); DESTROY(pair->v, apfl_expr_deinit); } void apfl_expr_dict_deinit(struct apfl_expr_dict *dict) { DEINIT_LIST(dict->items, dict->len, apfl_expr_dict_pair_deinit); } void apfl_expr_call_deinit(struct apfl_expr_call *call) { DESTROY(call->callee, apfl_expr_deinit); apfl_expr_list_deinit(&call->arguments); } void apfl_expr_body_deinit(struct apfl_expr_body *body) { DEINIT_LIST(body->items, body->len, apfl_expr_deinit); } void apfl_expr_const_deinit(struct apfl_expr_const *constant) { switch (constant->type) { case APFL_EXPR_CONST_NIL: case APFL_EXPR_CONST_BOOLEAN: case APFL_EXPR_CONST_NUMBER: // nop break; case APFL_EXPR_CONST_STRING: apfl_string_deinit(&constant->string); break; } } #define DEINIT_GENERIC_LHS_RHS_EXPR(x, lhs_deiniter) \ do { \ DESTROY(x->lhs, lhs_deiniter); \ DESTROY(x->rhs, apfl_expr_deinit); \ } while (0) void apfl_expr_param_predicate_deinit(struct apfl_expr_param_predicate *pred) { DEINIT_GENERIC_LHS_RHS_EXPR(pred, apfl_expr_param_deinit); } void apfl_expr_param_list_deinit(struct apfl_expr_param_list *list) { DEINIT_LIST(list->children, list->len, apfl_expr_param_deinit); } void apfl_expr_params_deinit(struct apfl_expr_params *params) { DEINIT_LIST(params->params, params->len, apfl_expr_param_deinit); } void apfl_expr_param_deinit(struct apfl_expr_param *param) { switch (param->type) { case APFL_EXPR_PARAM_VAR: apfl_string_deinit(¶m->var); break; case APFL_EXPR_PARAM_CONSTANT: apfl_expr_const_deinit(¶m->constant); break; 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; } } void apfl_expr_subfunc_deinit(struct apfl_expr_subfunc *subfunc) { apfl_expr_params_deinit(&subfunc->params); apfl_expr_body_deinit(&subfunc->body); } void apfl_expr_complex_func_deinit(struct apfl_expr_complex_func *cf) { DEINIT_LIST(cf->subfuncs, cf->len, apfl_expr_subfunc_deinit); } void apfl_expr_assignable_predicate_deinit(struct apfl_expr_assignable_predicate *pred) { 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_deinit(struct apfl_expr_assignable_list *list) { DEINIT_LIST(list->children, list->len, apfl_expr_assignable_deinit); } void apfl_expr_assignable_deinit(struct apfl_expr_assignable *a) { switch (a->type) { case APFL_EXPR_ASSIGNABLE_VAR: apfl_string_deinit(&a->var); break; case APFL_EXPR_ASSIGNABLE_CONSTANT: apfl_expr_const_deinit(&a->constant); break; 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; 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; } } void apfl_expr_assignment_deinit(struct apfl_expr_assignment *a) { apfl_expr_assignable_deinit(&a->lhs); DESTROY(a->rhs, apfl_expr_deinit); } void apfl_expr_dot_deinit(struct apfl_expr_dot *dot) { GENERIC_DOT_DEINIT(dot, apfl_expr_deinit); } void apfl_expr_at_deinit(struct apfl_expr_at *at) { DEINIT_GENERIC_LHS_RHS_EXPR(at, apfl_expr_deinit); } // Move functions struct apfl_expr apfl_expr_move(struct apfl_expr *in) { struct apfl_expr out = *in; switch (in->type) { case APFL_EXPR_LIST: out.list = apfl_expr_list_move(&in->list); break; case APFL_EXPR_DICT: out.dict = apfl_expr_dict_move(&in->dict); break; case APFL_EXPR_CALL: out.call = apfl_expr_call_move(&in->call); break; case APFL_EXPR_SIMPLE_FUNC: out.simple_func = apfl_expr_body_move(&in->simple_func); break; case APFL_EXPR_COMPLEX_FUNC: out.complex_func = apfl_expr_complex_func_move(&in->complex_func); break; case APFL_EXPR_ASSIGNMENT: out.assignment = apfl_expr_assignment_move(&in->assignment); break; case APFL_EXPR_DOT: out.dot = apfl_expr_dot_move(&in->dot); break; case APFL_EXPR_AT: out.at = apfl_expr_at_move(&in->at); break; case APFL_EXPR_CONSTANT: out.constant = apfl_expr_const_move(&in->constant); break; case APFL_EXPR_VAR: out.var = apfl_string_move(&in->var); break; } return out; } #define MOVE_LIST(out, in, items, len) \ do { \ MOVEPTR(out.items, in->items); \ out.len = in->len; \ in->len = 0; \ } while (0) struct apfl_expr_list apfl_expr_list_move(struct apfl_expr_list *in) { struct apfl_expr_list out; MOVE_LIST(out, in, items, len); return out; } struct apfl_expr_list_item apfl_expr_list_item_move(struct apfl_expr_list_item *in) { struct apfl_expr_list_item out = *in; in->expr = NULL; return out; } struct apfl_expr_dict_pair apfl_expr_dict_pair_move(struct apfl_expr_dict_pair *in) { struct apfl_expr_dict_pair out = *in; in->k = NULL; in->v = NULL; return out; } struct apfl_expr_dict apfl_expr_dict_move(struct apfl_expr_dict *in) { struct apfl_expr_dict out; MOVE_LIST(out, in, items, len); return out; } struct apfl_expr_call apfl_expr_call_move(struct apfl_expr_call *in) { struct apfl_expr_call out; MOVEPTR(out.callee, in->callee); out.arguments = apfl_expr_list_move(&in->arguments); return out; } struct apfl_expr_body apfl_expr_body_move(struct apfl_expr_body *in) { struct apfl_expr_body out; MOVE_LIST(out, in, items, len); return out; } struct apfl_expr_const apfl_expr_const_move(struct apfl_expr_const *in) { struct apfl_expr_const out = *in; switch (in->type) { case APFL_EXPR_CONST_NIL: case APFL_EXPR_CONST_BOOLEAN: case APFL_EXPR_CONST_NUMBER: // nop break; case APFL_EXPR_CONST_STRING: out.string = apfl_string_move(&in->string); } return out; } #define GENERIC_LHS_RHS_PTRS_MOVE(out, in) \ do { \ MOVEPTR(out.lhs, in->lhs); \ MOVEPTR(out.rhs, in->rhs); \ } while (0) struct apfl_expr_param_predicate apfl_expr_param_predicate_move(struct apfl_expr_param_predicate *in) { struct apfl_expr_param_predicate out; GENERIC_LHS_RHS_PTRS_MOVE(out, in); return out; } struct apfl_expr_param_list apfl_expr_param_list_move(struct apfl_expr_param_list *in) { struct apfl_expr_param_list out; MOVE_LIST(out, in, children, len); return out; } struct apfl_expr_params apfl_expr_params_move(struct apfl_expr_params *in) { struct apfl_expr_params out; MOVE_LIST(out, in, params, len); return out; } struct apfl_expr_param apfl_expr_param_move(struct apfl_expr_param *in) { struct apfl_expr_param out = *in; switch (in->type) { case APFL_EXPR_PARAM_VAR: out.var = apfl_string_move(&in->var); break; case APFL_EXPR_PARAM_CONSTANT: out.constant = apfl_expr_const_move(&in->constant); break; 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; } return out; } struct apfl_expr_subfunc apfl_expr_subfunc_move(struct apfl_expr_subfunc *in) { return (struct apfl_expr_subfunc) { .params = apfl_expr_params_move(&in->params), .body = apfl_expr_body_move(&in->body), }; } struct apfl_expr_complex_func apfl_expr_complex_func_move(struct apfl_expr_complex_func *in) { struct apfl_expr_complex_func out; MOVE_LIST(out, in, subfuncs, len); return out; } struct apfl_expr_assignable_predicate apfl_expr_assignable_predicate_move(struct apfl_expr_assignable_predicate *in) { struct apfl_expr_assignable_predicate out; GENERIC_LHS_RHS_PTRS_MOVE(out, 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) { struct apfl_expr_assignable_list out; MOVE_LIST(out, in, children, len); return out; } struct apfl_expr_assignable 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); break; case APFL_EXPR_ASSIGNABLE_CONSTANT: out.constant = apfl_expr_const_move(&in->constant); break; 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; 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; } return out; } struct apfl_expr_assignment apfl_expr_assignment_move(struct apfl_expr_assignment *in) { struct apfl_expr_assignment out = *in; out.lhs = apfl_expr_assignable_move(&in->lhs); MOVEPTR(out.rhs, in->rhs); return out; } struct apfl_expr_dot apfl_expr_dot_move(struct apfl_expr_dot *in) { struct apfl_expr_dot out; GENERIC_DOT_MOVE(out, in); return out; } struct apfl_expr_at apfl_expr_at_move(struct apfl_expr_at *in) { struct apfl_expr_at out; GENERIC_LHS_RHS_PTRS_MOVE(out, in); return out; } #define POSFMT "%d:%d" #define POSARGS(p) (p).line, (p).col static void print_expr(struct apfl_expr *expr, unsigned indent, FILE *f); static void print_expr_list(struct apfl_expr_list *list, unsigned indent, FILE *f) { for (size_t i = 0; i < list->len; i++) { unsigned item_indent = indent; if (list->items[i].expand) { apfl_print_indented(indent, f, "Expand\n"); item_indent++; } print_expr(list->items[i].expr, item_indent, f); } } static void print_body(struct apfl_expr_body *body, unsigned indent, FILE *f) { for (size_t i = 0; i < body->len; i++) { print_expr(&body->items[i], indent, f); } } static void print_constant_with_pos(struct apfl_expr_const constant, struct apfl_position pos, unsigned indent, FILE *f) { switch (constant.type) { case APFL_EXPR_CONST_NIL: apfl_print_indented(indent, f, "Const (nil) @ " POSFMT "\n", POSARGS(pos)); break; case APFL_EXPR_CONST_BOOLEAN: apfl_print_indented(indent, f, "Const (%s) @ " POSFMT "\n", constant.boolean ? "true" : "false", POSARGS(pos)); break; case APFL_EXPR_CONST_STRING: apfl_print_indented(indent, f, "Const (" APFL_STR_FMT ") @ " POSFMT "\n", APFL_STR_FMT_ARGS(constant.string), POSARGS(pos)); break; case APFL_EXPR_CONST_NUMBER: apfl_print_indented(indent, f, "Const (%f) @ " POSFMT "\n", constant.number, POSARGS(pos)); break; } } static void print_constant(struct apfl_expr_const constant, unsigned indent, FILE *f) { switch (constant.type) { case APFL_EXPR_CONST_NIL: apfl_print_indented(indent, f, "Const (nil)\n"); break; case APFL_EXPR_CONST_BOOLEAN: apfl_print_indented(indent, f, "Const (%s)\n", constant.boolean ? "true" : "false"); break; case APFL_EXPR_CONST_STRING: apfl_print_indented(indent, f, "Const (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(constant.string)); break; case APFL_EXPR_CONST_NUMBER: apfl_print_indented(indent, f, "Const (%f)\n", constant.number); break; } } static void print_param(struct apfl_expr_param *param, unsigned indent, FILE *f) { switch (param->type) { case APFL_EXPR_PARAM_VAR: apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(param->var)); break; case APFL_EXPR_PARAM_CONSTANT: print_constant(param->constant, indent, f); break; case APFL_EXPR_PARAM_PREDICATE: apfl_print_indented(indent, f, "Predicate\n"); apfl_print_indented(indent+1, f, "LHS\n"); print_param(param->predicate.lhs, indent+2, 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); } 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)); break; case APFL_EXPR_ASSIGNABLE_CONSTANT: print_constant(assignable.constant, indent, f); break; case APFL_EXPR_ASSIGNABLE_PREDICATE: apfl_print_indented(indent, f, "Predicate\n"); apfl_print_indented(indent+1, f, "LHS\n"); print_assignable(*assignable.predicate.lhs, indent+2, f); 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); 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++) { print_assignable(assignable.list.children[i], indent+1, f); } break; } } static void print_expr(struct apfl_expr *expr, unsigned indent, FILE *f) { switch (expr->type) { case APFL_EXPR_LIST: apfl_print_indented(indent, f, "List @ " POSFMT "\n", POSARGS(expr->position)); print_expr_list(&expr->list, indent+1, f); break; case APFL_EXPR_DICT: apfl_print_indented(indent, f, "Dict @ " POSFMT "\n", POSARGS(expr->position)); for (size_t i = 0; i < expr->dict.len; i++) { apfl_print_indented(indent+1, f, "Dict item\n"); apfl_print_indented(indent+2, f, "Key\n"); print_expr(expr->dict.items[i].k, indent+3, f); apfl_print_indented(indent+2, f, "Value\n"); print_expr(expr->dict.items[i].v, indent+3, f); } break; case APFL_EXPR_CALL: apfl_print_indented(indent, f, "Call @ " POSFMT "\n", POSARGS(expr->position)); apfl_print_indented(indent+1, f, "Callee\n"); print_expr(expr->call.callee, indent+2, f); apfl_print_indented(indent+1, f, "Args\n"); print_expr_list(&expr->call.arguments, indent+2, f); break; case APFL_EXPR_SIMPLE_FUNC: apfl_print_indented(indent, f, "Simple function @ " POSFMT "\n", POSARGS(expr->position)); print_body(&expr->simple_func, indent+1, f); break; case APFL_EXPR_COMPLEX_FUNC: apfl_print_indented(indent, f, "Complex function @ " POSFMT "\n", POSARGS(expr->position)); for (size_t i = 0; i < expr->complex_func.len; i++) { apfl_print_indented(indent+1, f, "Subfunction\n"); 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); } apfl_print_indented(indent+2, f, "Body\n"); print_body(&sub->body, indent+3, f); } break; case APFL_EXPR_ASSIGNMENT: apfl_print_indented(indent, f, "Assignment\n"); apfl_print_indented(indent+1, f, "LHS\n"); print_assignable(expr->assignment.lhs, indent+2, f); apfl_print_indented(indent+1, f, "RHS\n"); print_expr(expr->assignment.rhs, indent+2, f); break; case APFL_EXPR_DOT: apfl_print_indented(indent, f, "Dot (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(expr->dot.rhs)); print_expr(expr->dot.lhs, indent+1, f); break; case APFL_EXPR_AT: apfl_print_indented(indent, f, "At\n"); apfl_print_indented(indent+1, f, "LHS\n"); print_expr(expr->at.lhs, indent+2, f); apfl_print_indented(indent+1, f, "RHS\n"); print_expr(expr->at.rhs, indent+2, f); break; case APFL_EXPR_CONSTANT: print_constant_with_pos(expr->constant, expr->position, indent, f); break; case APFL_EXPR_VAR: apfl_print_indented(indent, f, "Var (" APFL_STR_FMT ") @ " POSFMT "\n", APFL_STR_FMT_ARGS(expr->var), POSARGS(expr->position)); break; } } void apfl_expr_print(struct apfl_expr expr, FILE *f) { print_expr(&expr, 0, f); } static bool expr_list_eq(struct apfl_expr_list a, struct apfl_expr_list b) { if (a.len != b.len) { return false; } for (size_t i = 0; i < a.len; i++) { if ( a.items[i].expand != b.items[i].expand || !apfl_expr_eq(*a.items[i].expr, *b.items[i].expr) ) { return false; } } return true; } static bool body_eq(struct apfl_expr_body a, struct apfl_expr_body b) { if (a.len != b.len) { return false; } for (size_t i = 0; i < a.len; i++) { if (!apfl_expr_eq(a.items[i], b.items[i])) { return false; } } return true; } static bool param_eq(struct apfl_expr_param, struct apfl_expr_param); static bool params_eq(struct apfl_expr_params a, struct apfl_expr_params b) { if (a.len != b.len) { return false; } for (size_t i = 0; i < a.len; i++) { if (!param_eq(a.params[i], b.params[i])) { return false; } } return true; } static bool const_eq(struct apfl_expr_const a, struct apfl_expr_const b) { if (a.type != b.type) { return false; } switch (a.type) { case APFL_EXPR_CONST_NIL: return true; case APFL_EXPR_CONST_BOOLEAN: return a.boolean == b.boolean; case APFL_EXPR_CONST_STRING: return apfl_string_eq(a.string, b.string); case APFL_EXPR_CONST_NUMBER: return a.number == b.number; } assert(false); return false; } static bool param_eq(struct apfl_expr_param a, struct apfl_expr_param b) { if (a.type != b.type) { return false; } switch (a.type) { case APFL_EXPR_PARAM_VAR: return apfl_string_eq(a.var, b.var); case APFL_EXPR_PARAM_CONSTANT: return const_eq(a.constant, b.constant); 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); } assert(false); return false; } static bool assignable_eq(struct apfl_expr_assignable a, struct apfl_expr_assignable b) { if (a.type != b.type) { return false; } switch (a.type) { case APFL_EXPR_ASSIGNABLE_VAR: return apfl_string_eq(a.var, b.var); 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_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); 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; } for (size_t i = 0; i < a.list.len; i++) { if (!assignable_eq(a.list.children[i], b.list.children[i])) { return false; } } return true; } assert(false); return false; } bool apfl_expr_eq(struct apfl_expr a, struct apfl_expr b) { if (a.type != b.type) { return false; } if (!apfl_position_eq(a.position, b.position)) { return false; } switch (a.type) { case APFL_EXPR_LIST: return expr_list_eq(a.list, b.list); case APFL_EXPR_DICT: if (a.dict.len != b.dict.len) { return false; } for (size_t i = 0; i < a.dict.len; i++) { if ( !apfl_expr_eq(*a.dict.items[i].k, *b.dict.items[i].k) || !apfl_expr_eq(*a.dict.items[i].v, *b.dict.items[i].v) ) { return false; } } return true; case APFL_EXPR_CALL: return apfl_expr_eq(*a.call.callee, *b.call.callee) && expr_list_eq(a.call.arguments, b.call.arguments); case APFL_EXPR_SIMPLE_FUNC: return body_eq(a.simple_func, b.simple_func); case APFL_EXPR_COMPLEX_FUNC: if (a.complex_func.len != b.complex_func.len) { return false; } for (size_t i = 0; i < a.complex_func.len; i++) { if ( !params_eq(a.complex_func.subfuncs[i].params, b.complex_func.subfuncs[i].params) || !body_eq(a.complex_func.subfuncs[i].body, b.complex_func.subfuncs[i].body) ) { return false; } } return true; case APFL_EXPR_ASSIGNMENT: return assignable_eq(a.assignment.lhs, b.assignment.lhs) && apfl_expr_eq(*a.assignment.rhs, *b.assignment.rhs); case APFL_EXPR_DOT: return apfl_expr_eq(*a.dot.lhs, *b.dot.lhs) && apfl_string_eq(a.dot.rhs, b.dot.rhs); case APFL_EXPR_AT: return apfl_expr_eq(*a.at.lhs, *b.at.lhs) && apfl_expr_eq(*a.at.rhs, *b.at.rhs); case APFL_EXPR_CONSTANT: return const_eq(a.constant, b.constant); case APFL_EXPR_VAR: return apfl_string_eq(a.var, b.var); } assert(false); return false; }