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