{"id":13338370,"url":"https://github.com/tibordp/tree-sitter-visitor","last_synced_at":"2026-05-16T13:02:34.923Z","repository":{"id":146071316,"uuid":"425621115","full_name":"tibordp/tree-sitter-visitor","owner":"tibordp","description":"Procedural macro for generating a visitor trait for Tree Sitter Rust bindings","archived":false,"fork":false,"pushed_at":"2021-11-08T01:43:50.000Z","size":18,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-03-29T16:55:00.624Z","etag":null,"topics":["tree-sitter","visitor-pattern"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tibordp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-07T21:34:04.000Z","updated_at":"2021-11-08T20:01:20.000Z","dependencies_parsed_at":"2023-05-22T08:45:46.605Z","dependency_job_id":null,"html_url":"https://github.com/tibordp/tree-sitter-visitor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tibordp/tree-sitter-visitor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibordp%2Ftree-sitter-visitor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibordp%2Ftree-sitter-visitor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibordp%2Ftree-sitter-visitor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibordp%2Ftree-sitter-visitor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tibordp","download_url":"https://codeload.github.com/tibordp/tree-sitter-visitor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibordp%2Ftree-sitter-visitor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33103970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["tree-sitter","visitor-pattern"],"created_at":"2024-07-29T19:16:18.250Z","updated_at":"2026-05-16T13:02:34.908Z","avatar_url":"https://github.com/tibordp.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tree-sitter-visitor\n\nProcedural macro that generates a visitor trait for a given [Tree Sitter](https://github.com/tree-sitter/tree-sitter)\nlanguage based on `node-types.json` that is part of the generated parser.\n\nIt generates `visit_\u003cnode type\u003e()` methods for each node type in the tree-sitter grammar and a generic `visit(...)`\nthat dispatches to the appropriate typed method. All the trait methods have default implementations that panic, making\nit easier to implement visitors for large grammars incrementally.\n\n## Example\n\nLet's take a simple Tree Sitter arithmetic expression grammar:\n\n```js\nmodule.exports = grammar({\n  name: 'dummy',\n\n  rules: {\n    root: $ =\u003e $._expr,\n    _expr: $ =\u003e choice(\n      $.add_expr,\n      $.sub_expr,\n      $.mul_expr,\n      $.div_expr,\n      $.paren_expr,\n      $.number\n    ),\n\n    add_expr: $ =\u003e prec.left(1, seq(field(\"lhs\", $._expr), '+', field(\"rhs\", $._expr))),\n    sub_expr: $ =\u003e prec.left(1, seq(field(\"lhs\", $._expr), '-', field(\"rhs\", $._expr))),\n    mul_expr: $ =\u003e prec.left(2, seq(field(\"lhs\", $._expr), '*', field(\"rhs\", $._expr))),\n    div_expr: $ =\u003e prec.left(2, seq(field(\"lhs\", $._expr), '/', field(\"rhs\", $._expr))),\n    paren_expr: $ =\u003e seq('(', field(\"body\", $._expr), ')'),\n\n    number: $ =\u003e /\\d+(\\.\\d*)?/\n  }\n});\n```\n\nNow we can implement a visitor using the auto generated trait\n\n```rust\nuse tree_sitter_visitor::generate_visitor_trait;\nuse tree_sitter::Node;\n\n#[visitor_trait(\"path/to/grammar/src/node-types.json\")]\npub trait CalcVisitor { /* will be auto-generated */ }\n\n#[derive(Default)]\nstruct Calculator\u003c't\u003e {\n    src: \u0026't str,\n}\n\nimpl\u003c't\u003e CalcVisitor for Calculator\u003c't\u003e {\n    type ReturnType = f64;\n\n    fn visit_root(\u0026mut self, node: \u0026Node) -\u003e f64 {\n        self.visit(\u0026node.child(0).unwrap())\n    }\n\n    fn visit_number(\u0026mut self, node: \u0026Node) -\u003e f64 {\n        self.src[node.byte_range()].parse().unwrap()\n    }\n\n    fn visit_add_expr(\u0026mut self, node: \u0026Node) -\u003e f64 {\n        let lhs = self\n            .visit(\u0026node.child_by_field_name(\"lhs\").unwrap());\n        let rhs = self\n            .visit(\u0026node.child_by_field_name(\"rhs\").unwrap());\n\n        lhs + rhs\n    }\n\n    // we don't have to override all the methods, the \n    // unimplemented ones will just panic if visited\n}\n\nfn main() {\n    let mut parser = tree_sitter::Parser::new();\n    parser\n        .set_language(\u003clanguage\u003e)\n        .unwrap();\n\n    let src = \"1 + 2\";\n    let parsed = parser.parse(src, None).expect(\"Could not parse\");\n\n    let root_node = parsed.root_node();\n\n    let mut visitor = Calculator { src };\n    let result = visitor.visit(\u0026root_node);\n\n    assert_eq!(result, 3.0);\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftibordp%2Ftree-sitter-visitor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftibordp%2Ftree-sitter-visitor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftibordp%2Ftree-sitter-visitor/lists"}