<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Structural Search on RockB</title><link>https://baeseokjae.github.io/tags/structural-search/</link><description>Recent content in Structural Search on RockB</description><image><title>RockB</title><url>https://baeseokjae.github.io/images/og-default.png</url><link>https://baeseokjae.github.io/images/og-default.png</link></image><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 28 Jul 2026 16:03:06 +0000</lastBuildDate><atom:link href="https://baeseokjae.github.io/tags/structural-search/index.xml" rel="self" type="application/rss+xml"/><item><title>AST-grep Rewrote Tree-sitter in Rust: 30% Faster Code Analysis for AI Tools</title><link>https://baeseokjae.github.io/posts/ast-grep-tree-sitter-rust-rewrite-2026/</link><pubDate>Tue, 28 Jul 2026 16:03:06 +0000</pubDate><guid>https://baeseokjae.github.io/posts/ast-grep-tree-sitter-rust-rewrite-2026/</guid><description>AST-grep rewrote Tree-sitter&amp;#39;s C core in Rust using ChatGPT, achieving 29.74% faster parsing and 22.2% faster end-to-end code analysis for AI tools.</description><content:encoded><![CDATA[<h2 id="what-is-the-ast-grep-tree-sitter-rust-rewrite">What Is the AST-grep Tree-sitter Rust Rewrite?</h2>
<p>AST-grep, the popular structural code search tool with over 15,000 GitHub stars, rewrote Tree-sitter&rsquo;s C parsing core entirely in Rust using ChatGPT-assisted code generation. The result is a 29.74% improvement in raw parsing throughput and a 22.2% faster end-to-end code analysis pipeline, making it significantly faster for AI coding agents and developer tools that rely on syntax-tree-based code understanding.</p>
<h2 id="why-did-ast-grep-rewrite-tree-sitter-in-rust">Why Did AST-grep Rewrite Tree-sitter in Rust?</h2>
<p>Tree-sitter has been the gold standard for incremental parsing in code editors since its release. Its C core is battle-tested and powers syntax highlighting in editors like Neovim, VS Code, and Zed. But AST-grep&rsquo;s use case is fundamentally different from an editor&rsquo;s.</p>
<h3 id="the-problem-with-tree-sitters-c-core-for-ai-workloads">The Problem with Tree-sitter&rsquo;s C Core for AI Workloads</h3>
<p>Tree-sitter was designed for interactive editing, where incremental parsing — reusing the old syntax tree after small edits — is critical. AI coding agents, however, don&rsquo;t edit files character by character. They analyze entire codebases at once, searching for structural patterns across thousands of files. For this workload, incremental parsing is unnecessary overhead.</p>
<p>The C codebase also presented maintenance challenges. AST-grep is written in Rust, and maintaining a C foreign-function interface (FFI) to Tree-sitter introduced complexity, build friction, and limited optimization opportunities. By rewriting the parser in Rust, the team could eliminate the FFI boundary, remove features irrelevant to AI workloads, and apply Rust-specific optimizations like arena allocation.</p>
<h3 id="removing-incremental-parsing-a-feature-not-a-bug">Removing Incremental Parsing: A Feature, Not a Bug</h3>
<p>The most controversial decision in the rewrite was removing incremental old-tree reuse — a core Tree-sitter feature. For AI agent workloads that parse fresh code on every invocation, this feature was pure overhead. The Rust rewrite simply skips it, which simplifies the parser and contributes directly to the performance gains.</p>
<h2 id="how-did-chatgpt-assist-in-writing-the-rust-parser">How Did ChatGPT Assist in Writing the Rust Parser?</h2>
<p>One of the most remarkable aspects of this project is that ChatGPT generated the majority of the Rust code. The AST-grep team used the AI model as a code generation engine, translating Tree-sitter&rsquo;s C parsing logic into idiomatic Rust.</p>
<h3 id="the-ai-assisted-rewrite-workflow">The AI-Assisted Rewrite Workflow</h3>
<p>The team fed Tree-sitter&rsquo;s C source code to ChatGPT and asked it to produce equivalent Rust implementations. The AI handled the mechanical translation — converting C&rsquo;s manual memory management to Rust&rsquo;s ownership model, translating pointer arithmetic to safe Rust patterns, and restructuring C macros into Rust generics and traits.</p>
<p>However, the AI-generated code was not production-ready out of the box. The team described a &ldquo;load-bearing wall&rdquo; metaphor: AI made the rewrite possible by handling the bulk translation, but human expertise in profiling, benchmarking, and iterative optimization turned the translated code into a high-performance parser. The AI wrote the first draft; humans made it fast.</p>
<h3 id="what-this-means-for-systems-programming">What This Means for Systems Programming</h3>
<p>This project demonstrates a new paradigm for systems-level rewrites. Traditionally, porting a mature C codebase to Rust requires months of manual effort. With AI-assisted code generation, the mechanical translation phase is dramatically compressed. The human effort shifts from &ldquo;writing code&rdquo; to &ldquo;directing, profiling, and optimizing&rdquo; — a fundamentally different skill set that combines domain expertise with AI orchestration.</p>
<h2 id="what-performance-gains-did-the-rust-rewrite-achieve">What Performance Gains Did the Rust Rewrite Achieve?</h2>
<p>The rewrite was benchmarked extensively, and the results are documented across a four-part blog series. Here are the key numbers:</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>C Baseline</th>
          <th>Rust Rewrite</th>
          <th>Improvement</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Raw parsing throughput</td>
          <td>Baseline</td>
          <td>+29.74%</td>
          <td><strong>29.74% faster</strong></td>
      </tr>
      <tr>
          <td>Tree traversal throughput</td>
          <td>Baseline</td>
          <td>+10.16%</td>
          <td><strong>10.16% faster</strong></td>
      </tr>
      <tr>
          <td>End-to-end ast-grep outline (user CPU)</td>
          <td>1.233s</td>
          <td>0.960s</td>
          <td><strong>22.2% faster</strong></td>
      </tr>
      <tr>
          <td>Memory usage (RSS, ast-grep run)</td>
          <td>26.52 MiB</td>
          <td>34.43 MiB</td>
          <td>+29.8% more memory</td>
      </tr>
      <tr>
          <td>TypeScript stress corpus peak</td>
          <td>&gt;1 GiB</td>
          <td>91.2 MiB</td>
          <td><strong>~91% reduction</strong></td>
      </tr>
  </tbody>
</table>
<h3 id="raw-parsing-the-headline-30-gain">Raw Parsing: The Headline 30% Gain</h3>
<p>The raw parsing throughput improvement of 29.74% is the headline number. This measures how fast the parser can produce a syntax tree from source code, isolated from any application logic. The gain comes from several Rust-specific optimizations:</p>
<ul>
<li><strong>Arena allocation</strong>: Instead of individual heap allocations for each syntax node, the Rust parser uses arena allocators that batch memory in contiguous blocks. This reduces allocation overhead and improves cache locality.</li>
<li><strong>Compact indexes</strong>: The Rust version uses smaller, more cache-friendly data structures for internal node representations.</li>
<li><strong>Eliminated FFI overhead</strong>: Without the C-to-Rust FFI boundary, function calls that previously crossed the language barrier are now direct Rust calls.</li>
</ul>
<h3 id="end-to-end-performance-the-real-world-number">End-to-End Performance: The Real-World Number</h3>
<p>While the raw parser is 30% faster, the end-to-end ast-grep outline command — a realistic workload that parses code and extracts structural information — improved by 22.2% (0.960s vs 1.233s user CPU time). The gap between 30% and 22% is instructive: parser speed is only one component of total application performance. Other factors like I/O, tree traversal, and pattern matching also contribute to wall-clock time.</p>
<h2 id="how-did-glr-optimization-contribute-to-the-speedup">How Did GLR Optimization Contribute to the Speedup?</h2>
<p>Tree-sitter uses a Generalized LR (GLR) parsing algorithm, which can handle ambiguous grammars by maintaining a graph of possible parse states rather than a single stack. This is what makes Tree-sitter so robust for real-world code — it can parse incomplete or syntactically incorrect files that would choke a standard LR parser.</p>
<h3 id="the-99-optimization-insight">The 99% Optimization Insight</h3>
<p>During the rewrite, the AST-grep team made a critical observation: in real-world code analysis workloads, 99% of the parser stack follows a single straight path. The GLR graph — with its branching and merging — is rarely needed. This insight drove a key optimization: optimize for the common case (single-path parsing) and fall back to the full GLR machinery only when ambiguity is detected.</p>
<p>This is a textbook example of profile-driven optimization. Rather than optimizing the GLR algorithm in the abstract, the team measured actual workloads and discovered that the theoretical worst case (massive ambiguity) is practically nonexistent for the codebases AST-grep analyzes.</p>
<h3 id="memory-layout-and-arena-allocation">Memory Layout and Arena Allocation</h3>
<p>The Rust rewrite introduced arena-based memory management for syntax nodes. Instead of allocating each node individually on the heap — which causes fragmentation and poor cache behavior — the parser allocates nodes in contiguous memory regions. This has two benefits:</p>
<ol>
<li><strong>Faster allocation and deallocation</strong>: Arena allocation is essentially a bump-pointer operation, far cheaper than individual malloc/free cycles.</li>
<li><strong>Better cache locality</strong>: Contiguous nodes are more likely to be in the CPU cache together, speeding up tree traversal.</li>
</ol>
<p>The memory tradeoff is real: RSS increased by 29.8% (34.43 MiB vs 26.52 MiB) in the ast-grep benchmark. However, the TypeScript stress corpus tells a different story. Before optimization, peak memory exceeded 1 GiB. After arena optimization, it dropped to 91.2 MiB — a 91% reduction. The arena allocator prevents memory fragmentation that previously caused exponential growth on large files.</p>
<h2 id="what-is-the-gap-between-parser-benchmarks-and-application-performance">What Is the Gap Between Parser Benchmarks and Application Performance?</h2>
<p>This is one of the most important lessons from the rewrite. The raw parser benchmark shows a 30% improvement, but the end-to-end application only sees 22%. Why the gap?</p>
<h3 id="the-components-of-end-to-end-performance">The Components of End-to-End Performance</h3>
<p>An ast-grep command involves several stages:</p>
<ol>
<li><strong>File I/O</strong>: Reading source files from disk</li>
<li><strong>Parsing</strong>: Building syntax trees (the 30% faster part)</li>
<li><strong>Tree traversal</strong>: Walking the syntax tree to find matches</li>
<li><strong>Pattern matching</strong>: Applying the user&rsquo;s search pattern</li>
<li><strong>Output formatting</strong>: Displaying results</li>
</ol>
<p>Only step 2 benefits from the parser rewrite. Steps 1, 3, 4, and 5 are unchanged. The 22.2% end-to-end improvement is actually quite impressive when you consider that parsing is only one component of the pipeline.</p>
<h3 id="the-initial-performance-regression">The Initial Performance Regression</h3>
<p>Interestingly, the first version of the Rust rewrite was actually slower than the C baseline. The AI-generated code, while functionally correct, lacked the optimizations that years of C development had accumulated. Only after profiling and iterative tuning — arena allocation, compact indexes, GLR optimization — did the Rust version surpass the C baseline.</p>
<p>This is a crucial lesson for anyone considering AI-assisted rewrites: the AI can generate correct code quickly, but making it fast requires the same profiling and optimization skills that traditional performance engineering demands.</p>
<h2 id="what-lessons-does-this-project-offer-for-ai-assisted-systems-programming">What Lessons Does This Project Offer for AI-Assisted Systems Programming?</h2>
<p>The AST-grep Tree-sitter rewrite is a case study in the future of systems programming. Here are the key takeaways:</p>
<h3 id="ai-as-a-force-multiplier-not-a-replacement">AI as a Force Multiplier, Not a Replacement</h3>
<p>ChatGPT wrote the bulk of the Rust code, but human engineers directed the effort, profiled the results, and iterated on performance. The AI compressed the translation phase from months to weeks, but the optimization phase still required deep expertise in parsing algorithms, memory management, and Rust&rsquo;s performance characteristics.</p>
<h3 id="profile-before-you-optimize">Profile Before You Optimize</h3>
<p>The 99% single-path GLR insight came from profiling real workloads, not from theoretical analysis. The team didn&rsquo;t guess where the bottlenecks were — they measured them. This principle applies to any performance optimization project: measure first, optimize second.</p>
<h3 id="removing-features-is-a-legitimate-optimization">Removing Features Is a Legitimate Optimization</h3>
<p>The decision to remove incremental parsing and native Wasm grammar loading was controversial but correct for AST-grep&rsquo;s use case. Not every feature from the original codebase needs to survive a rewrite. Understanding which features are &ldquo;load-bearing&rdquo; for your specific workload and which are dead weight is a critical skill.</p>
<h3 id="rusts-ownership-model-pays-off">Rust&rsquo;s Ownership Model Pays Off</h3>
<p>The Rust rewrite eliminated an entire class of memory bugs that plague C codebases. While the C version of Tree-sitter is battle-tested, the Rust version gains compile-time memory safety guarantees. For a parser that processes untrusted source code, this is a significant security advantage.</p>
<h2 id="how-does-this-impact-ai-coding-tools-and-the-ecosystem">How Does This Impact AI Coding Tools and the Ecosystem?</h2>
<p>The implications extend far beyond AST-grep itself. Tree-sitter is the backbone of code analysis for many AI coding tools, including:</p>
<ul>
<li><strong>CodeRabbit</strong>: Uses AST-grep for AI-native code review and linting, combining structural search with LLM analysis for code quality at scale.</li>
<li><strong>CodeRLM</strong>: A Tree-sitter-backed code indexing system for LLM agents that improves code understanding through syntax-tree-aware indexing.</li>
<li><strong>VT Code</strong>: An AST-aware Rust TUI coding agent that integrates both Tree-sitter and AST-grep for terminal-based AI coding.</li>
</ul>
<h3 id="faster-code-analysis-for-agentic-workflows">Faster Code Analysis for Agentic Workflows</h3>
<p>AI coding agents analyze entire codebases to understand context before generating code. A 22% faster end-to-end analysis means agents can process more code in less time, leading to better context understanding and more accurate code generation. For agentic workflows that parse thousands of files per session, this performance improvement compounds significantly.</p>
<h3 id="the-growing-tree-sitter-ecosystem">The Growing Tree-sitter Ecosystem</h3>
<p>The Tree-sitter ecosystem is expanding rapidly. The Rust rewrite repo itself has already attracted attention, and the broader community is watching closely. If the Rust version proves stable and performant, it could become the foundation for a new generation of Rust-native code analysis tools.</p>
<h3 id="what-this-means-for-developer-tooling">What This Means for Developer Tooling</h3>
<p>Faster parsing means faster IDE features, faster linting, faster code search, and faster AI code generation. Every tool that depends on syntax-tree analysis benefits from a faster Tree-sitter. The Rust rewrite doesn&rsquo;t just make AST-grep faster — it raises the performance ceiling for the entire ecosystem of tools built on Tree-sitter.</p>
<h2 id="frequently-asked-questions">Frequently Asked Questions</h2>
<h3 id="is-the-rust-rewrite-of-tree-sitter-a-drop-in-replacement-for-the-c-version">Is the Rust rewrite of Tree-sitter a drop-in replacement for the C version?</h3>
<p>No. The Rust rewrite removes incremental parsing and native Wasm grammar loading, which are features designed for interactive editing. It is optimized for AI agent workloads and batch code analysis, not for use as an editor plugin. If you need incremental parsing for an editor, the C version remains the right choice.</p>
<h3 id="how-much-faster-is-the-rust-version-in-real-world-use">How much faster is the Rust version in real-world use?</h3>
<p>End-to-end ast-grep commands run approximately 22% faster in user CPU time. Raw parsing is 30% faster. The exact improvement depends on your workload — codebases with many large files benefit more than those with many small files, where I/O overhead dominates.</p>
<h3 id="did-chatgpt-write-all-the-rust-code">Did ChatGPT write all the Rust code?</h3>
<p>ChatGPT generated the initial translation from C to Rust, but the team performed extensive profiling and optimization to achieve the performance gains. The AI handled the mechanical translation; humans optimized the result. The final code is a collaboration between AI generation and human performance engineering.</p>
<h3 id="does-the-rust-rewrite-use-more-memory">Does the Rust rewrite use more memory?</h3>
<p>In typical workloads, the Rust version uses about 29.8% more RSS (34.43 MiB vs 26.52 MiB). However, for large files, the arena allocator prevents memory fragmentation, resulting in dramatically lower peak memory — 91.2 MiB vs over 1 GiB for the C version on a TypeScript stress corpus.</p>
<h3 id="will-the-rust-rewrite-replace-the-c-version-of-tree-sitter">Will the Rust rewrite replace the C version of Tree-sitter?</h3>
<p>For AST-grep&rsquo;s use case, yes. For the broader Tree-sitter ecosystem, it depends on whether the community adopts the Rust version for editor integration. The C version remains the standard for interactive editing due to its incremental parsing support. The two versions may coexist for different use cases.</p>
]]></content:encoded></item></channel></rss>