tc_scope.mx raw

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