#include #include "expr.h" double expr_eval(struct expr *expr, double time) { switch (expr->type) { case EXPR_NUMBER: return expr->number; case EXPR_TIME: return time; case EXPR_OP: { size_t n_args = expr->op.args.len; double args[n_args]; for (size_t i = 0; i < n_args; i++) args[i] = expr_eval(&expr->op.args.ptr[i], time); double accum; switch (expr->op.type) { case OP_ADD: accum = 0.0; for (size_t i = 0; i < n_args; i++) accum += args[i]; return accum; case OP_SUB: if (n_args == 1) return -args[0]; return args[0] - args[1]; case OP_MUL: accum = 1.0; for (size_t i = 0; i < n_args; i++) accum *= args[i]; return accum; case OP_DIV: if (n_args == 1) return 1.0 / args[0]; return args[0] / args[1]; case OP_MOD: return fmod(args[0], args[1]); case OP_MIN: for (size_t i = 0; i < n_args; i++) if (i == 0 || args[i] < accum) accum = args[i]; return accum; case OP_MAX: for (size_t i = 0; i < n_args; i++) if (i == 0 || args[i] > accum) accum = args[i]; return accum; case OP_CLAMP: if (args[0] < args[1]) return args[1]; if (args[0] > args[2]) return args[2]; return args[0]; case OP_MIX: return args[0] + (args[1] - args[0]) * args[2]; case OP_ABS: return fabs(args[0]); default: break; // unreachable } } } return 0.0; } void expr_free(struct expr *expr) { if (expr->type == EXPR_OP) { for (size_t i = 0; i < expr->op.args.len; i++) expr_free(&expr->op.args.ptr[i]); free(expr->op.args.ptr); } } void expr_copy(struct expr *dst, struct expr *src) { *dst = *src; if (src->type == EXPR_OP) array_dup(&dst->op.args, &src->op.args); }