diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-20 22:22:34 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-20 22:22:34 +0200 |
| commit | 8fb02e7bfc0669fea2adb5d38af2a8a12a1eb6b5 (patch) | |
| tree | 5ac5faf8f9e660d8e76e25806ab235ecb30bac01 /internal/rpn/operations.go | |
| parent | 59d8038a2188319640863ecad33ea855b2cf3c0e (diff) | |
feat: Add hyper operator methods for stack operations
- Added HyperAdd, HyperMultiply, HyperSubtract, HyperDivide, HyperPower, HyperModulo
- Each hyper operator pops all values from stack and applies left-associative operation
- Updated token evaluation to recognize [op] pattern (e.g., [+], [-], [*], [/], [^], [%])
- Added comprehensive test cases for all hyper operators
- Updated README.md with hyper operator documentation and fixed persistent RPN state notes
Hyper operators allow operating on all stack values at once, while regular operators
work on the top two values.
Diffstat (limited to 'internal/rpn/operations.go')
| -rw-r--r-- | internal/rpn/operations.go | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go index cbcc8fe..2f4b84c 100644 --- a/internal/rpn/operations.go +++ b/internal/rpn/operations.go @@ -123,6 +123,182 @@ func (o *Operations) Modulo(stack *Stack) error { return nil } +// Hyper operators - operate on all values on the stack + +// HyperAdd pops all values from stack, adds them left-associative, and pushes result. +func (o *Operations) HyperAdd(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hyperadd: need at least 2 values") + } + + // Pop all values into a slice (in reverse order - top first) + var values []float64 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hyperadd: %w", err) + } + values = append(values, val) + } + + // Reverse to get left-to-right order (first pushed = first in) + for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { + values[i], values[j] = values[j], values[i] + } + + // Process left-associative + sum := 0.0 + for i := 0; i < len(values); i++ { + sum += values[i] + } + stack.Push(sum) + return nil +} + +// HyperMultiply pops all values from stack, multiplies them left-associative, and pushes result. +func (o *Operations) HyperMultiply(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hypermultiply: need at least 2 values") + } + + product := 1.0 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hypermultiply: %w", err) + } + product *= val + } + stack.Push(product) + return nil +} + +// HyperSubtract pops all values from stack, subtracts them left-associative, and pushes result. +func (o *Operations) HyperSubtract(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hypersubtract: need at least 2 values") + } + + // Pop all values into a slice (in reverse order - top first) + var values []float64 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hypersubtract: %w", err) + } + values = append(values, val) + } + + // Reverse to get left-to-right order (first pushed = first in) + for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { + values[i], values[j] = values[j], values[i] + } + + // Process left-associative + result := values[0] + for i := 1; i < len(values); i++ { + result -= values[i] + } + stack.Push(result) + return nil +} + +// HyperDivide pops all values from stack, divides them left-associative, and pushes result. +func (o *Operations) HyperDivide(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hyperdivide: need at least 2 values") + } + + // Pop all values into a slice (in reverse order - top first) + var values []float64 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hyperdivide: %w", err) + } + values = append(values, val) + } + + // Reverse to get left-to-right order (first pushed = first in) + for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { + values[i], values[j] = values[j], values[i] + } + + // Process left-associative + result := values[0] + for i := 1; i < len(values); i++ { + if values[i] == 0 { + return fmt.Errorf("division by zero") + } + result /= values[i] + } + stack.Push(result) + return nil +} + +// HyperPower pops all values from stack, raises to power left-associative, and pushes result. +func (o *Operations) HyperPower(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hyperpower: need at least 2 values") + } + + // Pop all values into a slice (in reverse order - top first) + var values []float64 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hyperpower: %w", err) + } + values = append(values, val) + } + + // Reverse to get left-to-right order (first pushed = first in) + for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { + values[i], values[j] = values[j], values[i] + } + + // Process left-associative + result := values[0] + for i := 1; i < len(values); i++ { + result = math.Pow(result, values[i]) + } + stack.Push(result) + return nil +} + +// HyperModulo pops all values from stack, computes modulo left-associative, and pushes result. +func (o *Operations) HyperModulo(stack *Stack) error { + if stack.Len() < 2 { + return fmt.Errorf("insufficient operands for hypermodulo: need at least 2 values") + } + + // Pop all values into a slice (in reverse order - top first) + var values []float64 + for stack.Len() > 0 { + val, err := stack.Pop() + if err != nil { + return fmt.Errorf("hypermodulo: %w", err) + } + values = append(values, val) + } + + // Reverse to get left-to-right order (first pushed = first in) + for i, j := 0, len(values)-1; i < j; i, j = i+1, j-1 { + values[i], values[j] = values[j], values[i] + } + + // Process left-associative + result := values[0] + for i := 1; i < len(values); i++ { + if values[i] == 0 { + return fmt.Errorf("modulo by zero") + } + result = math.Mod(result, values[i]) + } + stack.Push(result) + return nil +} + // stack manipulation operators // Dup duplicates the top stack value. |
