package compiler import "testing" func TestDefine(t *testing.T) { expected := map[string]Symbol{ "a": { Name: "a", Scope: GlobalScope, Index: 0, }, "b": { Name: "b", Scope: GlobalScope, Index: 1, }, "c": {Name: "c", Scope: LocalScope, Index: 0}, "d": {Name: "d", Scope: LocalScope, Index: 1}, "e": {Name: "e", Scope: LocalScope, Index: 0}, "f": {Name: "f", Scope: LocalScope, Index: 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("expected 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{ Symbol{ Name: "a", Scope: GlobalScope, Index: 0, }, Symbol{ 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) } 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{ Symbol{Name: "a", Scope: GlobalScope, Index: 0}, Symbol{Name: "b", Scope: GlobalScope, Index: 1}, Symbol{Name: "c", Scope: LocalScope, Index: 0}, Symbol{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(global) secondLocal.Define("e") secondLocal.Define("f") tests := []struct { table *SymbolTable expectedSymbols []Symbol }{ { firstLocal, []Symbol{ Symbol{Name: "a", Scope: GlobalScope, Index: 0}, Symbol{Name: "b", Scope: GlobalScope, Index: 1}, Symbol{Name: "c", Scope: LocalScope, Index: 0}, Symbol{Name: "d", Scope: LocalScope, Index: 1}, }, }, { secondLocal, []Symbol{ Symbol{Name: "a", Scope: GlobalScope, Index: 0}, Symbol{Name: "b", Scope: GlobalScope, Index: 1}, Symbol{Name: "e", Scope: LocalScope, Index: 0}, Symbol{Name: "f", Scope: LocalScope, Index: 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 to resolve to %+v, got=%+v", sym.Name, sym, result) } } } } func TestDefineResolveBuiltins(t *testing.T) { global := NewSymbolTable() firstLocal := NewEnclosedSymbolTable(global) secondLocal := NewEnclosedSymbolTable(firstLocal) expected := []Symbol{ Symbol{Name: "a", Scope: BuiltinScope, Index: 0}, Symbol{Name: "c", Scope: BuiltinScope, Index: 1}, Symbol{Name: "e", Scope: BuiltinScope, Index: 2}, Symbol{Name: "f", Scope: BuiltinScope, Index: 3}, } for i, v := range expected { global.DefineBuiltin(i, v.Name) } for _, table := range []*SymbolTable{global, firstLocal, secondLocal} { for _, sym := range expected { result, ok := table.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) } } } }