From a3d3b676796f93f41f5b44b1d2b86b15f99080a0 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 25 Mar 2026 17:57:54 +0200 Subject: Fix Ln operation and add comprehensive tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed Ln operation to handle Value conversion before math.Log using Float64() which handles boolean conversion (true → 1, false → 0) - Added TestLnWithBoolean and TestLnEdgeCases tests for comprehensive coverage - Refactored operations.go into separate files (arithmetic.go, boolean_ops.go, hyper.go, stack.go, variable.go) - Removed unused toNumber function from number.go - Added Float64() method to Value struct for boolean conversion --- internal/rpn/boolean_ops.go | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 internal/rpn/boolean_ops.go (limited to 'internal/rpn/boolean_ops.go') diff --git a/internal/rpn/boolean_ops.go b/internal/rpn/boolean_ops.go new file mode 100644 index 0000000..d07aa26 --- /dev/null +++ b/internal/rpn/boolean_ops.go @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Paul Buetow + +package rpn + +import ( + "fmt" +) + +// BooleanOperations provides boolean comparison operator implementations. +type BooleanOperations struct { +} + +// NewBooleanOperations creates a new BooleanOperations instance. +func NewBooleanOperations() *BooleanOperations { + return &BooleanOperations{} +} + +// GT pops two values from stack, compares (a > b), and pushes a boolean result. +func (o *BooleanOperations) GT(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for gt: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for gt: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() > b.Float64())) + return nil +} + +// LT pops two values from stack, compares (a < b), and pushes a boolean result. +func (o *BooleanOperations) LT(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for lt: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for lt: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() < b.Float64())) + return nil +} + +// GTE pops two values from stack, compares (a >= b), and pushes a boolean result. +func (o *BooleanOperations) GTE(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for gte: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for gte: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() >= b.Float64())) + return nil +} + +// LTE pops two values from stack, compares (a <= b), and pushes a boolean result. +func (o *BooleanOperations) LTE(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for lte: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for lte: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() <= b.Float64())) + return nil +} + +// EQ pops two values from stack, compares (a == b), and pushes a boolean result. +func (o *BooleanOperations) EQ(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for eq: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for eq: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() == b.Float64())) + return nil +} + +// NEQ pops two values from stack, compares (a != b), and pushes a boolean result. +func (o *BooleanOperations) NEQ(stack *Stack) error { + b, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for neq: %w", err) + } + + a, err := stack.Pop() + if err != nil { + return fmt.Errorf("insufficient operands for neq: %w", err) + } + + stack.Push(NewFloatFromBool(a.Float64() != b.Float64())) + return nil +} -- cgit v1.2.3