package hbrt import ( "testing" ) func TestMemvar_PublicCreate(t *testing.T) { m := NewMemvarTable() m.SetPublic("NAME", MakeString("Charles")) v, ok := m.Get("NAME") if !ok { t.Fatal("not found") } if v.AsString() != "Charles" { t.Errorf("got %q", v.AsString()) } if m.Count() != 1 { t.Errorf("count=%d", m.Count()) } } func TestMemvar_PublicCaseInsensitive(t *testing.T) { m := NewMemvarTable() m.SetPublic("Name", MakeString("Charles")) v, ok := m.Get("name") if !ok { t.Fatal("case: not found") } if v.AsString() != "Charles" { t.Error("case") } v, ok = m.Get("NAME") if !ok { t.Fatal("upper: not found") } if v.AsString() != "Charles" { t.Error("upper") } } func TestMemvar_PublicUpdate(t *testing.T) { m := NewMemvarTable() m.SetPublic("X", MakeInt(1)) m.Set("X", MakeInt(42)) v, _ := m.Get("X") if v.AsInt() != 42 { t.Errorf("got %d", v.AsInt()) } } func TestMemvar_PrivateBasic(t *testing.T) { m := NewMemvarTable() m.SetPrivate("TEMP", MakeInt(10), 1) v, ok := m.Get("TEMP") if !ok { t.Fatal("not found") } if v.AsInt() != 10 { t.Errorf("got %d", v.AsInt()) } } func TestMemvar_PrivateShadow(t *testing.T) { m := NewMemvarTable() // PUBLIC x = 100 m.SetPublic("X", MakeInt(100)) // Enter function scope — PRIVATE x = 200 (shadows PUBLIC) m.BeginPrivateScope(1) m.SetPrivate("X", MakeInt(200), 1) v, _ := m.Get("X") if v.AsInt() != 200 { t.Errorf("shadow: got %d", v.AsInt()) } // Return from function — restore PUBLIC x = 100 m.EndPrivateScope() v, _ = m.Get("X") if v.AsInt() != 100 { t.Errorf("restore: got %d", v.AsInt()) } } func TestMemvar_PrivateNestedShadow(t *testing.T) { m := NewMemvarTable() m.SetPublic("V", MakeString("pub")) // Level 1: PRIVATE V = "priv1" m.BeginPrivateScope(1) m.SetPrivate("V", MakeString("priv1"), 1) // Level 2: PRIVATE V = "priv2" m.BeginPrivateScope(2) m.SetPrivate("V", MakeString("priv2"), 2) v, _ := m.Get("V") if v.AsString() != "priv2" { t.Errorf("L2: %q", v.AsString()) } // Return level 2 m.EndPrivateScope() v, _ = m.Get("V") if v.AsString() != "priv1" { t.Errorf("L1: %q", v.AsString()) } // Return level 1 m.EndPrivateScope() v, _ = m.Get("V") if v.AsString() != "pub" { t.Errorf("pub: %q", v.AsString()) } } func TestMemvar_PrivateNewVar(t *testing.T) { m := NewMemvarTable() // Enter scope — create new PRIVATE (no prior value) m.BeginPrivateScope(1) m.SetPrivate("TEMP", MakeInt(42), 1) v, ok := m.Get("TEMP") if !ok { t.Fatal("not found") } if v.AsInt() != 42 { t.Errorf("got %d", v.AsInt()) } // Return — TEMP should be gone m.EndPrivateScope() _, ok = m.Get("TEMP") if ok { t.Error("TEMP should not exist after scope exit") } } func TestMemvar_Release(t *testing.T) { m := NewMemvarTable() m.SetPublic("X", MakeInt(1)) m.Release("X") if m.Exists("X") { t.Error("should not exist") } } func TestMemvar_ReleaseAll(t *testing.T) { m := NewMemvarTable() m.SetPublic("A", MakeInt(1)) m.SetPublic("B", MakeInt(2)) m.SetPrivate("C", MakeInt(3), 1) m.ReleaseAll() if m.Count() != 0 { t.Errorf("count=%d", m.Count()) } } func TestMemvar_Names(t *testing.T) { m := NewMemvarTable() m.SetPublic("ALPHA", MakeInt(1)) m.SetPublic("BETA", MakeInt(2)) names := m.Names() if len(names) != 2 { t.Errorf("names=%d", len(names)) } } func TestMemvar_ThreadIntegration(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) // PUBLIC via Thread th.DeclarePublic("GNAME") th.PushMemvar("GNAME") v := th.pop() if !v.IsNil() { t.Error("should be NIL initially") } // Set via memvar th.push(MakeString("Charles")) th.PopMemvar("GNAME") th.PushMemvar("GNAME") v = th.pop() if v.AsString() != "Charles" { t.Errorf("got %q", v.AsString()) } // PRIVATE th.DeclarePrivate("TEMP") th.push(MakeInt(42)) th.PopMemvar("TEMP") th.PushMemvar("TEMP") v = th.pop() if v.AsInt() != 42 { t.Errorf("got %d", v.AsInt()) } } func TestMemvar_MacroAccess(t *testing.T) { vm := NewVM() th := vm.NewThread() th.Frame(0, 0) // Set PUBLIC via memvar table th.Memvars.SetPublic("MYVAR", MakeString("hello from memvar")) // MacroEval should find it v := th.MacroEval("MYVAR") if v.AsString() != "hello from memvar" { t.Errorf("macro lookup: got %q", v.AsString()) } }