Skip to content

BlogEngineering

What is an AST, and how tree-sitter builds one

· 3 minute read

Tree-sitter is a parser that turns source code into a syntax tree. A code graph is built by parsing each source file into a syntax tree, walking that tree, and recording what it finds. Definitions become nodes. Calls, imports, and inheritance become edges. Because the parser reads syntax directly, no language model is needed for this step. Graphify, an open-source CLI, builds its code graph this way.

What is tree-sitter?Link to What is tree-sitter?

Tree-sitter is a parser generator and incremental parsing library. Its documentation describes it as a tool that builds a concrete syntax tree for a source file and updates it efficiently as the file is edited. It has grammars for many languages and is used by editors such as Neovim, Zed, and Helix for highlighting and navigation.

Is a tree-sitter tree an AST or a CST?Link to Is a tree-sitter tree an AST or a CST?

Strictly, tree-sitter produces a concrete syntax tree. A CST keeps every token, including punctuation. An abstract syntax tree drops details that do not affect meaning. In practice, tree-sitter marks nodes as named or anonymous, and tools that skip anonymous nodes get an AST-like view. Most code graph tools, Graphify included, say "AST" in this looser sense.

How does a tree-sitter tree become a code graph?Link to How does a tree-sitter tree become a code graph?

The extractor walks each file's tree and looks for specific node types.

| Tree node | Graph element | |---|---| | Function or method definition | Node | | Class definition | Node, plus contains edges to methods | | Call expression | calls edge from caller to callee | | Import statement | imports edge to a module or symbol | | Superclass list | inherits edge | | Comment or docstring | Rationale node linked to its code |

Tree-sitter's query language lets you match these patterns with S-expressions instead of hand-written walks.

How are calls across files resolved?Link to How are calls across files resolved?

This is the hard part. A call to check_token() in app.py names a symbol, not a file. The extractor has to match it to a definition, often through an import. Some links are certain from syntax. Others are a best guess.

Graphify tags each edge so you can tell. Edges read directly from one file's syntax are EXTRACTED. Edges resolved by a heuristic are INFERRED, with a confidence score. On a two-file test project at Graphify 0.8.16, graphify path shows both kinds:

text
handle() <--calls [INFERRED]-- check_token() --calls [EXTRACTED]--> verify()

handle in app.py calls check_token, imported from auth.py, which calls verify.

How do you build one?Link to How do you build one?

bash
uv tool install graphifyy
graphify update .

graphify update . parses every supported code file locally and writes graphify-out/graph.json, a report, and an HTML view. No source code is sent anywhere for this step.

What can tree-sitter not see?Link to What can tree-sitter not see?

Syntax only shows what the code says. Dynamic dispatch, reflection, dependency injection, and calls built from strings are invisible or ambiguous. A type checker or language server resolves more, at higher cost. A graph built from syntax is a fast, broad map, not a proof.

Why does tree-sitter tolerate broken code?Link to Why does tree-sitter tolerate broken code?

Tree-sitter keeps parsing when it hits a syntax error. It marks the bad region with an error node and still builds the rest of the tree. That matters for tools that run while you type. It also means a graph can still be built from a repository with a half-finished file.

Tree-sitter can also re-parse only the part of a file that changed, which keeps updates fast.

FAQLink to FAQ

Does tree-sitter need the code to compile?Link to Does tree-sitter need the code to compile?

No. It tolerates syntax errors and still produces a tree for the rest of the file.

Is tree-sitter the same as a language server?Link to Is tree-sitter the same as a language server?

No. A language server type-checks and resolves symbols. Tree-sitter parses syntax only.

Which languages does Graphify parse?Link to Which languages does Graphify parse?

The languages docs list supported extensions.

Why are some edges INFERRED?Link to Why are some edges INFERRED?

Because syntax alone did not prove the link. See Graphify's edge tags.

Get startedLink to Get started

Graphify is open source on GitHub. Install it with uv: uv tool install graphifyy. Read the tree-sitter glossary entry. Related: what is GraphRAG?

Try Graphify now.

Try for free