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