Documentation
¶
Overview ¶
Package grep provides structural code search, match, and rewrite using tree-sitter parse trees. It is an AST-grep-inspired pattern matching engine built on gotreesitter's query system.
Code patterns use metavariables ($NAME, $$$ARGS, $_, $E:type) that match AST nodes structurally. Patterns are parsed as real code in the target language, then compiled to tree-sitter S-expression queries.
Basic usage:
lang := grammars.DetectLanguageByName("go").Language()
results, err := grep.Match(lang, `func $NAME($$$) error`, source)
for _, r := range results {
fmt.Printf("found: %s\n", r.Captures["NAME"].Text)
}
Rewrite usage:
result, err := grep.Replace(lang, `$E.unwrap()`, `$E.expect("failed")`, source)
output := grep.ApplyEdits(source, result.Edits)
Full query syntax:
find <lang>::<pattern> [where { <constraints> }] [replace { <template> }]
Package grep implements a structural code search engine.
The query language supports finding code patterns, optionally scoped to a language, with constraint and replacement blocks:
find <lang>::<code-pattern> [where { <constraints> }] [replace { <template> }]
The find keyword and language prefix are both optional.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyEdits ¶
ApplyEdits applies non-overlapping edits to source, returning new source. Edits are applied back-to-front (by StartByte descending) so that earlier byte offsets remain valid as later portions of the source are modified.
func Preprocess ¶
Preprocess replaces metavariables in a code pattern with language-valid placeholder identifiers so tree-sitter can parse the result.
It returns the modified pattern, a map from placeholder identifier to MetaVar descriptor, and any error encountered.
Metavariable conventions:
$NAME → __GREP_CAP_NAME__ (single capture) $$$ITEMS → __GREP_VAR_ITEMS__ (variadic capture) $_ → __GREP_WILD_1__ (wildcard, numbered for uniqueness) $NAME:type → __GREP_TYPED_NAME__T__type__ (typed capture)
Types ¶
type Capture ¶
type Capture struct {
// Name is the user-facing metavariable name (e.g., "NAME", "PARAMS").
Name string
// Text is the source text of the captured node.
Text []byte
// StartByte is the byte offset where the capture begins.
StartByte uint32
// EndByte is the byte offset where the capture ends (exclusive).
EndByte uint32
// Node is the captured syntax tree node.
Node *gotreesitter.Node
}
Capture holds information about a single captured node within a match.
type CompiledPattern ¶
type CompiledPattern struct {
// Query is the compiled tree-sitter S-expression query ready for
// matching against syntax trees.
Query *gotreesitter.Query
// MetaVars maps placeholder identifier to its MetaVar descriptor.
// The keys are the same as in the Preprocess output.
MetaVars map[string]*MetaVar
// Lang is the language the pattern was compiled for.
Lang *gotreesitter.Language
// SExpr is the generated S-expression query string (useful for debugging).
SExpr string
}
CompiledPattern holds a compiled tree-sitter query along with metavariable metadata from the original code pattern.
func Compile ¶
func Compile(lang *gotreesitter.Language, pattern string) (*CompiledPattern, error)
Compile parses a code pattern into a reusable CompiledPattern. The returned pattern can be matched against multiple source files via its Match method without re-compilation.
func CompilePattern ¶
func CompilePattern(lang *gotreesitter.Language, pattern string) (*CompiledPattern, error)
CompilePattern compiles a code pattern string into a tree-sitter query for the given language. The pattern may contain metavariables ($NAME, $$$NAME, $_, $NAME:type) that are converted into query captures.
The compilation pipeline:
- Preprocess: replace metavariables with language-valid placeholders
- Parse: parse the preprocessed string using the language's grammar
- Translate: walk the parse tree and emit an S-expression query
func CompilePatternForLang ¶
func CompilePatternForLang(langName, pattern string) (*CompiledPattern, error)
CompilePatternForLang is a convenience that looks up a language by name before compiling.
type Diagnostic ¶
Diagnostic reports a non-fatal issue encountered during rewriting.
type LangResolver ¶
type LangResolver func(name string) *gotreesitter.Language
LangResolver maps a language name to a tree-sitter Language object. It returns nil if the language is not available.
func DefaultResolver ¶
func DefaultResolver() LangResolver
DefaultResolver returns a LangResolver that uses the grammars registry to look up languages by name.
type MetaVar ¶
type MetaVar struct {
// Name is the user-facing name (e.g., "NAME", "PARAMS", "_").
Name string
// Placeholder is the language-valid identifier that replaced the
// metavariable in the preprocessed pattern (e.g., "__GREP_CAP_NAME__").
Placeholder string
// Variadic is true for $$$ captures (zero or more).
Variadic bool
// Wildcard is true for $_ (anonymous wildcard).
Wildcard bool
// TypeConstraint is the node type constraint for $NAME:type captures,
// or empty if unconstrained.
TypeConstraint string
}
MetaVar describes a metavariable found in a code pattern.
type Query ¶
type Query struct {
// Lang is the language name (e.g. "go", "rust", "sexp"), or empty if
// unspecified.
Lang string
// Pattern is the code pattern or S-expression to match against.
Pattern string
// Where is the raw constraint block content (text between the braces in
// a where { ... } clause), or empty if no where clause was given.
Where string
// Replace is the raw replacement template content (text between the
// braces in a replace { ... } clause), or empty if no replace clause
// was given.
Replace string
}
Query is the parsed representation of a structural grep query.
func ParseQuery ¶
ParseQuery parses a structural grep query string into a Query.
Accepted forms:
find go::func $NAME($$$) error — full form go::func $NAME($$$) error — shorthand (no find keyword) func $NAME($$$) error — bare pattern (no language prefix) find sexp::(function_definition) — S-expression mode
The where { ... } and replace { ... } blocks are optional and support nested braces.
type QueryResult ¶
type QueryResult struct {
// Matches contains the structural match results after any where-clause
// filtering has been applied.
Matches []Result
// ReplaceResult holds the computed edits if a replace clause was present
// in the query. It is nil when no replace clause was specified.
ReplaceResult *ReplaceResult
}
QueryResult holds the results of executing a full structural grep query.
func RunQuery ¶
func RunQuery(query string, source []byte, resolver LangResolver) (*QueryResult, error)
RunQuery executes a full structural grep query string against source code. The resolver maps language names (e.g., "go", "javascript") to Language objects.
The query string follows the format:
find <lang>::<pattern> [where { <constraints> }] [replace { <template> }]
The pipeline:
- Parse the query string
- Resolve the language using the resolver
- Match the pattern against the source
- Apply where-clause filtering (if present)
- Compute replacement edits (if present)
func RunQueryWithLang ¶
func RunQueryWithLang(query string, source []byte, lang *gotreesitter.Language) (*QueryResult, error)
RunQueryWithLang executes a query when the language is already known. The query string can omit the language prefix — the provided lang is used directly for parsing and matching.
This is useful for:
- Bare patterns without a language prefix (e.g., "func $NAME()")
- When the caller already has a Language object from prior detection
type ReplaceResult ¶
type ReplaceResult struct {
Edits []Edit
Diagnostics []Diagnostic
}
ReplaceResult holds the computed edits and any diagnostics produced by a Replace operation.
func Replace ¶
func Replace(lang *gotreesitter.Language, pattern string, replacement string, source []byte) (*ReplaceResult, error)
Replace finds all matches of pattern in source and computes replacement edits by substituting capture references ($NAME, $$$NAME) in the replacement template with matched text.
Overlapping matches are discarded (the earlier match wins) and reported as diagnostics. After computing edits, the result is validated by re-parsing with tree-sitter; new ERROR nodes are reported as diagnostics.
type Result ¶
type Result struct {
// StartByte is the byte offset where the overall match begins.
StartByte uint32
// EndByte is the byte offset where the overall match ends (exclusive).
EndByte uint32
// Captures maps user-facing metavariable names (e.g., "NAME", "PARAMS")
// to the captured node information.
Captures map[string]Capture
}
Result represents a single structural match of a pattern against source code.
func Match ¶
Match finds all structural matches of a code pattern in source code. The pattern may contain metavariables ($NAME, $$$NAME, $_, $NAME:type). Returns an empty slice (not an error) when no matches are found.
type WhereFilter ¶
type WhereFilter func(result *Result, source []byte, lang *gotreesitter.Language) bool
WhereFilter is a predicate that tests whether a match result satisfies a where-clause constraint. It returns true if the result passes the filter.
func CompileWhere ¶
func CompileWhere(where string) (WhereFilter, error)
CompileWhere compiles a where-clause string into a WhereFilter function.
Supported constraint forms:
contains($CAP, <text>) — capture text contains literal text not contains($CAP, <text>) — capture text does NOT contain literal text matches($CAP, "regex") — capture text matches regex not matches($CAP, "regex") — capture text does NOT match regex
Multiple constraints can be combined with semicolons or newlines; all must pass (logical AND).