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(¶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; \
|
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:
|
2021-12-15 20:25:40 +00:00
|
|
|
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(¶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:
|
|
|
|
|
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++) {
|
2021-12-15 20:25:40 +00:00
|
|
|
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];
|
2021-12-15 20:25:40 +00:00
|
|
|
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++) {
|
2021-12-15 20:25:40 +00:00
|
|
|
print_param(&sub->params.params[j], indent+3, f);
|
2021-12-10 20:22:16 +00:00
|
|
|
}
|
2021-12-15 20:25:40 +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;
|
|
|
|
|
}
|