What is tree-sitter-graph
maintree-sitter-graph library provides a Domain Specific Language (DSL) for constructing arbitrary graph structures from source code that has been parsed using [tree-sitter][].repository·main·Indexed 43 days ago
https://github.com/tree-sitter/tree-sitter-graphA Rust library and CLI tool that provides a Domain Specific Language (DSL) for constructing arbitrary graph structures from source code parsed with tree-sitter. Version 0.12.0 includes a Graph DSL for defining nodes and edges, a CLI for generating graphs from TSG files, and a VS Code extension for syntax highlighting.
tree-sitter-graph library provides a Domain Specific Language (DSL) for constructing arbitrary graph structures from source code that has been parsed using [tree-sitter][].To integrate tree-sitter-graph into your Rust project, add it as a dependency in your Cargo.toml file.
[dependencies]
tree-sitter-graph = "0.12"The project is written in Rust. To build and test the project locally, use standard cargo commands. Note that to include the CLI in your local builds or tests, you must specify the --features cli or --all-features flag.
# Build the project
$ cargo build
# Run tests (include CLI features to test the CLI as well)
$ cargo test --features cli
# Format source code
$ cargo fmtYou can install tree-sitter-graph as a command-line program using cargo install. You must enable the cli feature during installation to include the executable.
$ cargo install --features cli tree-sitter-graph
$ tree-sitter-graph --helptree-sitter-graph files within Visual Studio Code. To use it, install the extension from the VS Code Marketplace.The Graph DSL (Domain Specific Language) is represented by an Abstract Syntax Tree (AST) composed of several hierarchical components. A File is the top-level container, which holds globals, inherited_variables, a combined query, and a collection of stanzas.
Each Stanza contains a tree-sitter query and a list of statements. Statements are the executable units of the DSL, ranging from variable declarations and graph node/edge creation to control flow like if and for loops.
Expressions are the values used within statements. The Expression enum includes:
TrueLiteral (true), FalseLiteral (false), NullLiteral (#null), IntegerConstant, StringConstant, ListLiteral ([...]), and SetLiteral ({...}).ListComprehension ([ x for x in y ]) and SetComprehension ({ x for x in y }).Variable (scoped or unscoped) and Capture (@name referencing a tree-sitter capture).Call (function(args)) and RegexCapture ($index referencing a regex match from a scan statement).The Statement enum defines all possible operations within a stanza. When building or analyzing DSL files, you will encounter these statement types:
DeclareImmutable (let), DeclareMutable (var), and Assign (set).CreateGraphNode (node) and AddGraphNodeAttribute (attr for nodes).CreateEdge (edge) and AddEdgeAttribute (attr for edges).If (if/elif/else) and ForIn (for ... in ...).Scan (scan with regex), Print (print), and If.The parser uses Location and Range to track the position of entities within the source code:
Location: Represents a specific point in the file using row and column (1-indexed when displayed).Range: Represents a span of text defined by a start and end Location.Errors in tree-sitter-graph can be wrapped in a Context to provide traceability.
Context::Statement(Vec<StatementContext>): Represents a sequence of statements being executed when the error occurred.Context::Other(String): A generic context message.StatementContext captures the specific state of the execution at the time of failure, including:
statement text.statement_location: Where the statement exists in the DSL.stanza_location: The location of the stanza containing the statement.source_location: The location in the original source code that the statement was targeting.node_kind: The type of the tree-sitter node being processed.Because ParseError contains Node references that are tied to the lifetime of a Tree, it is difficult to move a Tree and its errors together in a single structure. tree-sitter-graph provides specialized wrapper types to solve this by owning both the Tree and the errors (using 'static lifetimes internally via unsafe transmute, which is safe here because nodes point to heap-allocated memory shared by the tree).
Use these types when you need to return a tree along with its error information from a function:
ParseError::into_first(tree): Returns a TreeWithParseErrorOption containing the tree and an Option<ParseError>.ParseError::into_all(tree): Returns a TreeWithParseErrorVec containing the tree and a Vec<ParseError>.Methods for TreeWithParseErrorOption:
.tree(): Returns &Tree..error(): Returns &Option<ParseError>..into_tree(): Consumes the wrapper and returns the original Tree..into_option(): Converts the wrapper into an Option<TreeWithParseError> (where TreeWithParseError contains a single error).Methods for TreeWithParseErrorVec:
.tree(): Returns &Tree..errors(): Returns &Vec<ParseError>..into_tree(): Consumes the wrapper and returns the original Tree.// Capture a tree and its first error to return safely
let tree_with_error = ParseError::into_first(tree);
if let Some(err) = tree_with_error.error() {
println!("Found error: {:?}", err);
}
// Or capture all errors
let tree_with_all = ParseError::into_all(tree);
for err in tree_with_all.errors() {
println!("Error: {:?}", err);
}When working with the tree-sitter-graph DSL, execution failures are represented by the ExecutionError enum. This enum covers a wide range of runtime errors including variable assignment issues, duplicate definitions, type mismatches (e.g., ExpectedList, ExpectedString), and undefined references (e.g., UndefinedVariable, UndefinedFunction).
Common error categories include:
CannotAssignImmutableVariable, UndefinedVariable, DuplicateVariable, MissingGlobalVariable.CannotAssignScopedVariable, InvalidVariableScope, UndefinedScopedVariable.DuplicateEdge, DuplicateAttribute, ExpectedGraphNode.ExpectedBoolean, ExpectedInteger, ExpectedString, ExpectedList.InContext (wraps an error with additional execution context).