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. 4 5 // This file implements Scopes. 6 7 package types 8 9 import ( 10 "bytes" 11 "fmt" 12 "go/token" 13 "io" 14 "sort" 15 "strings" 16 ) 17 18 // A Scope maintains a set of objects and links to its containing 19 // (parent) and contained (children) scopes. Objects may be inserted 20 // and looked up by name. The zero value for Scope is a ready-to-use 21 // empty scope. 22 type Scope struct { 23 parent *Scope 24 children []*Scope 25 elems map[string]Object // lazily allocated 26 pos, end token.Pos // scope extent; may be invalid 27 comment string // for debugging only 28 isFunc bool // set if this is a function scope (internal use only) 29 } 30 31 // NewScope returns a new, empty scope contained in the given parent 32 // scope, if any. The comment is for debugging only. 33 func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope { 34 s := &Scope{parent, nil, nil, pos, end, comment, false} 35 // don't add children to Universe scope! 36 if parent != nil && parent != Universe { 37 parent.children = append(parent.children, s) 38 } 39 return s 40 } 41 42 // Parent returns the scope's containing (parent) scope. 43 func (s *Scope) Parent() *Scope { return s.parent } 44 45 // Len returns the number of scope elements. 46 func (s *Scope) Len() int { return len(s.elems) } 47 48 // Names returns the scope's element names in sorted order. 49 func (s *Scope) Names() []string { 50 names := make([]string, len(s.elems)) 51 i := 0 52 for name := range s.elems { 53 names[i] = name 54 i++ 55 } 56 sort.Strings(names) 57 return names 58 } 59 60 // NumChildren returns the number of scopes nested in s. 61 func (s *Scope) NumChildren() int { return len(s.children) } 62 63 // Child returns the i'th child scope for 0 <= i < NumChildren(). 64 func (s *Scope) Child(i int) *Scope { return s.children[i] } 65 66 // Lookup returns the object in scope s with the given name if such an 67 // object exists; otherwise the result is nil. 68 func (s *Scope) Lookup(name string) Object { 69 return s.elems[name] 70 } 71 72 // LookupParent follows the parent chain of scopes starting with s until 73 // it finds a scope where Lookup(name) returns a non-nil object, and then 74 // returns that scope and object. If a valid position pos is provided, 75 // only objects that were declared at or before pos are considered. 76 // If no such scope and object exists, the result is (nil, nil). 77 // 78 // Note that obj.Parent() may be different from the returned scope if the 79 // object was inserted into the scope and already had a parent at that 80 // time (see Insert, below). This can only happen for dot-imported objects 81 // whose scope is the scope of the package that exported them. 82 func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { 83 for ; s != nil; s = s.parent { 84 if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) { 85 return s, obj 86 } 87 } 88 return nil, nil 89 } 90 91 // Insert attempts to insert an object obj into scope s. 92 // If s already contains an alternative object alt with 93 // the same name, Insert leaves s unchanged and returns alt. 94 // Otherwise it inserts obj, sets the object's parent scope 95 // if not already set, and returns nil. 96 func (s *Scope) Insert(obj Object) Object { 97 name := obj.Name() 98 if alt := s.elems[name]; alt != nil { 99 return alt 100 } 101 if s.elems == nil { 102 s.elems = make(map[string]Object) 103 } 104 s.elems[name] = obj 105 if obj.Parent() == nil { 106 obj.setParent(s) 107 } 108 return nil 109 } 110 111 // Pos and End describe the scope's source code extent [pos, end). 112 // The results are guaranteed to be valid only if the type-checked 113 // AST has complete position information. The extent is undefined 114 // for Universe and package scopes. 115 func (s *Scope) Pos() token.Pos { return s.pos } 116 func (s *Scope) End() token.Pos { return s.end } 117 118 // Contains reports whether pos is within the scope's extent. 119 // The result is guaranteed to be valid only if the type-checked 120 // AST has complete position information. 121 func (s *Scope) Contains(pos token.Pos) bool { 122 return s.pos <= pos && pos < s.end 123 } 124 125 // Innermost returns the innermost (child) scope containing 126 // pos. If pos is not within any scope, the result is nil. 127 // The result is also nil for the Universe scope. 128 // The result is guaranteed to be valid only if the type-checked 129 // AST has complete position information. 130 func (s *Scope) Innermost(pos token.Pos) *Scope { 131 // Package scopes do not have extents since they may be 132 // discontiguous, so iterate over the package's files. 133 if s.parent == Universe { 134 for _, s := range s.children { 135 if inner := s.Innermost(pos); inner != nil { 136 return inner 137 } 138 } 139 } 140 141 if s.Contains(pos) { 142 for _, s := range s.children { 143 if s.Contains(pos) { 144 return s.Innermost(pos) 145 } 146 } 147 return s 148 } 149 return nil 150 } 151 152 // WriteTo writes a string representation of the scope to w, 153 // with the scope elements sorted by name. 154 // The level of indentation is controlled by n >= 0, with 155 // n == 0 for no indentation. 156 // If recurse is set, it also writes nested (children) scopes. 157 func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { 158 const ind = ". " 159 indn := strings.Repeat(ind, n) 160 161 fmt.Fprintf(w, "%s%s scope %p {\n", indn, s.comment, s) 162 163 indn1 := indn + ind 164 for _, name := range s.Names() { 165 fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) 166 } 167 168 if recurse { 169 for _, s := range s.children { 170 s.WriteTo(w, n+1, recurse) 171 } 172 } 173 174 fmt.Fprintf(w, "%s}\n", indn) 175 } 176 177 // String returns a string representation of the scope, for debugging. 178 func (s *Scope) String() string { 179 var buf bytes.Buffer 180 s.WriteTo(&buf, 0, false) 181 return buf.String() 182 } 183