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 7package ast 8 9import ( 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]. 20type Scope struct { 21 Outer *Scope 22 Objects map[string]*Object 23} 24 25// NewScope creates a new scope nested in the outer scope. 26func 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. 34func (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. 42func (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 50func (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. 87type 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. 96func 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). 103func (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. 148type ObjKind int 149 150// The list of possible [Object] kinds. 151const ( 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 161var 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 171func (kind ObjKind) String() string { return objKindStrings[kind] } 172