package compiler type SymbolScope string const ( LocalScope SymbolScope = "LOCAL" GlobalScope SymbolScope = "GLOBAL" BuiltinScope SymbolScope = "BUILTIN" FreeScope SymbolScope = "FREE" FunctionScope SymbolScope = "FUNCTION" ) type Symbol struct { Name string Scope SymbolScope Index int } type SymbolTable struct { Outer *SymbolTable Store map[string]Symbol NumDefinitions int FreeSymbols []Symbol } func NewEnclosedSymbolTable(outer *SymbolTable) *SymbolTable { s := NewSymbolTable() s.Outer = outer return s } func NewSymbolTable() *SymbolTable { s := make(map[string]Symbol) free := []Symbol{} return &SymbolTable{Store: s, FreeSymbols: free} } func (s *SymbolTable) Define(name string) Symbol { symbol := Symbol{Name: name, Index: s.NumDefinitions} if s.Outer == nil { symbol.Scope = GlobalScope } else { symbol.Scope = LocalScope } s.Store[name] = symbol s.NumDefinitions++ return symbol } func (s *SymbolTable) Resolve(name string) (Symbol, bool) { obj, ok := s.Store[name] if !ok && s.Outer != nil { obj, ok = s.Outer.Resolve(name) if !ok { return obj, ok } if obj.Scope == GlobalScope || obj.Scope == BuiltinScope { return obj, ok } free := s.DefineFree(obj) return free, true } return obj, ok } func (s *SymbolTable) DefineBuiltin(index int, name string) Symbol { symbol := Symbol{Name: name, Index: index, Scope: BuiltinScope} s.Store[name] = symbol return symbol } func (s *SymbolTable) DefineFree(original Symbol) Symbol { s.FreeSymbols = append(s.FreeSymbols, original) symbol := Symbol{Name: original.Name, Index: len(s.FreeSymbols) - 1} symbol.Scope = FreeScope s.Store[original.Name] = symbol return symbol } func (s *SymbolTable) DefineFunctionName(name string) Symbol { symbol := Symbol{Name: name, Index: 0, Scope: FunctionScope} s.Store[name] = symbol return symbol }