package compiler type ScopeID int type ScopeChain struct { scopes []Scope } func NewScopeChain() ScopeChain { scopes := make([]Scope, 1) scopes[0] = Scope{ kind: ScopeKindGlobal, symbols: make(map[string]Symbol), } return ScopeChain{ scopes: scopes, } } func (sc *ScopeChain) Current() *Scope { return &sc.scopes[len(sc.scopes)-1] } func (sc *ScopeChain) Enter(kind ScopeKind) { sc.scopes = append(sc.scopes, Scope{ kind: kind, symbols: make(map[string]Symbol), }) } func (sc *ScopeChain) Exit() { sc.scopes[len(sc.scopes)-1] = Scope{} sc.scopes = sc.scopes[:len(sc.scopes)-1] } func (sc *ScopeChain) Declare(name string) bool { // Check whether the symbol is already declared in any of the scopes. for _, scope := range sc.scopes { if _, ok := scope.symbols[name]; ok { return false } } // Declare the symbol in the current scope. sc.Current().symbols[name] = Symbol{ kind: SymbolKindVariable, name: name, localIndex: len(sc.Current().symbols), } return true } func (sc *ScopeChain) Lookup(name string) (Symbol, bool) { for i := len(sc.scopes) - 1; i >= 0; i-- { if symbol, ok := sc.scopes[i].symbols[name]; ok { return symbol, true } } return Symbol{}, false } type ScopeKind int const ( ScopeKindGlobal ScopeKind = iota ScopeKindFunction ScopeKindBlock ) type Scope struct { kind ScopeKind symbols map[string]Symbol }