Ruby tree-sitter bindings
Ruby bindings for tree-sitter.
The official bindings are
very old, unmaintained, and don't work with modern tree-sitter
APIs.
Usage
TreeSitter API
The TreeSitter API is a low-level Ruby binding for tree-sitter.
require 'tree_sitter'
parser = TreeSitter::Parser.new
language = TreeSitter::Language.load('javascript', 'path/to/libtree-sitter-javascript.{so,dylib}')
# Or simply
language = TreeSitter.lang('javascript')
# Which will try to look in your local directory and the system for installed parsers.
# See TreeSitter::Mixin::Language#lib_dirs
src = "[1, null]"
parser.language = language
tree = parser.parse_string(nil, src)
root = tree.root_node
root.each do |child|
# ...
end
The main philosophy behind the TreeSitter bindings is to do a 1:1 mapping between
tree-sitter's C
API and Ruby
, which makes it easier to experiment and port
ideas from different languages/bindings.
But it feels like writing some managed C
with Ruby
, and that's why we provide
a high-level API (TreeStand) as well.
TreeStand API
The TreeStand API is a high-level Ruby wrapper for the TreeSitter bindings. It makes it easier to configure the parsers, and work with the underlying syntax tree.
require 'tree_stand'
TreeStand.configure do
config.parser_path = "path/to/parser/folder/"
end
sql_parser = TreeStand::Parser.new("sql")
ruby_parser = TreeStand::Parser.new("ruby")
TreeStand provides an idiomatic Ruby interface to work with tree-sitter parsers.
Dependencies
This gem is a binding for tree-sitter
, and comes with a pre-built version
of tree-sitter
bundled with it, so you can start using it without any
special configuration.
We support the following platforms:
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
x86_64-linux-gnu
x86_64-linux-musl
x86-linux-musl
arm64-darwin
x86_64-darwin
(see Build from source).
You can either install tree-sitter
from source or through your go-to package manager.
Linux
ubuntu >= 22.04
sudo apt install libtree-sitter-dev
arch
sudo pacman -S tree-sitter
MacOS
sudo port install tree-sitter
or
brew install tree-sitter
Install
From rubygems, in your Gemfile
:
gem 'ruby_tree_sitter', '~> 1.6'
Or manually:
gem install ruby_tree_sitter
Or from git
sources, which will compile on installation:
gem 'ruby_tree_sitter', git: 'https://github.com/Faveod/ruby-tree-sitter'
Enable system libraries
To install with --enable-sys-libs
, you can either:
gem install ruby_tree_sitter --platform=ruby -- --enable-sys-libs
Or via bundle:
bundle config force_ruby_platform true
bundle config set build.ruby_tree_sitter --enable-sys-libs
No compilation
If you don't want to install from rubygems
, git
, or if you don't want to
compile on install, then download a native gem from this repository's
releases, or you can
compile it yourself (see Build from source .)
In that case, you'd have to point your Gemfile
to the gem
as such:
gem 'tree_sitter', path: 'path/to/native/tree_sitter.gem'
⚠️ We're currently missing a lot of platforms and architectures. Cross-build will come back in the near future.
Parsers
You will have to install parsers yourself, either by:
- Downloading and building from source.
- Downloading from your package manager, if available.
- Downloading a pre-built binary from Faveod/tree-sitter-parsers which supports numerous architectures.
Examples
See examples
directory.
Development
See docs/Contributing.md
.
🚧 👷♀️ Notes 👷 🚧
Since we're doing a 1:1 mapping between the tree-sitter
API and the bindings,
you need to be extra-careful when playing with the provided objects. Some of
them have their underlying C
data-structure automatically freed, so you might
get yourself in undesirable situations if you don't pay attention to what you're
doing.
We're only talking about Tree
, TreeCursor
, Query
, and QueryCursor
. Just
don't copy them left and right, and then expect them to work without
SEGFAULT
ing and creating a black-hole in your living-room. Assume that you
have to work locally with them. If you get a SEGFAULT
, you can debug the
native C
code using gdb
. You can read more on SEGFAULT
s
here, and debugging here.
That said, we do aim at providing an idiomatic Ruby
interface. It should also
provide a safer interface, where you don't have to worry about when and how
resources are freed.
To See a full list of the ruby-specific APIs, see here.