summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-23 23:01:02 +0200
committerPaul Buetow <paul@buetow.org>2026-03-23 23:01:02 +0200
commit2b1f044aa59d516d2e3497066751d3baa5b1c749 (patch)
tree2737e0729e30c803c0dc8c62acff2d4704dc5853
parent55b5f40cc1f2d42bc3a277f60a3798742ce29170 (diff)
Refactor calculator.Parse to use registration pattern for parsing strategies
Created ParsingStrategy type and strategyRegistry struct to manage parsing strategies. All parsing strategies are now registered in a registry and executed in sequence. This makes the parsing logic more maintainable and extensible.
-rw-r--r--internal/calculator/calculator.go54
1 files changed, 43 insertions, 11 deletions
diff --git a/internal/calculator/calculator.go b/internal/calculator/calculator.go
index edf529f..f3ebc17 100644
--- a/internal/calculator/calculator.go
+++ b/internal/calculator/calculator.go
@@ -9,6 +9,36 @@ import (
"codeberg.org/snonux/perc/internal/rpn"
)
+// ParsingStrategy represents a parsing function that attempts to parse input.
+type ParsingStrategy func(input string) (result string, handled bool)
+
+// strategyRegistry maintains a registry of parsing strategies.
+type strategyRegistry struct {
+ strategies []ParsingStrategy
+}
+
+// newStrategyRegistry creates a new strategy registry.
+func newStrategyRegistry() *strategyRegistry {
+ return &strategyRegistry{
+ strategies: make([]ParsingStrategy, 0),
+ }
+}
+
+// register adds a parsing strategy to the registry.
+func (r *strategyRegistry) register(strategy ParsingStrategy) {
+ r.strategies = append(r.strategies, strategy)
+}
+
+// parse attempts to parse input using registered strategies in order.
+func (r *strategyRegistry) parse(input string) (string, bool) {
+ for _, strategy := range r.strategies {
+ if result, handled := strategy(input); handled {
+ return result, true
+ }
+ }
+ return "", false
+}
+
// Parse parses a percentage calculation input string and returns the result.
// It handles formats like "20% of 150", "30 is what % of 150", and "30 is 20% of what".
func Parse(input string) (string, error) {
@@ -16,25 +46,27 @@ func Parse(input string) (string, error) {
input = strings.ReplaceAll(input, "what is ", "")
input = strings.TrimSpace(input)
- if result, ok := parseXPercentOfY(input); ok {
- return result, nil
- }
+ // Create registry and register parsing strategies
+ registry := newStrategyRegistry()
+ registry.register(parseXPercentOfY)
+ registry.register(parseXIsWhatPercentOfY)
+ registry.register(parseXIsYPercentOfWhat)
+ registry.register(parseRPNFallback)
- if result, ok := parseXIsWhatPercentOfY(input); ok {
+ if result, ok := registry.parse(input); ok {
return result, nil
}
- if result, ok := parseXIsYPercentOfWhat(input); ok {
- return result, nil
- }
+ return "", fmt.Errorf("calculator: unable to parse input %q. See usage for examples", input)
+}
- // Try RPN as a fallback
+// parseRPNFallback is a parsing strategy that delegates to ParseRPN.
+func parseRPNFallback(input string) (string, bool) {
result, err := ParseRPN(input)
if err == nil {
- return result, nil
+ return result, true
}
-
- return "", fmt.Errorf("calculator: unable to parse input %q. See usage for examples", input)
+ return "", false
}
// ParseRPN parses and evaluates an RPN (Reverse Polish Notation) expression.