diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-25 17:25:00 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-25 17:25:00 +0200 |
| commit | 6b5bee78c239b221188eea2bebe0e87714970866 (patch) | |
| tree | c35622e61aa629c0912621b21655fdb8c04cfa1c /internal | |
| parent | f692d72dc840be8eb17857b2ef85ee42dde5fd3f (diff) | |
refactor: Refactor RPN to use Number interface uniformly for stack values
This commit refactors the internal/rpn package to use the Number interface
instead of the old Value struct for stack values. Key changes:
1. Updated Number interface to include IsBool() and Bool() methods for
boolean value support
2. Modified Float and Rat types to support boolean mode with:
- isBool and boolVal fields
- Float64() returns 1 for true, 0 for false
- String() returns 'true' or 'false' for boolean values
3. Updated Stack to use []Number instead of []Value
4. Updated all operations to use the Number interface methods directly
- Add, Sub, Mul, Div, Pow, Mod now use Float64() for values
5. Updated tests to use NewNumber() with mode parameter instead of
NewNumberValue(), and use Float64() instead of Number()
Benefits:
- Simplified code - no need for toNumber() and NewNumberValue() wrappers
- Better type safety - stack values are Number interface instances
- Boolean-to-number coercion works correctly in all operations
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/rpn/number.go | 102 | ||||
| -rw-r--r-- | internal/rpn/operations.go | 166 | ||||
| -rw-r--r-- | internal/rpn/operations_test.go | 166 | ||||
| -rw-r--r-- | internal/rpn/rpn_ops.go | 14 | ||||
| -rw-r--r-- | internal/rpn/rpn_parse.go | 8 | ||||
| -rw-r--r-- | internal/rpn/rpn_state.go | 8 | ||||
| -rw-r--r-- | internal/rpn/rpn_test.go | 4 | ||||
| -rw-r--r-- | internal/rpn/variables.go | 22 |
8 files changed, 302 insertions, 188 deletions
diff --git a/internal/rpn/number.go b/internal/rpn/number.go index 277b054..9cf9216 100644 --- a/internal/rpn/number.go +++ b/internal/rpn/number.go @@ -28,6 +28,7 @@ func toNumber(v Value) float64 { // Number represents a number that can be used in RPN calculations. // It can be either a float64 or a *big.Rat for precise rational calculations. +// Booleans are also supported through IsBool() and Bool() methods. type Number interface { // String returns the string representation of the number. String() string @@ -53,6 +54,10 @@ type Number interface { IsNegative() bool // Compare returns -1, 0, or 1 if this number is less than, equal to, or greater than another. Compare(other Number) int + // IsBool returns true if this number represents a boolean value. + IsBool() bool + // Bool returns the boolean value, or false if not a boolean. + Bool() bool } // NewNumber creates a Number from a float64 value. @@ -61,42 +66,75 @@ func NewNumber(value float64, mode CalculationMode) Number { if mode == RationalMode { return NewRat(value) } - return &Float{n: value} + return NewFloat(value) } // Float is a Number implementation using float64. +// It can also represent boolean values (true=1, false=0). type Float struct { - n float64 + n float64 + isBool bool + boolVal bool } // NewFloat creates a new Float number. func NewFloat(n float64) *Float { - return &Float{n: n} + return &Float{n: n, isBool: false, boolVal: false} +} + +// NewFloatFromBool creates a new Float representing a boolean. +func NewFloatFromBool(b bool) *Float { + return &Float{n: 0, isBool: true, boolVal: b} } // String returns the string representation of the float. func (f *Float) String() string { + if f.isBool { + if f.boolVal { + return "true" + } + return "false" + } return fmt.Sprintf("%.10g", f.n) } // Float64 returns the float64 value. func (f *Float) Float64() float64 { + if f.isBool { + if f.boolVal { + return 1 + } + return 0 + } return f.n } +// IsBool returns true if this number represents a boolean value. +func (f *Float) IsBool() bool { + return f.isBool +} + +// Bool returns the boolean value, or false if not a boolean. +func (f *Float) Bool() bool { + return f.boolVal +} + // Add returns the sum of two float numbers. func (f *Float) Add(other Number) Number { - return NewFloat(f.n + other.Float64()) + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(f.Float64() + other.Float64()) } // Sub returns the difference of two float numbers. func (f *Float) Sub(other Number) Number { - return NewFloat(f.n - other.Float64()) + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(f.Float64() - other.Float64()) } // Mul returns the product of two float numbers. func (f *Float) Mul(other Number) Number { - return NewFloat(f.n * other.Float64()) + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(f.Float64() * other.Float64()) } // Div returns the quotient of two float numbers. @@ -104,12 +142,14 @@ func (f *Float) Div(other Number) (Number, error) { if other.IsZero() { return nil, fmt.Errorf("division by zero") } - return NewFloat(f.n / other.Float64()), nil + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(f.Float64() / other.Float64()), nil } // Pow returns this float raised to the power of another. func (f *Float) Pow(other Number) Number { - return NewFloat(math.Pow(f.n, other.Float64())) + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(math.Pow(f.Float64(), other.Float64())) } // Mod returns the remainder of this float divided by another. @@ -117,12 +157,14 @@ func (f *Float) Mod(other Number) (Number, error) { if other.IsZero() { return nil, fmt.Errorf("modulo by zero") } - return NewFloat(math.Mod(f.n, other.Float64())), nil + // Use Float64() to handle both regular numbers and boolean values + return NewFloat(math.Mod(f.Float64(), other.Float64())), nil } // IsZero returns true if the float is zero. +// For boolean values, false (0) is zero, true (1) is not zero. func (f *Float) IsZero() bool { - return f.n == 0 + return f.Float64() == 0 } // IsNegative returns true if the float is negative. @@ -143,15 +185,29 @@ func (f *Float) Compare(other Number) int { } // Rat is a Number implementation using *big.Rat. +// It can also represent boolean values (true=1, false=0). type Rat struct { - n *big.Rat + n *big.Rat + isBool bool + boolVal bool } // NewRat creates a new Rat number from a float64. func NewRat(n float64) *Rat { r := &big.Rat{} r.SetFloat64(n) - return &Rat{n: r} + return &Rat{n: r, isBool: false, boolVal: false} +} + +// NewRatFromBool creates a new Rat representing a boolean. +func NewRatFromBool(b bool) *Rat { + r := &big.Rat{} + if b { + r.SetInt64(1) + } else { + r.SetInt64(0) + } + return &Rat{n: r, isBool: true, boolVal: b} } // NewRatFromString creates a new Rat number from a string representation. @@ -166,6 +222,12 @@ func NewRatFromString(s string) (*Rat, error) { // String returns the string representation of the rational number. func (r *Rat) String() string { + if r.isBool { + if r.boolVal { + return "true" + } + return "false" + } // Format as decimal for consistency with Float // Use a reasonable precision return r.n.FloatString(10) @@ -173,10 +235,26 @@ func (r *Rat) String() string { // Float64 returns the float64 representation. func (r *Rat) Float64() float64 { + if r.isBool { + if r.boolVal { + return 1 + } + return 0 + } f, _ := r.n.Float64() return f } +// IsBool returns true if this number represents a boolean value. +func (r *Rat) IsBool() bool { + return r.isBool +} + +// Bool returns the boolean value, or false if not a boolean. +func (r *Rat) Bool() bool { + return r.boolVal +} + // Add returns the sum of two rational numbers. func (r *Rat) Add(other Number) Number { result := &big.Rat{} diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go index 2b37c39..1c9182a 100644 --- a/internal/rpn/operations.go +++ b/internal/rpn/operations.go @@ -220,7 +220,7 @@ func (r *OperatorRegistry) IsHyperOperator(token string) bool { // arithmetic operators -// Add pops two values from stack, adds them (with boolean-to-number coercion), and pushes result. +// Add pops two values from stack, adds them, and pushes result. func (o *Operations) Add(stack *Stack) error { bVal, err := stack.Pop() if err != nil { @@ -232,8 +232,8 @@ func (o *Operations) Add(stack *Stack) error { return fmt.Errorf("insufficient operands for +: %w", err) } - // Use toNumber for automatic boolean-to-number coercion - stack.Push(NewNumberValue(toNumber(aVal) + toNumber(bVal))) + // Use the Number interface for arithmetic + stack.Push(aVal.Add(bVal)) return nil } @@ -249,7 +249,7 @@ func (o *Operations) Subtract(stack *Stack) error { return fmt.Errorf("insufficient operands for -: %w", err) } - stack.Push(NewNumberValue(toNumber(a) - toNumber(b))) + stack.Push(a.Sub(b)) return nil } @@ -265,7 +265,7 @@ func (o *Operations) Multiply(stack *Stack) error { return fmt.Errorf("insufficient operands for *: %w", err) } - stack.Push(NewNumberValue(toNumber(a) * toNumber(b))) + stack.Push(a.Mul(b)) return nil } @@ -276,16 +276,20 @@ func (o *Operations) Divide(stack *Stack) error { return fmt.Errorf("insufficient operands for /: %w", err) } + if b.IsZero() { + return fmt.Errorf("division by zero") + } + a, err := stack.Pop() if err != nil { return fmt.Errorf("insufficient operands for /: %w", err) } - if toNumber(b) == 0 { - return fmt.Errorf("division by zero") + result, err := a.Div(b) + if err != nil { + return fmt.Errorf("division error: %w", err) } - - stack.Push(NewNumberValue(toNumber(a) / toNumber(b))) + stack.Push(result) return nil } @@ -301,7 +305,7 @@ func (o *Operations) Power(stack *Stack) error { return fmt.Errorf("insufficient operands for ^: %w", err) } - stack.Push(NewNumberValue(math.Pow(toNumber(a), toNumber(b)))) + stack.Push(a.Pow(b)) return nil } @@ -317,11 +321,15 @@ func (o *Operations) Modulo(stack *Stack) error { return fmt.Errorf("insufficient operands for %%: %w", err) } - if toNumber(b) == 0 { + if b.IsZero() { return fmt.Errorf("modulo by zero") } - stack.Push(NewNumberValue(math.Mod(toNumber(a), toNumber(b)))) + result, err := a.Mod(b) + if err != nil { + return fmt.Errorf("modulo error: %w", err) + } + stack.Push(result) return nil } @@ -332,11 +340,14 @@ func (o *Operations) Log2(stack *Stack) error { return fmt.Errorf("insufficient operands for lg: %w", err) } - if toNumber(a) <= 0 { + // Check if value is zero or negative + val := a.Float64() + if val <= 0 { return fmt.Errorf("log2 undefined for non-positive numbers") } - stack.Push(NewNumberValue(math.Log2(toNumber(a)))) + // Compute log2 using the number interface + stack.Push(NewNumber(math.Log2(val), o.mode)) return nil } @@ -347,11 +358,14 @@ func (o *Operations) Log10(stack *Stack) error { return fmt.Errorf("insufficient operands for log: %w", err) } - if toNumber(a) <= 0 { + // Check if value is zero or negative + val := a.Float64() + if val <= 0 { return fmt.Errorf("log10 undefined for non-positive numbers") } - stack.Push(NewNumberValue(math.Log10(toNumber(a)))) + // Compute log10 using the number interface + stack.Push(NewNumber(math.Log10(val), o.mode)) return nil } @@ -362,11 +376,14 @@ func (o *Operations) Ln(stack *Stack) error { return fmt.Errorf("insufficient operands for ln: %w", err) } - if toNumber(a) <= 0 { + // Check if value is zero or negative + val := a.Float64() + if val <= 0 { return fmt.Errorf("ln undefined for non-positive numbers") } - stack.Push(NewNumberValue(math.Log(toNumber(a)))) + // Compute ln using the number interface + stack.Push(NewNumber(math.Log(val), o.mode)) return nil } @@ -379,7 +396,7 @@ func (o *Operations) HyperAdd(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -393,12 +410,12 @@ func (o *Operations) HyperAdd(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative with toNumber coercion + // Process left-associative with Number interface sum := 0.0 for i := 0; i < len(values); i++ { - sum += toNumber(values[i]) + sum += values[i].Float64() } - stack.Push(NewNumberValue(sum)) + stack.Push(NewNumber(sum, o.mode)) return nil } @@ -414,9 +431,9 @@ func (o *Operations) HyperMultiply(stack *Stack) error { if err != nil { return fmt.Errorf("hypermultiply: %w", err) } - product *= toNumber(val) + product *= val.Float64() } - stack.Push(NewNumberValue(product)) + stack.Push(NewNumber(product, o.mode)) return nil } @@ -427,7 +444,7 @@ func (o *Operations) HyperSubtract(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -441,12 +458,12 @@ func (o *Operations) HyperSubtract(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative with toNumber coercion - result := toNumber(values[0]) + // Process left-associative with Number interface + result := values[0].Float64() for i := 1; i < len(values); i++ { - result -= toNumber(values[i]) + result -= values[i].Float64() } - stack.Push(NewNumberValue(result)) + stack.Push(NewNumber(result, o.mode)) return nil } @@ -457,7 +474,7 @@ func (o *Operations) HyperDivide(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -471,15 +488,16 @@ func (o *Operations) HyperDivide(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative with toNumber coercion - result := toNumber(values[0]) + // Process left-associative with Number interface + result := values[0].Float64() for i := 1; i < len(values); i++ { - if toNumber(values[i]) == 0 { + val := values[i].Float64() + if val == 0 { return fmt.Errorf("division by zero") } - result /= toNumber(values[i]) + result /= val } - stack.Push(NewNumberValue(result)) + stack.Push(NewNumber(result, o.mode)) return nil } @@ -490,7 +508,7 @@ func (o *Operations) HyperPower(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -504,12 +522,12 @@ func (o *Operations) HyperPower(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative with toNumber coercion - result := toNumber(values[0]) + // Process left-associative with Number interface + result := values[0].Float64() for i := 1; i < len(values); i++ { - result = math.Pow(result, toNumber(values[i])) + result = math.Pow(result, values[i].Float64()) } - stack.Push(NewNumberValue(result)) + stack.Push(NewNumber(result, o.mode)) return nil } @@ -520,7 +538,7 @@ func (o *Operations) HyperModulo(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -534,15 +552,16 @@ func (o *Operations) HyperModulo(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Process left-associative with toNumber coercion - result := toNumber(values[0]) + // Process left-associative with Number interface + result := values[0].Float64() for i := 1; i < len(values); i++ { - if toNumber(values[i]) == 0 { + val := values[i].Float64() + if val == 0 { return fmt.Errorf("modulo by zero") } - result = math.Mod(result, toNumber(values[i])) + result = math.Mod(result, val) } - stack.Push(NewNumberValue(result)) + stack.Push(NewNumber(result, o.mode)) return nil } @@ -554,7 +573,7 @@ func (o *Operations) HyperLog2(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -568,15 +587,18 @@ func (o *Operations) HyperLog2(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the log2 of all values with toNumber coercion + // Sum the log2 of all values with Number interface var result float64 = 0 for i := 0; i < len(values); i++ { - if toNumber(values[i]) <= 0 { + val := values[i].Float64() + if val <= 0 { return fmt.Errorf("hyperlog2 undefined for non-positive numbers") } - result += math.Log2(toNumber(values[i])) + result += math.Log2(val) } - stack.Push(NewNumberValue(result)) + + // Push the result as a Number + stack.Push(NewNumber(result, o.mode)) return nil } @@ -588,7 +610,7 @@ func (o *Operations) HyperLog10(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -602,15 +624,18 @@ func (o *Operations) HyperLog10(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the log10 of all values with toNumber coercion + // Sum the log10 of all values var result float64 = 0 for i := 0; i < len(values); i++ { - if toNumber(values[i]) <= 0 { + val := values[i].Float64() + if val <= 0 { return fmt.Errorf("hyperlog10 undefined for non-positive numbers") } - result += math.Log10(toNumber(values[i])) + result += math.Log10(val) } - stack.Push(NewNumberValue(result)) + + // Push the result as a Number + stack.Push(NewNumber(result, o.mode)) return nil } @@ -622,7 +647,7 @@ func (o *Operations) HyperLn(stack *Stack) error { } // Pop all values into a slice (in reverse order - top first) - var values []Value + var values []Number for stack.Len() > 0 { val, err := stack.Pop() if err != nil { @@ -636,15 +661,16 @@ func (o *Operations) HyperLn(stack *Stack) error { values[i], values[j] = values[j], values[i] } - // Sum the natural log of all values with toNumber coercion + // Sum the natural log of all values with Number interface var result float64 = 0 for i := 0; i < len(values); i++ { - if toNumber(values[i]) <= 0 { + val := values[i].Float64() + if val <= 0 { return fmt.Errorf("hyperln undefined for non-positive numbers") } - result += math.Log(toNumber(values[i])) + result += math.Log(val) } - stack.Push(NewNumberValue(result)) + stack.Push(NewNumber(result, o.mode)) return nil } @@ -662,7 +688,7 @@ func (o *Operations) GT(stack *Stack) error { return fmt.Errorf("insufficient operands for gt: %w", err) } - stack.Push(NewBoolValue(toNumber(a) > toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() > b.Float64())) return nil } @@ -678,7 +704,7 @@ func (o *Operations) LT(stack *Stack) error { return fmt.Errorf("insufficient operands for lt: %w", err) } - stack.Push(NewBoolValue(toNumber(a) < toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() < b.Float64())) return nil } @@ -694,7 +720,7 @@ func (o *Operations) GTE(stack *Stack) error { return fmt.Errorf("insufficient operands for gte: %w", err) } - stack.Push(NewBoolValue(toNumber(a) >= toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() >= b.Float64())) return nil } @@ -710,7 +736,7 @@ func (o *Operations) LTE(stack *Stack) error { return fmt.Errorf("insufficient operands for lte: %w", err) } - stack.Push(NewBoolValue(toNumber(a) <= toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() <= b.Float64())) return nil } @@ -726,7 +752,7 @@ func (o *Operations) EQ(stack *Stack) error { return fmt.Errorf("insufficient operands for eq: %w", err) } - stack.Push(NewBoolValue(toNumber(a) == toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() == b.Float64())) return nil } @@ -742,7 +768,7 @@ func (o *Operations) NEQ(stack *Stack) error { return fmt.Errorf("insufficient operands for neq: %w", err) } - stack.Push(NewBoolValue(toNumber(a) != toNumber(b))) + stack.Push(NewFloatFromBool(a.Float64() != b.Float64())) return nil } @@ -830,8 +856,8 @@ func (o *Operations) AssignVariable(stack *Stack, name string) error { return err } - // Convert Value to float64 for variable storage - return o.vars.SetVariable(name, toNumber(val)) + // Convert Number to float64 for variable storage + return o.vars.SetVariable(name, val.Float64()) } // UseVariable pushes a variable's value onto the stack. @@ -846,7 +872,7 @@ func (o *Operations) UseVariable(stack *Stack, name string) error { return fmt.Errorf("%w: %s", ErrVariableNotFound, name) } - stack.Push(NewNumberValue(val)) + stack.Push(NewNumber(val, o.mode)) return nil } diff --git a/internal/rpn/operations_test.go b/internal/rpn/operations_test.go index 02e07c3..dc70ebe 100644 --- a/internal/rpn/operations_test.go +++ b/internal/rpn/operations_test.go @@ -23,9 +23,9 @@ func TestStackNewStack(t *testing.T) { func TestStackPushPop(t *testing.T) { s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) if s.Len() != 3 { t.Errorf("Length after 3 pushes = %d, want 3", s.Len()) @@ -35,7 +35,7 @@ func TestStackPushPop(t *testing.T) { if err != nil { t.Fatalf("Pop() returned error: %v", err) } - if val.Number() != 3.0 { + if val.Float64() != 3.0 { t.Errorf("Pop() = %v, want 3.0", val) } @@ -46,13 +46,13 @@ func TestStackPushPop(t *testing.T) { func TestStackPeek(t *testing.T) { s := NewStack() - s.Push(NewNumberValue(5.0)) + s.Push(NewNumber(5.0, FloatMode)) val, err := s.Peek() if err != nil { t.Fatalf("Peek() returned error: %v", err) } - if val.Number() != 5.0 { + if val.Float64() != 5.0 { t.Errorf("Peek() = %v, want 5.0", val) } @@ -83,9 +83,9 @@ func TestStackPopEmpty(t *testing.T) { func TestStackValues(t *testing.T) { s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) vals := s.Values() if len(vals) != 3 { @@ -94,16 +94,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].Number() != 1.0 || vals[1].Number() != 2.0 || vals[2].Number() != 3.0 { + if vals[0].Float64() != 1.0 || vals[1].Float64() != 2.0 || vals[2].Float64() != 3.0 { t.Errorf("Values() = %v, want [1 2 3] (bottom-to-top)", vals) } } func TestStackClear(t *testing.T) { s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) s.Clear() @@ -116,8 +116,8 @@ func TestOperationsAdd(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(3.0)) - s.Push(NewNumberValue(4.0)) + s.Push(NewNumber(3.0, FloatMode)) + s.Push(NewNumber(4.0, FloatMode)) err := o.Add(s) if err != nil { @@ -128,7 +128,7 @@ func TestOperationsAdd(t *testing.T) { if err != nil { t.Fatalf("Pop() after Add() returned error: %v", err) } - if val.Number() != 7.0 { + if val.Float64() != 7.0 { t.Errorf("Add result = %v, want 7.0", val) } } @@ -137,8 +137,8 @@ func TestOperationsSubtract(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(10.0)) - s.Push(NewNumberValue(4.0)) + s.Push(NewNumber(10.0, FloatMode)) + s.Push(NewNumber(4.0, FloatMode)) err := o.Subtract(s) if err != nil { @@ -149,7 +149,7 @@ func TestOperationsSubtract(t *testing.T) { if err != nil { t.Fatalf("Pop() after Subtract() returned error: %v", err) } - if val.Number() != 6.0 { + if val.Float64() != 6.0 { t.Errorf("Subtract result = %v, want 6.0 (10 - 4)", val) } } @@ -158,8 +158,8 @@ func TestOperationsMultiply(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(5.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(5.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) err := o.Multiply(s) if err != nil { @@ -170,7 +170,7 @@ func TestOperationsMultiply(t *testing.T) { if err != nil { t.Fatalf("Pop() after Multiply() returned error: %v", err) } - if val.Number() != 15.0 { + if val.Float64() != 15.0 { t.Errorf("Multiply result = %v, want 15.0", val) } } @@ -179,8 +179,8 @@ func TestOperationsDivide(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(20.0)) - s.Push(NewNumberValue(4.0)) + s.Push(NewNumber(20.0, FloatMode)) + s.Push(NewNumber(4.0, FloatMode)) err := o.Divide(s) if err != nil { @@ -191,7 +191,7 @@ func TestOperationsDivide(t *testing.T) { if err != nil { t.Fatalf("Pop() after Divide() returned error: %v", err) } - if val.Number() != 5.0 { + if val.Float64() != 5.0 { t.Errorf("Divide result = %v, want 5.0", val) } } @@ -200,8 +200,8 @@ func TestOperationsDivideByZero(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(10.0)) - s.Push(NewNumberValue(0.0)) + s.Push(NewNumber(10.0, FloatMode)) + s.Push(NewNumber(0.0, FloatMode)) err := o.Divide(s) if err == nil { @@ -216,8 +216,8 @@ func TestOperationsPower(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) err := o.Power(s) if err != nil { @@ -228,7 +228,7 @@ func TestOperationsPower(t *testing.T) { if err != nil { t.Fatalf("Pop() after Power() returned error: %v", err) } - if val.Number() != 8.0 { + if val.Float64() != 8.0 { t.Errorf("Power result = %v, want 8.0 (2^3)", val) } } @@ -237,8 +237,8 @@ func TestOperationsModulo(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(10.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(10.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) err := o.Modulo(s) if err != nil { @@ -249,7 +249,7 @@ func TestOperationsModulo(t *testing.T) { if err != nil { t.Fatalf("Pop() after Modulo() returned error: %v", err) } - if val.Number() != 1.0 { + if val.Float64() != 1.0 { t.Errorf("Modulo result = %v, want 1.0 (10 %% 3)", val) } } @@ -258,8 +258,8 @@ func TestOperationsModuloByZero(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(10.0)) - s.Push(NewNumberValue(0.0)) + s.Push(NewNumber(10.0, FloatMode)) + s.Push(NewNumber(0.0, FloatMode)) err := o.Modulo(s) if err == nil { @@ -271,7 +271,7 @@ func TestOperationsInsufficientOperands(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(5.0)) + s.Push(NewNumber(5.0, FloatMode)) // Try to add with only one operand err := o.Add(s) @@ -284,7 +284,7 @@ func TestOperationsDup(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(7.0)) + s.Push(NewNumber(7.0, FloatMode)) err := o.Dup(s) if err != nil { @@ -297,7 +297,7 @@ func TestOperationsDup(t *testing.T) { val1, _ := s.Pop() val2, _ := s.Pop() - if val1.Number() != 7.0 || val2.Number() != 7.0 { + if val1.Float64() != 7.0 || val2.Float64() != 7.0 { t.Errorf("Dup values = %v, %v, want both 7.0", val1, val2) } } @@ -306,8 +306,8 @@ func TestOperationsSwap(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) err := o.Swap(s) if err != nil { @@ -316,7 +316,7 @@ func TestOperationsSwap(t *testing.T) { val1, _ := s.Pop() val2, _ := s.Pop() - if val1.Number() != 1.0 || val2.Number() != 2.0 { + if val1.Float64() != 1.0 || val2.Float64() != 2.0 { t.Errorf("After Swap, values = %v, %v, want 1.0, 2.0 (swapped)", val1, val2) } } @@ -325,7 +325,7 @@ func TestOperationsSwapInsufficient(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(5.0)) + s.Push(NewNumber(5.0, FloatMode)) err := o.Swap(s) if err == nil { @@ -337,9 +337,9 @@ func TestOperationsPop(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) err := o.Pop(s) if err != nil { @@ -366,9 +366,9 @@ func TestOperationsShow(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(1.0)) - s.Push(NewNumberValue(2.0)) - s.Push(NewNumberValue(3.0)) + s.Push(NewNumber(1.0, FloatMode)) + s.Push(NewNumber(2.0, FloatMode)) + s.Push(NewNumber(3.0, FloatMode)) result, err := o.Show(s) if err != nil { @@ -399,7 +399,7 @@ func TestOperationsAssignVariable(t *testing.T) { v := NewVariables() o := NewOperations(v) s := NewStack() - s.Push(NewNumberValue(5.0)) + s.Push(NewNumber(5.0, FloatMode)) err := o.AssignVariable(s, "x") if err != nil { @@ -449,7 +449,7 @@ func TestOperationsUseVariable(t *testing.T) { if err != nil { t.Fatalf("Pop() after UseVariable() returned error: %v", err) } - if val.Number() != 3.14159 { + if val.Float64() != 3.14159 { t.Errorf("Variable value pushed to stack = %v, want 3.14159", val) } } @@ -545,7 +545,7 @@ func TestOperationsConcurrent(t *testing.T) { go func(id int) { name := fmt.Sprintf("concurrent%d", id) s := NewStack() - s.Push(NewNumberValue(float64(id))) + s.Push(NewNumber(float64(id), FloatMode)) if err := o.AssignVariable(s, name); err != nil { t.Errorf("AssignVariable() returned error: %v", err) } @@ -567,7 +567,7 @@ func TestLog2(t *testing.T) { stack := NewStack() // Test log₂(8) = 3 - stack.Push(NewNumberValue(8)) + stack.Push(NewNumber(8, FloatMode)) err := o.Log2(stack) if err != nil { t.Errorf("Log2() returned error: %v", err) @@ -576,12 +576,12 @@ func TestLog2(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val.Number() != 3.0 { - t.Errorf("Log2(8) = %f, want 3.0)", val.Number()) + if val.Float64() != 3.0 { + t.Errorf("Log2(8) = %f, want 3.0)", val.Float64()) } // Test log₂(1) = 0 - stack.Push(NewNumberValue(1)) + stack.Push(NewNumber(1.0, FloatMode)) err = o.Log2(stack) if err != nil { t.Errorf("Log2(1) returned error: %v", err) @@ -590,12 +590,12 @@ func TestLog2(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val.Number() != 0.0 { - t.Errorf("Log2(1) = %f, want 0.0)", val.Number()) + if val.Float64() != 0.0 { + t.Errorf("Log2(1) = %f, want 0.0)", val.Float64()) } // Test log₂(0) should error - stack.Push(NewNumberValue(0)) + stack.Push(NewNumber(0.0, FloatMode)) err = o.Log2(stack) if err == nil { t.Errorf("Log2(0) should return error, got nil") @@ -607,7 +607,7 @@ func TestLog10(t *testing.T) { stack := NewStack() // Test log₁₀(100) = 2 - stack.Push(NewNumberValue(100)) + stack.Push(NewNumber(100.0, FloatMode)) err := o.Log10(stack) if err != nil { t.Errorf("Log10() returned error: %v", err) @@ -616,12 +616,12 @@ func TestLog10(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val.Number() != 2.0 { - t.Errorf("Log10(100) = %f, want 2.0)", val.Number()) + if val.Float64() != 2.0 { + t.Errorf("Log10(100) = %f, want 2.0)", val.Float64()) } // Test log₁₀(1) = 0 - stack.Push(NewNumberValue(1)) + stack.Push(NewNumber(1.0, FloatMode)) err = o.Log10(stack) if err != nil { t.Errorf("Log10(1) returned error: %v", err) @@ -630,8 +630,8 @@ func TestLog10(t *testing.T) { if err != nil { t.Errorf("Pop() returned error: %v", err) } - if val.Number() != 0.0 { - t.Errorf("Log10(1) = %f, want 0.0)", val.Number()) + if val.Float64() != 0.0 { + t.Errorf("Log10(1) = %f, want 0.0)", val.Float64()) } } @@ -640,7 +640,7 @@ func TestLn(t *testing.T) { stack := NewStack() // Test ln(e) ≈ 1 - stack.Push(NewNumberValue(math.E)) + stack.Push(NewNumber(math.E, FloatMode)) er |
