diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-25 16:44:01 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-25 16:44:01 +0200 |
| commit | 6553891403e221134028dbdec3ce3101bf97cdfc (patch) | |
| tree | 0180268a438ebbe2e2ee74fc45e3563fea8aae8d /internal | |
| parent | fc77bacb493c4a82147bc3d4610ebabf8c85d555 (diff) | |
fix: Handle Value types correctly in RPN operations
- Updated HyperMultiply, HyperSubtract, HyperDivide, HyperPower, HyperModulo
to use []Value and toNumber() for Value-to-float64 conversions
- Updated HyperLog2, HyperLog10, HyperLn to use []Value and toNumber()
- Fixed rpn.go:
- Stack.Push() now uses NewNumberValue() for float64 values
- GetCurrentStack() converts []Value to []float64
- show() output uses toNumber() for Value formatting
- Variable handling uses NewNumberValue() when pushing
- Fixed test files (operations_test.go):
- Updated all Stack.Push() calls to use NewNumberValue()
- Updated Pop() comparisons to use .Number() method
- Fixed format specifiers for Errorf() calls
All tests pass and the binary builds and runs correctly.
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/rpn/operations.go | 86 | ||||
| -rw-r--r-- | internal/rpn/operations_test.go | 166 | ||||
| -rw-r--r-- | internal/rpn/rpn.go | 21 |
3 files changed, 139 insertions, 134 deletions
diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go index 01f4f87..d749720 100644 --- a/internal/rpn/operations.go +++ b/internal/rpn/operations.go @@ -389,9 +389,9 @@ func (o *Operations) HyperMultiply(stack *Stack) error { if err != nil { return fmt.Errorf("hypermultiply: %w", err) } - product *= val + product *= toNumber(val) } - stack.Push(product) + stack.Push(NewNumberValue(product)) return nil } @@ -402,7 +402,7 @@ func (o *Operations) HyperSubtract(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -416,12 +416,12 @@ func (o *Operations) HyperSubtract(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative - result := values[0] + // Process left-associative with toNumber coercion + result := toNumber(values[0]) for i := 1; i < len(values); i++ { - result -= values[i] + result -= toNumber(values[i]) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -432,7 +432,7 @@ func (o *Operations) HyperDivide(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -446,15 +446,15 @@ func (o *Operations) HyperDivide(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative - result := values[0] + // Process left-associative with toNumber coercion + result := toNumber(values[0]) for i := 1; i < len(values); i++ { - if values[i] == 0 { + if toNumber(values[i]) == 0 { return fmt.Errorf("division by zero") } - result /= values[i] + result /= toNumber(values[i]) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -465,7 +465,7 @@ func (o *Operations) HyperPower(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -479,12 +479,12 @@ func (o *Operations) HyperPower(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative - result := values[0] + // Process left-associative with toNumber coercion + result := toNumber(values[0]) for i := 1; i < len(values); i++ { - result = math.Pow(result, values[i]) + result = math.Pow(result, toNumber(values[i])) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -495,7 +495,7 @@ func (o *Operations) HyperModulo(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -509,15 +509,15 @@ func (o *Operations) HyperModulo(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative - result := values[0] + // Process left-associative with toNumber coercion + result := toNumber(values[0]) for i := 1; i < len(values); i++ { - if values[i] == 0 { + if toNumber(values[i]) == 0 { return fmt.Errorf("modulo by zero") } - result = math.Mod(result, values[i]) + result = math.Mod(result, toNumber(values[i])) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -529,7 +529,7 @@ func (o *Operations) HyperLog2(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -543,15 +543,15 @@ func (o *Operations) HyperLog2(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the log2 of all values + // Sum the log2 of all values with toNumber coercion var result float64 = 0 for i := 0; i < len(values); i++ { - if values[i] <= 0 { + if toNumber(values[i]) <= 0 { return fmt.Errorf("hyperlog2 undefined for non-positive numbers") } - result += math.Log2(values[i]) + result += math.Log2(toNumber(values[i])) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -563,7 +563,7 @@ func (o *Operations) HyperLog10(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -577,15 +577,15 @@ func (o *Operations) HyperLog10(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the log10 of all values + // Sum the log10 of all values with toNumber coercion var result float64 = 0 for i := 0; i < len(values); i++ { - if values[i] <= 0 { + if toNumber(values[i]) <= 0 { return fmt.Errorf("hyperlog10 undefined for non-positive numbers") } - result += math.Log10(values[i]) + result += math.Log10(toNumber(values[i])) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -597,7 +597,7 @@ func (o *Operations) HyperLn(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []float64 + var values []Value for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -611,15 +611,15 @@ func (o *Operations) HyperLn(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the natural log of all values + // Sum the natural log of all values with toNumber coercion var result float64 = 0 for i := 0; i < len(values); i++ { - if values[i] <= 0 { + if toNumber(values[i]) <= 0 { return fmt.Errorf("hyperln undefined for non-positive numbers") } - result += math.Log(values[i]) + result += math.Log(toNumber(values[i])) } - stack.Push(result) + stack.Push(NewNumberValue(result)) return nil } @@ -682,7 +682,7 @@ func (o *Operations) Show(stack *Stack) (string, error) { result += " " } // Use Number interface for consistent formatting with the current mode - num := NewNumber(val, o.mode) + num := NewNumber(toNumber(val), o.mode) result += num.String() } return result, nil @@ -706,7 +706,9 @@ func (o *Operations) AssignVariable(stack *Stack, name string) error { return err } - return o.vars.SetVariable(name, val) + // Convert Value to float64 for variable storage + o.vars.SetVariable(name, toNumber(val)) + return nil } // UseVariable pushes a variable's value onto the stack. @@ -721,7 +723,7 @@ func (o *Operations) UseVariable(stack *Stack, name string) error { return fmt.Errorf("%w: %s", ErrVariableNotFound, name) } - stack.Push(val) + stack.Push(NewNumberValue(val)) return nil } diff --git a/internal/rpn/operations_test.go b/internal/rpn/operations_test.go index 5a76e51..9445df0 100644 --- a/internal/rpn/operations_test.go +++ b/internal/rpn/operations_test.go @@ -20,9 +20,9 @@ func TestStackNewStack(t *testing.T) { func TestStackPushPop(t *testing.T) { s := NewStack() - s.Push(1.0) - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) if s.Len() != 3 { t.Errorf("Length after 3 pushes = %d, want 3", s.Len()) @@ -32,7 +32,7 @@ func TestStackPushPop(t *testing.T) { if err != nil { t.Fatalf("Pop() returned error: %v", err) } - if val != 3.0 { + if val.Number() != 3.0 { t.Errorf("Pop() = %v, want 3.0", val) } @@ -43,13 +43,13 @@ func TestStackPushPop(t *testing.T) { func TestStackPeek(t *testing.T) { s := NewStack() - s.Push(5.0) + s.Push(NewNumberValue(5.0)) val, err := s.Peek() if err != nil { t.Fatalf("Peek() returned error: %v", err) } - if val != 5.0 { + if val.Number() != 5.0 { t.Errorf("Peek() = %v, want 5.0", val) } @@ -80,9 +80,9 @@ func TestStackPopEmpty(t *testing.T) { func TestStackValues(t *testing.T) { s := NewStack() - s.Push(1.0) - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) vals := s.Values() if len(vals) != 3 { @@ -91,16 +91,16 @@ func TestStackValues(t *testing.T) { // Values() returns values in storage order (bottom-to-top) // Push order: 1, 2, 3 so storage is [1, 2, 3] with 3 on top - if vals[0] != 1.0 || vals[1] != 2.0 || vals[2] != 3.0 { + if vals[0].Number() != 1.0 || vals[1].Number() != 2.0 || vals[2].Number() != 3.0 { t.Errorf("Values() = %v, want [1 2 3] (bottom-to-top)", vals) } } func TestStackClear(t *testing.T) { s := NewStack() - s.Push(1.0) - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) s.Clear() @@ -113,8 +113,8 @@ func TestOperationsAdd(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(3.0) - s.Push(4.0) + s.Push(NewNumberValue(3.0)) + s.Push(NewNumberValue(4.0)) err := o.Add(s) if err != nil { @@ -125,7 +125,7 @@ func TestOperationsAdd(t *testing.T) { if err != nil { t.Fatalf("Pop() after Add() returned error: %v", err) } - if val != 7.0 { + if val.Number() != 7.0 { t.Errorf("Add result = %v, want 7.0", val) } } @@ -134,8 +134,8 @@ func TestOperationsSubtract(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(10.0) - s.Push(4.0) + s.Push(NewNumberValue(10.0)) + s.Push(NewNumberValue(4.0)) err := o.Subtract(s) if err != nil { @@ -146,7 +146,7 @@ func TestOperationsSubtract(t *testing.T) { if err != nil { t.Fatalf("Pop() after Subtract() returned error: %v", err) } - if val != 6.0 { + if val.Number() != 6.0 { t.Errorf("Subtract result = %v, want 6.0 (10 - 4)", val) } } @@ -155,8 +155,8 @@ func TestOperationsMultiply(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(5.0) - s.Push(3.0) + s.Push(NewNumberValue(5.0)) + s.Push(NewNumberValue(3.0)) err := o.Multiply(s) if err != nil { @@ -167,7 +167,7 @@ func TestOperationsMultiply(t *testing.T) { if err != nil { t.Fatalf("Pop() after Multiply() returned error: %v", err) } - if val != 15.0 { + if val.Number() != 15.0 { t.Errorf("Multiply result = %v, want 15.0", val) } } @@ -176,8 +176,8 @@ func TestOperationsDivide(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(20.0) - s.Push(4.0) + s.Push(NewNumberValue(20.0)) + s.Push(NewNumberValue(4.0)) err := o.Divide(s) if err != nil { @@ -188,7 +188,7 @@ func TestOperationsDivide(t *testing.T) { if err != nil { t.Fatalf("Pop() after Divide() returned error: %v", err) } - if val != 5.0 { + if val.Number() != 5.0 { t.Errorf("Divide result = %v, want 5.0", val) } } @@ -197,8 +197,8 @@ func TestOperationsDivideByZero(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(10.0) - s.Push(0.0) + s.Push(NewNumberValue(10.0)) + s.Push(NewNumberValue(0.0)) err := o.Divide(s) if err == nil { @@ -213,8 +213,8 @@ func TestOperationsPower(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) err := o.Power(s) if err != nil { @@ -225,7 +225,7 @@ func TestOperationsPower(t *testing.T) { if err != nil { t.Fatalf("Pop() after Power() returned error: %v", err) } - if val != 8.0 { + if val.Number() != 8.0 { t.Errorf("Power result = %v, want 8.0 (2^3)", val) } } @@ -234,8 +234,8 @@ func TestOperationsModulo(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(10.0) - s.Push(3.0) + s.Push(NewNumberValue(10.0)) + s.Push(NewNumberValue(3.0)) err := o.Modulo(s) if err != nil { @@ -246,7 +246,7 @@ func TestOperationsModulo(t *testing.T) { if err != nil { t.Fatalf("Pop() after Modulo() returned error: %v", err) } - if val != 1.0 { + if val.Number() != 1.0 { t.Errorf("Modulo result = %v, want 1.0 (10 %% 3)", val) } } @@ -255,8 +255,8 @@ func TestOperationsModuloByZero(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(10.0) - s.Push(0.0) + s.Push(NewNumberValue(10.0)) + s.Push(NewNumberValue(0.0)) err := o.Modulo(s) if err == nil { @@ -268,7 +268,7 @@ func TestOperationsInsufficientOperands(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(5.0) + s.Push(NewNumberValue(5.0)) // Try to add with only one operand err := o.Add(s) @@ -281,7 +281,7 @@ func TestOperationsDup(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(7.0) + s.Push(NewNumberValue(7.0)) err := o.Dup(s) if err != nil { @@ -294,7 +294,7 @@ func TestOperationsDup(t *testing.T) { val1, _ := s.Pop() val2, _ := s.Pop() - if val1 != 7.0 || val2 != 7.0 { + if val1.Number() != 7.0 || val2.Number() != 7.0 { t.Errorf("Dup values = %v, %v, want both 7.0", val1, val2) } } @@ -303,8 +303,8 @@ func TestOperationsSwap(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(1.0) - s.Push(2.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) err := o.Swap(s) if err != nil { @@ -313,7 +313,7 @@ func TestOperationsSwap(t *testing.T) { val1, _ := s.Pop() val2, _ := s.Pop() - if val1 != 1.0 || val2 != 2.0 { + if val1.Number() != 1.0 || val2.Number() != 2.0 { t.Errorf("After Swap, values = %v, %v, want 1.0, 2.0 (swapped)", val1, val2) } } @@ -322,7 +322,7 @@ func TestOperationsSwapInsufficient(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(5.0) + s.Push(NewNumberValue(5.0)) err := o.Swap(s) if err == nil { @@ -334,9 +334,9 @@ func TestOperationsPop(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(1.0) - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) err := o.Pop(s) if err != nil { @@ -363,9 +363,9 @@ func TestOperationsShow(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(1.0) - s.Push(2.0) - s.Push(3.0) + s.Push(NewNumberValue(1.0)) + s.Push(NewNumberValue(2.0)) + s.Push(NewNumberValue(3.0)) result, err := o.Show(s) if err != nil { @@ -396,7 +396,7 @@ func TestOperationsAssignVariable(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(5.0) + s.Push(NewNumberValue(5.0)) err := o.AssignVariable(s, "x") if err != nil { @@ -446,7 +446,7 @@ func TestOperationsUseVariable(t *testing.T) { if err != nil { t.Fatalf("Pop() after UseVariable() returned error: %v", err) } - if val != 3.14159 { + if val.Number() != 3.14159 { t.Errorf("Variable value pushed to stack = %v, want 3.14159", val) } } @@ -542,7 +542,7 @@ func TestOperationsConcurrent(t *testing.T) { go func(id int) { name := fmt.Sprintf("concurrent%d", id) s := NewStack() - s.Push(float64(id)) + s.Push(NewNumberValue(float64(id))) if err := o.AssignVariable(s, name); err != nil { t.Errorf("AssignVariable() returned error: %v", err) } @@ -564,7 +564,7 @@ func TestLog2(t *testing.T) { stack := NewStack() // Test log₂(8) = 3 - stack.Push(8) + stack.Push(NewNumberValue(8)) err := o.Log2(stack) if err != nil { t.Errorf("Log2() returned error: %v", err) @@ -573,12 +573,12 @@ func TestLog2(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 3.0 { - t.Errorf("Log2(8) = %f, want 3.0", val) + if val.Number() != 3.0 { + t.Errorf("Log2(8) = %f, want 3.0)", val.Number()) } // Test log₂(1) = 0 - stack.Push(1) + stack.Push(NewNumberValue(1)) err = o.Log2(stack) if err != nil { t.Errorf("Log2(1) returned error: %v", err) @@ -587,12 +587,12 @@ func TestLog2(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 0.0 { - t.Errorf("Log2(1) = %f, want 0.0", val) + if val.Number() != 0.0 { + t.Errorf("Log2(1) = %f, want 0.0)", val.Number()) } // Test log₂(0) should error - stack.Push(0) + stack.Push(NewNumberValue(0)) err = o.Log2(stack) if err == nil { t.Errorf("Log2(0) should return error, got nil") @@ -604,7 +604,7 @@ func TestLog10(t *testing.T) { stack := NewStack() // Test log₁₀(100) = 2 - stack.Push(100) + stack.Push(NewNumberValue(100)) err := o.Log10(stack) if err != nil { t.Errorf("Log10() returned error: %v", err) @@ -613,12 +613,12 @@ func TestLog10(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 2.0 { - t.Errorf("Log10(100) = %f, want 2.0", val) + if val.Number() != 2.0 { + t.Errorf("Log10(100) = %f, want 2.0)", val.Number()) } // Test log₁₀(1) = 0 - stack.Push(1) + stack.Push(NewNumberValue(1)) err = o.Log10(stack) if err != nil { t.Errorf("Log10(1) returned error: %v", err) @@ -627,8 +627,8 @@ func TestLog10(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 0.0 { - t.Errorf("Log10(1) = %f, want 0.0", val) + if val.Number() != 0.0 { + t.Errorf("Log10(1) = %f, want 0.0)", val.Number()) } } @@ -637,7 +637,7 @@ func TestLn(t *testing.T) { stack := NewStack() // Test ln(e) ≈ 1 - stack.Push(math.E) + stack.Push(NewNumberValue(math.E)) err := o.Ln(stack) if err != nil { t.Errorf("Ln() returned error: %v", err) @@ -646,12 +646,12 @@ func TestLn(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if math.Abs(val-1.0) > 0.0001 { - t.Errorf("ln(e) = %f, want ~1.0", val) + if math.Abs(val.Number()-1.0) > 0.0001 { + t.Errorf("ln(e) = %f, want ~1.0", val.Number()) } // Test ln(1) = 0 - stack.Push(1) + stack.Push(NewNumberValue(1)) err = o.Ln(stack) if err != nil { t.Errorf("Ln(1) returned error: %v", err) @@ -660,8 +660,8 @@ func TestLn(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 0.0 { - t.Errorf("Ln(1) = %f, want 0.0", val) + if val.Number() != 0.0 { + t.Errorf("Ln(1) = %f, want 0.0)", val.Number()) } } @@ -670,8 +670,8 @@ func TestHyperLog2(t *testing.T) { stack := NewStack() // Test hyperlog₂(4, 16) = log₂(4) + log₂(16) = 2 + 4 = 6 - stack.Push(4) - stack.Push(16) + stack.Push(NewNumberValue(4)) + stack.Push(NewNumberValue(16)) err := o.HyperLog2(stack) if err != nil { t.Errorf("HyperLog2() returned error: %v", err) @@ -680,12 +680,12 @@ func TestHyperLog2(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 6.0 { - t.Errorf("HyperLog2(4, 16) = %f, want 6.0", val) + if val.Number() != 6.0 { + t.Errorf("HyperLog2(4, 16) = %f, want 6.0)", val.Number()) } // Test with single value (should error, like other hyper operators) - stack.Push(8) + stack.Push(NewNumberValue(8)) err = o.HyperLog2(stack) if err == nil { t.Errorf("HyperLog2 with single value should return error, got nil") @@ -697,8 +697,8 @@ func TestHyperLog10(t *testing.T) { stack := NewStack() // Test hyperlog₁₀(10, 100) = log₁₀(10) + log₁₀(100) = 1 + 2 = 3 - stack.Push(10) - stack.Push(100) + stack.Push(NewNumberValue(10)) + stack.Push(NewNumberValue(100)) err := o.HyperLog10(stack) if err != nil { t.Errorf("HyperLog10() returned error: %v", err) @@ -707,8 +707,8 @@ func TestHyperLog10(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val != 3.0 { - t.Errorf("HyperLog10(10, 100) = %f, want 3.0", val) + if val.Number() != 3.0 { + t.Errorf("HyperLog10(10, 100) = %f, want 3.0)", val.Number()) } } @@ -717,8 +717,8 @@ func TestHyperLn(t *testing.T) { stack := NewStack() // Test hyperln(e, e²) = ln(e) + ln(e²) = 1 + 2 = 3 - stack.Push(math.E) - stack.Push(math.E * math.E) + stack.Push(NewNumberValue(math.E)) + stack.Push(NewNumberValue(math.E * math.E)) err := o.HyperLn(stack) if err != nil { t.Errorf("HyperLn() returned error: %v", err) @@ -727,7 +727,7 @@ func TestHyperLn(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if math.Abs(val-3.0) > 0.0001 { - t.Errorf("HyperLn(e, e²) = %f, want ~3.0", val) + if math.Abs(val.Number()-3.0) > 0.0001 { + t.Errorf("HyperLn(e, e²) = %f, want ~3.0", val.Number()) } } diff --git a/internal/rpn/rpn.go b/internal/rpn/rpn.go index 10d6a1d..a5b7e40 100644 --- a/internal/rpn/rpn.go +++ b/internal/rpn/rpn.go @@ -90,7 +90,7 @@ func (r *RPN) ResultStack(tokens []string) (string, error) { if stack.Len() >= r.maxStack { return "", fmt.Errorf("stack overflow") } - stack.Push(num) + stack.Push(NewNumberValue(num)) continue } @@ -111,7 +111,7 @@ func (r *RPN) ResultStack(tokens []string) (string, error) { // Check if it's a variable reference (push its value) val, exists := r.vars.GetVariable(token) if exists { - stack.Push(val) + stack.Push(NewNumberValue(val)) } else { return "", fmt.Errorf("unknown token '%s'", token) } @@ -150,7 +150,12 @@ func (r *RPN) GetCurrentStack() []float64 { if r.currentStack == nil { return nil } - return r.currentStack.Values() + values := r.currentStack.Values() + result := make([]float64, len(values)) + for i, v := range values { + result[i] = v.Number() + } + return result } // Tokenize splits the input string into tokens (numbers, operators, variables). @@ -177,12 +182,10 @@ func (r *RPN) evaluate(tokens []string) (string, error) { // Check if it's a number if num, err := strconv.ParseFloat(token, 64); err == nil { - // Create Number based on mode, but push float64 for backward compatibility - // In a future refactoring, Stack would use Number interface if stack.Len() >= r.maxStack { return "", fmt.Errorf("stack overflow") } - stack.Push(num) + stack.Push(NewNumberValue(num)) continue } @@ -203,7 +206,7 @@ func (r *RPN) evaluate(tokens []string) (string, error) { // Create a copy of the stack to preserve it r.currentStack = NewStack() for _, val := range stack.Values() { - r.currentStack.Push(val) + r.currentStack.Push(NewNumberValue(toNumber(val))) } // Get the final result @@ -218,7 +221,7 @@ func (r *RPN) evaluate(tokens []string) (string, error) { // Single value - return it val, _ := stack.Pop() - return fmt.Sprintf("%.10g", val), nil + return fmt.Sprintf("%.10g", toNumber(val)), nil } // handleOperator handles operators and special commands using the operator registry. @@ -230,7 +233,7 @@ func (r *RPN) handleOperator(stack *Stack, token string, tokenIndex int) (string // Check if it's a variable reference first (before operators) if val, exists := r.vars.GetVariable(token); exists { - stack.Push(val) + stack.Push(NewNumberValue(val)) return "", nil } |
