1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements Scopes.
18 // TODO(gri) Provide scopes with a name or other mechanism so that
19 // objects can use that information for better printing.
21 // A Scope maintains a set of objects and links to its containing
22 // (parent) and contained (children) scopes. Objects may be inserted
23 // and looked up by name. The zero value for Scope is a ready-to-use
28 elems
map[string]Object
// lazily allocated
29 pos
, end token
.Pos
// scope extent; may be invalid
30 comment
string // for debugging only
33 // NewScope returns a new, empty scope contained in the given parent
34 // scope, if any. The comment is for debugging only.
35 func NewScope(parent
*Scope
, pos
, end token
.Pos
, comment
string) *Scope
{
36 s
:= &Scope
{parent
, nil, nil, pos
, end
, comment
}
37 // don't add children to Universe scope!
38 if parent
!= nil && parent
!= Universe
{
39 parent
.children
= append(parent
.children
, s
)
44 // Parent returns the scope's containing (parent) scope.
45 func (s
*Scope
) Parent() *Scope
{ return s
.parent
}
47 // Len() returns the number of scope elements.
48 func (s
*Scope
) Len() int { return len(s
.elems
) }
50 // Names returns the scope's element names in sorted order.
51 func (s
*Scope
) Names() []string {
52 names
:= make([]string, len(s
.elems
))
54 for name
:= range s
.elems
{
62 // NumChildren() returns the number of scopes nested in s.
63 func (s
*Scope
) NumChildren() int { return len(s
.children
) }
65 // Child returns the i'th child scope for 0 <= i < NumChildren().
66 func (s
*Scope
) Child(i
int) *Scope
{ return s
.children
[i
] }
68 // Lookup returns the object in scope s with the given name if such an
69 // object exists; otherwise the result is nil.
70 func (s
*Scope
) Lookup(name
string) Object
{
74 // LookupParent follows the parent chain of scopes starting with s until
75 // it finds a scope where Lookup(name) returns a non-nil object, and then
76 // returns that scope and object. If a valid position pos is provided,
77 // only objects that were declared at or before pos are considered.
78 // If no such scope and object exists, the result is (nil, nil).
80 // Note that obj.Parent() may be different from the returned scope if the
81 // object was inserted into the scope and already had a parent at that
82 // time (see Insert, below). This can only happen for dot-imported objects
83 // whose scope is the scope of the package that exported them.
84 func (s
*Scope
) LookupParent(name
string, pos token
.Pos
) (*Scope
, Object
) {
85 for ; s
!= nil; s
= s
.parent
{
86 if obj
:= s
.elems
[name
]; obj
!= nil && (!pos
.IsValid() || obj
.scopePos() <= pos
) {
93 // Insert attempts to insert an object obj into scope s.
94 // If s already contains an alternative object alt with
95 // the same name, Insert leaves s unchanged and returns alt.
96 // Otherwise it inserts obj, sets the object's parent scope
97 // if not already set, and returns nil.
98 func (s
*Scope
) Insert(obj Object
) Object
{
100 if alt
:= s
.elems
[name
]; alt
!= nil {
104 s
.elems
= make(map[string]Object
)
107 if obj
.Parent() == nil {
113 // Pos and End describe the scope's source code extent [pos, end).
114 // The results are guaranteed to be valid only if the type-checked
115 // AST has complete position information. The extent is undefined
116 // for Universe and package scopes.
117 func (s
*Scope
) Pos() token
.Pos
{ return s
.pos
}
118 func (s
*Scope
) End() token
.Pos
{ return s
.end
}
120 // Contains returns true if pos is within the scope's extent.
121 // The result is guaranteed to be valid only if the type-checked
122 // AST has complete position information.
123 func (s
*Scope
) Contains(pos token
.Pos
) bool {
124 return s
.pos
<= pos
&& pos
< s
.end
127 // Innermost returns the innermost (child) scope containing
128 // pos. If pos is not within any scope, the result is nil.
129 // The result is also nil for the Universe scope.
130 // The result is guaranteed to be valid only if the type-checked
131 // AST has complete position information.
132 func (s
*Scope
) Innermost(pos token
.Pos
) *Scope
{
133 // Package scopes do not have extents since they may be
134 // discontiguous, so iterate over the package's files.
135 if s
.parent
== Universe
{
136 for _
, s
:= range s
.children
{
137 if inner
:= s
.Innermost(pos
); inner
!= nil {
144 for _
, s
:= range s
.children
{
146 return s
.Innermost(pos
)
154 // WriteTo writes a string representation of the scope to w,
155 // with the scope elements sorted by name.
156 // The level of indentation is controlled by n >= 0, with
157 // n == 0 for no indentation.
158 // If recurse is set, it also writes nested (children) scopes.
159 func (s
*Scope
) WriteTo(w io
.Writer
, n
int, recurse
bool) {
161 indn
:= strings
.Repeat(ind
, n
)
163 fmt
.Fprintf(w
, "%s%s scope %p {", indn
, s
.comment
, s
)
164 if len(s
.elems
) == 0 {
165 fmt
.Fprintf(w
, "}\n")
171 for _
, name
:= range s
.Names() {
172 fmt
.Fprintf(w
, "%s%s\n", indn1
, s
.elems
[name
])
176 for _
, s
:= range s
.children
{
178 s
.WriteTo(w
, n
+1, recurse
)
182 fmt
.Fprintf(w
, "%s}", indn
)
185 // String returns a string representation of the scope, for debugging.
186 func (s
*Scope
) String() string {
188 s
.WriteTo(&buf
, 0, false)