apfl/src/expr.c

921 lines
25 KiB
C
Raw Normal View History

2021-12-10 20:22:16 +00:00
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#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);
}
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(&param->var);
break;
case APFL_EXPR_PARAM_CONSTANT:
apfl_expr_const_deinit(&param->constant);
break;
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;
}
}
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; \
2021-12-15 20:25:04 +00:00
in->len = 0; \
2021-12-10 20:22:16 +00:00
} 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;
}
static void
print_indented(unsigned indent, FILE *f, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
while (indent--) {
fputs(" ", f);
}
vfprintf(f, fmt, ap);
va_end(ap);
}
#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) {
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(struct apfl_expr_const constant, unsigned indent, FILE *f)
{
switch (constant.type) {
case APFL_EXPR_CONST_NIL:
print_indented(indent, f, "Const (nil)\n");
break;
case APFL_EXPR_CONST_BOOLEAN:
print_indented(indent, f, "Const (%s)\n", constant.boolean ? "true" : "false");
break;
case APFL_EXPR_CONST_STRING:
print_indented(indent, f, "Const (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(constant.string));
break;
case APFL_EXPR_CONST_NUMBER:
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:
print_indented(indent, f, "Var (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(param->var));
2021-12-10 20:22:16 +00:00
break;
case APFL_EXPR_PARAM_CONSTANT:
print_constant(param->constant, indent, f);
break;
case APFL_EXPR_PARAM_PREDICATE:
print_indented(indent, f, "Predicate\n");
print_indented(indent+1, f, "LHS\n");
print_param(param->predicate.lhs, indent+2, f);
print_indented(indent+1, f, "RHS\n");
print_expr(param->predicate.rhs, indent+2, f);
break;
case APFL_EXPR_PARAM_EXPAND:
print_indented(indent, f, "Expand\n");
print_param(param->expand, indent+1, f);
break;
case APFL_EXPR_PARAM_LIST:
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);
}
break;
}
}
static void
print_assignable(struct apfl_expr_assignable assignable, unsigned indent, FILE *f)
{
switch(assignable.type) {
case APFL_EXPR_ASSIGNABLE_VAR:
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:
print_indented(indent, f, "Predicate\n");
print_indented(indent+1, f, "LHS\n");
print_assignable(*assignable.predicate.lhs, indent+2, f);
print_indented(indent+1, f, "RHS\n");
print_expr(assignable.predicate.rhs, indent+2, f);
break;
case APFL_EXPR_ASSIGNABLE_EXPAND:
print_indented(indent, f, "Expand\n");
print_assignable(*assignable.expand, indent+1, f);
break;
case APFL_EXPR_ASSIGNABLE_DOT:
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:
print_indented(indent, f, "At\n");
print_indented(indent+1, f, "LHS\n");
print_assignable(*assignable.at.lhs, indent+2, f);
print_indented(indent+1, f, "RHS\n");
print_expr(assignable.at.rhs, indent+2, f);
break;
case APFL_EXPR_ASSIGNABLE_LIST:
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:
print_indented(indent, f, "List @ " POSFMT "\n", POSARGS(expr->position));
print_expr_list(&expr->list, indent+1, f);
break;
case APFL_EXPR_DICT:
print_indented(indent, f, "Dict @ " POSFMT "\n", POSARGS(expr->position));
for (size_t i = 0; i < expr->dict.len; i++) {
print_indented(indent+1, f, "Dict item\n");
print_indented(indent+2, f, "Key\n");
print_expr(expr->dict.items[i].k, indent+3, f);
print_indented(indent+2, f, "Value\n");
print_expr(expr->dict.items[i].v, indent+3, f);
}
break;
case APFL_EXPR_CALL:
print_indented(indent, f, "Call @ " POSFMT "\n", POSARGS(expr->position));
print_indented(indent+1, f, "Callee\n");
print_expr(expr->call.callee, indent+2, f);
print_indented(indent+1, f, "Args\n");
print_expr_list(&expr->call.arguments, indent+2, f);
break;
case APFL_EXPR_SIMPLE_FUNC:
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:
print_indented(indent, f, "Complex function @ " POSFMT "\n", POSARGS(expr->position));
for (size_t i = 0; i < expr->complex_func.len; i++) {
print_indented(indent+1, f, "Subfunction\n");
2021-12-10 20:22:16 +00:00
struct apfl_expr_subfunc *sub = &expr->complex_func.subfuncs[i];
print_indented(indent+2, f, "Parameters\n");
2021-12-10 20:22:16 +00:00
for (size_t j = 0; j < sub->params.len; j++) {
print_param(&sub->params.params[j], indent+3, f);
2021-12-10 20:22:16 +00:00
}
print_indented(indent+2, f, "Body\n");
print_body(&sub->body, indent+3, f);
2021-12-10 20:22:16 +00:00
}
break;
case APFL_EXPR_ASSIGNMENT:
2021-12-15 22:11:54 +00:00
print_indented(indent, f, "Assignment\n");
print_indented(indent+1, f, "LHS\n");
2021-12-10 20:22:16 +00:00
print_assignable(expr->assignment.lhs, indent+2, f);
2021-12-15 22:11:54 +00:00
print_indented(indent+1, f, "RHS\n");
2021-12-10 20:22:16 +00:00
print_expr(expr->assignment.rhs, indent+2, f);
break;
case APFL_EXPR_DOT:
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:
print_indented(indent, f, "At\n");
print_indented(indent+1, f, "LHS\n");
print_expr(expr->at.lhs, indent+2, f);
print_indented(indent+1, f, "RHS\n");
print_expr(expr->at.rhs, indent+2, f);
break;
case APFL_EXPR_CONSTANT:
print_constant(expr->constant, indent, f);
break;
case APFL_EXPR_VAR:
print_indented(indent, f, "Var (" APFL_STR_FMT ")\n", APFL_STR_FMT_ARGS(expr->var));
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_cmp(a.string, b.string) == 0;
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_cmp(a.var, b.var) == 0;
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_cmp(a.var, b.var) == 0;
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_cmp(a.dot.rhs, b.dot.rhs) == 0;
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_cmp(a.dot.rhs, b.dot.rhs) == 0;
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_cmp(a.var, b.var) == 0;
}
assert(false);
return false;
}