index

package
v0.9.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package index defines the indexing pipeline: walk -> hash -> parse (per language) -> resolve cross-language bindings -> populate the graph.

Parser backends are pluggable behind LanguageParser. The target picture is cgo-free: Go is parsed with the stdlib go/parser (never tree-sitter), Plan 9 asm with a custom scanner (internal/plan9, shared with internal/resolve), and C/C++/CUDA start on cgo tree-sitter bindings in M1/M2 with a planned migration to tree-sitter grammars compiled to WASM executed via wazero (pure Go). See docs/architecture.md §2 and docs/roadmap.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LangOf

func LangOf(path string) graph.Lang

LangOf returns the language for a path, or "" if unrecognized.

func MatchIgnore

func MatchIgnore(globs []string, rel string) bool

MatchIgnore reports whether a repo-relative path matches any of the config ignore globs ("**/" prefixes match any directory depth, including zero).

func ResolveTypedCalls

func ResolveTypedCalls(ctx context.Context, g graph.Graph, root string, s store.Store) (int, error)

Types

type AsmParser

type AsmParser struct{}

AsmParser is the Plan 9 assembly LanguageParser. It wraps plan9.Scan to extract TEXT (KAsmProc) and GLOBL (KVar) symbol definitions; it emits no same-language edges (the Go<->asm binding is resolve.Plan9AsmResolver's job, edge kind graph.EAsm).

func (AsmParser) CacheVersion

func (AsmParser) CacheVersion() string

CacheVersion implements index.CacheVersioner.

func (AsmParser) Extensions

func (AsmParser) Extensions() []string

Extensions are the file suffixes this parser claims.

func (AsmParser) Lang

func (AsmParser) Lang() graph.Lang

Lang identifies the parser's language.

func (AsmParser) Parse

func (AsmParser) Parse(path string, src []byte) (ParseResult, error)

Parse turns one Plan 9 asm file into symbol nodes. Symbols are qualified by their containing directory's base name (the Go package convention: a mat_amd64.s file living beside package mat mints "mat.mulVec"), matching the qualified names GoParser mints for the corresponding Go package so the resolver can pair them by ID alone.

type CacheVersioner

type CacheVersioner interface {
	CacheVersion() string
}

CacheVersioner is the optional half of LanguageParser that keeps the parse cache honest across parser upgrades. Determinism only says identical bytes yield identical results *for one parser build*; the cached blob outlives the parser that produced it, so a parser whose output changed must also change this string or the cache serves the old graph forever (B-0007). A parser that does not implement it keys exactly as before.

type CudaParser

type CudaParser struct{}

CudaParser is a line-oriented regex scanner for .cu/.cuh files (no cgo tree-sitter dependency yet — see docs/architecture.md §2 for the planned wazero-hosted grammar migration). It extracts two symbol shapes:

  • `__global__` kernel definitions -> KKernel nodes with IDs "cu:<name>".
  • `extern "C"` host wrapper functions -> KFunc nodes with IDs "c:<name>". The wrapper IS the C symbol that resolve.CgoResolver's Go -> c:<name> edge already targets as a stub; this parser upgrades that stub to a real, located node.

No edges are emitted here — the kernel launch (ELaunch) is a cross-file, cross-symbol relation and belongs to resolve.CudaResolver. Parsing is deterministic: identical bytes yield identical results (SPX-GRA-001).

func (CudaParser) CacheVersion

func (CudaParser) CacheVersion() string

CacheVersion implements CacheVersioner.

func (CudaParser) Extensions

func (CudaParser) Extensions() []string

Extensions are the file suffixes this parser claims.

func (CudaParser) Lang

func (CudaParser) Lang() graph.Lang

Lang identifies the parser's language.

func (CudaParser) Parse

func (CudaParser) Parse(path string, src []byte) (ParseResult, error)

Parse scans one .cu/.cuh file line by line for kernel and extern "C" wrapper definitions.

type GoParser

type GoParser struct{}

GoParser is the stdlib-backed Go language parser (never tree-sitter for Go: go/parser has strictly better fidelity and keeps the target binary cgo-free). It extracts top-level func/method/type/var symbols with 1-based Line/EndLine spans (the drift anchor needs EndLine) and best-effort same/cross-package call edges resolved by naming convention. The `import "C"` boundary is left to resolve.CgoResolver — a C.<ident> selector is deliberately NOT emitted as a Go call edge here.

func (GoParser) CacheVersion

func (GoParser) CacheVersion() string

CacheVersion implements CacheVersioner.

func (GoParser) Extensions

func (GoParser) Extensions() []string

Extensions are the file suffixes this parser claims.

func (GoParser) Lang

func (GoParser) Lang() graph.Lang

Lang identifies the parser's language.

func (GoParser) Parse

func (GoParser) Parse(path string, src []byte) (ParseResult, error)

Parse turns one Go file into symbol nodes and candidate call edges. Call edges carry the intended callee ID by convention (go:<pkg>.<fn> for an unqualified call, go:<x>.<sel> for a qualified X.Sel call); the indexer prunes any whose destination node does not exist after the whole tree is indexed. Parsing is deterministic: identical bytes yield identical results (SPX-GRA-001).

type Indexer

type Indexer interface {
	// IndexAll walks root, parses every recognized file (cache-accelerated)
	// and runs all binding resolvers.
	IndexAll(ctx context.Context, root string) (Stats, error)
	// IndexPaths re-indexes only the given files and re-runs the resolvers
	// whose languages intersect the changed set.
	IndexPaths(ctx context.Context, paths []string) (Stats, error)
}

Indexer builds and refreshes the graph.

func New

func New(g graph.Graph, s store.Store, parsers []LanguageParser, resolvers []resolve.BindingResolver, ignore ...string) Indexer

New wires the pipeline with a set of parsers and binding resolvers. The trailing ignore globs are config.yaml-style patterns (see MatchIgnore) that IndexAll consults in addition to the built-in directory skips (see workspace.DefaultSkipName / workspace.IsNestedGitBoundary); omitting them is backward compatible with existing callers.

type LanguageParser

type LanguageParser interface {
	Lang() graph.Lang
	Extensions() []string // e.g. [".cu", ".cuh"]
	Parse(path string, src []byte) (ParseResult, error)
}

LanguageParser turns one source file into nodes and same-language edges. Implementations must be deterministic: identical bytes yield identical results (SPX-GRA-001 depends on it).

type ParseResult

type ParseResult struct {
	Nodes []graph.Node
	Edges []graph.Edge
	Hash  [32]byte
}

ParseResult is the per-file output of a LanguageParser, cacheable by content hash.

type Stats

type Stats struct {
	Files, Nodes, Edges, Skipped int
}

Stats summarizes one indexing run.

type TypedPassError added in v0.2.0

type TypedPassError struct {
	// Packages is the number of packages that individually failed to load or
	// type-check. It is 0 when the whole-module load itself failed before any
	// per-package breakdown existed (e.g. packages.Load's own driver command
	// erroring) — there is no count to report in that case, only the cause.
	Packages int
	// contains filtered or unexported fields
}

ResolveTypedCalls is the go/types-based call-edge upgrade pass (M3 slice 1, docs/design-go-types-calls.md). It loads and type-checks the Go module rooted at root with golang.org/x/tools/go/packages, resolves every *ast.CallExpr's callee through *types.Info (which flattens chained and embedded selectors — s.cd.Sweep() — to the concrete method regardless of how many field hops sit in between), and adds any ECall edge the fast syntactic pass in GoParser.callEdges missed or mis-minted.

This is a two-tier upgrade, not a replacement (design doc §4): it never removes or duplicates edges the syntactic pass already produced. It is intended to run once per IndexAll, not per file change — packages.Load type-checks the whole module and is 10-100x slower than a bare go/parser.ParseFile per file.

An edge is added only when both endpoints already exist as nodes in g (mirroring the syntactic pass's dangling-edge pruning), the edge is not a self-loop, and it is not already present — either newly discovered earlier in this same pass, or already an ECall edge out of the same source node from a prior run (memGraph.Upsert appends rather than replaces, so callers running ResolveTypedCalls repeatedly must not re-add the same edge).

ID minting mirrors GoParser/ids exactly: go:<pkg>.<recv>.<name> (recv omitted for a plain function), pkg = fn.Pkg().Name() — the declaring package's source name, not its import path — so resolved edges land on the very same node IDs the syntactic pass and every other tool already key on.

A call resolving into the cgo pseudo-package (import "C") is skipped: that boundary is owned by resolve.CgoResolver. In practice cmd/cgo rewrites C.foo(...) call sites to a wrapped identifier before go/types ever sees them, so this rarely fires; it is kept as a defensive, explicit guard rather than relying on that incidentally.

Interface-typed call sites resolve to the interface method node itself (not to every implementer) — whole-program Implements-closure resolution is out of scope for this slice (design doc §3, "Interface dispatch").

packages.Load failures (a broken module, a bad build) and any non-empty Package.Errors are returned as a *TypedPassError; the caller (the BuildGraph orchestrator, internal/mcpserver) treats a failed upgrade pass as non-fatal to the syntactic index it already has — but see TypedPassError's doc comment for why the failure must not stop there (issue 28).

s is the same content-hash store the syntactic pass uses to skip re-parsing unchanged files (design doc §Performance, mitigation (c)); a nil s reproduces the pre-cache behavior exactly (always packages.Load, never cached). When s is non-nil, ResolveTypedCalls first computes a module hash key — sha256 over go.mod's contents plus every tracked .go file's (relpath, sha256(contents)) pair, walked the same way IndexAll walks the tree (same ignoreDirs) — and looks it up under the sentinel path typedCallsCacheKey. A hit decodes the cached edge list and applies it through the exact same node-existence/self-loop/dedupe gate a fresh packages.Load result goes through, so packages.Load is never called on a cache hit. A miss runs the full type-checking pass as before and, on success, best-effort Puts the resulting edge list back under that key — a cache-write failure must never fail the pass.

TypedPassError is what a failed pass returns. Before issue 28 this was a plain fmt.Errorf: BuildGraph logged it and moved on, so a resident server driven over stdio/HTTP (or the `call` subcommand) never learned the graph it just got "ok" back from has zero typed call edges — exactly the capability the server's own instructions cite as the reason to prefer `get depth` over a shell search (cross-language impact radius, what-calls- X). TypedPassError implements error so ResolveTypedCalls' signature is unchanged for existing callers, but carries the fields a caller needs to turn "the pass errored" into a real record instead of re-parsing Error()'s text: Packages, so state/check can name how much of the module is affected without guessing from a string.

func (*TypedPassError) Error added in v0.2.0

func (e *TypedPassError) Error() string

func (*TypedPassError) Unwrap added in v0.2.0

func (e *TypedPassError) Unwrap() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL