diff options
Diffstat (limited to 'src/expr.c')
| -rw-r--r-- | src/expr.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/expr.c b/src/expr.c new file mode 100644 index 0000000..a808232 --- /dev/null +++ b/src/expr.c @@ -0,0 +1,73 @@ +#include <math.h> +#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); +} |
