diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-23 22:43:15 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-23 22:43:15 +0300 |
| commit | d126bab04b149ea51d61ddf1d558b2f0764a711f (patch) | |
| tree | ae709a75fa3339277ff8da7ad77c4d8d1ec92588 | |
| parent | a12987997b682854d3c91705002d74928d8cb5e6 (diff) | |
refactor: eliminate duplication between handleAssignRight and handleAssignLeft
Both functions had identical structure (~37 lines each, ~74 total).
Extracted shared logic into handleAssignmentOp() and tryAssignment()
helpers, reducing to ~25 lines of shared code plus two 3-line wrappers.
The helpers parameterize the operator string (':=', '=:') and handle
the two field orderings (value name vs name value) automatically.
| -rw-r--r-- | internal/rpn/rpn_parse.go | 127 |
1 files changed, 34 insertions, 93 deletions
diff --git a/internal/rpn/rpn_parse.go b/internal/rpn/rpn_parse.go index eb4f0b9..b68d8f3 100644 --- a/internal/rpn/rpn_parse.go +++ b/internal/rpn/rpn_parse.go @@ -62,120 +62,61 @@ func (h *assignmentHandler) handle(input string, r *RPN) (string, bool, error) { return h.registry.parse(input, r) } -// assignRightHandler handles the := operator (right assignment). -// Format: value name := (value on bottom, name on top) - stack variant -// Or: name value := (name on bottom, value on top) - direct variant -func handleAssignRight(input string, r *RPN) (string, bool, error) { - if !strings.Contains(input, ":=") { - return "", false, nil - } - - pos := strings.Index(input, ":=") - if pos < 0 { +// handleAssignmentOp is the shared implementation for := and =: operators. +// Both share identical logic: check for operator, extract fields, try two +// orderings (value name, then name value), parse, set variable, evaluate remainder. +func handleAssignmentOp(input string, r *RPN, op string) (string, bool, error) { + if !strings.Contains(input, op) { return "", false, nil } + pos := strings.Index(input, op) before := strings.TrimSpace(input[:pos]) - after := strings.TrimSpace(input[pos+2:]) + after := strings.TrimSpace(input[pos+len(op):]) beforeFields := strings.Fields(before) if len(beforeFields) != 2 { return "", false, nil } - // Try value name := format first (stack variant) - name := beforeFields[1] - valueStr := beforeFields[0] - - val, err := strconv.ParseFloat(valueStr, 64) - if err == nil { - varName := extractVariableName(name) - if err := r.vars.SetVariable(varName, val); err != nil { - return "", false, err - } - if after == "" { - return fmt.Sprintf("%s = %.10g", varName, val), true, nil - } - result, err := r.evaluate(input, strings.Fields(after)) - return result, true, err - } - - // Try name value := format (for backward compatibility) - name = beforeFields[0] - valueStr = beforeFields[1] - - val, err = strconv.ParseFloat(valueStr, 64) - if err == nil { - varName := extractVariableName(name) - if err := r.vars.SetVariable(varName, val); err != nil { - return "", false, err - } - if after == "" { - return fmt.Sprintf("%s = %.10g", varName, val), true, nil - } - result, err := r.evaluate(input, strings.Fields(after)) - return result, true, err + // Try value name op format first (stack variant) + if result, ok, err := tryAssignment(beforeFields[1], beforeFields[0], r, input, after); ok || err != nil { + return result, ok, err } - return "", false, nil + // Try name value op format (for backward compatibility) + return tryAssignment(beforeFields[0], beforeFields[1], r, input, after) } -// assignLeftHandler handles the =: operator (left assignment). -// Format: value name =: (value on bottom, name on top) - stack variant -// Or: name value =: (name on bottom, value on top) - direct variant -func handleAssignLeft(input string, r *RPN) (string, bool, error) { - if !strings.Contains(input, "=:") { +// tryAssignment attempts to parse valueStr as a float, set the variable, +// and optionally evaluate remaining tokens. +func tryAssignment(name, valueStr string, r *RPN, input, after string) (string, bool, error) { + val, err := strconv.ParseFloat(valueStr, 64) + if err != nil { return "", false, nil } - pos := strings.Index(input, "=:") - if pos < 0 { - return "", false, nil + varName := extractVariableName(name) + if err := r.vars.SetVariable(varName, val); err != nil { + return "", false, err } - - before := strings.TrimSpace(input[:pos]) - after := strings.TrimSpace(input[pos+2:]) - - beforeFields := strings.Fields(before) - if len(beforeFields) != 2 { - return "", false, nil - } - - // Try value name =: format first (stack variant) - name := beforeFields[1] - valueStr := beforeFields[0] - - val, err := strconv.ParseFloat(valueStr, 64) - if err == nil { - varName := extractVariableName(name) - if err := r.vars.SetVariable(varName, val); err != nil { - return "", false, err - } - if after == "" { - return fmt.Sprintf("%s = %.10g", varName, val), true, nil - } - result, err := r.evaluate(input, strings.Fields(after)) - return result, true, err + if after == "" { + return fmt.Sprintf("%s = %.10g", varName, val), true, nil } + result, err := r.evaluate(input, strings.Fields(after)) + return result, true, err +} - // Try name value =: format (for backward compatibility) - name = beforeFields[0] - valueStr = beforeFields[1] - - val, err = strconv.ParseFloat(valueStr, 64) - if err == nil { - varName := extractVariableName(name) - if err := r.vars.SetVariable(varName, val); err != nil { - return "", false, err - } - if after == "" { - return fmt.Sprintf("%s = %.10g", varName, val), true, nil - } - result, err := r.evaluate(input, strings.Fields(after)) - return result, true, err - } +// handleAssignRight handles the := operator (right assignment). +// Format: value name := (stack variant) or name value := (direct variant) +func handleAssignRight(input string, r *RPN) (string, bool, error) { + return handleAssignmentOp(input, r, ":=") +} - return "", false, nil +// handleAssignLeft handles the =: operator (left assignment). +// Format: value name =: (stack variant) or name value =: (direct variant) +func handleAssignLeft(input string, r *RPN) (string, bool, error) { + return handleAssignmentOp(input, r, "=:") } // standardAssignHandler handles the standard = operator. |
