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