tc_scope.mx raw

   1  package main
   2  
   3  // Scope is a mapping from names to Objects. Scopes are chained:
   4  // a lookup that misses in the current scope walks up to the parent.
   5  type Scope struct {
   6  	parent   *Scope
   7  	children []*Scope
   8  	elems    map[string]Object
   9  }
  10  
  11  func NewScope(parent *Scope) *Scope {
  12  	return &Scope{parent: parent, elems: map[string]Object{}}
  13  }
  14  
  15  func (s *Scope) Parent() *Scope   { return s.parent }
  16  func (s *Scope) Len() int         { return len(s.elems) }
  17  
  18  func (s *Scope) Lookup(name string) Object {
  19  	return s.elems[name]
  20  }
  21  
  22  // LookupParent looks up name starting at s, walking the parent chain.
  23  // Returns the scope where it was found and the object, or nil, nil.
  24  func (s *Scope) LookupParent(name string) (*Scope, Object) {
  25  	for sc := s; sc != nil; sc = sc.parent {
  26  		if obj, ok := sc.elems[name]; ok {
  27  			return sc, obj
  28  		}
  29  	}
  30  	return nil, nil
  31  }
  32  
  33  // Insert inserts obj into s. Returns an existing object with the same name
  34  // if there is one (caller must report the error).
  35  func (s *Scope) Insert(obj Object) Object {
  36  	name := obj.Name()
  37  	if alt, ok := s.elems[name]; ok {
  38  		return alt
  39  	}
  40  	// Copy name to avoid aliasing with parser's internal buffer.
  41  	// Moxie's string=[]byte means map keys can be mutated through shared backing.
  42  	key := string(append([]byte(nil), name...))
  43  	s.elems[key] = obj
  44  	return nil
  45  }
  46  
  47  // Names returns all names in this scope, unsorted.
  48  func (s *Scope) Names() []string {
  49  	names := []string{:0:len(s.elems)}
  50  	for n := range s.elems {
  51  		names = append(names, n)
  52  	}
  53  	return names
  54  }
  55