Source file
src/go/types/scope.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "fmt"
12 "go/token"
13 "io"
14 "sort"
15 "strings"
16 "sync"
17 )
18
19
20
21
22
23 type Scope struct {
24 parent *Scope
25 children []*Scope
26 number int
27 elems map[string]Object
28 pos, end token.Pos
29 comment string
30 isFunc bool
31 }
32
33
34
35 func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
36 s := &Scope{parent, nil, 0, nil, pos, end, comment, false}
37
38 if parent != nil && parent != Universe {
39 parent.children = append(parent.children, s)
40 s.number = len(parent.children)
41 }
42 return s
43 }
44
45
46 func (s *Scope) Parent() *Scope { return s.parent }
47
48
49 func (s *Scope) Len() int { return len(s.elems) }
50
51
52 func (s *Scope) Names() []string {
53 names := make([]string, len(s.elems))
54 i := 0
55 for name := range s.elems {
56 names[i] = name
57 i++
58 }
59 sort.Strings(names)
60 return names
61 }
62
63
64 func (s *Scope) NumChildren() int { return len(s.children) }
65
66
67 func (s *Scope) Child(i int) *Scope { return s.children[i] }
68
69
70
71 func (s *Scope) Lookup(name string) Object {
72 return resolve(name, s.elems[name])
73 }
74
75
76
77
78
79
80
81
82
83
84
85 func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
86 for ; s != nil; s = s.parent {
87 if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
88 return s, obj
89 }
90 }
91 return nil, nil
92 }
93
94
95
96
97
98
99 func (s *Scope) Insert(obj Object) Object {
100 name := obj.Name()
101 if alt := s.Lookup(name); alt != nil {
102 return alt
103 }
104 s.insert(name, obj)
105 if obj.Parent() == nil {
106 obj.setParent(s)
107 }
108 return nil
109 }
110
111
112
113
114
115
116
117
118 func (s *Scope) _InsertLazy(name string, resolve func() Object) bool {
119 if s.elems[name] != nil {
120 return false
121 }
122 s.insert(name, &lazyObject{parent: s, resolve: resolve})
123 return true
124 }
125
126 func (s *Scope) insert(name string, obj Object) {
127 if s.elems == nil {
128 s.elems = make(map[string]Object)
129 }
130 s.elems[name] = obj
131 }
132
133
134
135
136
137
138
139 func (s *Scope) squash(err func(obj, alt Object)) {
140 p := s.parent
141 assert(p != nil)
142 for name, obj := range s.elems {
143 obj = resolve(name, obj)
144 obj.setParent(nil)
145 if alt := p.Insert(obj); alt != nil {
146 err(obj, alt)
147 }
148 }
149
150 j := -1
151 for i, ch := range p.children {
152 if ch == s {
153 j = i
154 break
155 }
156 }
157 assert(j >= 0)
158 k := len(p.children) - 1
159 p.children[j] = p.children[k]
160 p.children = p.children[:k]
161
162 p.children = append(p.children, s.children...)
163
164 s.children = nil
165 s.elems = nil
166 }
167
168
169
170
171
172 func (s *Scope) Pos() token.Pos { return s.pos }
173 func (s *Scope) End() token.Pos { return s.end }
174
175
176
177
178 func (s *Scope) Contains(pos token.Pos) bool {
179 return s.pos <= pos && pos < s.end
180 }
181
182
183
184
185
186
187 func (s *Scope) Innermost(pos token.Pos) *Scope {
188
189
190 if s.parent == Universe {
191 for _, s := range s.children {
192 if inner := s.Innermost(pos); inner != nil {
193 return inner
194 }
195 }
196 }
197
198 if s.Contains(pos) {
199 for _, s := range s.children {
200 if s.Contains(pos) {
201 return s.Innermost(pos)
202 }
203 }
204 return s
205 }
206 return nil
207 }
208
209
210
211
212
213
214 func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
215 const ind = ". "
216 indn := strings.Repeat(ind, n)
217
218 fmt.Fprintf(w, "%s%s scope %p {\n", indn, s.comment, s)
219
220 indn1 := indn + ind
221 for _, name := range s.Names() {
222 fmt.Fprintf(w, "%s%s\n", indn1, s.Lookup(name))
223 }
224
225 if recurse {
226 for _, s := range s.children {
227 s.WriteTo(w, n+1, recurse)
228 }
229 }
230
231 fmt.Fprintf(w, "%s}\n", indn)
232 }
233
234
235 func (s *Scope) String() string {
236 var buf bytes.Buffer
237 s.WriteTo(&buf, 0, false)
238 return buf.String()
239 }
240
241
242
243 type lazyObject struct {
244 parent *Scope
245 resolve func() Object
246 obj Object
247 once sync.Once
248 }
249
250
251
252 func resolve(name string, obj Object) Object {
253 if lazy, ok := obj.(*lazyObject); ok {
254 lazy.once.Do(func() {
255 obj := lazy.resolve()
256
257 if _, ok := obj.(*lazyObject); ok {
258 panic("recursive lazy object")
259 }
260 if obj.Name() != name {
261 panic("lazy object has unexpected name")
262 }
263
264 if obj.Parent() == nil {
265 obj.setParent(lazy.parent)
266 }
267 lazy.obj = obj
268 })
269
270 obj = lazy.obj
271 }
272 return obj
273 }
274
275
276
277 func (*lazyObject) Parent() *Scope { panic("unreachable") }
278 func (*lazyObject) Pos() token.Pos { panic("unreachable") }
279 func (*lazyObject) Pkg() *Package { panic("unreachable") }
280 func (*lazyObject) Name() string { panic("unreachable") }
281 func (*lazyObject) Type() Type { panic("unreachable") }
282 func (*lazyObject) Exported() bool { panic("unreachable") }
283 func (*lazyObject) Id() string { panic("unreachable") }
284 func (*lazyObject) String() string { panic("unreachable") }
285 func (*lazyObject) order() uint32 { panic("unreachable") }
286 func (*lazyObject) color() color { panic("unreachable") }
287 func (*lazyObject) setType(Type) { panic("unreachable") }
288 func (*lazyObject) setOrder(uint32) { panic("unreachable") }
289 func (*lazyObject) setColor(color color) { panic("unreachable") }
290 func (*lazyObject) setParent(*Scope) { panic("unreachable") }
291 func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") }
292 func (*lazyObject) scopePos() token.Pos { panic("unreachable") }
293 func (*lazyObject) setScopePos(pos token.Pos) { panic("unreachable") }
294
View as plain text