tree-sitter-graph

repository·main·Indexed 43 days ago

https://github.com/tree-sitter/tree-sitter-graph

A 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.

Tokens
7.6K
Snippets
25
Records
36
Agent score
56%

What's inside tree-sitter-graph

  1. Develop with tree-sitter-graph

    main

    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 fmt
  2. Understand the Graph DSL AST structure

    main

    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.

  3. Use Graph DSL Expressions

    main

    Expressions are the values used within statements. The Expression enum includes:

    • Literals: TrueLiteral (true), FalseLiteral (false), NullLiteral (#null), IntegerConstant, StringConstant, ListLiteral ([...]), and SetLiteral ({...}).
    • Comprehensions: ListComprehension ([ x for x in y ]) and SetComprehension ({ x for x in y }).
    • References: Variable (scoped or unscoped) and Capture (@name referencing a tree-sitter capture).
    • Operations: Call (function(args)) and RegexCapture ($index referencing a regex match from a scan statement).
  4. Identify available Graph DSL Statements

    main

    The Statement enum defines all possible operations within a stanza. When building or analyzing DSL files, you will encounter these statement types:

    • Variables: DeclareImmutable (let), DeclareMutable (var), and Assign (set).
    • Graph Nodes: CreateGraphNode (node) and AddGraphNodeAttribute (attr for nodes).
    • Edges: CreateEdge (edge) and AddEdgeAttribute (attr for edges).
    • Control Flow: If (if/elif/else) and ForIn (for ... in ...).
    • Logic & Debugging: Scan (scan with regex), Print (print), and If.
  5. Understand `Location` and `Range` in the graph DSL

    main

    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.
  6. Understand ExecutionError context and StatementContext

    main

    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:

    • The raw 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.
  7. Combine a Tree and its ParseErrors using TreeWithParseError types

    main

    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);
    }
  8. Handle execution errors with ExecutionError

    main

    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:

    • Variable Errors: CannotAssignImmutableVariable, UndefinedVariable, DuplicateVariable, MissingGlobalVariable.
    • Scope Errors: CannotAssignScopedVariable, InvalidVariableScope, UndefinedScopedVariable.
    • Structure Errors: DuplicateEdge, DuplicateAttribute, ExpectedGraphNode.
    • Type Errors: ExpectedBoolean, ExpectedInteger, ExpectedString, ExpectedList.
    • Contextual Errors: InContext (wraps an error with additional execution context).