summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-24 18:50:00 +0300
committerPaul Buetow <paul@buetow.org>2026-05-24 18:50:00 +0300
commitdc89fa2bbcdea7c8847828f64be5e46ddded33fb (patch)
tree67dd57478d39d9e75ccfcb576f5651bf53896379
parent4188db97bcb771c1c8790ddbac2db3f9ee8884c3 (diff)
fix(rpn): change variadic NewRPN/NewOperations to single optional MetricReader (task ok)
-rw-r--r--cmd/gt/main.go2
-rw-r--r--internal/repl/concurrent_test.go10
-rw-r--r--internal/repl/repl.go2
-rw-r--r--internal/repl/repl_test.go24
-rw-r--r--internal/repl/rpnstate_test.go10
-rw-r--r--internal/rpn/assignment_test.go52
-rw-r--r--internal/rpn/boolean_test.go8
-rw-r--r--internal/rpn/compare_metric_test.go8
-rw-r--r--internal/rpn/constants_test.go26
-rw-r--r--internal/rpn/custom_metric_test.go24
-rw-r--r--internal/rpn/metric_test.go18
-rw-r--r--internal/rpn/operations.go6
-rw-r--r--internal/rpn/operations_fastpower_test.go2
-rw-r--r--internal/rpn/operations_hyper_test.go6
-rw-r--r--internal/rpn/operations_metric_cmd_test.go50
-rw-r--r--internal/rpn/operations_stack_test.go20
-rw-r--r--internal/rpn/operations_test.go96
-rw-r--r--internal/rpn/rpn_state.go4
-rw-r--r--internal/rpn/rpn_state_test.go16
-rw-r--r--internal/rpn/rpn_test.go62
20 files changed, 223 insertions, 223 deletions
diff --git a/cmd/gt/main.go b/cmd/gt/main.go
index 85292fb..3203c34 100644
--- a/cmd/gt/main.go
+++ b/cmd/gt/main.go
@@ -170,7 +170,7 @@ func runREPL() error {
// making it suitable for one-off calculations.
func runRPN(input string) (string, error) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
// Strip "rpn " or "calc " prefix if present
input = strings.TrimSpace(input)
diff --git a/internal/repl/concurrent_test.go b/internal/repl/concurrent_test.go
index 501b363..62bf7dc 100644
--- a/internal/repl/concurrent_test.go
+++ b/internal/repl/concurrent_test.go
@@ -15,7 +15,7 @@ func TestConcurrentExecutor(t *testing.T) {
go func(id int) {
defer wg.Done()
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -37,7 +37,7 @@ func TestConcurrentRPN(t *testing.T) {
go func(id int) {
defer wg.Done()
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
_, _ = rpnCalc.ParseAndEvaluate("3 4 +")
}(i)
}
@@ -52,7 +52,7 @@ func TestConcurrentRatModeToggle(t *testing.T) {
go func(id int) {
defer wg.Done()
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -74,7 +74,7 @@ func TestConcurrentExecutorAndRPN(t *testing.T) {
go func(id int) {
defer wg.Done()
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -87,7 +87,7 @@ func TestConcurrentExecutorAndRPN(t *testing.T) {
go func(id int) {
defer wg.Done()
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
_, _ = rpnCalc.ParseAndEvaluate("3 4 +")
}(i)
}
diff --git a/internal/repl/repl.go b/internal/repl/repl.go
index 2ecd9ea..451b6c3 100644
--- a/internal/repl/repl.go
+++ b/internal/repl/repl.go
@@ -179,7 +179,7 @@ func NewREPL(executor func(string), completer func() []string, logWriter io.Writ
fmt.Printf("Warning: Could not load saved variables: %v\n", err)
}
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpnState := NewRPNState(vars, rpnCalc)
repl := &REPL{
diff --git a/internal/repl/repl_test.go b/internal/repl/repl_test.go
index f8e22a2..a7fd2f8 100644
--- a/internal/repl/repl_test.go
+++ b/internal/repl/repl_test.go
@@ -18,7 +18,7 @@ func createTestREPL() *REPL {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, rpnCalc: rpn.NewRPN(vars)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpn.NewRPN(vars, nil)},
}
}
@@ -186,7 +186,7 @@ func TestRunRPN(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
input := strings.TrimSpace(tt.input)
if strings.HasPrefix(input, "rpn ") {
@@ -408,7 +408,7 @@ func TestExecutorWithCalcPrefixMixed(t *testing.T) {
// TestExecutorWithRatModeOn tests that rat on works with fresh REPL
func TestExecutorWithRatModeOn(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -425,7 +425,7 @@ func TestExecutorWithRatModeOn(t *testing.T) {
// TestExecutorWithRatModeOff tests that rat off works with fresh REPL
func TestExecutorWithRatModeOff(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -442,7 +442,7 @@ func TestExecutorWithRatModeOff(t *testing.T) {
// TestExecutorWithRatModeToggle tests that rat toggle works with fresh REPL
func TestExecutorWithRatModeToggle(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -487,7 +487,7 @@ func TestIsBuiltinCommandWithSubcommandHelp(t *testing.T) {
// TestExecutorWithAssignmentRight tests := and =: operators
func TestExecutorWithAssignmentRight(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -520,7 +520,7 @@ func TestExecutorWithAssignmentRight(t *testing.T) {
// TestExecutorWithAssignmentAfterCalculation tests assignment after a calculation
func TestExecutorWithAssignmentAfterCalculation(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -543,7 +543,7 @@ func TestExecutorWithAssignmentAfterCalculation(t *testing.T) {
// TestExecutorWithIncrementalAssignment tests that assignment works after a calculation with separate commands
func TestExecutorWithIncrementalAssignment(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -570,7 +570,7 @@ func TestExecutorWithIncrementalAssignment(t *testing.T) {
// TestExecutorWithSimpleIncrementalAssignment tests x =: after 2 in REPL
func TestExecutorWithSimpleIncrementalAssignment(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -596,7 +596,7 @@ func TestExecutorWithSimpleIncrementalAssignment(t *testing.T) {
// TestExecutorWithExactUserScenario tests the exact user scenario: 2 then x =:
func TestExecutorWithExactUserScenario(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -628,7 +628,7 @@ func TestExecutorWithExactUserScenario(t *testing.T) {
// TestExecutorWithExactUserScenarioWithOutput tests that x =: assigns and shows result
func TestExecutorWithExactUserScenarioWithOutput(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
@@ -660,7 +660,7 @@ func TestExecutorWithExactUserScenarioWithOutput(t *testing.T) {
// TestExecutorWithExactUserScenarioDirect simulates REPL input flow
func TestExecutorWithExactUserScenarioDirect(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
diff --git a/internal/repl/rpnstate_test.go b/internal/repl/rpnstate_test.go
index 1d54dea..80c7f65 100644
--- a/internal/repl/rpnstate_test.go
+++ b/internal/repl/rpnstate_test.go
@@ -14,7 +14,7 @@ import (
func TestNewRPNState(t *testing.T) {
vars := rpn.NewVariables()
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
state := NewRPNState(vars, rpnCalc)
if state == nil {
t.Fatal("NewRPNState() returned nil")
@@ -25,7 +25,7 @@ func TestRPNStateLoadVariablesEmpty(t *testing.T) {
// When varStoreFile is empty, LoadVariables should return nil
state := &RPNState{
vars: rpn.NewVariables(),
- rpnCalc: rpn.NewRPN(rpn.NewVariables()),
+ rpnCalc: rpn.NewRPN(rpn.NewVariables(), nil),
varStoreFile: "",
}
err := state.LoadVariables()
@@ -37,7 +37,7 @@ func TestRPNStateLoadVariablesEmpty(t *testing.T) {
func TestRPNStateSaveVariablesEmpty(t *testing.T) {
state := &RPNState{
vars: rpn.NewVariables(),
- rpnCalc: rpn.NewRPN(rpn.NewVariables()),
+ rpnCalc: rpn.NewRPN(rpn.NewVariables(), nil),
varStoreFile: "",
}
err := state.SaveVariables()
@@ -70,7 +70,7 @@ func TestRPNStateSaveLoadRoundTrip(t *testing.T) {
vars.SetVariable("x", 42.0)
vars.SetVariable("y", 3.14)
- rpnCalc := rpn.NewRPN(vars)
+ rpnCalc := rpn.NewRPN(vars, nil)
state := &RPNState{
vars: vars,
rpnCalc: rpnCalc,
@@ -91,7 +91,7 @@ func TestRPNStateSaveLoadRoundTrip(t *testing.T) {
newVars := rpn.NewVariables()
newState := &RPNState{
vars: newVars,
- rpnCalc: rpn.NewRPN(newVars),
+ rpnCalc: rpn.NewRPN(newVars, nil),
varStoreFile: varStorePath,
}
diff --git a/internal/rpn/assignment_test.go b/internal/rpn/assignment_test.go
index 82d4a12..f9f4a3e 100644
--- a/internal/rpn/assignment_test.go
+++ b/internal/rpn/assignment_test.go
@@ -11,7 +11,7 @@ import (
// TestAssignmentStandard tests standard assignment 'x 5 ='
func TestAssignmentStandard(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("x 5 =")
if err != nil {
@@ -33,7 +33,7 @@ func TestAssignmentStandard(t *testing.T) {
// TestAssignmentRight tests right assignment '5 x :='
func TestAssignmentRight(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("5 x :=")
if err != nil {
@@ -55,7 +55,7 @@ func TestAssignmentRight(t *testing.T) {
// TestAssignmentLeft tests left assignment '5 x =:'
func TestAssignmentLeft(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("5 x =:")
if err != nil {
@@ -77,7 +77,7 @@ func TestAssignmentLeft(t *testing.T) {
// TestAssignmentReassignment tests variable reassignment
func TestAssignmentReassignment(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("x 5 =")
if err != nil {
@@ -104,7 +104,7 @@ func TestAssignmentReassignment(t *testing.T) {
// TestAssignmentInExpression tests assignment used in an expression
func TestAssignmentInExpression(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// 'x 5 = x 2 +' should assign x=5, then push x and 2, then add: 5 + 2 = 7
result, err := rpn.ParseAndEvaluate("x 5 = x 2 +")
@@ -119,7 +119,7 @@ func TestAssignmentInExpression(t *testing.T) {
// TestAssignmentMultipleVariables tests multiple variable assignments
func TestAssignmentMultipleVariables(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, _ = rpn.ParseAndEvaluate("x 5 =")
_, _ = rpn.ParseAndEvaluate("y 10 =")
@@ -146,7 +146,7 @@ func TestAssignmentMultipleVariables(t *testing.T) {
// TestAssignmentArithmeticWithVariable tests arithmetic using assigned variable
func TestAssignmentArithmeticWithVariable(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, _ = rpn.ParseAndEvaluate("x 5 =")
@@ -163,7 +163,7 @@ func TestAssignmentArithmeticWithVariable(t *testing.T) {
// TestAssignmentNegativeValue tests assignment with negative value
func TestAssignmentNegativeValue(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("x -5 =")
if err != nil {
@@ -182,7 +182,7 @@ func TestAssignmentNegativeValue(t *testing.T) {
// TestAssignmentDecimalValue tests assignment with decimal value
func TestAssignmentDecimalValue(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("x 3.14 =")
if err != nil {
@@ -201,7 +201,7 @@ func TestAssignmentDecimalValue(t *testing.T) {
// TestAssignmentUnderscoreVariable tests assignment with underscore variable
func TestAssignmentUnderscoreVariable(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("my_var 42 =")
if err != nil {
@@ -220,7 +220,7 @@ func TestAssignmentUnderscoreVariable(t *testing.T) {
// TestAssignmentWithCalculationResult tests assigning result of calculation
func TestAssignmentWithCalculationResult(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// 3 4 + x =: should push 3, 4, add (=7), then assign 7 to x
_, err := rpn.ParseAndEvaluate("3 4 + x =:")
@@ -240,7 +240,7 @@ func TestAssignmentWithCalculationResult(t *testing.T) {
// TestAssignmentAllOperatorsInSequence tests all three assignment operators
func TestAssignmentAllOperatorsInSequence(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, _ = rpn.ParseAndEvaluate("a 1 =") // standard
_, _ = rpn.ParseAndEvaluate("2 b :=") // right
@@ -260,7 +260,7 @@ func TestAssignmentAllOperatorsInSequence(t *testing.T) {
// TestAssignmentOperatorRegistry verifies all assignment operators are registered
func TestAssignmentOperatorRegistry(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
reg := NewOperatorRegistry(ops)
// Verify assignment operators are registered as standard operators
@@ -278,7 +278,7 @@ func TestAssignmentOperatorRegistry(t *testing.T) {
// TestAssignmentNotTriggeredByEqualEqual ensures that == is not misparsed as an assignment.
func TestAssignmentNotTriggeredByEqualEqual(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// "a == b" should NOT be treated as an assignment
_, err := rpn.ParseAndEvaluate("a == b")
@@ -297,7 +297,7 @@ func TestAssignmentNotTriggeredByEqualEqual(t *testing.T) {
// TestAssignmentNotTriggeredByNotEqual ensures that != is not misparsed as an assignment.
func TestAssignmentNotTriggeredByNotEqual(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// "a != b" should NOT be treated as an assignment
_, err := rpn.ParseAndEvaluate("a != b")
@@ -311,7 +311,7 @@ func TestAssignmentNotTriggeredByNotEqual(t *testing.T) {
// TestAssignmentAfterEqualEqual ensures "x 5 =" still works even when == exists in the expression.
func TestAssignmentAfterEqualEqual(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// A standalone assignment should work regardless of == elsewhere
result, err := rpn.ParseAndEvaluate("x 5 =")
@@ -342,7 +342,7 @@ func TestAssignRightOperator(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
result, err := r.ParseAndEvaluate(tt.expr)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) error = %v", tt.expr, err)
@@ -367,7 +367,7 @@ func TestAssignLeftOperator(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
result, err := r.ParseAndEvaluate(tt.expr)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) error = %v", tt.expr, err)
@@ -393,7 +393,7 @@ func TestStandardAssignOperator(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
result, err := r.ParseAndEvaluate(tt.expr)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) error = %v", tt.expr, err)
@@ -421,7 +421,7 @@ func TestVariableInExpression(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
_, err := r.ParseAndEvaluate(tt.setup)
if err != nil {
t.Fatalf("Setup failed for %q: %v", tt.setup, err)
@@ -439,7 +439,7 @@ func TestVariableInExpression(t *testing.T) {
// TestChainedAssignments tests chaining multiple assignments in one expression.
func TestChainedAssignments(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
result, err := r.ParseAndEvaluate("a 10 := b 3 := c 2 :=")
if err != nil {
t.Fatalf("Chained assignment failed: %v", err)
@@ -472,7 +472,7 @@ func TestChainedAssignments(t *testing.T) {
// TestVarsCommand tests the vars command.
func TestVarsCommand(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
// Empty vars
result, err := r.ParseAndEvaluate("vars")
@@ -501,7 +501,7 @@ func TestVarsCommand(t *testing.T) {
// TestClearCommand tests the clear command.
func TestClearCommand(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
r.ParseAndEvaluate("x 5 :=")
r.ParseAndEvaluate("y 10 :=")
@@ -521,7 +521,7 @@ func TestClearCommand(t *testing.T) {
// TestDeleteVariableOperator tests the d (delete) operator.
func TestDeleteVariableOperator(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
// Create variable
r.ParseAndEvaluate("x 5 :=")
@@ -544,7 +544,7 @@ func TestDeleteVariableOperator(t *testing.T) {
// TestDeleteNonExistentVariableOperator tests deleting a variable that doesn't exist.
func TestDeleteNonExistentVariableOperator(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
_, err := r.ParseAndEvaluate(":nonexistent d")
if err == nil {
t.Error("Deleting non-existent variable should return error")
@@ -554,7 +554,7 @@ func TestDeleteNonExistentVariableOperator(t *testing.T) {
// TestVariablePersistenceAcrossExpressions tests that variables persist across
// multiple ParseAndEvaluate calls on the same RPN instance.
func TestVariablePersistenceAcrossExpressions(t *testing.T) {
- r := NewRPN(NewVariables())
+ r := NewRPN(NewVariables(), nil)
r.ParseAndEvaluate("a 10 :=")
r.ParseAndEvaluate("b 3 :=")
diff --git a/internal/rpn/boolean_test.go b/internal/rpn/boolean_test.go
index f0ced89..6eea269 100644
--- a/internal/rpn/boolean_test.go
+++ b/internal/rpn/boolean_test.go
@@ -98,7 +98,7 @@ func TestBooleanOperators(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
@@ -163,7 +163,7 @@ func TestBooleanToNumberCoercion(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
@@ -221,7 +221,7 @@ func TestMixedBooleanNumericArithmetic(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
@@ -268,7 +268,7 @@ func TestBooleanShowFormat(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
diff --git a/internal/rpn/compare_metric_test.go b/internal/rpn/compare_metric_test.go
index e1b5134..d32ac60 100644
--- a/internal/rpn/compare_metric_test.go
+++ b/internal/rpn/compare_metric_test.go
@@ -177,7 +177,7 @@ func TestMetricAwareComparisons(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
if tt.prefixMode == IEC {
rpnCalc.SetPrefixMode(IEC)
@@ -282,7 +282,7 @@ func TestShorthandComparisonOperators(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
@@ -356,7 +356,7 @@ func TestIncompatibleCategoryComparison(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
_, err := rpnCalc.ParseAndEvaluate(tt.expression)
@@ -414,7 +414,7 @@ func TestMetricComparisonEdgeCases(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
if tt.prefixMode == IEC {
rpnCalc.SetPrefixMode(IEC)
diff --git a/internal/rpn/constants_test.go b/internal/rpn/constants_test.go
index 68b79d1..4eb2129 100644
--- a/internal/rpn/constants_test.go
+++ b/internal/rpn/constants_test.go
@@ -213,7 +213,7 @@ func TestConstants_ThreadSafety(t *testing.T) {
func TestConstants_RetrieveInRPN(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test pi constant
result, err := r.ParseAndEvaluate("pi")
@@ -226,7 +226,7 @@ func TestConstants_RetrieveInRPN(t *testing.T) {
// Create a new RPN instance for each test to avoid stack state conflicts
v2 := NewVariables()
- r2 := NewRPN(v2)
+ r2 := NewRPN(v2, nil)
// Test e constant
result, err = r2.ParseAndEvaluate("e")
@@ -239,7 +239,7 @@ func TestConstants_RetrieveInRPN(t *testing.T) {
// Create a new RPN instance for the next test
v3 := NewVariables()
- r3 := NewRPN(v3)
+ r3 := NewRPN(v3, nil)
// Test pi in expression
result, err = r3.ParseAndEvaluate("pi 2 *")
@@ -252,7 +252,7 @@ func TestConstants_RetrieveInRPN(t *testing.T) {
// Create a new RPN instance for phi test
v4 := NewVariables()
- r4 := NewRPN(v4)
+ r4 := NewRPN(v4, nil)
// Test phi constant
result, err = r4.ParseAndEvaluate("phi")
@@ -266,7 +266,7 @@ func TestConstants_RetrieveInRPN(t *testing.T) {
func TestConstants_RetrieveWithGreekLetters(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test pi with Greek letter
result, err := r.ParseAndEvaluate("π")
@@ -279,7 +279,7 @@ func TestConstants_RetrieveWithGreekLetters(t *testing.T) {
// Create a new RPN instance for phi test
v2 := NewVariables()
- r2 := NewRPN(v2)
+ r2 := NewRPN(v2, nil)
// Test phi with Greek letter
result, err = r2.ParseAndEvaluate("φ")
@@ -293,7 +293,7 @@ func TestConstants_RetrieveWithGreekLetters(t *testing.T) {
func TestConstants_ConflictWithVariables(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// First set a variable named pi
result, err := r.ParseAndEvaluate("pi = 3.0")
@@ -316,7 +316,7 @@ func TestConstants_ConflictWithVariables(t *testing.T) {
func TestConstantsCommand(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate("constants")
if err != nil {
t.Fatalf("ParseAndEvaluate(\"constants\") returned error: %v", err)
@@ -328,7 +328,7 @@ func TestConstantsCommand(t *testing.T) {
func TestClearConstantsCommand(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// First add a custom constant
result, err := r.ParseAndEvaluate("custom 42 =")
@@ -409,7 +409,7 @@ func TestConstants_NewConstants(t *testing.T) {
// TestConstants_ParseInRPN tests that new constants can be used in RPN expressions
func TestConstants_ParseInRPN(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
tests := []struct {
expression string
@@ -532,7 +532,7 @@ func TestConstants_MoreInRPN(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate(tt.expression)
if err != nil {
@@ -567,7 +567,7 @@ func TestConstants_ListConstantsIncludesUserDefined(t *testing.T) {
// TestConstants_NegativeInfInRPN tests negative infinity constant in RPN
func TestConstants_NegativeInfInRPN(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
result, err := rpnCalc.ParseAndEvaluate("-inf")
if err != nil {
@@ -581,7 +581,7 @@ func TestConstants_NegativeInfInRPN(t *testing.T) {
// TestConstants_InfExpression tests infinity in RPN expressions
func TestConstants_InfExpression(t *testing.T) {
vars := NewVariables()
- rpnCalc := NewRPN(vars)
+ rpnCalc := NewRPN(vars, nil)
// inf 1 + should still be inf
result, err := rpnCalc.ParseAndEvaluate("inf 1 +")
diff --git a/internal/rpn/custom_metric_test.go b/internal/rpn/custom_metric_test.go
index e555cee..47ece0f 100644
--- a/internal/rpn/custom_metric_test.go
+++ b/internal/rpn/custom_metric_test.go
@@ -20,7 +20,7 @@ func customCleanup(t *testing.T, rpn *RPN, name string) {
// TestCustomDefineFactorZero tests defining a custom metric with factor=0
func TestCustomDefineFactorZero(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "zero")
result, err := rpn.ParseAndEvaluate("custom define zero 0 Custom")
@@ -42,7 +42,7 @@ func TestCustomDefineFactorZero(t *testing.T) {
// TestCustomDefineNegativeFactor tests defining a custom metric with negative factor
func TestCustomDefineNegativeFactor(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "negtest")
result, err := rpn.ParseAndEvaluate("custom define negtest -5 Custom")
@@ -64,7 +64,7 @@ func TestCustomDefineNegativeFactor(t *testing.T) {
// TestCustomDefineMalformedInput tests that malformed custom define input
func TestCustomDefineMalformedInput(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom define 1 Custom")
// Double-space collapses: fields = ["custom", "define", "1", "Custom"] (metric "" already exists as alias or empty check)
@@ -78,7 +78,7 @@ func TestCustomDefineMalformedInput(t *testing.T) {
// that conflicts with an existing metric
func TestCustomDefineConflictingAlias(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Try to define a metric with a name that matches an existing one
_, err := rpn.ParseAndEvaluate("custom define Mbps 1000 DataRate")
@@ -90,7 +90,7 @@ func TestCustomDefineConflictingAlias(t *testing.T) {
// TestCustomMetricArithmetic tests using a custom metric in arithmetic operations
func TestCustomMetricArithmetic(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "arithmetic_test")
_, err := rpn.ParseAndEvaluate("custom define arithmetic_test 42 Custom")
@@ -109,7 +109,7 @@ func TestCustomMetricArithmetic(t *testing.T) {
// TestCustomMetricHyperOperations tests using a custom metric in hyper operations
func TestCustomMetricHyperOperations(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "hyper_test")
_, err := rpn.ParseAndEvaluate("custom define hyper_test 100 Custom")
@@ -128,7 +128,7 @@ func TestCustomMetricHyperOperations(t *testing.T) {
// TestCustomMetricSubtraction tests subtraction with custom metrics
func TestCustomMetricSubtraction(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "sub_test")
_, err := rpn.ParseAndEvaluate("custom define sub_test 10 Custom")
@@ -146,7 +146,7 @@ func TestCustomMetricSubtraction(t *testing.T) {
// TestCustomMetricMultiplication tests multiplication with custom metrics
func TestCustomMetricMultiplication(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "mul_test")
_, err := rpn.ParseAndEvaluate("custom define mul_test 5 Custom")
@@ -164,7 +164,7 @@ func TestCustomMetricMultiplication(t *testing.T) {
// TestCustomMetricDivision tests division with custom metrics
func TestCustomMetricDivision(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "div_test")
_, err := rpn.ParseAndEvaluate("custom define div_test 10 Custom")
@@ -183,7 +183,7 @@ func TestCustomMetricDivision(t *testing.T) {
// between different categories
func TestCustomMetricConversionFail(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "conv_test")
_, err := rpn.ParseAndEvaluate("custom define conv_test 10 Custom")
@@ -202,7 +202,7 @@ func TestCustomMetricConversionFail(t *testing.T) {
// can't be mixed in operations
func TestCustomMetricCrossCategory(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "cat_test1")
defer customCleanup(t, rpn, "cat_test2")
@@ -219,7 +219,7 @@ func TestCustomMetricCrossCategory(t *testing.T) {
// TestCustomMetricShow tests that custom metrics display correctly in Show
func TestCustomMetricShow(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "show_test")
_, err := rpn.ParseAndEvaluate("custom define show_test 100 Custom")
diff --git a/internal/rpn/metric_test.go b/internal/rpn/metric_test.go
index 69923cb..5a41f6f 100644
--- a/internal/rpn/metric_test.go
+++ b/internal/rpn/metric_test.go
@@ -832,7 +832,7 @@ func TestAtPrefixMetricParsing(t *testing.T) {
func TestAtPrefixIntegration(t *testing.T) {
// Test that @GB parses correctly through the full RPN pipeline
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Parse a standalone @ metric
result, err := rpn.ParseAndEvaluate("@GB")
@@ -880,7 +880,7 @@ func TestMetricAwareArithmetic(t *testing.T) {
for _, tt := range tests {
t.Run(tt.expr, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate(tt.expr)
if tt.wantErr {
if err == nil {
@@ -985,7 +985,7 @@ func TestMetricOperationsUnit(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
s := NewStack()
tc.setup(s)
@@ -1040,7 +1040,7 @@ func TestConvertSameCategory(t *testing.T) {
for _, tt := range tests {
t.Run(tt.expr, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate(tt.expr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -1064,7 +1064,7 @@ func TestConvertSameCategory(t *testing.T) {
func TestConvertCoolAbsorbing(t *testing.T) {
reg := GetMetricRegistry()
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Cool to metric: 100 @GB convert → 100 GB
// With Cool absorption, 100 is treated as 100 in GB's space
@@ -1086,7 +1086,7 @@ func TestConvertCoolAbsorbing(t *testing.T) {
}
// Metric to Cool: 1hr @Cool convert → 3600 Cool
- rpn2 := NewRPN(NewVariables())
+ rpn2 := NewRPN(NewVariables(), nil)
result2, err := rpn2.ParseAndEvaluate("1hr @Cool convert")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -1107,7 +1107,7 @@ func TestConvertCoolAbsorbing(t *testing.T) {
func TestConvertIncompatible(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("100Mbps @hr convert")
if err == nil {
@@ -1121,7 +1121,7 @@ func TestConvertIncompatible(t *testing.T) {
func TestConvertInsufficientOperands(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Missing value (only target on stack)
_, err := rpn.ParseAndEvaluate("@Gbps convert")
@@ -1130,7 +1130,7 @@ func TestConvertInsufficientOperands(t *testing.T) {
}
// Missing target (only value on stack, no @X before convert)
- rpn2 := NewRPN(NewVariables())
+ rpn2 := NewRPN(NewVariables(), nil)
_, err = rpn2.ParseAndEvaluate("100Mbps convert")
if err == nil {
t.Error("expected error for missing target metric operand")
diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go
index 989ce87..3a85ee5 100644
--- a/internal/rpn/operations.go
+++ b/internal/rpn/operations.go
@@ -38,10 +38,10 @@ var (
// NewOperations creates a new Operations instance with the given variable store.
// Does not create a ConstantsProvider internally; caller must use SetConstants.
// If no registry is provided, defaults to the global MetricRegistry.
-func NewOperations(vars VariableStore, reg ...MetricReader) *Operations {
+func NewOperations(vars VariableStore, reg MetricReader) *Operations {
r := MetricReader(GetMetricRegistry())
- if len(reg) > 0 && reg[0] != nil {
- r = reg[0]
+ if reg != nil {
+ r = reg
}
return &Operations{
vars: vars,
diff --git a/internal/rpn/operations_fastpower_test.go b/internal/rpn/operations_fastpower_test.go
index 06a79e0..cdd4c04 100644
--- a/internal/rpn/operations_fastpower_test.go
+++ b/internal/rpn/operations_fastpower_test.go
@@ -70,7 +70,7 @@ func TestFastPower(t *testing.T) {
stack := NewStack()
tt.prepare(stack)
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
err := o.FastPower(stack)
if tt.wantErr {
diff --git a/internal/rpn/operations_hyper_test.go b/internal/rpn/operations_hyper_test.go
index 352e503..2a1607a 100644
--- a/internal/rpn/operations_hyper_test.go
+++ b/internal/rpn/operations_hyper_test.go
@@ -81,7 +81,7 @@ func TestHyperMetricAwareOperations(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate(tc.expr)
if tc.wantErr {
if err == nil {
@@ -162,7 +162,7 @@ func TestHyperCoolResultOperations(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate(tc.expr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -198,7 +198,7 @@ func TestHyperErrorCases(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate(tc.expr)
if err == nil {
t.Fatal("expected error, got none")
diff --git a/internal/rpn/operations_metric_cmd_test.go b/internal/rpn/operations_metric_cmd_test.go
index e7307f7..ea9431d 100644
--- a/internal/rpn/operations_metric_cmd_test.go
+++ b/internal/rpn/operations_metric_cmd_test.go
@@ -11,7 +11,7 @@ import (
func TestMetricShow(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("100Mbps metric show")
if err != nil {
@@ -27,7 +27,7 @@ func TestMetricShow(t *testing.T) {
func TestMetricShowUniversal(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("42 metric show")
if err != nil {
@@ -43,7 +43,7 @@ func TestMetricShowUniversal(t *testing.T) {
func TestMetricShowEmptyStack(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("metric show")
if err == nil {
t.Error("expected error for empty stack")
@@ -52,7 +52,7 @@ func TestMetricShowEmptyStack(t *testing.T) {
func TestMetricList(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("metric list")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -67,7 +67,7 @@ func TestMetricList(t *testing.T) {
func TestMetricCategory(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("metric DataRate")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -82,7 +82,7 @@ func TestMetricCategory(t *testing.T) {
func TestMetricCategoryTime(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("metric Time")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -97,7 +97,7 @@ func TestMetricCategoryTime(t *testing.T) {
func TestMetricCategoryUnknown(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("metric Nope")
if err == nil {
t.Error("expected error for unknown category")
@@ -106,7 +106,7 @@ func TestMetricCategoryUnknown(t *testing.T) {
func TestMetricCategoryCustom(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Custom category exists but has no built-in metrics, so result should be empty
result, err := rpn.ParseAndEvaluate("metric Custom")
if err != nil {
@@ -118,7 +118,7 @@ func TestMetricCategoryCustom(t *testing.T) {
func TestMetricSetModeDecimal(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("metric decimal set")
if err != nil {
@@ -134,7 +134,7 @@ func TestMetricSetModeDecimal(t *testing.T) {
func TestMetricSetModeBinary(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("metric binary set")
if err != nil {
@@ -150,7 +150,7 @@ func TestMetricSetModeBinary(t *testing.T) {
func TestMetricSetModeToggle(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Default is SI
if rpn.GetPrefixMode() != SI {
@@ -172,7 +172,7 @@ func TestMetricSetModeToggle(t *testing.T) {
func TestMetricSetModeBinaryIncomplete(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("metric binary")
if err == nil {
t.Error("expected error for incomplete 'metric binary'")
@@ -181,7 +181,7 @@ func TestMetricSetModeBinaryIncomplete(t *testing.T) {
func TestMetricSetModeDecimalIncomplete(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("metric decimal")
if err == nil {
t.Error("expected error for incomplete 'metric decimal'")
@@ -190,7 +190,7 @@ func TestMetricSetModeDecimalIncomplete(t *testing.T) {
func TestMetricCompatibleSameCategory(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("100Mbps 1Gbps metric compatible")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -202,7 +202,7 @@ func TestMetricCompatibleSameCategory(t *testing.T) {
func TestMetricCompatibleDifferentCategory(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("100Mbps 2hr metric compatible")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -221,7 +221,7 @@ func TestMetricCompatibleDifferentCategory(t *testing.T) {
func TestMetricCompatibleWithUniversal(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("100Mbps 42 metric compatible")
if err != nil {
t.Fatalf("unexpected error: %v", err)
@@ -234,7 +234,7 @@ func TestMetricCompatibleWithUniversal(t *testing.T) {
func TestMetricCompatibleNotEnoughValues(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("100 metric compatible")
if err == nil {
t.Error("expected error for insufficient stack values")
@@ -243,7 +243,7 @@ func TestMetricCompatibleNotEnoughValues(t *testing.T) {
func TestMetricCompatibleEmptyStack(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("metric compatible")
if err == nil {
t.Error("expected error for empty stack")
@@ -349,7 +349,7 @@ func TestPrefixMode(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
if tc.setMode == "iec" {
if _, err := rpn.ParseAndEvaluate("metric binary set"); err != nil {
@@ -383,7 +383,7 @@ func TestPrefixMode(t *testing.T) {
func TestCustomDefineAndList(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
// Define a custom metric
result, err := rpn.ParseAndEvaluate("custom define foobar 42 Custom")
@@ -421,7 +421,7 @@ func TestCustomDefineAndList(t *testing.T) {
func TestCustomDefineDuplicate(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom define Cool 1 Universal")
if err == nil {
t.Error("expected error for duplicate metric name")
@@ -430,7 +430,7 @@ func TestCustomDefineDuplicate(t *testing.T) {
func TestCustomDefineInvalidCategory(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom define foo 1 Nope")
if err == nil {
t.Error("expected error for invalid category")
@@ -439,7 +439,7 @@ func TestCustomDefineInvalidCategory(t *testing.T) {
func TestCustomUndefineBuiltIn(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom undefine Cool")
if err == nil {
t.Error("expected error for undefining built-in metric")
@@ -448,7 +448,7 @@ func TestCustomUndefineBuiltIn(t *testing.T) {
func TestCustomUndefineNotFound(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom undefine nonexistent")
if err == nil {
t.Error("expected error for undefining non-existent metric")
@@ -457,7 +457,7 @@ func TestCustomUndefineNotFound(t *testing.T) {
func TestCustomListEmpty(t *testing.T) {
vars := NewVariables()
- rpn := NewRPN(vars)
+ rpn := NewRPN(vars, nil)
result, err := rpn.ParseAndEvaluate("custom list")
if err != nil {
t.Fatalf("unexpected error: %v", err)
diff --git a/internal/rpn/operations_stack_test.go b/internal/rpn/operations_stack_test.go
index 7c0252c..7d74558 100644
--- a/internal/rpn/operations_stack_test.go
+++ b/internal/rpn/operations_stack_test.go
@@ -11,7 +11,7 @@ import (
func TestShowWithMetrics(t *testing.T) {
reg := GetMetricRegistry()
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
mbps, _ := reg.Find("Mbps")
@@ -39,7 +39,7 @@ func TestShowWithMetrics(t *testing.T) {
func TestShowEmptyStack(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
result, err := ops.Show(stack)
@@ -53,7 +53,7 @@ func TestShowEmptyStack(t *testing.T) {
func TestShowWithBooleanValues(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
stack.Push(NewFloatFromBool(true))
@@ -74,7 +74,7 @@ func TestShowWithBooleanValues(t *testing.T) {
func TestShowWithSymbols(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
stack.Push(NewSymbol("x"))
@@ -99,7 +99,7 @@ func TestShowWithSymbols(t *testing.T) {
func TestShowWithStringNum(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
stack.Push(NewStringNum("hello"))
@@ -120,7 +120,7 @@ func TestShowWithStringNum(t *testing.T) {
func TestShowWithMixedTypes(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
reg := GetMetricRegistry()
@@ -158,7 +158,7 @@ func TestShowWithMixedTypes(t *testing.T) {
func TestShowWithMultipleMetrics(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
reg := GetMetricRegistry()
@@ -187,7 +187,7 @@ func TestShowWithMultipleMetrics(t *testing.T) {
func TestShowWithRat(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
// Rational numbers
@@ -210,7 +210,7 @@ func TestShowWithRat(t *testing.T) {
func TestShowWithRatFromBool(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
stack.Push(NewRatFromBool(true))
@@ -231,7 +231,7 @@ func TestShowWithRatFromBool(t *testing.T) {
func TestShowValuesOrder(t *testing.T) {
vars := NewVariables()
- ops := NewOperations(vars)
+ ops := NewOperations(vars, nil)
stack := NewStack()
// Push in order: 1, 2, 3
diff --git a/internal/rpn/operations_test.go b/internal/rpn/operations_test.go
index 155a53d..77d2f54 100644
--- a/internal/rpn/operations_test.go
+++ b/internal/rpn/operations_test.go
@@ -124,7 +124,7 @@ func TestStackClear(t *testing.T) {
func TestOperationsAdd(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(3.0, FloatMode))
s.Push(NewNumber(4.0, FloatMode))
@@ -147,7 +147,7 @@ func TestOperationsAdd(t *testing.T) {
func TestOperationsSubtract(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(10.0, FloatMode))
s.Push(NewNumber(4.0, FloatMode))
@@ -170,7 +170,7 @@ func TestOperationsSubtract(t *testing.T) {
func TestOperationsMultiply(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(5.0, FloatMode))
s.Push(NewNumber(3.0, FloatMode))
@@ -193,7 +193,7 @@ func TestOperationsMultiply(t *testing.T) {
func TestOperationsDivide(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(20.0, FloatMode))
s.Push(NewNumber(4.0, FloatMode))
@@ -216,7 +216,7 @@ func TestOperationsDivide(t *testing.T) {
func TestOperationsDivideByZero(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(10.0, FloatMode))
s.Push(NewNumber(0.0, FloatMode))
@@ -232,7 +232,7 @@ func TestOperationsDivideByZero(t *testing.T) {
func TestOperationsPower(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(2.0, FloatMode))
s.Push(NewNumber(3.0, FloatMode))
@@ -255,7 +255,7 @@ func TestOperationsPower(t *testing.T) {
func TestOperationsPowerLargeExponent(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// Test 2^10 = 1024 (large exponent)
@@ -299,7 +299,7 @@ func TestOperationsPowerLargeExponent(t *testing.T) {
func TestOperationsPowerNegativeExponent(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// Test 2^-3 = 1/8 = 0.125
@@ -343,7 +343,7 @@ func TestOperationsPowerNegativeExponent(t *testing.T) {
func TestOperationsPowInt(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// Test PowInt(2, 10) = 1024
@@ -387,7 +387,7 @@ func TestOperationsPowInt(t *testing.T) {
func TestOperationsPowIntRat(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// Enable rational mode
@@ -435,7 +435,7 @@ func TestOperationsPowIntRat(t *testing.T) {
func TestOperationsModulo(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(10.0, FloatMode))
s.Push(NewNumber(3.0, FloatMode))
@@ -458,7 +458,7 @@ func TestOperationsModulo(t *testing.T) {
func TestOperationsModuloByZero(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(10.0, FloatMode))
s.Push(NewNumber(0.0, FloatMode))
@@ -471,7 +471,7 @@ func TestOperationsModuloByZero(t *testing.T) {
func TestOperationsInsufficientOperands(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(5.0, FloatMode))
@@ -484,7 +484,7 @@ func TestOperationsInsufficientOperands(t *testing.T) {
func TestOperationsDup(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(7.0, FloatMode))
@@ -513,7 +513,7 @@ func TestOperationsDup(t *testing.T) {
func TestOperationsSwap(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(1.0, FloatMode))
s.Push(NewNumber(2.0, FloatMode))
@@ -539,7 +539,7 @@ func TestOperationsSwap(t *testing.T) {
func TestOperationsSwapInsufficient(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(5.0, FloatMode))
@@ -551,7 +551,7 @@ func TestOperationsSwapInsufficient(t *testing.T) {
func TestOperationsPop(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(1.0, FloatMode))
s.Push(NewNumber(2.0, FloatMode))
@@ -569,7 +569,7 @@ func TestOperationsPop(t *testing.T) {
func TestOperationsPopEmpty(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
err := o.Pop(s)
@@ -580,7 +580,7 @@ func TestOperationsPopEmpty(t *testing.T) {
func TestOperationsShow(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(1.0, FloatMode))
s.Push(NewNumber(2.0, FloatMode))
@@ -598,7 +598,7 @@ func TestOperationsShow(t *testing.T) {
func TestOperationsShowEmpty(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
result, err := o.Show(s)
@@ -613,7 +613,7 @@ func TestOperationsShowEmpty(t *testing.T) {
func TestOperationsAssignVariable(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
s.Push(NewNumber(5.0, FloatMode))
@@ -638,7 +638,7 @@ func TestOperationsAssignVariable(t *testing.T) {
func TestOperationsAssignVariableEmptyName(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
err := o.AssignVariable(s, "")
@@ -649,7 +649,7 @@ func TestOperationsAssignVariableEmptyName(t *testing.T) {
func TestOperationsUseVariable(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
if err := v.SetVariable("pi", 3.14159); err != nil {
@@ -674,7 +674,7 @@ func TestOperationsUseVariable(t *testing.T) {
func TestOperationsUseVariableUndefined(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
err := o.UseVariable(s, "undefined")
@@ -688,7 +688,7 @@ func TestOperationsUseVariableUndefined(t *testing.T) {
func TestOperationsDeleteVariable(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
if err := v.SetVariable("temp", 100.0); err != nil {
t.Fatalf("SetVariable() returned error: %v", err)
@@ -707,7 +707,7 @@ func TestOperationsDeleteVariable(t *testing.T) {
func TestOperationsDeleteVariableUndefined(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
err := o.DeleteVariable("nonexistent")
if err == nil {
@@ -717,7 +717,7 @@ func TestOperationsDeleteVariableUndefined(t *testing.T) {
func TestOperationsListVariables(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
if err := v.SetVariable("x", 1.0); err != nil {
t.Fatalf("SetVariable() returned error: %v", err)
@@ -741,7 +741,7 @@ func TestOperationsListVariables(t *testing.T) {
func TestOperationsClearVariables(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
_, _ = v.SetVariable("x", 1.0), v.SetVariable("y", 2.0)
@@ -754,7 +754,7 @@ func TestOperationsClearVariables(t *testing.T) {
func TestOperationsConcurrent(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
// Test concurrent variable access
// Each goroutine uses its own stack to avoid race conditions
@@ -781,7 +781,7 @@ func TestOperationsConcurrent(t *testing.T) {
}
func TestLog2(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test log₂(8) = 3
@@ -825,7 +825,7 @@ func TestLog2(t *testing.T) {
}
func TestLog10(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test log₁₀(100) = 2
@@ -862,7 +862,7 @@ func TestLog10(t *testing.T) {
}
func TestLn(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test ln(e) ≈ 1
@@ -899,7 +899,7 @@ func TestLn(t *testing.T) {
}
func TestLog2WithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test with boolean true (should be converted to 1, log₂(1) = 0)
@@ -927,7 +927,7 @@ func TestLog2WithBoolean(t *testing.T) {
}
func TestLog10WithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test with boolean true (should be converted to 1, log₁₀(1) = 0)
@@ -955,7 +955,7 @@ func TestLog10WithBoolean(t *testing.T) {
}
func TestLnWithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test with boolean true (should be converted to 1, ln(1) = 0)
@@ -983,7 +983,7 @@ func TestLnWithBoolean(t *testing.T) {
}
func TestLnEdgeCases(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test ln(negative) should error
@@ -1018,7 +1018,7 @@ func TestLnEdgeCases(t *testing.T) {
}
func TestHyperLog2WithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperlog₂(4, true) = log₂(4) + log₂(1) = 2 + 0 = 2
@@ -1050,7 +1050,7 @@ func TestHyperLog2WithBoolean(t *testing.T) {
}
func TestHyperLog10WithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperlog₁₀(10, true) = log₁₀(10) + log₁₀(1) = 1 + 0 = 1
@@ -1081,7 +1081,7 @@ func TestHyperLog10WithBoolean(t *testing.T) {
}
func TestHyperLnWithBoolean(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperln(e, true) = ln(e) + ln(1) = 1 + 0 = 1
@@ -1112,7 +1112,7 @@ func TestHyperLnWithBoolean(t *testing.T) {
}
func TestHyperLog2(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperlog₂(4, 16) = log₂(4) + log₂(16) = 2 + 4 = 6
@@ -1141,7 +1141,7 @@ func TestHyperLog2(t *testing.T) {
}
func TestHyperLog10(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperlog₁₀(10, 100) = log₁₀(10) + log₁₀(100) = 1 + 2 = 3
@@ -1163,7 +1163,7 @@ func TestHyperLog10(t *testing.T) {
}
func TestHyperLn(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
stack := NewStack()
// Test hyperln(e, e²) = ln(e) + ln(e²) = 1 + 2 = 3
@@ -1185,7 +1185,7 @@ func TestHyperLn(t *testing.T) {
}
func TestOperatorRegistry(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
registry := NewOperatorRegistry(o)
// Test IsStandardOperator with valid operators
@@ -1221,7 +1221,7 @@ func TestOperatorRegistry(t *testing.T) {
}
func TestOperatorRegistryHandleStandardOperator(t *testing.T) {
- o := NewOperations(NewVariables())
+ o := NewOperations(NewVariables(), nil)
registry := NewOperatorRegistry(o)
stack := NewStack()
@@ -1266,7 +1266,7 @@ func TestOperatorRegistryHandleStandardOperator(t *testing.T) {
func TestAssignLeft(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// For "5 x =:":
@@ -1297,7 +1297,7 @@ func TestAssignLeft(t *testing.T) {
func TestAssignRight(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
// For "x 5 :=":
@@ -1328,7 +1328,7 @@ func TestAssignRight(t *testing.T) {
func TestAssignLeftErrorCases(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
err := o.AssignLeft(s)
@@ -1339,7 +1339,7 @@ func TestAssignLeftErrorCases(t *testing.T) {
func TestAssignRightErrorCases(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
s := NewStack()
err := o.AssignRight(s)
diff --git a/internal/rpn/rpn_state.go b/internal/rpn/rpn_state.go
index f2cc4ed..2d5c1ab 100644
--- a/internal/rpn/rpn_state.go
+++ b/internal/rpn/rpn_state.go
@@ -22,9 +22,9 @@ type RPN struct {
// NewRPN creates a new RPN parser and evaluator with the given variable store.
// If no registry is provided, defaults to the global MetricRegistry.
-func NewRPN(vars VariableStore, reg ...MetricReader) *RPN {
+func NewRPN(vars VariableStore, reg MetricReader) *RPN {
consts := NewConstants()
- ops := NewOperations(vars, reg...)
+ ops := NewOperations(vars, reg)
ops.SetMode(FloatMode) // Set default mode
ops.SetConstants(consts) // Share the same constants provider
return &RPN{
diff --git a/internal/rpn/rpn_state_test.go b/internal/rpn/rpn_state_test.go
index 42e5b70..d756f7c 100644
--- a/internal/rpn/rpn_state_test.go
+++ b/internal/rpn/rpn_state_test.go
@@ -9,7 +9,7 @@ import (
func TestRPNGetConstants(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
consts := r.GetConstants()
if consts == nil {
t.Fatal("GetConstants() returned nil")
@@ -26,7 +26,7 @@ func TestRPNGetConstants(t *testing.T) {
func TestRPNGetModeAndSetMode(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Default should be FloatMode
if r.GetMode() != FloatMode {
@@ -48,7 +48,7 @@ func TestRPNGetModeAndSetMode(t *testing.T) {
func TestRPNSetCurrentStack(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Start with empty stack
if got := r.GetCurrentStack(); len(got) != 0 {
@@ -76,7 +76,7 @@ func TestRPNSetCurrentStack(t *testing.T) {
func TestRPNStack(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
values := []StackValue{
NewNumber(42.0, FloatMode),
@@ -94,7 +94,7 @@ func TestRPNStack(t *testing.T) {
func TestRPNIsStandardOperator(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
tests := []struct {
token string
@@ -125,7 +125,7 @@ func TestRPNIsStandardOperator(t *testing.T) {
func TestRPNIsHyperOperator(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
tests := []struct {
token string
@@ -155,7 +155,7 @@ func TestRPNIsHyperOperator(t *testing.T) {
func TestOperationsMetricRegistry(t *testing.T) {
v := NewVariables()
- o := NewOperations(v)
+ o := NewOperations(v, nil)
reg := o.MetricRegistry()
if reg == nil {
@@ -174,7 +174,7 @@ func TestOperationsMetricRegistry(t *testing.T) {
func TestRPNSetPrefixMode(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Default should be SI
if r.GetPrefixMode() != SI {
diff --git a/internal/rpn/rpn_test.go b/internal/rpn/rpn_test.go
index bd8e0fa..085eb1c 100644
--- a/internal/rpn/rpn_test.go
+++ b/internal/rpn/rpn_test.go
@@ -11,7 +11,7 @@ import (
func TestNewRPN(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
if r == nil {
t.Fatal("NewRPN() returned nil")
}
@@ -102,7 +102,7 @@ func TestParseAndEvaluateSimple(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate(tt.input)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) returned error: %v", tt.input, err)
@@ -140,7 +140,7 @@ func TestParseAndEvaluateChain(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate(tt.input)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) returned error: %v", tt.input, err)
@@ -178,7 +178,7 @@ func TestParseAndEvaluateStackOps(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate(tt.input)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) returned error: %v", tt.input, err)
@@ -192,7 +192,7 @@ func TestParseAndEvaluateStackOps(t *testing.T) {
func TestParseAndEvaluateVariables(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test variable assignment and reuse
// First assign a variable
@@ -216,7 +216,7 @@ func TestParseAndEvaluateVariables(t *testing.T) {
func TestParseAndEvaluateEmpty(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate("")
if err == nil {
@@ -249,7 +249,7 @@ func TestParseAndEvaluateAssignment(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate(tt.input)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) returned error: %v", tt.input, err)
@@ -263,7 +263,7 @@ func TestParseAndEvaluateAssignment(t *testing.T) {
func TestParseAndEvaluateDivisionByZero(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate("5 0 /")
if err == nil {
@@ -276,7 +276,7 @@ func TestParseAndEvaluateDivisionByZero(t *testing.T) {
func TestParseAndEvaluateUndefinedVariable(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate("undefined +")
if err == nil {
@@ -290,7 +290,7 @@ func TestParseAndEvaluateUndefinedVariable(t *testing.T) {
func TestParseAndEvaluateUnknownToken(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate("1 2 + hello")
if err == nil {
@@ -314,7 +314,7 @@ func TestParseAndEvaluateInsufficientOperands(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate(tt.input)
if err == nil {
t.Errorf("%q should return error for insufficient operands", tt.input)
@@ -325,7 +325,7 @@ func TestParseAndEvaluateInsufficientOperands(t *testing.T) {
func TestParseAndEvaluateShow(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate("1 2 3 show")
if err != nil {
@@ -338,7 +338,7 @@ func TestParseAndEvaluateShow(t *testing.T) {
func TestParseAndEvaluateVars(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Set some variables using new format: "name = value"
if _, err := r.ParseAndEvaluate("x = 5"); err != nil {
@@ -359,7 +359,7 @@ func TestParseAndEvaluateVars(t *testing.T) {
func TestParseAndEvaluateClear(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Set and clear
if _, err := r.ParseAndEvaluate("x 5 ="); err != nil {
@@ -376,7 +376,7 @@ func TestParseAndEvaluateClear(t *testing.T) {
func TestRPNConcurrency(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
done := make(chan bool, 10)
for i := 0; i < 5; i++ {
@@ -399,7 +399,7 @@ func TestRPNConcurrency(t *testing.T) {
func TestResultStack(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
tokens := []string{"1", "2", "3", "+"}
result, err := r.ResultStack(tokens)
@@ -413,7 +413,7 @@ func TestResultStack(t *testing.T) {
func TestResultStackEmpty(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
tokens := []string{}
result, err := r.ResultStack(tokens)
@@ -452,7 +452,7 @@ func TestParseAndEvaluateAssignmentExpression(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
result, err := r.ParseAndEvaluate(tt.input)
if err != nil {
t.Fatalf("ParseAndEvaluate(%q) returned error: %v", tt.input, err)
@@ -496,7 +496,7 @@ func TestParseAndEvaluateAssignmentErrors(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate(tt.input)
if err == nil {
t.Errorf("ParseAndEvaluate(%q) expected error, got nil", tt.input)
@@ -546,7 +546,7 @@ func TestParseAndEvaluateEvaluateErrors(t *testing.T) {
}
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate(tt.input)
if err == nil {
t.Errorf("ParseAndEvaluate(%q) expected error, got nil", tt.input)
@@ -561,7 +561,7 @@ func TestParseAndEvaluateEvaluateErrors(t *testing.T) {
func TestResultStackErrors(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test error cases in ResultStack function
tests := []struct {
@@ -612,7 +612,7 @@ func TestResultStackErrors(t *testing.T) {
func TestResultStackMultipleValues(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test Case where stack has multiple values at the end
tests := []struct {
@@ -659,7 +659,7 @@ func TestResultStackMultipleValues(t *testing.T) {
func TestRPNIncrementalOperations(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// Test: 1 2 3 + then +
// First evaluate "1 2 3 +"
@@ -684,7 +684,7 @@ func TestRPNIncrementalOperations(t *testing.T) {
// TestIncrementalAssignmentRPN tests x =: with value on stack in ParseAndEvaluate
func TestIncrementalAssignmentRPN(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
// First, put 2 on the stack
result, err := r.ParseAndEvaluate("2")
@@ -753,7 +753,7 @@ func TestParseAndEvaluateAssignmentLeftRight(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := NewVariables()
- r := NewRPN(v)
+ r := NewRPN(v, nil)
_, err := r.ParseAndEvaluate(tt.input)
if err != nil {
@@ -775,7 +775,7 @@ func TestParseAndEvaluateAssignmentLeftRight(t *testing.T) {
// TestSymbolPush verifies that :x syntax pushes a symbol
func TestSymbolPush(t *testing.T) {
vars := NewVariables()
- r := NewRPN(vars)
+ r := NewRPN(vars, nil)
// Test :x syntax
result, err := r.ParseAndEvaluate(":x")
@@ -807,7 +807,7 @@ func TestSymbolPush(t *testing.T) {
// TestUnboundIdentifierAsSymbol verifies that unbound identifiers push symbols
func TestUnboundIdentifierAsSymbol(t *testing.T) {
vars := NewVariables()
- r := NewRPN(vars)
+ r := NewRPN(vars, nil)
// Use bare identifier x (unbound)
result, err := r.ParseAndEvaluate("x")
@@ -824,7 +824,7 @@ func TestUnboundIdentifierAsSymbol(t *testing.T) {
// TestBoundIdentifierPushesValue verifies that bound identifiers push values
func TestBoundIdentifierPushesValue(t *testing.T) {
vars := NewVariables()
- r := NewRPN(vars)
+ r := NewRPN(vars, nil)
// First bind x to 5
if _, err := r.ParseAndEvaluate("x = 5"); err != nil {
@@ -847,7 +847,7 @@ func TestBoundIdentifierPushesValue(t *testing.T) {
func TestSymbolWithAssignment(t *testing.T) {
// Test :x 10 := (symbol then value with right assignment)
vars := NewVariables()
- r := NewRPN(vars)
+ r := NewRPN(vars, nil)
_, err := r.ParseAndEvaluate(":x 10 :=")
if err != nil {
@@ -865,7 +865,7 @@ func TestSymbolWithAssignment(t *testing.T) {
// Test 10 :x =: (value then symbol with left assignment)
vars2 := NewVariables()
- r2 := NewRPN(vars2)
+ r2 := NewRPN(vars2, nil)
_, err = r2.ParseAndEvaluate("10 :x =:")
if err != nil {
@@ -884,7 +884,7 @@ func TestSymbolWithAssignment(t *testing.T) {
// TestStackBasedAssignmentWithSymbol verifies stack-based assignment with symbol
func TestStackBasedAssignmentWithSymbol(t *testing.T) {
vars := NewVariables()
- r := NewRPN(vars)
+ r := NewRPN(vars, nil)
// Push 42 onto stack
_, err := r.ParseAndEvaluate("42")