What Languages Are Supported in code-review-graph and How the Tree-sitter Parser Handles Them
The code-review-graph library supports over 25 programming languages out of the box through Tree-sitter grammars provided by tree-sitter-language-pack, implementing lazy grammar loading with subprocess probing, cache-based availability checks, and regex-based fallbacks for unsupported languages.
The tirth8205/code-review-graph repository extracts structural code elements—such as classes, functions, and imports—to build dependency graphs. It relies on the Tree-sitter parsing engine via the tree-sitter-language-pack distribution to handle language-specific syntax across its supported language set.
Built-in Language Coverage
The core language detection resides in code_review_graph/parser.py, where an extension-to-language table (lines 83–107) maps file extensions to Tree-sitter grammar identifiers. The table currently includes:
- Python (
.py) - JavaScript (
.js,.jsx,.mjs) - TypeScript / TSX (
.ts,.tsx,.astro) - Go (
.go) - Rust (
.rs) - Java (
.java) - C# (
.cs) - Ruby (
.rb) - C / C++ (
.c,.h,.cpp,.cc,.cxx,.hpp,.hh) - Kotlin (
.kt) - Swift (
.swift) - PHP (
.php) - Scala (
.scala) - Solidity (
.sol) - Vue (
.vue) - Dart (
.dart) - R (
.r,.R) - Lua / Luau (
.lua,.luau) - Objective-C (
.m) - Bash / Zsh / Ksh (
.sh,.bash,.zsh,.ksh) - Elixir (
.ex,.exs) - Perl (
.pl,.pm,.t) - Zig (
.zig) - PowerShell (
.ps1,.psm1,.psd1) - Svelte (
.svelte) - Julia (
.jl) - Verilog / SystemVerilog (
.v,.vh,.sv,.svh)
For each language, the parser maintains node-type mappings (lines 837–1070) such as _CLASS_TYPES, _FUNCTION_TYPES, _IMPORT_TYPES, and _CALL_TYPES, which tell the generic walker which Tree-sitter nodes represent structural elements.
Lazy Grammar Loading and Probe Caching
When a file requires parsing, the engine attempts to load the corresponding Tree-sitter grammar lazily. The _load_tree_sitter_parser function in code_review_graph/parser.py handles this by importing tree_sitter_language_pack and calling get_parser(grammar):
def _load_tree_sitter_parser(grammar: str):
if not _parser_load_probe_succeeds(grammar):
return None
language_pack = importlib.import_module("tree_sitter_language_pack")
return language_pack.get_parser(grammar)
The helper _parser_load_probe_succeeds (lines 510–545) spawns a short-lived subprocess to test if the grammar is available. If loading fails, the result is cached to prevent repeated subprocess overhead, and the parser returns None.
Fallback Heuristics for Unsupported Grammars
When a Tree-sitter grammar is unavailable, the system falls back to language-specific heuristics or regex-based extraction. This covers languages like VB.NET, ReScript, SQL, and HCL that may not be present in the language pack. These fallback implementations reside in code_review_graph/parser.py alongside the primary Tree-sitter logic, as documented in docs/CUSTOM_LANGUAGES.md.
Custom Language Configuration
Users can extend support without modifying the library code by providing a .code-review-graph/languages.toml file. The custom_languages.py module (lines 1–35) reads this configuration, validates that the grammar exists in tree-sitter-language-pack, and merges the custom extension mappings into the core tables.
For example, to add Erlang support:
[[language]]
extension = ".erl"
grammar = "erlang"
class_node_types = ["attribute", "record"]
function_node_types = ["function"]
import_node_types = ["include"]
call_node_types = ["call"]
Load the configuration at runtime:
from code_review_graph.custom_languages import load_custom_languages
load_custom_languages(Path(".code-review-graph/languages.toml"))
Generic Syntax Tree Walking
Once a tree_sitter.Parser is obtained, the generic walker executes the following steps:
- Identify language from file extension or shebang (see
SHEBANG_INTERPRETER_TO_LANGUAGEin lines 560–684) - Select node-type lists (
_CLASS_TYPES,_FUNCTION_TYPES, etc.) for the identified language - Traverse the tree, collecting nodes whose
typeappears in the selected lists, recordingNodeInfoandEdgeInfoobjects (defined around line 650) - Apply static dead-guard detection (lines 888–938) to ignore calls inside
if falseor#if 0blocks for non-Python languages
This generic approach ensures that new grammars require only node-type mappings without changes to the core parsing logic.
Practical Code Examples
Parsing a Python File
To process a built-in language like Python:
from code_review_graph.parser import CodeReviewGraphParser
parser = CodeReviewGraphParser()
nodes, edges = parser.parse_file(Path("my_project/main.py"))
print(f"Found {len(nodes)} nodes, {len(edges)} edges")
Handling Missing Grammars
If a file extension is not recognized or the grammar is unavailable, the parser returns empty collections and logs a warning:
from code_review_graph.parser import CodeReviewGraphParser
parser = CodeReviewGraphParser()
# Suppose ".xyz" is not shipped in tree_sitter_language_pack
nodes, edges = parser.parse_file(Path("unknown.xyz"))
# Returns empty nodes/edges with warning: "Skipping unavailable tree-sitter parser for xyz"
Summary
- code-review-graph supports 25+ languages via
tree-sitter-language-packgrammars defined incode_review_graph/parser.py(lines 83–107) - The Tree-sitter parser loads grammars lazily using
_load_tree_sitter_parserwith subprocess probing (_parser_load_probe_succeeds, lines 508–545) and caches availability results to avoid overhead - Node-type mappings (
_CLASS_TYPES,_FUNCTION_TYPES, etc., lines 837–1070) drive the generic syntax tree walker - Fallback parsers handle unsupported languages when Tree-sitter grammars are unavailable
- Custom languages are supported via
.code-review-graph/languages.tomlprocessed bycustom_languages.pywithout code changes - Shebang detection (lines 560–684) and dead-guard analysis (lines 888–938) provide robust edge-case handling
Frequently Asked Questions
How does code-review-graph handle files without extensions?
The parser examines shebang lines (e.g., #!/usr/bin/env python3) using the SHEBANG_INTERPRETER_TO_LANGUAGE mapping (lines 560–684 in code_review_graph/parser.py) to determine the language when file extensions are absent.
Can I add support for a language not listed in the built-in table?
Yes. Create a .code-review-graph/languages.toml file specifying the grammar name (must exist in tree-sitter-language-pack) and node types, then call load_custom_languages() from code_review_graph/custom_languages.py. No source code modifications are required.
What happens if tree-sitter-language-pack doesn't include a grammar I need?
The system marks the grammar as unavailable via the probe cache (lines 508–545) and falls back to regex-based extraction or language-specific heuristics defined in code_review_graph/parser.py, or skips the file with a warning if no fallback exists.
How does the parser optimize performance for missing grammars?
The _parser_load_probe_succeeds function caches failed probe results to ensure that unavailable grammars are not retried within the same process, eliminating repeated subprocess overhead during batch operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →