summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-23 20:29:29 +0300
committerPaul Buetow <paul@buetow.org>2026-05-23 20:29:29 +0300
commitb379e39ce81a995812895f4aa4fe079372f76ba0 (patch)
tree09b2ebd9a1b8ba3fc7d41ce1c37d38fbaba52c38
parentf075b188fde9e201f3825b16ce9f562282854a49 (diff)
style: run gofmt on all Go source files
Fix formatting in 12 files to match gofmt standards. No logical changes.
-rw-r--r--cmd/gt/main.go24
-rw-r--r--cmd/gt/main_test.go40
-rw-r--r--integrationtests/cli_test.go10
-rw-r--r--internal/repl/handlers.go2
-rw-r--r--internal/repl/repl.go4
-rw-r--r--internal/repl/repl_test.go56
-rw-r--r--internal/rpn/metric_test.go38
-rw-r--r--internal/rpn/operations_hyper.go2
-rw-r--r--internal/rpn/operations_hyper_test.go14
-rw-r--r--internal/rpn/operations_test.go9
-rw-r--r--internal/rpn/rpn_parse.go17
-rw-r--r--internal/rpn/rpn_test.go37
12 files changed, 124 insertions, 129 deletions
diff --git a/cmd/gt/main.go b/cmd/gt/main.go
index e01bcef..647f70f 100644
--- a/cmd/gt/main.go
+++ b/cmd/gt/main.go
@@ -6,14 +6,14 @@
// gt is a versatile calculator that supports both percentage calculations and
// Reverse Polish Notation (RPN) expressions. It can be used in two modes:
//
-// 1. Command-line mode: Pass calculations as arguments
-// gt 20% of 150 # Calculate 20% of 150
-// gt 3 4 + # RPN expression: 3 + 4
+// 1. Command-line mode: Pass calculations as arguments
+// gt 20% of 150 # Calculate 20% of 150
+// gt 3 4 + # RPN expression: 3 + 4
//
-// 2. Interactive REPL mode: Run without arguments to start an interactive session
-// gt # Start interactive REPL
+// 2. Interactive REPL mode: Run without arguments to start an interactive session
+// gt # Start interactive REPL
//
-// Percentage Calculations
+// # Percentage Calculations
//
// The calculator supports various percentage formats:
// - Basic percentage: "20% of 150" → 30
@@ -21,7 +21,7 @@
// - Reverse percentage: "30 is what % of 150" → 20%
// - Find base: "30 is 20% of what" → 150
//
-// RPN (Reverse Polish Notation) Support
+// # RPN (Reverse Polish Notation) Support
//
// RPN expressions use postfix notation where operators follow operands:
// - Basic operations: "3 4 +" (3 + 4), "5 2 -" (5 - 2)
@@ -30,12 +30,12 @@
// - Variable assignment: "x 5 = x x +" (assign x=5, then x + x)
// - Stack operations: "dup swap pop show"
//
-// Error Handling
+// # Error Handling
//
// Errors from calculations or parsing are printed to stdout with exit code 1.
// Invalid RPN expressions and malformed percentage queries both return errors.
//
-// Architecture
+// # Architecture
//
// The package uses a layered architecture:
// - main.go: Entry point and command routing
@@ -98,7 +98,7 @@ func runCommand(args []string) (string, error) {
// Check for --log flag
var logFile string
var remainingArgs []string
-
+
for i := 0; i < len(args); i++ {
if args[i] == "--log" && i+1 < len(args) {
logFile = args[i+1]
@@ -107,10 +107,10 @@ func runCommand(args []string) (string, error) {
remainingArgs = append(remainingArgs, args[i])
}
}
-
+
// Update args to exclude --log flag
args = remainingArgs
-
+
if len(args) < 2 {
// No args provided - check if stdin is a TTY for REPL mode
if isatty.IsTerminal(os.Stdin.Fd()) {
diff --git a/cmd/gt/main_test.go b/cmd/gt/main_test.go
index 9146d6d..617b741 100644
--- a/cmd/gt/main_test.go
+++ b/cmd/gt/main_test.go
@@ -178,32 +178,32 @@ func TestRunCommandNoArgs(t *testing.T) {
// TestRunCommandAssignmentSyntaxes tests all variable assignment syntaxes
func TestRunCommandAssignmentSyntaxes(t *testing.T) {
tests := []struct {
- name string
- input string
- expectedVar string
- expectedVal float64
- expectedOut string
+ name string
+ input string
+ expectedVar string
+ expectedVal float64
+ expectedOut string
}{
{
- name: "x 5 = x x + (standard assignment)",
- input: "x 5 = x x +",
- expectedVar: "x",
- expectedVal: 5,
- expectedOut: "10",
+ name: "x 5 = x x + (standard assignment)",
+ input: "x 5 = x x +",
+ expectedVar: "x",
+ expectedVal: 5,
+ expectedOut: "10",
},
{
- name: "x 5 =: x x + (left assignment)",
- input: "5 x =: x x +",
- expectedVar: "x",
- expectedVal: 5,
- expectedOut: "10",
+ name: "x 5 =: x x + (left assignment)",
+ input: "5 x =: x x +",
+ expectedVar: "x",
+ expectedVal: 5,
+ expectedOut: "10",
},
{
- name: "x 5 := x x + (right assignment)",
- input: "x 5 := x x +",
- expectedVar: "x",
- expectedVal: 5,
- expectedOut: "10",
+ name: "x 5 := x x + (right assignment)",
+ input: "x 5 := x x +",
+ expectedVar: "x",
+ expectedVal: 5,
+ expectedOut: "10",
},
}
diff --git a/integrationtests/cli_test.go b/integrationtests/cli_test.go
index deded52..5567ad1 100644
--- a/integrationtests/cli_test.go
+++ b/integrationtests/cli_test.go
@@ -13,7 +13,7 @@ import (
// buildBinary builds the gt binary to a temporary location.
func buildBinary(t *testing.T) string {
t.Helper()
-
+
// Get the project root directory
projectRoot := os.Getenv("GITHUB_WORKSPACE")
if projectRoot == "" {
@@ -25,19 +25,19 @@ func buildBinary(t *testing.T) string {
if err := buildCmd.Run(); err != nil {
t.Fatalf("build failed: %v", err)
}
-
+
t.Cleanup(func() {
// Explicitly ignore error return from os.Remove during cleanup
_ = os.Remove("/tmp/gt-test")
})
-
+
return "/tmp/gt-test"
}
// TestCLIVersion tests that the version command works correctly.
func TestCLIVersion(t *testing.T) {
binaryPath := buildBinary(t)
-
+
cmd := exec.Command(binaryPath, "version")
output, err := cmd.CombinedOutput()
if err != nil {
@@ -53,7 +53,7 @@ func TestCLIVersion(t *testing.T) {
// TestCLIVersionOnly tests that the version command works correctly.
func TestCLIVersionOnly(t *testing.T) {
binaryPath := buildBinary(t)
-
+
cmd := exec.Command(binaryPath, "version")
output, err := cmd.CombinedOutput()
if err != nil {
diff --git a/internal/repl/handlers.go b/internal/repl/handlers.go
index 78f07dd..f5fb909 100644
--- a/internal/repl/handlers.go
+++ b/internal/repl/handlers.go
@@ -193,7 +193,7 @@ func (h *RPNHandler) Handle(repl *REPL, input string) (output string, handled bo
return result, true, nil
}
}
-
+
// Check if input is a symbol syntax (:x) - valid RPN that pushes a symbol
if len(fields) == 1 {
token := fields[0]
diff --git a/internal/repl/repl.go b/internal/repl/repl.go
index 29314eb..01c9822 100644
--- a/internal/repl/repl.go
+++ b/internal/repl/repl.go
@@ -94,8 +94,8 @@ type REPL struct {
// - Tab completion
// - Multi-line input
type ReadlinePrompt struct {
- instance *readline.Instance
- executor func(string)
+ instance *readline.Instance
+ executor func(string)
}
// NewReadlinePrompt creates a new readline-based prompt instance.
diff --git a/internal/repl/repl_test.go b/internal/repl/repl_test.go
index a242956..8112227 100644
--- a/internal/repl/repl_test.go
+++ b/internal/repl/repl_test.go
@@ -450,15 +450,15 @@ func TestExecutorWithRatModeToggle(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// First toggle
defaultExecutor(rpl, "rat toggle")
mode1 := rpnCalc.GetMode()
-
+
// Second toggle
defaultExecutor(rpl, "rat toggle")
mode2 := rpnCalc.GetMode()
-
+
// Modes should be different after toggle
if mode1 == mode2 {
t.Errorf("Modes should be different after toggle: %v -> %v", mode1, mode2)
@@ -495,7 +495,7 @@ func TestExecutorWithAssignmentRight(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// Test := operator
defaultExecutor(rpl, "5 x :=")
val, exists := vars.GetVariable("x")
@@ -505,7 +505,7 @@ func TestExecutorWithAssignmentRight(t *testing.T) {
if val != 5 {
t.Errorf("Variable x = %v, want 5", val)
}
-
+
// Test =: operator
defaultExecutor(rpl, "y 3 =:")
val, exists = vars.GetVariable("y")
@@ -528,7 +528,7 @@ func TestExecutorWithAssignmentAfterCalculation(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// Test that assignment works after a calculation
defaultExecutor(rpl, "1 2 + z =:")
val, exists := vars.GetVariable("z")
@@ -551,13 +551,13 @@ func TestExecutorWithIncrementalAssignment(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// Test that assignment works after a calculation
defaultExecutor(rpl, "1 2 +")
-
+
// Now use z =: to assign the top of stack (3) to variable z
defaultExecutor(rpl, "z =:")
-
+
val, exists := vars.GetVariable("z")
if !exists {
t.Errorf("Variable z should exist after z =:")
@@ -578,10 +578,10 @@ func TestExecutorWithSimpleIncrementalAssignment(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// First execute 2 to put it on the stack
defaultExecutor(rpl, "2")
-
+
// Then use x =: to assign the top of stack to variable x
defaultExecutor(rpl, "x =:")
val, exists := vars.GetVariable("x")
@@ -604,17 +604,17 @@ func TestExecutorWithExactUserScenario(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// This test replicates the exact user interaction:
// > 2
// > x =:
// The variable should be assigned the value 2
-
+
defaultExecutor(rpl, "2")
-
+
// Verify stack has 2
// (can't directly check stack without exposing it, but next command will fail if stack is empty)
-
+
defaultExecutor(rpl, "x =:")
val, exists := vars.GetVariable("x")
if !exists {
@@ -636,18 +636,18 @@ func TestExecutorWithExactUserScenarioWithOutput(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// Clear any previous state
defaultExecutor(rpl, "rpn clear")
-
+
// Put 2 on stack
defaultExecutor(rpl, "2")
_, _ = rpnCalc.ResultStack([]string{})
-
+
// Assign to x =:
result, err := rpnCalc.ParseAndEvaluate("x =:")
t.Logf("ParseAndEvaluate('x =:') returned result=%q, err=%v", result, err)
-
+
val, exists := vars.GetVariable("x")
if !exists {
t.Errorf("Variable x should exist after x =:")
@@ -668,16 +668,16 @@ func TestExecutorWithExactUserScenarioDirect(t *testing.T) {
commandChain: NewCommandChain(),
rpnState: &RPNState{vars: vars, rpnCalc: rpnCalc},
}
-
+
// Clear any previous state
defaultExecutor(rpl, "rpn clear")
-
+
// Simulate typing "2" in REPL
defaultExecutor(rpl, "2")
-
+
// Simulate typing "x =:" in REPL
defaultExecutor(rpl, "x =:")
-
+
// Verify variable was set
val, exists := vars.GetVariable("x")
if !exists {
@@ -697,19 +697,19 @@ func TestExecutorWithUnknownCommand(t *testing.T) {
func TestDefaultExecutorCodePaths(t *testing.T) {
// Test all code paths in defaultExecutor
repl := createTestREPL()
-
+
// Path 1: Empty input
defaultExecutor(repl, "")
-
+
// Path 2: Built-in command with error (clear should not error but let's verify)
defaultExecutor(repl, "clear")
-
+
// Path 3: Built-in command with output (help returns help text)
defaultExecutor(repl, "help")
-
+
// Path 4: Unknown command (error handler returns handled=false, err!=nil)
defaultExecutor(repl, "completelyunknowncommand123")
-
+
// Path 5: Whitespace only (trimmed to empty, returns early)
defaultExecutor(repl, " ")
}
diff --git a/internal/rpn/metric_test.go b/internal/rpn/metric_test.go
index 4ac3238..7441705 100644
--- a/internal/rpn/metric_test.go
+++ b/internal/rpn/metric_test.go
@@ -98,9 +98,9 @@ func TestMetricRegistryFindCaseInsensitive(t *testing.T) {
func TestMetricRegistryDuplicatePanics(t *testing.T) {
reg := NewMetricRegistry()
reg.Register(&Metric{
- Name: "dup",
+ Name: "dup",
Category: Custom,
- Factor: func(PrefixMode) float64 { return 1 },
+ Factor: func(PrefixMode) float64 { return 1 },
})
defer func() {
if r := recover(); r == nil {
@@ -108,9 +108,9 @@ func TestMetricRegistryDuplicatePanics(t *testing.T) {
}
}()
reg.Register(&Metric{
- Name: "dup",
+ Name: "dup",
Category: Custom,
- Factor: func(PrefixMode) float64 { return 2 },
+ Factor: func(PrefixMode) float64 { return 2 },
})
}
@@ -161,9 +161,9 @@ func TestBuiltInMetricFactors(t *testing.T) {
tolerance := 0.0001
tests := []struct {
- name string
- mode PrefixMode
- expect float64
+ name string
+ mode PrefixMode
+ expect float64
}{
// Universal
{"Cool", SI, 1},
@@ -177,13 +177,13 @@ func TestBuiltInMetricFactors(t *testing.T) {
// DataSize (base: bits)
{"bits", SI, 1},
{"bytes", SI, 8},
- {"KB", SI, 8000}, // 8 * 1000
+ {"KB", SI, 8000}, // 8 * 1000
{"MB", SI, 8e6},
{"GB", SI, 8e9},
{"TB", SI, 8e12},
{"PB", SI, 8e15},
// IEC (base: bits)
- {"KiB", SI, 8192}, // 8 * 1024
+ {"KiB", SI, 8192}, // 8 * 1024
{"MiB", SI, 8 * 1048576},
{"GiB", SI, 8 * 1073741824},
{"TiB", SI, 8 * float64(uint64(1)<<40)},
@@ -466,7 +466,7 @@ func TestMetricRegistryAliases(t *testing.T) {
reg := GetMetricRegistry()
tests := []struct {
- alias string
+ alias string
canonical string
}{
{"bit/s", "bps"},
@@ -509,9 +509,9 @@ func TestMetricRegistryAliases(t *testing.T) {
func TestFindWithAliasesPriority(t *testing.T) {
reg := NewMetricRegistry()
reg.Register(&Metric{
- Name: "Foo",
+ Name: "Foo",
Category: Custom,
- Factor: func(PrefixMode) float64 { return 1 },
+ Factor: func(PrefixMode) float64 { return 1 },
})
reg.RegisterAlias("foo", "Foo")
@@ -803,7 +803,7 @@ func TestAtPrefixMetricParsing(t *testing.T) {
{"@GB", "GB", true},
{"@Mbps", "Mbps", true},
{"@hr", "hr", true},
- {"@sec", "s", true}, // alias
+ {"@sec", "s", true}, // alias
{"@foot", "ft", true}, // alias
{"@nope", "", false},
{"@", "", false},
@@ -915,12 +915,12 @@ func TestMetricOperationsUnit(t *testing.T) {
tolerance := 0.001
cases := []struct {
- name string
- setup func(s *Stack)
- op func(*Operations, *Stack) error
- wantVal float64
- wantMet string
- wantErr bool
+ name string
+ setup func(s *Stack)
+ op func(*Operations, *Stack) error
+ wantVal float64
+ wantMet string
+ wantErr bool
}{
{
name: "same-category addition 1000bps+1Kbps",
diff --git a/internal/rpn/operations_hyper.go b/internal/rpn/operations_hyper.go
index b9be48a..087fc67 100644
--- a/internal/rpn/operations_hyper.go
+++ b/internal/rpn/operations_hyper.go
@@ -265,5 +265,3 @@ func (o *Operations) HyperLog10(stack *Stack) error {
func (o *Operations) HyperLn(stack *Stack) error {
return o.hyperLog(stack, "[ln]", math.Log, "ln undefined for non-positive numbers")
}
-
-
diff --git a/internal/rpn/operations_hyper_test.go b/internal/rpn/operations_hyper_test.go
index 4ea7dc6..352e503 100644
--- a/internal/rpn/operations_hyper_test.go
+++ b/internal/rpn/operations_hyper_test.go
@@ -14,12 +14,12 @@ func TestHyperMetricAwareOperations(t *testing.T) {
reg := GetMetricRegistry()
tests := []struct {
- name string
- expr string
- wantNum float64
- wantMet string // empty skips metric check
- tol float64
- wantErr bool
+ name string
+ expr string
+ wantNum float64
+ wantMet string // empty skips metric check
+ tol float64
+ wantErr bool
}{
// Addition
{
@@ -154,7 +154,7 @@ func TestHyperCoolResultOperations(t *testing.T) {
wantNum: 3, tol: 0.001,
},
{
- name: "log2 with metrics", expr: "100Mbps 1000Mbps [lg]",
+ name: "log2 with metrics", expr: "100Mbps 1000Mbps [lg]",
wantNum: math.Log2(100) + math.Log2(1000), tol: 0.01,
},
}
diff --git a/internal/rpn/operations_test.go b/internal/rpn/operations_test.go
index 2592cc7..155a53d 100644
--- a/internal/rpn/operations_test.go
+++ b/internal/rpn/operations_test.go
@@ -1264,7 +1264,6 @@ func TestOperatorRegistryHandleStandardOperator(t *testing.T) {
}
}
-
func TestAssignLeft(t *testing.T) {
v := NewVariables()
o := NewOperations(v)
@@ -1273,8 +1272,8 @@ func TestAssignLeft(t *testing.T) {
// For "5 x =:":
// AssignLeft pops name first, then value
// Push value first (will be popped second), then name (will be popped first)
- s.Push(NewNumber(5, FloatMode)) // value (will be popped second)
- s.Push(NewStringNum("x")) // name (will be popped first)
+ s.Push(NewNumber(5, FloatMode)) // value (will be popped second)
+ s.Push(NewStringNum("x")) // name (will be popped first)
err := o.AssignLeft(s)
if err != nil {
@@ -1304,8 +1303,8 @@ func TestAssignRight(t *testing.T) {
// For "x 5 :=":
// AssignRight pops value first, then name
// Push name first (will be popped second), then value (will be popped first)
- s.Push(NewStringNum("x")) // name (will be popped second)
- s.Push(NewNumber(5, FloatMode)) // value (will be popped first)
+ s.Push(NewStringNum("x")) // name (will be popped second)
+ s.Push(NewNumber(5, FloatMode)) // value (will be popped first)
err := o.AssignRight(s)
if err != nil {
diff --git a/internal/rpn/rpn_parse.go b/internal/rpn/rpn_parse.go
index 99b7c25..3633db9 100644
--- a/internal/rpn/rpn_parse.go
+++ b/internal/rpn/rpn_parse.go
@@ -293,7 +293,7 @@ func (r *RPN) ParseAndEvaluate(input string) (string, error) {
func (r *RPN) evaluate(input string, tokens []string) (string, error) {
r.mu.Lock()
defer r.mu.Unlock()
-
+
// Use the current stack for evaluation to preserve state
// This allows incremental operations in REPL mode
if r.currentStack == nil {
@@ -444,7 +444,7 @@ func (r *RPN) evaluate(input string, tokens []string) (string, error) {
// For := (right assignment): name value := - first token is always a variable name
// For =: (left assignment): value name =: - token before =: is a variable name
shouldPushName := false
-
+
if i+1 < len(tokens) {
nextToken := tokens[i+1]
if nextToken == ":=" || nextToken == "=:" {
@@ -476,7 +476,7 @@ func (r *RPN) evaluate(input string, tokens []string) (string, error) {
}
}
}
-
+
// Special case: first token in := expression (e.g., "x 5 :=")
// Only push as name if the first token is not a number (it's a variable name)
if i == 0 && len(tokens) >= 3 && tokens[len(tokens)-1] == ":=" {
@@ -484,13 +484,13 @@ func (r *RPN) evaluate(input string, tokens []string) (string, error) {
shouldPushName = true
}
}
-
+
if shouldPushName {
// This token is a variable name, push as StringNum
stack.Push(NewStringNum(token))
continue
}
-
+
// Special case: if token is a defined variable and appears before an assignment operator
// (within the next few tokens), push the variable NAME (StringNum) instead of VALUE
// to allow reassignment.
@@ -585,7 +585,6 @@ func (r *RPN) handleOperator(stack *Stack, token string, tokenIndex int) (string
return "", nil
}
-
// Handle standard operators (common logic extracted for DRY)
// This must be done BEFORE pushing Symbol for unknown identifiers,
// so that operators are properly handled
@@ -628,13 +627,13 @@ func isValidIdentifier(token string) bool {
if len(token) == 0 {
return false
}
-
+
// Check first character - must be letter or underscore
first := token[0]
if !((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || first == '_') {
return false
}
-
+
// Check remaining characters - must be alphanumeric or underscore
for i := 1; i < len(token); i++ {
c := token[i]
@@ -642,7 +641,7 @@ func isValidIdentifier(token string) bool {
return false
}
}
-
+
// Only allow single-character identifiers for symbol support
// This prevents words like "what", "is", "of" from becoming symbols
return len(token) == 1
diff --git a/internal/rpn/rpn_test.go b/internal/rpn/rpn_test.go
index 0822125..0460271 100644
--- a/internal/rpn/rpn_test.go
+++ b/internal/rpn/rpn_test.go
@@ -682,7 +682,6 @@ func TestRPNIncrementalOperations(t *testing.T) {
}
}
-
// TestIncrementalAssignmentRPN tests x =: with value on stack in ParseAndEvaluate
func TestIncrementalAssignmentRPN(t *testing.T) {
v := NewVariables()
@@ -778,24 +777,24 @@ func TestParseAndEvaluateAssignmentLeftRight(t *testing.T) {
func TestSymbolPush(t *testing.T) {
vars := NewVariables()
r := NewRPN(vars)
-
+
// Test :x syntax
result, err := r.ParseAndEvaluate(":x")
if err != nil {
t.Fatalf("ParseAndEvaluate(':x') returned error: %v", err)
}
-
+
// The result should be the symbol displayed
if result != ":x" {
t.Errorf("Expected ':x', got '%s'", result)
}
-
+
// Verify the stack has a Symbol
stack := r.GetCurrentStack()
if len(stack) != 1 {
t.Fatalf("Expected 1 item on stack, got %d", len(stack))
}
-
+
// Check that it's a Symbol
sym, ok := stack[0].(*Symbol)
if !ok {
@@ -810,13 +809,13 @@ func TestSymbolPush(t *testing.T) {
func TestUnboundIdentifierAsSymbol(t *testing.T) {
vars := NewVariables()
r := NewRPN(vars)
-
+
// Use bare identifier x (unbound)
result, err := r.ParseAndEvaluate("x")
if err != nil {
t.Fatalf("ParseAndEvaluate('x') returned error: %v", err)
}
-
+
// The result should be the symbol displayed
if result != ":x" {
t.Errorf("Expected ':x', got '%s'", result)
@@ -827,18 +826,18 @@ func TestUnboundIdentifierAsSymbol(t *testing.T) {
func TestBoundIdentifierPushesValue(t *testing.T) {
vars := NewVariables()
r := NewRPN(vars)
-
+
// First bind x to 5
if _, err := r.ParseAndEvaluate("x = 5"); err != nil {
t.Fatalf("ParseAndEvaluate('x = 5') returned error: %v", err)
}
-
+
// Now use x (bound) - should push value
result, err := r.ParseAndEvaluate("x")
if err != nil {
t.Fatalf("ParseAndEvaluate('x') after binding returned error: %v", err)
}
-
+
// The result should be 5
if result != "5" {
t.Errorf("Expected '5', got '%s'", result)
@@ -850,12 +849,12 @@ func TestSymbolWithAssignment(t *testing.T) {
// Test :x 10 := (symbol then value with right assignment)
vars := NewVariables()
r := NewRPN(vars)
-
+
_, err := r.ParseAndEvaluate(":x 10 :=")
if err != nil {
t.Fatalf("ParseAndEvaluate(':x 10 :=') returned error: %v", err)
}
-
+
// Verify x was set to 10
val, exists := vars.GetVariable("x")
if !exists {
@@ -864,16 +863,16 @@ func TestSymbolWithAssignment(t *testing.T) {
if val != 10 {
t.Errorf("Variable x = %v, want 10", val)
}
-
+
// Test 10 :x =: (value then symbol with left assignment)
vars2 := NewVariables()
r2 := NewRPN(vars2)
-
+
_, err = r2.ParseAndEvaluate("10 :x =:")
if err != nil {
t.Fatalf("ParseAndEvaluate('10 :x =:') returned error: %v", err)
}
-
+
val, exists = vars2.GetVariable("x")
if !exists {
t.Errorf("Variable x should exist after assignment")
@@ -887,19 +886,19 @@ func TestSymbolWithAssignment(t *testing.T) {
func TestStackBasedAssignmentWithSymbol(t *testing.T) {
vars := NewVariables()
r := NewRPN(vars)
-
+
// Push 42 onto stack
_, err := r.ParseAndEvaluate("42")
if err != nil {
t.Fatalf("ParseAndEvaluate('42') returned error: %v", err)
}
-
+
// Now y =: - this should assign 42 to y
result, err := r.ParseAndEvaluate("y =:")
if err != nil {
t.Fatalf("ParseAndEvaluate('y =:') returned error: %v", err)
}
-
+
// Verify y was set to 42
val, exists := vars.GetVariable("y")
if !exists {
@@ -908,7 +907,7 @@ func TestStackBasedAssignmentWithSymbol(t *testing.T) {
if val != 42 {
t.Errorf("Variable y = %v, want 42", val)
}
-
+
// The result should show the assignment confirmation
if result != "y = 42" {
t.Errorf("Expected 'y = 42', got '%s'", result)