summaryrefslogtreecommitdiff
path: root/internal/repl
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-23 20:17:01 +0300
committerPaul Buetow <paul@buetow.org>2026-05-23 20:17:01 +0300
commitd02c4ff623141704489f41088ca861e75a632b87 (patch)
treed7de9adc38f6b68df3ad9ab5a29f645d68794dba /internal/repl
parent8988ba5e03a61825f644841789b8654c233e1936 (diff)
refactor: remove Calculator/RPNCalculator passthrough adapter (KISS)
Delete internal/repl/calculator.go which defined the Calculator interface and RPNCalculator adapter. Every method delegated directly to *rpn.RPN with zero transformation — unnecessary indirection. RPNState now holds *rpn.RPN directly instead of the Calculator interface. Updated NewRPNState, NewREPL, handleRatCommand, and RPNHandler.Handle() to access *rpn.RPN directly. Removes 71 net lines, zero behavioral changes.
Diffstat (limited to 'internal/repl')
-rw-r--r--internal/repl/calculator.go61
-rw-r--r--internal/repl/concurrent_test.go9
-rw-r--r--internal/repl/handlers.go26
-rw-r--r--internal/repl/repl.go17
-rw-r--r--internal/repl/repl_test.go22
5 files changed, 32 insertions, 103 deletions
diff --git a/internal/repl/calculator.go b/internal/repl/calculator.go
deleted file mode 100644
index 7843577..0000000
--- a/internal/repl/calculator.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright (c) 2026 Paul Buetow
-
-package repl
-
-import (
- "codeberg.org/snonux/gt/internal/rpn"
-)
-
-// Calculator defines the interface for RPN calculation operations.
-// This interface abstracts the RPN engine to decouple the REPL from specific
-// RPN implementation details.
-type Calculator interface {
- // ParseAndEvaluate parses and evaluates an RPN expression.
- // Returns the result string and any error encountered.
- ParseAndEvaluate(input string) (string, error)
-
- // EvalOperator evaluates a single RPN operator on the current stack.
- // Returns the result string and any error encountered.
- EvalOperator(op string) (string, error)
-
- // GetMode returns the current calculation mode.
- GetMode() rpn.CalculationMode
-
- // SetMode sets the calculation mode.
- SetMode(mode rpn.CalculationMode)
-}
-
-// RPNCalculator is an adapter that wraps an rpn.RPN instance to implement Calculator.
-type RPNCalculator struct {
- rpnCalc *rpn.RPN
-}
-
-// NewRPNCalculator creates a new RPNCalculator that wraps the given RPN instance.
-func NewRPNCalculator(rpnCalc *rpn.RPN) *RPNCalculator {
- return &RPNCalculator{rpnCalc: rpnCalc}
-}
-
-// ParseAndEvaluate parses and evaluates an RPN expression.
-// Implements Calculator interface.
-func (c *RPNCalculator) ParseAndEvaluate(input string) (string, error) {
- return c.rpnCalc.ParseAndEvaluate(input)
-}
-
-// EvalOperator evaluates a single RPN operator on the current stack.
-// Implements Calculator interface.
-func (c *RPNCalculator) EvalOperator(op string) (string, error) {
- return c.rpnCalc.EvalOperator(op)
-}
-
-// GetMode returns the current calculation mode.
-// Implements Calculator interface.
-func (c *RPNCalculator) GetMode() rpn.CalculationMode {
- return c.rpnCalc.GetMode()
-}
-
-// SetMode sets the calculation mode.
-// Implements Calculator interface.
-func (c *RPNCalculator) SetMode(mode rpn.CalculationMode) {
- c.rpnCalc.SetMode(mode)
-}
diff --git a/internal/repl/concurrent_test.go b/internal/repl/concurrent_test.go
index d4065ff..501b363 100644
--- a/internal/repl/concurrent_test.go
+++ b/internal/repl/concurrent_test.go
@@ -16,13 +16,12 @@ func TestConcurrentExecutor(t *testing.T) {
defer wg.Done()
vars := rpn.NewVariables()
rpnCalc := rpn.NewRPN(vars)
- calculator := NewRPNCalculator(rpnCalc)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: calculator},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
defaultExecutor(rpl, "20% of 150")
}(i)
@@ -54,13 +53,12 @@ func TestConcurrentRatModeToggle(t *testing.T) {
defer wg.Done()
vars := rpn.NewVariables()
rpnCalc := rpn.NewRPN(vars)
- calculator := NewRPNCalculator(rpnCalc)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: calculator},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
defaultExecutor(rpl, "rat toggle")
}(i)
@@ -77,13 +75,12 @@ func TestConcurrentExecutorAndRPN(t *testing.T) {
defer wg.Done()
vars := rpn.NewVariables()
rpnCalc := rpn.NewRPN(vars)
- calculator := NewRPNCalculator(rpnCalc)
rpl := &REPL{
ttyChecker: &TTYChecker{},
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: calculator},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
defaultExecutor(rpl, "20% of 150")
}(i)
diff --git a/internal/repl/handlers.go b/internal/repl/handlers.go
index 737ae71..5e568a3 100644
--- a/internal/repl/handlers.go
+++ b/internal/repl/handlers.go
@@ -104,22 +104,21 @@ func handleRatCommand(repl *REPL, input string) (string, bool, error) {
}
modeArg := strings.ToLower(args[1])
- rpnState := repl.rpnState
- calculator := rpnState.calculator
+ rpnCalc := repl.rpnState.rpnCalc
switch modeArg {
case "on":
- calculator.SetMode(rpn.RationalMode)
+ rpnCalc.SetMode(rpn.RationalMode)
return "Rational mode enabled", true, nil
case "off":
- calculator.SetMode(rpn.FloatMode)
+ rpnCalc.SetMode(rpn.FloatMode)
return "Rational mode disabled (using float64)", true, nil
case "toggle":
- if calculator.GetMode() == rpn.FloatMode {
- calculator.SetMode(rpn.RationalMode)
+ if rpnCalc.GetMode() == rpn.FloatMode {
+ rpnCalc.SetMode(rpn.RationalMode)
return "Rational mode enabled", true, nil
} else {
- calculator.SetMode(rpn.FloatMode)
+ rpnCalc.SetMode(rpn.FloatMode)
return "Rational mode disabled (using float64)", true, nil
}
default:
@@ -152,7 +151,7 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
if strings.HasPrefix(lowerInput, "rpn ") || strings.HasPrefix(lowerInput, "calc ") {
// Extract the expression after rpn/calc
rest := strings.TrimSpace(strings.TrimPrefix(input, strings.SplitN(input, " ", 2)[0]))
- result, err := repl.rpnState.calculator.ParseAndEvaluate(rest)
+ result, err := repl.rpnState.rpnCalc.ParseAndEvaluate(rest)
if err != nil {
return "", true, err
}
@@ -160,11 +159,10 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
}
// Try RPN parsing first (for bare RPN expressions like "3 4 +")
- if state := repl.rpnState; state != nil {
- calculator := state.calculator
+ if repl.rpnState != nil {
// Check if input looks like RPN (contains spaces or is a single known operator)
if strings.Contains(input, " ") {
- result, err := calculator.ParseAndEvaluate(input)
+ result, err := repl.rpnState.rpnCalc.ParseAndEvaluate(input)
if err == nil {
return result, true, nil
}
@@ -182,7 +180,7 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
op == "[lg]" || op == "[log]" || op == "[ln]"
if isStandardOp || isHyperOp {
- result, err := calculator.EvalOperator(op)
+ result, err := repl.rpnState.rpnCalc.EvalOperator(op)
if err != nil {
return "", true, err
}
@@ -195,7 +193,7 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
if _, err := strconv.ParseFloat(fields[0], 64); err == nil {
// Push the number onto the RPN stack using ParseAndEvaluate
// This maintains the RPN state across multiple inputs in REPL mode
- result, err := calculator.ParseAndEvaluate(fields[0])
+ result, err := repl.rpnState.rpnCalc.ParseAndEvaluate(fields[0])
if err != nil {
return "", true, err
}
@@ -208,7 +206,7 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
token := fields[0]
if len(token) > 0 && token[0] == ':' {
// This is a symbol syntax like :x
- result, err := calculator.ParseAndEvaluate(token)
+ result, err := repl.rpnState.rpnCalc.ParseAndEvaluate(token)
if err != nil {
return "", true, err
}
diff --git a/internal/repl/repl.go b/internal/repl/repl.go
index 842abbf..29314eb 100644
--- a/internal/repl/repl.go
+++ b/internal/repl/repl.go
@@ -16,26 +16,22 @@ import (
)
// RPNState holds the state for RPN (Reverse Polish Notation) operations in the REPL.
-// It maintains a variable store and calculator instance.
+// It maintains a variable store and RPN engine.
//
// Note: This struct should never be copied - use pointer receivers only.
type RPNState struct {
vars rpn.VariableStore
- calculator Calculator
+ rpnCalc *rpn.RPN
varStoreFile string // Path to persistent variable store file
}
-// NewRPNState creates a new RPNState with the given variable store and calculator.
+// NewRPNState creates a new RPNState with the given variable store and RPN engine.
// It also configures the variable store file path in the user's config directory.
-//
-// vars: the VariableStore instance to use
-// calculator: the Calculator instance for RPN operations
-// Returns a new RPNState instance with configured variable store file path
-func NewRPNState(vars rpn.VariableStore, calculator Calculator) *RPNState {
+func NewRPNState(vars rpn.VariableStore, rpnCalc *rpn.RPN) *RPNState {
varStoreFile := getVarStoreFilePath()
return &RPNState{
vars: vars,
- calculator: calculator,
+ rpnCalc: rpnCalc,
varStoreFile: varStoreFile,
}
}
@@ -176,8 +172,7 @@ func NewREPL(executor func(string), completer func() []string, logWriter io.Writ
}
rpnCalc := rpn.NewRPN(vars)
- calculator := NewRPNCalculator(rpnCalc)
- rpnState := NewRPNState(vars, calculator)
+ rpnState := NewRPNState(vars, rpnCalc)
repl := &REPL{
ttyChecker: &TTYChecker{},
diff --git a/internal/repl/repl_test.go b/internal/repl/repl_test.go
index 830102f..a242956 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, calculator: NewRPNCalculator(rpn.NewRPN(vars))},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpn.NewRPN(vars)},
}
}
@@ -414,7 +414,7 @@ func TestExecutorWithRatModeOn(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
defaultExecutor(rpl, "rat on")
if rpnCalc.GetMode() != rpn.RationalMode {
@@ -431,7 +431,7 @@ func TestExecutorWithRatModeOff(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
defaultExecutor(rpl, "rat off")
if rpnCalc.GetMode() != rpn.FloatMode {
@@ -448,7 +448,7 @@ func TestExecutorWithRatModeToggle(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// First toggle
@@ -493,7 +493,7 @@ func TestExecutorWithAssignmentRight(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// Test := operator
@@ -526,7 +526,7 @@ func TestExecutorWithAssignmentAfterCalculation(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// Test that assignment works after a calculation
@@ -549,7 +549,7 @@ func TestExecutorWithIncrementalAssignment(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// Test that assignment works after a calculation
@@ -576,7 +576,7 @@ func TestExecutorWithSimpleIncrementalAssignment(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// First execute 2 to put it on the stack
@@ -602,7 +602,7 @@ func TestExecutorWithExactUserScenario(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// This test replicates the exact user interaction:
@@ -634,7 +634,7 @@ func TestExecutorWithExactUserScenarioWithOutput(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// Clear any previous state
@@ -666,7 +666,7 @@ func TestExecutorWithExactUserScenarioDirect(t *testing.T) {
historyMgr: NewHistoryManager(".gt_history"),
signalHandler: NewSignalHandler(),
commandChain: NewCommandChain(),
- rpnState: &RPNState{vars: vars, calculator: NewRPNCalculator(rpnCalc)},
+ rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
// Clear any previous state