Source file src/go/ast/scope.go
1 // Copyright 2009 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 and the objects they contain. 6 7 package ast 8 9 import ( 10 "fmt" 11 "go/token" 12 "strings" 13 ) 14 15 // A Scope maintains the set of named language entities declared 16 // in the scope and a link to the immediately surrounding (outer) 17 // scope. 18 // 19 // Deprecated: use the type checker [go/types] instead; see [Object]. 20 type Scope struct { 21 Outer *Scope 22 Objects map[string]*Object 23 } 24 25 // NewScope creates a new scope nested in the outer scope. 26 func NewScope(outer *Scope) *Scope { 27 const n = 4 // initial scope capacity 28 return &Scope{outer, make(map[string]*Object, n)} 29 } 30 31 // Lookup returns the object with the given name if it is 32 // found in scope s, otherwise it returns nil. Outer scopes 33 // are ignored. 34 func (s *Scope) Lookup(name string) *Object { 35 return s.Objects[name] 36 } 37 38 // Insert attempts to insert a named object obj into the scope s. 39 // If the scope already contains an object alt with the same name, 40 // Insert leaves the scope unchanged and returns alt. Otherwise 41 // it inserts obj and returns nil. 42 func (s *Scope) Insert(obj *Object) (alt *Object) { 43 if alt = s.Objects[obj.Name]; alt == nil { 44 s.Objects[obj.Name] = obj 45 } 46 return 47 } 48 49 // Debugging support 50 func (s *Scope) String() string { 51 var buf strings.Builder 52 fmt.Fprintf(&buf, "scope %p {", s) 53 if s != nil && len(s.Objects) > 0 { 54 fmt.Fprintln(&buf) 55 for _, obj := range s.Objects { 56 fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name) 57 } 58 } 59 fmt.Fprintf(&buf, "}\n") 60 return buf.String() 61 } 62 63 // ---------------------------------------------------------------------------- 64 // Objects 65 66 // An Object describes a named language entity such as a package, 67 // constant, type, variable, function (incl. methods), or label. 68 // 69 // The Data fields contains object-specific data: 70 // 71 // Kind Data type Data value 72 // Pkg *Scope package scope 73 // Con int iota for the respective declaration 74 // 75 // Deprecated: The relationship between Idents and Objects cannot be 76 // correctly computed without type information. For example, the 77 // expression T{K: 0} may denote a struct, map, slice, or array 78 // literal, depending on the type of T. If T is a struct, then K 79 // refers to a field of T, whereas for the other types it refers to a 80 // value in the environment. 81 // 82 // New programs should set the [parser.SkipObjectResolution] parser 83 // flag to disable syntactic object resolution (which also saves CPU 84 // and memory), and instead use the type checker [go/types] if object 85 // resolution is desired. See the Defs, Uses, and Implicits fields of 86 // the [types.Info] struct for details. 87 type Object struct { 88 Kind ObjKind 89 Name string // declared name 90 Decl any // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil 91 Data any // object-specific data; or nil 92 Type any // placeholder for type information; may be nil 93 } 94 95 // NewObj creates a new object of a given kind and name. 96 func NewObj(kind ObjKind, name string) *Object { 97 return &Object{Kind: kind, Name: name} 98 } 99 100 // Pos computes the source position of the declaration of an object name. 101 // The result may be an invalid position if it cannot be computed 102 // (obj.Decl may be nil or not correct). 103 func (obj *Object) Pos() token.Pos { 104 name := obj.Name 105 switch d := obj.Decl.(type) { 106 case *Field: 107 for _, n := range d.Names { 108 if n.Name == name { 109 return n.Pos() 110 } 111 } 112 case *ImportSpec: 113 if d.Name != nil && d.Name.Name == name { 114 return d.Name.Pos() 115 } 116 return d.Path.Pos() 117 case *ValueSpec: 118 for _, n := range d.Names { 119 if n.Name == name { 120 return n.Pos() 121 } 122 } 123 case *TypeSpec: 124 if d.Name.Name == name { 125 return d.Name.Pos() 126 } 127 case *FuncDecl: 128 if d.Name.Name == name { 129 return d.Name.Pos() 130 } 131 case *LabeledStmt: 132 if d.Label.Name == name { 133 return d.Label.Pos() 134 } 135 case *AssignStmt: 136 for _, x := range d.Lhs { 137 if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { 138 return ident.Pos() 139 } 140 } 141 case *Scope: 142 // predeclared object - nothing to do for now 143 } 144 return token.NoPos 145 } 146 147 // ObjKind describes what an [Object] represents. 148 type ObjKind int 149 150 // The list of possible [Object] kinds. 151 const ( 152 Bad ObjKind = iota // for error handling 153 Pkg // package 154 Con // constant 155 Typ // type 156 Var // variable 157 Fun // function or method 158 Lbl // label 159 ) 160 161 var objKindStrings = [...]string{ 162 Bad: "bad", 163 Pkg: "package", 164 Con: "const", 165 Typ: "type", 166 Var: "var", 167 Fun: "func", 168 Lbl: "label", 169 } 170 171 func (kind ObjKind) String() string { return objKindStrings[kind] } 172