Files
poimen-memory/knowledge/ast-grep.md
T
rock a5ff20c9f7 feat: add 'mem learn' CLI for markdown knowledge ingestion
6 knowledge files: rust, SOLID/DRY, ast-grep, karpathy, golang, caveman
65 chunks ingested to log/knowledge/learn/latest.jsonl
Chunks on ## headings, SHA256 dedup, configurable chunk size
2026-08-29 22:04:14 -07:00

2.9 KiB

AST-Grep (sg) — Structural Code Search & Transform

Core Concept

  • AST-grep searches/transforms code using Abstract Syntax Tree patterns, not regex.
  • Pattern matches structural meaning, ignoring whitespace, comments, formatting.
  • Works across: Rust, Go, Python, JS/TS, Java, C, C++, Ruby, Kotlin, Lua, CSS, HTML.

CLI Usage

  • sg --pattern 'unwrap()' -l rust — find all .unwrap() calls in Rust files.
  • sg --pattern 'println!($$$ARGS)' -l rust — find all println macros with any args.
  • sg --pattern '$A.unwrap()' --rewrite '$A.expect("TODO")' -l rust — rewrite unwrap to expect.
  • sg scan — run lint rules from sgconfig.yml.
  • sg test — test rules against fixtures.

Pattern Syntax

  • $VAR matches single AST node (identifier, expression, etc).
  • $$$VARS matches zero or more nodes (variadic).
  • $$VAR matches zero or one node (optional).
  • Literal code matches itself: if true { $$$BODY } matches any if true block.

Meta Variables

  • $A in pattern captures node, available in --rewrite as $A.
  • Named captures: same name must match same content. $A == $A matches x == x but not x == y.
  • $_ is anonymous — matches anything without capturing.

Rule YAML Format

id: no-unwrap
language: rust
rule:
  pattern: $A.unwrap()
  not:
    inside:
      kind: test_function
fix: $A.expect("handle error")
message: "Use .expect() instead of .unwrap() in production code"
severity: warning

Composite Rules

  • all: [rule1, rule2] — both must match.
  • any: [rule1, rule2] — either matches.
  • not: rule — negation.
  • matches: rule-id — reference another rule.
  • inside: { kind: function_item } — must be inside a function.
  • has: { pattern: $EXPR } — must contain sub-pattern.
  • follows: { pattern: ... } — must follow another pattern.
  • precedes: { pattern: ... } — must precede another pattern.

Kind Selectors

  • kind: function_item — match AST node type directly.
  • kind: call_expression — match function calls.
  • Use sg --debug-query='println!("hello")' to see AST node kinds.

Configuration (sgconfig.yml)

ruleDirs:
  - rules/
testConfigs:
  - rules/tests/

Advanced Patterns

  • Find unused variables: let $VAR = $EXPR; where $VAR not referenced later.
  • Find API migrations: old_function($$$ARGS)new_function($$$ARGS).
  • Enforce patterns: ensure all error handling uses ? not .unwrap().
  • Security: find eval($EXPR), SQL injection patterns, hardcoded secrets.

Integration

  • CI/CD: sg scan --json for machine-readable output.
  • Pre-commit hooks: sg scan --rule rules/ on staged files.
  • Editor: VSCode extension, LSP support.
  • Programmatic: @ast-grep/napi Node.js binding for custom tools.

vs Regex

  • Regex: unwrap\(\) matches in comments, strings, docs. AST-grep: only actual code.
  • Regex can't match nested structures. AST-grep handles if { if { unwrap() } }.
  • AST-grep understands scope, types, structure. Regex is text-level.