// Copyright 2025 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.

package inspector

import (
	
	
	
	
	

	
)

// A Cursor represents an [ast.Node]. It is immutable.
//
// Two Cursors compare equal if they represent the same node.
//
// The zero value of Cursor is not valid.
//
// Call [Inspector.Root] to obtain a cursor for the virtual root node
// of the traversal. This is the sole valid cursor for which [Cursor.Node]
// returns nil.
//
// Use the following methods to navigate efficiently around the tree:
//   - for ancestors, use [Cursor.Parent] and [Cursor.Enclosing];
//   - for children, use [Cursor.Child], [Cursor.Children],
//     [Cursor.FirstChild], and [Cursor.LastChild];
//   - for siblings, use [Cursor.PrevSibling] and [Cursor.NextSibling];
//   - for descendants, use [Cursor.FindByPos], [Cursor.FindNode],
//     [Cursor.Inspect], and [Cursor.Preorder].
//
// Use the [Cursor.ChildAt] and [Cursor.ParentEdge] methods for
// information about the edges in a tree: which field (and slice
// element) of the parent node holds the child.
type Cursor struct {
	in    *Inspector
	index int32 // index of push node; -1 for virtual root node
}

// Root returns a valid cursor for the virtual root node,
// whose children are the files provided to [New].
//
// Its [Cursor.Node] method return nil.
func ( *Inspector) () Cursor {
	return Cursor{, -1}
}

// At returns the cursor at the specified index in the traversal,
// which must have been obtained from [Cursor.Index] on a Cursor
// belonging to the same Inspector (see [Cursor.Inspector]).
func ( *Inspector) ( int32) Cursor {
	if  < 0 {
		panic("negative index")
	}
	if int() >= len(.events) {
		panic("index out of range for this inspector")
	}
	if .events[].index <  {
		panic("invalid index") // (a push, not a pop)
	}
	return Cursor{, }
}

// Valid reports whether the cursor is valid.
// The zero value of cursor is invalid.
// Unless otherwise documented, it is not safe to call
// any other method on an invalid cursor.
func ( Cursor) () bool {
	return .in != nil
}

// Inspector returns the cursor's Inspector.
// It returns nil if the Cursor is not valid.
func ( Cursor) () *Inspector { return .in }

// Index returns the index of this cursor position within the package.
//
// Clients should not assume anything about the numeric Index value
// except that it increases monotonically throughout the traversal.
// It is provided for use with [Inspector.At].
//
// Index must not be called on the Root node.
func ( Cursor) () int32 {
	if .index < 0 {
		panic("Index called on Root node")
	}
	return .index
}

// Node returns the node at the current cursor position,
// or nil for the cursor returned by [Inspector.Root].
func ( Cursor) () ast.Node {
	if .index < 0 {
		return nil
	}
	return .in.events[.index].node
}

// String returns information about the cursor's node, if any.
func ( Cursor) () string {
	if !.Valid() {
		return "(invalid)"
	}
	if .index < 0 {
		return "(root)"
	}
	return reflect.TypeOf(.Node()).String()
}

// indices return the [start, end) half-open interval of event indices.
func ( Cursor) () (int32, int32) {
	if .index < 0 {
		return 0, int32(len(.in.events)) // root: all events
	} else {
		return .index, .in.events[.index].index + 1 // just one subtree
	}
}

// Preorder returns an iterator over the nodes of the subtree
// represented by c in depth-first order. Each node in the sequence is
// represented by a Cursor that allows access to the Node, but may
// also be used to start a new traversal, or to obtain the stack of
// nodes enclosing the cursor.
//
// The traversal sequence is determined by [ast.Inspect]. The types
// argument, if non-empty, enables type-based filtering of events. The
// function f if is called only for nodes whose type matches an
// element of the types slice.
//
// If you need control over descent into subtrees,
// or need both pre- and post-order notifications, use [Cursor.Inspect]
func ( Cursor) ( ...ast.Node) iter.Seq[Cursor] {
	 := maskOf()

	return func( func(Cursor) bool) {
		 := .in.events

		for ,  := .indices();  < ; {
			 := []
			if .index >  { // push?
				if .typ& != 0 && !(Cursor{.in, }) {
					break
				}
				 := .index
				if [].typ& == 0 {
					// Subtree does not contain types: skip.
					 =  + 1
					continue
				}
			}
			++
		}
	}
}

// Inspect visits the nodes of the subtree represented by c in
// depth-first order. It calls f(n) for each node n before it
// visits n's children. If f returns true, Inspect invokes f
// recursively for each of the non-nil children of the node.
//
// Each node is represented by a Cursor that allows access to the
// Node, but may also be used to start a new traversal, or to obtain
// the stack of nodes enclosing the cursor.
//
// The complete traversal sequence is determined by [ast.Inspect].
// The types argument, if non-empty, enables type-based filtering of
// events. The function f if is called only for nodes whose type
// matches an element of the types slice.
func ( Cursor) ( []ast.Node,  func( Cursor) ( bool)) {
	 := maskOf()
	 := .in.events
	for ,  := .indices();  < ; {
		 := []
		if .index >  {
			// push
			 := .index
			if .typ& != 0 && !(Cursor{.in, }) ||
				[].typ& == 0 {
				// The user opted not to descend, or the
				// subtree does not contain types:
				// skip past the pop.
				 =  + 1
				continue
			}
		}
		++
	}
}

// Enclosing returns an iterator over the nodes enclosing the current
// current node, starting with the Cursor itself.
//
// Enclosing must not be called on the Root node (whose [Cursor.Node] returns nil).
//
// The types argument, if non-empty, enables type-based filtering of
// events: the sequence includes only enclosing nodes whose type
// matches an element of the types slice.
func ( Cursor) ( ...ast.Node) iter.Seq[Cursor] {
	if .index < 0 {
		panic("Cursor.Enclosing called on Root node")
	}

	 := maskOf()

	return func( func(Cursor) bool) {
		 := .in.events
		for  := .index;  >= 0;  = [].parent {
			if [].typ& != 0 && !(Cursor{.in, }) {
				break
			}
		}
	}
}

// Parent returns the parent of the current node.
//
// Parent must not be called on the Root node (whose [Cursor.Node] returns nil).
func ( Cursor) () Cursor {
	if .index < 0 {
		panic("Cursor.Parent called on Root node")
	}

	return Cursor{.in, .in.events[.index].parent}
}

// ParentEdge returns the identity of the field in the parent node
// that holds this cursor's node, and if it is a list, the index within it.
//
// For example, f(x, y) is a CallExpr whose three children are Idents.
// f has edge kind [edge.CallExpr_Fun] and index -1.
// x and y have kind [edge.CallExpr_Args] and indices 0 and 1, respectively.
//
// If called on a child of the Root node, it returns ([edge.Invalid], -1).
//
// ParentEdge must not be called on the Root node (whose [Cursor.Node] returns nil).
func ( Cursor) () (edge.Kind, int) {
	if .index < 0 {
		panic("Cursor.ParentEdge called on Root node")
	}
	 := .in.events
	 := [.index].index
	return unpackEdgeKindAndIndex([].parent)
}

// ParentEdgeKind returns the kind component of the result of [Cursor.ParentEdge].
func ( Cursor) () edge.Kind {
	,  := .ParentEdge()
	return 
}

// ParentEdgeIndex returns the index component of the result of [Cursor.ParentEdge].
func ( Cursor) () int {
	,  := .ParentEdge()
	return 
}

// ChildAt returns the cursor for the child of the
// current node identified by its edge and index.
// The index must be -1 if the edge.Kind is not a slice.
// The indicated child node must exist.
//
// ChildAt must not be called on the Root node (whose [Cursor.Node] returns nil).
//
// Invariant: c.Parent().ChildAt(c.ParentEdge()) == c.
func ( Cursor) ( edge.Kind,  int) Cursor {
	 := packEdgeKindAndIndex(, )

	// Unfortunately there's no shortcut to looping.
	 := .in.events
	 := .index + 1
	for {
		 := [].index
		if  <  {
			break
		}
		if [].parent ==  {
			return Cursor{.in, }
		}
		 =  + 1
	}
	panic(fmt.Sprintf("ChildAt(%v, %d): no such child of %v", , , ))
}

// Child returns the cursor for n, which must be a direct child of c's Node.
//
// Child must not be called on the Root node (whose [Cursor.Node] returns nil).
func ( Cursor) ( ast.Node) Cursor {
	if .index < 0 {
		panic("Cursor.Child called on Root node")
	}

	if false {
		// reference implementation
		for  := range .Children() {
			if .Node() ==  {
				return 
			}
		}

	} else {
		// optimized implementation
		 := .in.events
		for  := .index + 1; [].index > ;  = [].index + 1 {
			if [].node ==  {
				return Cursor{.in, }
			}
		}
	}
	panic(fmt.Sprintf("Child(%T): not a child of %v", , ))
}

// NextSibling returns the cursor for the next sibling node in the same list
// (for example, of files, decls, specs, statements, fields, or expressions) as
// the current node. It returns (zero, false) if the node is the last node in
// the list, or is not part of a list.
//
// NextSibling must not be called on the Root node.
//
// See note at [Cursor.Children].
func ( Cursor) () (Cursor, bool) {
	if .index < 0 {
		panic("Cursor.NextSibling called on Root node")
	}

	 := .in.events
	 := [.index].index + 1 // after corresponding pop
	if  < int32(len()) {
		if [].index >  { // push?
			return Cursor{.in, }, true
		}
	}
	return Cursor{}, false
}

// PrevSibling returns the cursor for the previous sibling node in the
// same list (for example, of files, decls, specs, statements, fields,
// or expressions) as the current node. It returns zero if the node is
// the first node in the list, or is not part of a list.
//
// It must not be called on the Root node.
//
// See note at [Cursor.Children].
func ( Cursor) () (Cursor, bool) {
	if .index < 0 {
		panic("Cursor.PrevSibling called on Root node")
	}

	 := .in.events
	 := .index - 1
	if  >= 0 {
		if  := [].index;  <  { // pop?
			return Cursor{.in, }, true
		}
	}
	return Cursor{}, false
}

// FirstChild returns the first direct child of the current node,
// or zero if it has no children.
func ( Cursor) () (Cursor, bool) {
	 := .in.events
	 := .index + 1                                   // i=0 if c is root
	if  < int32(len()) && [].index >  { // push?
		return Cursor{.in, }, true
	}
	return Cursor{}, false
}

// LastChild returns the last direct child of the current node,
// or zero if it has no children.
func ( Cursor) () (Cursor, bool) {
	 := .in.events
	if .index < 0 { // root?
		if len() > 0 {
			// return push of final event (a pop)
			return Cursor{.in, [len()-1].index}, true
		}
	} else {
		 := [.index].index - 1 // before corresponding pop
		// Inv: j == c.index if c has no children
		//  or  j is last child's pop.
		if  > .index { // c has children
			return Cursor{.in, [].index}, true
		}
	}
	return Cursor{}, false
}

// Children returns an iterator over the direct children of the
// current node, if any.
//
// When using Children, NextChild, and PrevChild, bear in mind that a
// Node's children may come from different fields, some of which may
// be lists of nodes without a distinguished intervening container
// such as [ast.BlockStmt].
//
// For example, [ast.CaseClause] has a field List of expressions and a
// field Body of statements, so the children of a CaseClause are a mix
// of expressions and statements. Other nodes that have "uncontained"
// list fields include:
//
//   - [ast.ValueSpec] (Names, Values)
//   - [ast.CompositeLit] (Type, Elts)
//   - [ast.IndexListExpr] (X, Indices)
//   - [ast.CallExpr] (Fun, Args)
//   - [ast.AssignStmt] (Lhs, Rhs)
//
// So, do not assume that the previous sibling of an ast.Stmt is also
// an ast.Stmt, or if it is, that they are executed sequentially,
// unless you have established that, say, its parent is a BlockStmt
// or its [Cursor.ParentEdge] is [edge.BlockStmt_List].
// For example, given "for S1; ; S2 {}", the predecessor of S2 is S1,
// even though they are not executed in sequence.
func ( Cursor) () iter.Seq[Cursor] {
	return func( func(Cursor) bool) {
		,  := .FirstChild()
		for  && () {
			,  = .NextSibling()
		}
	}
}

// Contains reports whether c contains or is equal to c2.
//
// Both Cursors must belong to the same [Inspector];
// neither may be its Root node.
func ( Cursor) ( Cursor) bool {
	if .in != .in {
		panic("different inspectors")
	}
	 := .in.events
	return .index <= .index && [.index].index <= [.index].index
}

// FindNode returns the cursor for node n if it belongs to the subtree
// rooted at c. It returns zero if n is not found.
func ( Cursor) ( ast.Node) (Cursor, bool) {

	// FindNode is equivalent to this code,
	// but more convenient and 15-20% faster:
	if false {
		for  := range .Preorder() {
			if .Node() ==  {
				return , true
			}
		}
		return Cursor{}, false
	}

	// TODO(adonovan): opt: should we assume Node.Pos is accurate
	// and combine type-based filtering with position filtering
	// like FindByPos?

	 := maskOf([]ast.Node{})
	 := .in.events

	for ,  := .indices();  < ; ++ {
		 := []
		if .index >  { // push?
			if .typ& != 0 && .node ==  {
				return Cursor{.in, }, true
			}
			 := .index
			if [].typ& == 0 {
				// Subtree does not contain type of n: skip.
				 = 
			}
		}
	}
	return Cursor{}, false
}

// FindByPos returns the cursor for the innermost node n in the tree
// rooted at c such that n.Pos() <= start && end <= n.End().
// (For an *ast.File, it uses the bounds n.FileStart-n.FileEnd.)
//
// An empty range (start == end) between two adjacent nodes is
// considered to belong to the first node.
//
// It returns zero if none is found.
// Precondition: start <= end.
//
// See also [astutil.PathEnclosingInterval], which
// tolerates adjoining whitespace.
func ( Cursor) (,  token.Pos) (Cursor, bool) {
	if  <  {
		panic("end < start")
	}
	 := .in.events

	// This algorithm could be implemented using c.Inspect,
	// but it is about 2.5x slower.

	// best is the push-index of the latest (=innermost) node containing range.
	// (Beware: latest is not always innermost because FuncDecl.{Name,Type} overlap.)
	 := int32(-1)
	for ,  := .indices();  < ; ++ {
		 := []
		if .index >  { // push?
			 := .node
			var  token.Pos
			if ,  := .(*ast.File);  {
				 = .FileEnd
				// Note: files may be out of Pos order.
				if .FileStart >  {
					 = .index // disjoint, after; skip to next file
					continue
				}
			} else {
				// Edge case: FuncDecl.Name and .Type overlap:
				// Don't update best from Name to FuncDecl.Type.
				//
				// The condition can be read as:
				// - n is FuncType
				// - n.parent is FuncDecl
				// - best is strictly beneath the FuncDecl
				if .typ == 1<<nFuncType &&
					[.parent].typ == 1<<nFuncDecl &&
					 > .parent {
					continue
				}

				 = .End()
				if .Pos() >  {
					break // disjoint, after; stop
				}
			}

			// Inv: node.{Pos,FileStart} <= start
			if  <=  {
				// node fully contains target range
				 = 

				// Don't search beyond end of the first match.
				// This is important only for an empty range (start=end)
				// between two adjoining nodes, which would otherwise
				// match both nodes; we want to match only the first.
				 = .index
			} else if  <  {
				 = .index // disjoint, before; skip forward
			}
		}
	}
	if  >= 0 {
		return Cursor{.in, }, true
	}
	return Cursor{}, false
}