// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements scopes and the objects they contain.

package ast

import (
	
	
	
)

// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
//
// Deprecated: use the type checker [go/types] instead; see [Object].
type Scope struct {
	Outer   *Scope
	Objects map[string]*Object
}

// NewScope creates a new scope nested in the outer scope.
func ( *Scope) *Scope {
	const  = 4 // initial scope capacity
	return &Scope{, make(map[string]*Object, )}
}

// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
func ( *Scope) ( string) *Object {
	return .Objects[]
}

// Insert attempts to insert a named object obj into the scope s.
// If the scope already contains an object alt with the same name,
// Insert leaves the scope unchanged and returns alt. Otherwise
// it inserts obj and returns nil.
func ( *Scope) ( *Object) ( *Object) {
	if  = .Objects[.Name];  == nil {
		.Objects[.Name] = 
	}
	return
}

// Debugging support
func ( *Scope) () string {
	var  strings.Builder
	fmt.Fprintf(&, "scope %p {", )
	if  != nil && len(.Objects) > 0 {
		fmt.Fprintln(&)
		for ,  := range .Objects {
			fmt.Fprintf(&, "\t%s %s\n", .Kind, .Name)
		}
	}
	fmt.Fprintf(&, "}\n")
	return .String()
}

// ----------------------------------------------------------------------------
// Objects

// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
//
// The Data fields contains object-specific data:
//
//	Kind    Data type         Data value
//	Pkg     *Scope            package scope
//	Con     int               iota for the respective declaration
//
// Deprecated: The relationship between Idents and Objects cannot be
// correctly computed without type information. For example, the
// expression T{K: 0} may denote a struct, map, slice, or array
// literal, depending on the type of T. If T is a struct, then K
// refers to a field of T, whereas for the other types it refers to a
// value in the environment.
//
// New programs should set the [parser.SkipObjectResolution] parser
// flag to disable syntactic object resolution (which also saves CPU
// and memory), and instead use the type checker [go/types] if object
// resolution is desired. See the Defs, Uses, and Implicits fields of
// the [types.Info] struct for details.
type Object struct {
	Kind ObjKind
	Name string // declared name
	Decl any    // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
	Data any    // object-specific data; or nil
	Type any    // placeholder for type information; may be nil
}

// NewObj creates a new object of a given kind and name.
func ( ObjKind,  string) *Object {
	return &Object{Kind: , Name: }
}

// Pos computes the source position of the declaration of an object name.
// The result may be an invalid position if it cannot be computed
// (obj.Decl may be nil or not correct).
func ( *Object) () token.Pos {
	 := .Name
	switch d := .Decl.(type) {
	case *Field:
		for ,  := range .Names {
			if .Name ==  {
				return .Pos()
			}
		}
	case *ImportSpec:
		if .Name != nil && .Name.Name ==  {
			return .Name.Pos()
		}
		return .Path.Pos()
	case *ValueSpec:
		for ,  := range .Names {
			if .Name ==  {
				return .Pos()
			}
		}
	case *TypeSpec:
		if .Name.Name ==  {
			return .Name.Pos()
		}
	case *FuncDecl:
		if .Name.Name ==  {
			return .Name.Pos()
		}
	case *LabeledStmt:
		if .Label.Name ==  {
			return .Label.Pos()
		}
	case *AssignStmt:
		for ,  := range .Lhs {
			if ,  := .(*Ident);  && .Name ==  {
				return .Pos()
			}
		}
	case *Scope:
		// predeclared object - nothing to do for now
	}
	return token.NoPos
}

// ObjKind describes what an object represents.
type ObjKind int

// The list of possible Object kinds.
const (
	Bad ObjKind = iota // for error handling
	Pkg                // package
	Con                // constant
	Typ                // type
	Var                // variable
	Fun                // function or method
	Lbl                // label
)

var objKindStrings = [...]string{
	Bad: "bad",
	Pkg: "package",
	Con: "const",
	Typ: "type",
	Var: "var",
	Fun: "func",
	Lbl: "label",
}

func ( ObjKind) () string { return objKindStrings[] }