package hbrt import ( "testing" ) func TestMacroEval_Literal(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) // Numbers v := th.MacroEval("42") if v.AsInt() != 42 { t.Errorf("int: got %v", v) } v = th.MacroEval("3.14") if v.AsDouble()-3.14 > 0.001 { t.Errorf("float: got %v", v) } // Strings v = th.MacroEval(`"hello"`) if v.AsString() != "hello" { t.Errorf("string: got %v", v) } // Booleans v = th.MacroEval(".T.") if !v.AsBool() { t.Errorf("true: got %v", v) } v = th.MacroEval(".F.") if v.AsBool() { t.Errorf("false: got %v", v) } // NIL v = th.MacroEval("NIL") // returns string "NIL" for now (identifier) if v.AsString() != "NIL" { t.Errorf("nil: got %v", v) } } func TestMacroEval_Arithmetic(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval("2 + 3") if v.AsInt() != 5 { t.Errorf("add: got %v", v) } v = th.MacroEval("10 - 4") if v.AsInt() != 6 { t.Errorf("sub: got %v", v) } v = th.MacroEval("6 * 7") if v.AsInt() != 42 { t.Errorf("mul: got %v", v) } v = th.MacroEval("100 / 4") if int(v.AsNumDouble()) != 25 { t.Errorf("div: got %v", v.AsNumDouble()) } v = th.MacroEval("2 ** 10") if int(v.AsNumDouble()) != 1024 { t.Errorf("pow: got %v", v.AsNumDouble()) } } func TestMacroEval_StringOps(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval(`"hello" + " " + "world"`) if v.AsString() != "hello world" { t.Errorf("concat: got %q", v.AsString()) } } func TestMacroEval_Comparison(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval("10 > 5") if !v.AsBool() { t.Errorf("gt: got %v", v) } v = th.MacroEval("3 < 1") if v.AsBool() { t.Errorf("lt: got %v", v) } v = th.MacroEval("5 == 5") if !v.AsBool() { t.Errorf("eq: got %v", v) } v = th.MacroEval("5 != 3") if !v.AsBool() { t.Errorf("neq: got %v", v) } } func TestMacroEval_Complex(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval("(2 + 3) * 4") if v.AsInt() != 20 { t.Errorf("complex: got %v", v) } v = th.MacroEval(`"abc" + "def"`) if v.AsString() != "abcdef" { t.Errorf("strcat: got %q", v.AsString()) } } func TestMacroEval_FunctionCall(t *testing.T) { vm := NewVM() // Register a test function vm.RegisterSymbol(&Symbol{ Name: "DOUBLE", Func: func(t *Thread) { t.Frame(1, 0) defer t.EndProc() n := t.Local(1).AsInt() t.PushInt(n * 2) t.RetValue() }, }) th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval("Double(21)") if v.AsInt() != 42 { t.Errorf("funcall: got %v", v) } } func TestMacroEval_Array(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval(`{1, 2, 3}`) if !v.IsArray() { t.Fatalf("array: not array") } arr := v.AsArray() if len(arr.Items) != 3 { t.Fatalf("array: len=%d", len(arr.Items)) } if arr.Items[0].AsInt() != 1 || arr.Items[2].AsInt() != 3 { t.Errorf("array: got %v %v", arr.Items[0], arr.Items[2]) } } func TestMacroEval_Empty(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) v := th.MacroEval("") if !v.IsNil() { t.Errorf("empty: got %v", v) } v = th.MacroEval(" ") if !v.IsNil() { t.Errorf("whitespace: got %v", v) } }