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