|
|
@@ -6,6 +6,10 @@ 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()
|
|
|
@@ -18,6 +22,30 @@ func TestDefine(t *testing.T) {
|
|
|
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) {
|
|
|
@@ -42,3 +70,82 @@ func TestResolveGlobal(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|