diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-24 14:17:14 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-24 14:17:14 +0300 |
| commit | 9f83f4328f89ebd03c7455725e5d21fb4f4ff586 (patch) | |
| tree | 73f925adc481a3dcef8ad7c6cc85f5a00e04bd64 | |
| parent | c8b7f1dddd63f1ef02fb9414cfcff5727e98a911 (diff) | |
refactor(rpn): delegate Divide() to binaryMetricOp via preCheck (oj)
Add variadic preChecks parameter to binaryMetricOp, allowing callers to
run a validation on the right operand before metric resolution. This
eliminates the full pipeline duplication in Divide() — it now delegates
to binaryMetricOp with a preCheck that guards against division by zero.
| -rw-r--r-- | internal/rpn/operations_arithmetic.go | 66 |
1 files changed, 24 insertions, 42 deletions
diff --git a/internal/rpn/operations_arithmetic.go b/internal/rpn/operations_arithmetic.go index 95fbeab..1c4252c 100644 --- a/internal/rpn/operations_arithmetic.go +++ b/internal/rpn/operations_arithmetic.go @@ -18,18 +18,26 @@ import ( // - compatCheck: metric compatibility validator (nil to skip, e.g., for Multiply) // - compute: the arithmetic function to apply on base-unit values // - resultMetricFn: function to determine the result metric from input metrics +// - preChecks: optional functions called on the right operand (b) before metric resolution func (o *Operations) binaryMetricOp( stack *Stack, op string, compatCheck func(*Metric, *Metric) error, compute func(float64, float64) float64, resultMetricFn func(*MetricRegistry, *Metric, *Metric) (*Metric, error), + preChecks ...func(StackValue) error, ) error { a, b, err := popTwo(stack, op) if err != nil { return err } + for _, preCheck := range preChecks { + if err := preCheck(b); err != nil { + return err + } + } + aM, err := resolveMetric(o.metricRegistry, a) if err != nil { return buildError(op, err) @@ -112,48 +120,22 @@ func (o *Operations) Multiply(stack *Stack) error { // Divide pops two values from stack, divides (a / b), and pushes result. func (o *Operations) Divide(stack *Stack) error { - a, b, err := popTwo(stack, "/") - if err != nil { - return err - } - - bF, err := toFloat64(b, "/") - if err != nil { - return err - } - if bF == 0 { - return buildError("/", fmt.Errorf("division by zero")) - } - - aM, err := resolveMetric(o.metricRegistry, a) - if err != nil { - return buildError("/", err) - } - bM, err := resolveMetric(o.metricRegistry, b) - if err != nil { - return buildError("/", err) - } - - pm := o.GetPrefixMode() - resultMetric, err := resultMetricForDiv(o.metricRegistry, aM, bM) - if err != nil { - return buildError("/", err) - } - aBase, err := convertToBase(o.metricRegistry, a, pm, resultMetric) - if err != nil { - return buildError("/", err) - } - bBase, err := convertToBase(o.metricRegistry, b, pm, resultMetric) - if err != nil { - return buildError("/", err) - } - resultVal, err := convertFromBase(o.metricRegistry, aBase/bBase, resultMetric, pm) - if err != nil { - return buildError("/", err) - } - - stack.Push(NewNumberWithMetric(resultVal, o.GetMode(), resultMetric)) - return nil + return o.binaryMetricOp( + stack, "/", + nil, // no compatibility check — resultMetricForDiv handles result type + func(a, b float64) float64 { return a / b }, + resultMetricForDiv, + func(sv StackValue) error { + f, err := toFloat64(sv, "/") + if err != nil { + return err + } + if f == 0 { + return buildError("/", fmt.Errorf("division by zero")) + } + return nil + }, + ) } // Power pops two values from stack, raises first to power of second (a ^ b), and pushes result. |
