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