go-tree-sitter

Go bindings for tree-sitter with prebuilt parsers for 40+ languages, for building fast syntax trees from source code.

Library
Go
vv0.0.0-20240827094217-dd81d9e9be82
565stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
40/100Fair
Development Activity0
Maintenance0
Community72
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
60/100Good
Architecture68
Code Quality72
Innovation45
Learning Curve55

go-tree-sitter provides CGo bindings to the tree-sitter incremental parsing library, exposing a Go-native API (Parser, Tree, Node, Query, TreeCursor) over the C core so Go programs can parse source code into concrete syntax trees, run tree-sitter queries with predicate filtering, and incrementally re-parse edited buffers without a full re-parse.

Beyond the C core, the repository vendors grammar bindings for around 40 languages (JavaScript, Python, Go, Rust, HCL, CSS, and more) as buildable subpackages, each wrapping a generated parser.c/parser.h pair behind a small GetLanguage() Go function, so consumers pick only the grammars they need instead of shipping every language’s parser in their binary.

What You Get

  • A Go-idiomatic Parser/Tree/Node API wrapping the tree-sitter C runtime via cgo
  • Context-aware ParseCtx/ParseInputCtx that support mid-parse cancellation
  • A Query engine with eq?/not-eq?/match?/not-match? predicate filtering
  • DFS and BFS Iterator helpers for walking a parsed tree’s nodes
  • Over 40 prebuilt language grammar subpackages, each a one-line GetLanguage() import

Common Use Cases

  • Building custom static analysis or linting tools for Go codebases
  • Powering incremental syntax highlighting in editor and IDE plugins
  • Running structural code search across a repository with tree-sitter queries
  • Implementing structural (AST-aware) diff or refactoring CLIs

Under The Hood

Architecture The Go layer is a thin cgo wrapper rather than a multi-tier system: bindings.go (~1,200 lines) marshals C TSParser/TSTree/TSNode pointers into Go Parser, Tree, and Node structs, using runtime.SetFinalizer for cleanup and manual C.free for input buffers; ParseCtx runs the C parse on a goroutine and flips an atomic cancellation flag when the caller’s context.Context is cancelled. Query and predicate support (NewQuery, QueryCursor, FilterPredicates) sit directly on top of the same C core rather than a separate abstraction layer, and iter.go adds a small DFS/BFS Iterator over a node’s children. Each supported language lives in its own leaf subpackage (javascript/, golang/, rust/, etc.) that vendors a generated parser.c/parser.h and exposes a single GetLanguage() function, so a change to the shared Node/Tree API ripples across every grammar subpackage’s tests, while adding or updating one grammar stays isolated to its own folder.

Tech Stack The vendored tree-sitter C runtime and per-language C grammars make up over 99% of the repository’s bytes, fronted by a small Go (cgo) binding surface; go.mod targets Go 1.20+ and pulls in only stretchr/testify for tests. There is no web/ORM/CLI framework here — it’s a low-level parsing binding, not an application. Build tooling is a plain Makefile plus a custom _automation Go program that checks for and pulls upstream grammar updates via a grammars.json manifest. CI (.github/workflows/test.yml) runs go test -v ./... across a matrix of Go 1.20 through 1.23 on Ubuntu.

Code Quality Tests exist and are substantive: root-level bindings_test.go (~16KB), predicates_test.go (~8KB), and example_test.go, plus a binding_test.go per grammar subpackage (e.g. golang/binding_test.go, javascript/binding_test.go), all using testify’s assert/require. Error handling is explicit rather than swallowed: ParseCtx/ParseInputCtx return (*Tree, error) with named sentinel errors (ErrOperationLimit, ErrNoLanguage) instead of panicking, and cgo resources are freed deterministically alongside finalizers. No standalone lint-config file (e.g. golangci-lint) was found at the root, but the multi-version CI matrix catches compatibility regressions. Naming follows standard exported-Go conventions throughout.

What Makes It Unique The core parsing algorithm is not this project’s own — that innovation lives upstream in tree-sitter’s C implementation. What this binding adds is breadth and convenience: a large, ready-to-vendor set of language grammars packaged as one-import subpackages, plus Go-specific ergonomics like context-based parse cancellation that not every language binding for tree-sitter provides.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search