summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-25 16:44:01 +0200
committerPaul Buetow <paul@buetow.org>2026-03-25 16:44:01 +0200
commit6553891403e221134028dbdec3ce3101bf97cdfc (patch)
tree0180268a438ebbe2e2ee74fc45e3563fea8aae8d /internal
parentfc77bacb493c4a82147bc3d4610ebabf8c85d555 (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.go86
-rw-r--r--internal/rpn/operations_test.go166
-rw-r--r--internal/rpn/rpn.go21
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
}