diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-23 20:17:01 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-23 20:17:01 +0300 |
| commit | d02c4ff623141704489f41088ca861e75a632b87 (patch) | |
| tree | d7de9adc38f6b68df3ad9ab5a29f645d68794dba /internal/repl | |
| parent | 8988ba5e03a61825f644841789b8654c233e1936 (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.go | 61 | ||||
| -rw-r--r-- | internal/repl/concurrent_test.go | 9 | ||||
| -rw-r--r-- | internal/repl/handlers.go | 26 | ||||
| -rw-r--r-- | internal/repl/repl.go | 17 | ||||
| -rw-r--r-- | internal/repl/repl_test.go | 22 |
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 |
