package compiler import "testing" func TestDefine(t *testing.T) { expected := map[string]Symbol{ "a": {"a", GlobalScope, 0}, "b": {"b", GlobalScope, 1}, "c": {"c", LocalScope, 0}, "d": {"d", LocalScope, 1}, "e": {"e", LocalScope, 0}, "f": {"f", LocalScope, 1}, } global := NewSymbolTable() a := global.Define("a") if a != expected["a"] { t.Errorf("expected a=%+v, got=%+v", expected["a"], a) } b := global.Define("b") if b != expected["b"] { t.Errorf("expected b=%+v, got=%+v", expected["b"], b) } firstLocal := NewEnclosedSymbolTable(global) c := firstLocal.Define("c") if c != expected["c"] { t.Errorf("expected c=%+v, got=%+v", expected["c"], c) } d := firstLocal.Define("d") if d != expected["d"] { t.Errorf("expected d=%+v, got=%+v", expected["d"], d) } secondLocal := NewEnclosedSymbolTable(firstLocal) e := secondLocal.Define("e") if e != expected["e"] { t.Errorf("expeted e=%+v, got=%+v", expected["e"], e) } f := secondLocal.Define("f") if f != expected["f"] { t.Errorf("expected f=%+v, got=%+v", expected["f"], f) } } func TestResolveGlobal(t *testing.T) { global := NewSymbolTable() global.Define("a") global.Define("b") expected := []Symbol{ {Name: "a", Scope: GlobalScope, Index: 0}, {Name: "b", Scope: GlobalScope, Index: 1}, } for _, sym := range expected { result, ok := global.Resolve(sym.Name) if !ok { t.Errorf("name %s not resolvable", sym.Name) continue } if result != sym { t.Errorf("expected %s to resolve to %+v, got=%+v", sym.Name, sym, result) } } } func TestResolveLocal(t *testing.T) { global := NewSymbolTable() global.Define("a") global.Define("b") local := NewEnclosedSymbolTable(global) local.Define("c") local.Define("d") expected := []Symbol{ {Name: "a", Scope: GlobalScope, Index: 0}, {Name: "b", Scope: GlobalScope, Index: 1}, {Name: "c", Scope: LocalScope, Index: 0}, {Name: "d", Scope: LocalScope, Index: 1}, } for _, sym := range expected { result, ok := local.Resolve(sym.Name) if !ok { t.Errorf("name %s not resolvable", sym.Name) continue } if result != sym { t.Errorf("expected %s to resolve to %+v, got=%+v", sym.Name, sym, result) } } } func TestResolveNestedLocal(t *testing.T) { global := NewSymbolTable() global.Define("a") global.Define("b") firstLocal := NewEnclosedSymbolTable(global) firstLocal.Define("c") firstLocal.Define("d") secondLocal := NewEnclosedSymbolTable(firstLocal) secondLocal.Define("e") secondLocal.Define("f") tests := []struct { table *SymbolTable expectedSymbols []Symbol }{ { firstLocal, []Symbol{ {"a", GlobalScope, 0}, {"b", GlobalScope, 1}, {"c", LocalScope, 0}, {"d", LocalScope, 1}, }, }, { secondLocal, []Symbol{ {"a", GlobalScope, 0}, {"b", GlobalScope, 1}, {"e", LocalScope, 0}, {"f", LocalScope, 1}, }, }, } for _, tt := range tests { for _, sym := range tt.expectedSymbols { result, ok := tt.table.Resolve(sym.Name) if !ok { t.Errorf("name %s not resolvable", sym.Name) continue } if result != sym { t.Errorf("expected %s resolve to %+v, got=%+v", sym.Name, sym, result) } } } }