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