ruby_tree_sitter 0.20.6.3-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +152 -0
- data/ext/tree_sitter/encoding.c +29 -0
- data/ext/tree_sitter/extconf.rb +172 -0
- data/ext/tree_sitter/input.c +126 -0
- data/ext/tree_sitter/input_edit.c +42 -0
- data/ext/tree_sitter/language.c +134 -0
- data/ext/tree_sitter/logger.c +212 -0
- data/ext/tree_sitter/macros.h +163 -0
- data/ext/tree_sitter/node.c +310 -0
- data/ext/tree_sitter/parser.c +203 -0
- data/ext/tree_sitter/point.c +26 -0
- data/ext/tree_sitter/quantifier.c +43 -0
- data/ext/tree_sitter/query.c +157 -0
- data/ext/tree_sitter/query_capture.c +28 -0
- data/ext/tree_sitter/query_cursor.c +103 -0
- data/ext/tree_sitter/query_error.c +41 -0
- data/ext/tree_sitter/query_match.c +44 -0
- data/ext/tree_sitter/query_predicate_step.c +83 -0
- data/ext/tree_sitter/range.c +35 -0
- data/ext/tree_sitter/symbol_type.c +46 -0
- data/ext/tree_sitter/tree.c +145 -0
- data/ext/tree_sitter/tree_cursor.c +97 -0
- data/ext/tree_sitter/tree_sitter.c +32 -0
- data/ext/tree_sitter/tree_sitter.h +107 -0
- data/lib/tree_sitter/node.rb +164 -0
- data/lib/tree_sitter/tree_sitter.so +0 -0
- data/lib/tree_sitter/version.rb +5 -0
- data/lib/tree_sitter.rb +13 -0
- data/test/README.md +15 -0
- data/test/test_helper.rb +9 -0
- data/test/tree_sitter/language_test.rb +68 -0
- data/test/tree_sitter/logger_test.rb +69 -0
- data/test/tree_sitter/node_test.rb +355 -0
- data/test/tree_sitter/parser_test.rb +140 -0
- data/test/tree_sitter/query_test.rb +153 -0
- data/test/tree_sitter/tree_cursor_test.rb +83 -0
- data/test/tree_sitter/tree_test.rb +51 -0
- data/tree_sitter.gemspec +32 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 66f3c718ba1bb03d6db4b418d6ca9e6fa11a071f2d07379497d57298b57415c2
|
4
|
+
data.tar.gz: e25e0f44fc08cfacdc5f6aced98a26b127294726a835a41a605996189f5d317e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 628079b69ee0279679074bf76b8be2d179aa0fb0f419e306dce7472450389a6106ff049767a4d7a8b3ac756b458b0bc5cb0afb7658b740160cb2be29b1473dc9
|
7
|
+
data.tar.gz: aba7b46de4bc19d453cac906ca7784b4be2ba6a9482d6061e7a1ff15b86ca6a80173931c0f9ebc655785fd8e7ffd4f149a9e5d10cf5db499ff7a045dd70f90f8
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018-2021 Max Brunsfeld
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# Ruby tree-sitter bindings
|
2
|
+
|
3
|
+
[](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/ci.yml) [](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/valgrind.yml) [](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/asan.yml)
|
4
|
+
|
5
|
+
Ruby bindings for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
|
6
|
+
|
7
|
+
The [official bindings](https://github.com/tree-sitter/ruby-tree-sitter) are
|
8
|
+
very old, unmaintained, and don't work with modern `tree-sitter` APIs.
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
``` ruby
|
14
|
+
require 'tree_sitter'
|
15
|
+
|
16
|
+
parser = TreeSitter::Parser.new
|
17
|
+
language = TreeSitter::Language.load('javascript', 'path/to/libtree-sitter-javascript.{so,dylib}')
|
18
|
+
|
19
|
+
src = "[1, null]"
|
20
|
+
|
21
|
+
parser.language = language
|
22
|
+
|
23
|
+
tree = parser.parse_string(nil, src)
|
24
|
+
root = tree.root_node
|
25
|
+
|
26
|
+
root.each do |child|
|
27
|
+
# ...
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
## About
|
32
|
+
|
33
|
+
The main philosophy behind these bindings is to do a 1:1 mapping between
|
34
|
+
tree-sitter's `C` API and `Ruby`.
|
35
|
+
|
36
|
+
It doesn't mean that we're going to yield the best perormance, but this design
|
37
|
+
allows us to better experiment, and easily port ideas from other projects.
|
38
|
+
|
39
|
+
### Versioning
|
40
|
+
|
41
|
+
This gem follows the `tree-sitter` versioning scheme, and appends its own
|
42
|
+
version at the end.
|
43
|
+
|
44
|
+
For instance, `tree-sitter` is now at version `0.20.6`, so this gem's version
|
45
|
+
will be `0.20.6.x` where x is incremented with every notable batch of
|
46
|
+
bugfixes or some ruby-only additions.
|
47
|
+
|
48
|
+
## Dependencies
|
49
|
+
|
50
|
+
This gem is a binding for `tree-sitter`. It doesn't have a version of
|
51
|
+
`tree-sitter` baked in it.
|
52
|
+
|
53
|
+
You must install `tree-sitter` and make sure that their dynamic library is
|
54
|
+
accessible from `$PATH`, or build the gem with `--disable-sys-libs`, which will
|
55
|
+
download the latest tagged `tree-sitter` and build against it (see [Build from
|
56
|
+
source](docs/Development.md#build-from-source) .)
|
57
|
+
|
58
|
+
You can either install `tree-sitter` from source or through your go-to package manager.
|
59
|
+
|
60
|
+
### Linux
|
61
|
+
|
62
|
+
`ubuntu >= 22.04`
|
63
|
+
|
64
|
+
```console
|
65
|
+
sudo apt install libtree-sitter-dev
|
66
|
+
```
|
67
|
+
|
68
|
+
`arch`
|
69
|
+
|
70
|
+
```console
|
71
|
+
sudo pacman -S tree-sitter
|
72
|
+
```
|
73
|
+
|
74
|
+
### MacOS
|
75
|
+
|
76
|
+
```console
|
77
|
+
sudo port install tree-sitter
|
78
|
+
```
|
79
|
+
|
80
|
+
or
|
81
|
+
|
82
|
+
```console
|
83
|
+
brew install tree-sitter
|
84
|
+
```
|
85
|
+
|
86
|
+
## Install
|
87
|
+
|
88
|
+
We haven't released the gem on `Rubygems` as of yet, but we'e planning on doing so.
|
89
|
+
|
90
|
+
Meanwhile, please install from `git` source, which will compile on installation.
|
91
|
+
|
92
|
+
If you don't want to install from `git`, or if you don't want to compile on
|
93
|
+
install, download a native gem from this repository's
|
94
|
+
[releases](https://github.com/Faveod/ruby-tree-sitter/releases), or you can
|
95
|
+
compile it yourself (see [Build from
|
96
|
+
source](docs/Development.md#build-from-source) .)
|
97
|
+
|
98
|
+
### Gemfile
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
gem 'tree_sitter', git: 'https://github.com/Faveod/ruby-tree-sitter'
|
102
|
+
```
|
103
|
+
|
104
|
+
If you chose to install a native gem, then you'd have to download it somewhere
|
105
|
+
and then specify `path` as such:
|
106
|
+
|
107
|
+
``` ruby
|
108
|
+
gem 'tree_sitter', path: 'path/to/native/tree_sitter.gem'
|
109
|
+
```
|
110
|
+
|
111
|
+
### Parsers
|
112
|
+
|
113
|
+
You will have to install parsers yourself, either by:
|
114
|
+
|
115
|
+
1. Downloading and building from source.
|
116
|
+
1. Downloading from your package manager, if available.
|
117
|
+
1. Downloading a pre-built binary from
|
118
|
+
[Faveod/tree-sitter-parsers](https://github.com/Faveod/tree-sitter-parsers)
|
119
|
+
which supports numerous architectures.
|
120
|
+
|
121
|
+
## Examples
|
122
|
+
|
123
|
+
See `examples` directory.
|
124
|
+
|
125
|
+
## Development
|
126
|
+
|
127
|
+
See [`docs/README.md`](docs/Development.md).
|
128
|
+
|
129
|
+
## 🚧 👷♀️ Notes 👷 🚧
|
130
|
+
|
131
|
+
Since we're doing a 1:1 mapping between the `tree-sitter` API and the bindings,
|
132
|
+
you need to be extra-careful when playing with the provided objects. Some of
|
133
|
+
them have their underlying `C` data-structure automatically freed, so you might
|
134
|
+
get yourself in undesirable situations if you don't pay attention to what you're
|
135
|
+
doing.
|
136
|
+
|
137
|
+
We're only talking about `Tree`, `TreeCursor`, `Query`, and `QueryCursor`. Just
|
138
|
+
don't copy them left and right, and then expect them to work without
|
139
|
+
`SEGFAULT`ing and creating a black-hole in your living-room. Assume that you
|
140
|
+
have to work locally with them. If you get a `SEGFAULT`, you can debug the
|
141
|
+
native `C` code using `gdb`. You can read more on `SEGFAULT`s
|
142
|
+
[here](docs/SIGSEGV.md), and debugging [here](docs/Development.md#Debugging).
|
143
|
+
|
144
|
+
That said, we do aim at providing an idiomatic `Ruby` interface. It should also
|
145
|
+
provide a _safer_ interface, where you don't have to worry about when and how
|
146
|
+
resources are freed.
|
147
|
+
|
148
|
+
To See a full list of the ruby-specific APIs, see [here](lib/README.md).
|
149
|
+
|
150
|
+
## Sponsors
|
151
|
+
|
152
|
+
<img src="img/faveod.jpg" width="75%">
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#include "tree_sitter.h"
|
2
|
+
|
3
|
+
extern VALUE mTreeSitter;
|
4
|
+
|
5
|
+
VALUE mEncoding;
|
6
|
+
|
7
|
+
const char *utf8 = "utf8";
|
8
|
+
const char *utf16 = "utf16";
|
9
|
+
|
10
|
+
TSInputEncoding value_to_encoding(VALUE encoding) {
|
11
|
+
VALUE enc = SYM2ID(encoding);
|
12
|
+
/* VALUE u8 = rb_const_get_at(mEncoding, rb_intern(utf8)); */
|
13
|
+
VALUE u16 = SYM2ID(rb_const_get_at(mEncoding, rb_intern("UTF16")));
|
14
|
+
|
15
|
+
// NOTE: should we emit a warning instead of defaulting to UTF8?
|
16
|
+
if (enc == u16) {
|
17
|
+
return TSInputEncodingUTF16;
|
18
|
+
} else {
|
19
|
+
return TSInputEncodingUTF8;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
void init_encoding(void) {
|
24
|
+
mEncoding = rb_define_module_under(mTreeSitter, "Encoding");
|
25
|
+
|
26
|
+
/* Constants */
|
27
|
+
rb_define_const(mEncoding, "UTF8", ID2SYM(rb_intern(utf8)));
|
28
|
+
rb_define_const(mEncoding, "UTF16", ID2SYM(rb_intern(utf16)));
|
29
|
+
}
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
# ################################## #
|
5
|
+
# Some helpers #
|
6
|
+
# ################################## #
|
7
|
+
|
8
|
+
RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
9
|
+
|
10
|
+
cflags = []
|
11
|
+
ldflags = []
|
12
|
+
|
13
|
+
def system_tree_sitter?
|
14
|
+
enable_config('sys-libs', true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def sh cmd
|
18
|
+
if !system(cmd)
|
19
|
+
abort <<~MSG
|
20
|
+
|
21
|
+
Failed to run: #{cmd}
|
22
|
+
|
23
|
+
exiting…
|
24
|
+
|
25
|
+
MSG
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def env_var_on?(var)
|
30
|
+
%w[1 on true t yes y].include?(ENV.fetch(var, '').downcase)
|
31
|
+
end
|
32
|
+
|
33
|
+
# ################################## #
|
34
|
+
# System lib #
|
35
|
+
# #
|
36
|
+
# OR #
|
37
|
+
# #
|
38
|
+
# Downloaded libs #
|
39
|
+
# ################################## #
|
40
|
+
|
41
|
+
dir_include, dir_lib =
|
42
|
+
if system_tree_sitter?
|
43
|
+
[['/opt/include', '/opt/local/include', '/usr/include', '/usr/local/include'],
|
44
|
+
['/opt/lib', '/opt/local/lib', '/usr/lib', '/usr/local/lib']]
|
45
|
+
else
|
46
|
+
src = Pathname.pwd / "tree-sitter-#{TreeSitter::VERSION}"
|
47
|
+
if !Dir.exist? src
|
48
|
+
if find_executable('git')
|
49
|
+
sh "git clone https://github.com/tree-sitter/tree-sitter #{src}"
|
50
|
+
sh "cd #{src} && git checkout tags/v#{TreeSitter::VERSION}"
|
51
|
+
elsif find_executable('curl')
|
52
|
+
if find_executable('tar')
|
53
|
+
sh "curl -L https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{TreeSitter::VERSION}.tar.gz -o tree-sitter-v#{TreeSitter::VERSION}.tar.gz"
|
54
|
+
sh "tar -xf tree-sitter-v#{TreeSitter::VERSION}.tar.gz"
|
55
|
+
elsif find_executable('zip')
|
56
|
+
sh "curl -L https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{TreeSitter::VERSION}.zip -o tree-sitter-v#{TreeSitter::VERSION}.zip"
|
57
|
+
sh "unzip -q tree-sitter-v#{TreeSitter::VERSION}.zip"
|
58
|
+
else
|
59
|
+
abort('Could not find `tar` or `zip` (and `git` was not found!)')
|
60
|
+
end
|
61
|
+
else
|
62
|
+
abort('Could not find `git` or `curl` to download tree-sitter and build from sources.')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# We need to make sure we're selecting the proper toolchain.
|
67
|
+
# Especially needed for corss-compilation.
|
68
|
+
ENV.store('CC', RbConfig::CONFIG['CC'])
|
69
|
+
# We need to clean because the same folder is used over and over
|
70
|
+
# by rake-compiler-dock
|
71
|
+
sh "cd #{src} && make clean && make"
|
72
|
+
|
73
|
+
[[src / 'lib' / 'include'], [src.to_s]]
|
74
|
+
end
|
75
|
+
|
76
|
+
# ################################## #
|
77
|
+
# Generate Makefile #
|
78
|
+
# ################################## #
|
79
|
+
|
80
|
+
header = find_header('tree_sitter/api.h', *dir_include)
|
81
|
+
|
82
|
+
library = find_library('tree-sitter', # libtree-sitter
|
83
|
+
'ts_parser_new', # a symbol
|
84
|
+
*dir_lib)
|
85
|
+
|
86
|
+
if !header || !library
|
87
|
+
abort <<~MSG
|
88
|
+
|
89
|
+
* Missing header : #{header ? 'no' : 'yes'}
|
90
|
+
* Missing lib : #{library ? 'no' : 'yes'}
|
91
|
+
* Use system tree-sitter : #{system_tree_sitter?}
|
92
|
+
|
93
|
+
Try to install tree-sitter from source, or through your package manager,
|
94
|
+
or even try one of the following options to extconf.rb/rake compile:
|
95
|
+
|
96
|
+
--with-tree-sitter-dir=/path/to/tree-sitter
|
97
|
+
--with-tree-sitter-lib=/path/to/tree-sitter/lib
|
98
|
+
--with-tree-sitter-include=/path/to/tree-sitter/include
|
99
|
+
|
100
|
+
MSG
|
101
|
+
end
|
102
|
+
|
103
|
+
if env_var_on?('TREE_SITTER_PEDANTIC')
|
104
|
+
cflags << '-Werror'
|
105
|
+
end
|
106
|
+
|
107
|
+
if env_var_on?('DEBUG')
|
108
|
+
cflags << '-fbounds-check'
|
109
|
+
CONFIG['optflags'].gsub!(/-O\d/, '-O0')
|
110
|
+
else
|
111
|
+
cflags << '-DNDEBUG'
|
112
|
+
CONFIG['optflags'].gsub!(/-O\d/, '-O3')
|
113
|
+
end
|
114
|
+
|
115
|
+
sanitizers = ENV.fetch('SANITIZE', nil)
|
116
|
+
|
117
|
+
if sanitizers =~ /memory/
|
118
|
+
puts <<~MSG
|
119
|
+
|
120
|
+
We do not support memory sanitizers as of yet.
|
121
|
+
It requires building ruby with the same sanitizer, and maybe its dependencies.
|
122
|
+
|
123
|
+
exiting…
|
124
|
+
|
125
|
+
MSG
|
126
|
+
exit 1
|
127
|
+
end
|
128
|
+
|
129
|
+
if sanitizers
|
130
|
+
# NOTE: when sanitizing, the default generated warning flags emit a lot of …
|
131
|
+
# warnings.
|
132
|
+
#
|
133
|
+
# I couldn't make mkmf understand it's running with clang and not gcc, so
|
134
|
+
# I'm omitting the warning generating warnings.
|
135
|
+
#
|
136
|
+
# It should be harmless, since sanitization is meant for CI and dev builds.
|
137
|
+
%w[
|
138
|
+
-Wduplicated-cond
|
139
|
+
-Wimplicit-fallthrough=\d+
|
140
|
+
-Wno-cast-function-type
|
141
|
+
-Wno-packed-bitfield-compat
|
142
|
+
-Wsuggest-attribute=\w+
|
143
|
+
].each do |r|
|
144
|
+
$warnflags.gsub!(/#{r}/, '')
|
145
|
+
end
|
146
|
+
|
147
|
+
cflags.concat %W[
|
148
|
+
-fms-extensions
|
149
|
+
-fdeclspec
|
150
|
+
-fsanitize=#{sanitizers}
|
151
|
+
-fsanitize-blacklist=../../../../.asanignore
|
152
|
+
-fsanitize-recover=#{sanitizers}
|
153
|
+
-fno-sanitize-recover=all
|
154
|
+
-fno-sanitize=null
|
155
|
+
-fno-sanitize=alignment
|
156
|
+
-fno-omit-frame-pointer
|
157
|
+
]
|
158
|
+
|
159
|
+
ldflags.concat %W[
|
160
|
+
-fsanitize=#{sanitizers}
|
161
|
+
-dynamic-libasan
|
162
|
+
]
|
163
|
+
end
|
164
|
+
|
165
|
+
cflags.concat %w[-std=c99 -fPIC -Wall]
|
166
|
+
|
167
|
+
append_cflags(cflags)
|
168
|
+
append_ldflags(ldflags)
|
169
|
+
|
170
|
+
dir_config('tree-sitter')
|
171
|
+
create_header
|
172
|
+
create_makefile('tree_sitter/tree_sitter')
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#include "tree_sitter.h"
|
2
|
+
|
3
|
+
extern VALUE mTreeSitter;
|
4
|
+
|
5
|
+
VALUE cInput;
|
6
|
+
|
7
|
+
typedef struct {
|
8
|
+
TSInput data;
|
9
|
+
VALUE payload;
|
10
|
+
VALUE last_result;
|
11
|
+
} input_t;
|
12
|
+
|
13
|
+
const char *input_read(void *payload, uint32_t byte_index, TSPoint position,
|
14
|
+
uint32_t *bytes_read) {
|
15
|
+
input_t *input = (input_t *)payload;
|
16
|
+
VALUE read = rb_funcall(input->payload, rb_intern("read"), 2,
|
17
|
+
UINT2NUM(byte_index), new_point(&position));
|
18
|
+
if (NIL_P(read)) {
|
19
|
+
*bytes_read = 0;
|
20
|
+
input->last_result = Qnil;
|
21
|
+
return NULL;
|
22
|
+
}
|
23
|
+
|
24
|
+
VALUE size = rb_funcall(read, rb_intern("bytesize"), 0);
|
25
|
+
*bytes_read = NUM2UINT(size);
|
26
|
+
input->last_result = rb_funcall(read, rb_intern("to_str"), 0);
|
27
|
+
|
28
|
+
return StringValueCStr(input->last_result);
|
29
|
+
}
|
30
|
+
|
31
|
+
static void input_payload_set(input_t *input, VALUE value) {
|
32
|
+
input->payload = value;
|
33
|
+
input->last_result = Qnil;
|
34
|
+
input->data.payload = (void *)input;
|
35
|
+
input->data.read = input_read;
|
36
|
+
}
|
37
|
+
|
38
|
+
static void input_free(void *ptr) { xfree(ptr); }
|
39
|
+
|
40
|
+
static size_t input_memsize(const void *ptr) {
|
41
|
+
input_t *type = (input_t *)ptr;
|
42
|
+
return sizeof(type);
|
43
|
+
}
|
44
|
+
|
45
|
+
static void input_mark(void *ptr) {
|
46
|
+
input_t *input = (input_t *)ptr;
|
47
|
+
rb_gc_mark_movable(input->payload);
|
48
|
+
// we don't want last_result to move because its const char* content will be
|
49
|
+
// consumed by the parser.
|
50
|
+
//
|
51
|
+
// No funny things please.
|
52
|
+
rb_gc_mark(input->last_result);
|
53
|
+
}
|
54
|
+
|
55
|
+
static void input_compact(void *ptr) {
|
56
|
+
input_t *input = (input_t *)ptr;
|
57
|
+
input->payload = rb_gc_location(input->payload);
|
58
|
+
}
|
59
|
+
|
60
|
+
const rb_data_type_t input_data_type = {
|
61
|
+
.wrap_struct_name = "input",
|
62
|
+
.function =
|
63
|
+
{
|
64
|
+
.dmark = input_mark,
|
65
|
+
.dfree = input_free,
|
66
|
+
.dsize = input_memsize,
|
67
|
+
.dcompact = input_compact,
|
68
|
+
},
|
69
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
70
|
+
};
|
71
|
+
|
72
|
+
DATA_UNWRAP(input)
|
73
|
+
|
74
|
+
static VALUE input_allocate(VALUE klass) {
|
75
|
+
input_t *input;
|
76
|
+
return TypedData_Make_Struct(klass, input_t, &input_data_type, input);
|
77
|
+
}
|
78
|
+
|
79
|
+
TSInput value_to_input(VALUE self) { return SELF; }
|
80
|
+
|
81
|
+
VALUE new_input(const TSInput *ptr) {
|
82
|
+
if (ptr != NULL) {
|
83
|
+
VALUE res = input_allocate(cInput);
|
84
|
+
input_t *input = unwrap(res);
|
85
|
+
VALUE payload = Qnil;
|
86
|
+
if (ptr->payload != NULL) {
|
87
|
+
input_t *old_input = (input_t *)ptr->payload;
|
88
|
+
payload = old_input->payload;
|
89
|
+
}
|
90
|
+
input_payload_set(input, payload);
|
91
|
+
return res;
|
92
|
+
} else {
|
93
|
+
return Qnil;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
static VALUE input_initialize(int argc, VALUE *argv, VALUE self) {
|
98
|
+
input_t *input = unwrap(self);
|
99
|
+
VALUE payload;
|
100
|
+
rb_scan_args(argc, argv, "01", &payload);
|
101
|
+
input_payload_set(input, payload);
|
102
|
+
return self;
|
103
|
+
}
|
104
|
+
|
105
|
+
static VALUE input_inspect(VALUE self) {
|
106
|
+
return rb_sprintf("{payload=%+" PRIsVALUE "}", unwrap(self)->payload);
|
107
|
+
}
|
108
|
+
|
109
|
+
DEFINE_GETTER(input, payload)
|
110
|
+
|
111
|
+
static VALUE input_set_payload(VALUE self, VALUE payload) {
|
112
|
+
input_payload_set(unwrap(self), payload);
|
113
|
+
return Qnil;
|
114
|
+
}
|
115
|
+
|
116
|
+
void init_input(void) {
|
117
|
+
cInput = rb_define_class_under(mTreeSitter, "Input", rb_cObject);
|
118
|
+
|
119
|
+
rb_define_alloc_func(cInput, input_allocate);
|
120
|
+
|
121
|
+
/* Class methods */
|
122
|
+
DECLARE_ACCESSOR(cInput, input, payload)
|
123
|
+
rb_define_method(cInput, "initialize", input_initialize, -1);
|
124
|
+
rb_define_method(cInput, "inspect", input_inspect, 0);
|
125
|
+
rb_define_method(cInput, "to_s", input_inspect, 0);
|
126
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#include "tree_sitter.h"
|
2
|
+
|
3
|
+
extern VALUE mTreeSitter;
|
4
|
+
|
5
|
+
VALUE cInputEdit;
|
6
|
+
|
7
|
+
DATA_WRAP(InputEdit, input_edit)
|
8
|
+
DATA_DEFINE_ACCESSOR(input_edit, start_byte, UINT2NUM, NUM2UINT)
|
9
|
+
DATA_DEFINE_ACCESSOR(input_edit, old_end_byte, UINT2NUM, NUM2UINT)
|
10
|
+
DATA_DEFINE_ACCESSOR(input_edit, new_end_byte, UINT2NUM, NUM2UINT)
|
11
|
+
DATA_DEFINE_ACCESSOR(input_edit, start_point, new_point_by_val, value_to_point)
|
12
|
+
DATA_DEFINE_ACCESSOR(input_edit, old_end_point, new_point_by_val, value_to_point)
|
13
|
+
DATA_DEFINE_ACCESSOR(input_edit, new_end_point, new_point_by_val, value_to_point)
|
14
|
+
|
15
|
+
static VALUE input_edit_inspect(VALUE self) {
|
16
|
+
input_edit_t *input_edit = unwrap(self);
|
17
|
+
return rb_sprintf("{start_byte=%i, old_end_byte=%i , new_end_byte=%i, "
|
18
|
+
"start_point=%+" PRIsVALUE ", old_end_point=%+" PRIsVALUE
|
19
|
+
", new_end_point=%+" PRIsVALUE "}",
|
20
|
+
input_edit->data.start_byte, input_edit->data.old_end_byte,
|
21
|
+
input_edit->data.new_end_byte,
|
22
|
+
new_point_by_val(input_edit->data.start_point),
|
23
|
+
new_point_by_val(input_edit->data.old_end_point),
|
24
|
+
new_point_by_val(input_edit->data.new_end_point));
|
25
|
+
}
|
26
|
+
|
27
|
+
void init_input_edit(void) {
|
28
|
+
cInputEdit = rb_define_class_under(mTreeSitter, "InputEdit", rb_cObject);
|
29
|
+
|
30
|
+
rb_define_alloc_func(cInputEdit, input_edit_allocate);
|
31
|
+
|
32
|
+
/* Class methods */
|
33
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, start_byte)
|
34
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, old_end_byte)
|
35
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, new_end_byte)
|
36
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, start_point)
|
37
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, old_end_point)
|
38
|
+
DECLARE_ACCESSOR(cInputEdit, input_edit, new_end_point)
|
39
|
+
|
40
|
+
rb_define_method(cInputEdit, "inspect", input_edit_inspect, 0);
|
41
|
+
rb_define_method(cInputEdit, "to_s", input_edit_inspect, 0);
|
42
|
+
}
|
@@ -0,0 +1,134 @@
|
|
1
|
+
#include "tree_sitter.h"
|
2
|
+
#include <dlfcn.h>
|
3
|
+
#include <stdint.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
typedef TSLanguage *(tree_sitter_lang)(void);
|
7
|
+
const char *tree_sitter_prefix = "tree_sitter_";
|
8
|
+
|
9
|
+
extern VALUE mTreeSitter;
|
10
|
+
|
11
|
+
VALUE cLanguage;
|
12
|
+
|
13
|
+
DATA_TYPE(TSLanguage *, language)
|
14
|
+
DATA_FREE(language)
|
15
|
+
DATA_MEMSIZE(language)
|
16
|
+
DATA_DECLARE_DATA_TYPE(language)
|
17
|
+
DATA_ALLOCATE(language)
|
18
|
+
DATA_UNWRAP(language)
|
19
|
+
|
20
|
+
TSLanguage *value_to_language(VALUE self) { return SELF; }
|
21
|
+
|
22
|
+
VALUE new_language(const TSLanguage *language) {
|
23
|
+
VALUE res = language_allocate(cLanguage);
|
24
|
+
unwrap(res)->data = (TSLanguage *)language;
|
25
|
+
return res;
|
26
|
+
}
|
27
|
+
|
28
|
+
static VALUE language_symbol_count(VALUE self) {
|
29
|
+
return UINT2NUM(ts_language_symbol_count(SELF));
|
30
|
+
}
|
31
|
+
|
32
|
+
static VALUE language_symbol_name(VALUE self, VALUE symbol) {
|
33
|
+
return safe_str(ts_language_symbol_name(SELF, NUM2UINT(symbol)));
|
34
|
+
}
|
35
|
+
|
36
|
+
static VALUE language_symbol_for_name(VALUE self, VALUE string,
|
37
|
+
VALUE is_named) {
|
38
|
+
const char *str = rb_id2name(SYM2ID(string));
|
39
|
+
uint32_t length = (uint32_t)strlen(str);
|
40
|
+
bool named = RTEST(is_named);
|
41
|
+
return UINT2NUM(ts_language_symbol_for_name(SELF, str, length, named));
|
42
|
+
}
|
43
|
+
|
44
|
+
static VALUE language_field_count(VALUE self) {
|
45
|
+
return UINT2NUM(ts_language_field_count(SELF));
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE language_field_name_for_id(VALUE self, VALUE field_id) {
|
49
|
+
return safe_str(ts_language_field_name_for_id(SELF, NUM2UINT(field_id)));
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE language_field_id_for_name(VALUE self, VALUE name) {
|
53
|
+
TSLanguage *language = SELF;
|
54
|
+
const char *str = StringValuePtr(name);
|
55
|
+
uint32_t length = (uint32_t)RSTRING_LEN(name);
|
56
|
+
return UINT2NUM(ts_language_field_id_for_name(language, str, length));
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE language_symbol_type(VALUE self, VALUE symbol) {
|
60
|
+
return new_symbol_type(ts_language_symbol_type(SELF, NUM2UINT(symbol)));
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE language_version(VALUE self) {
|
64
|
+
return UINT2NUM(ts_language_version(SELF));
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE language_load(VALUE self, VALUE name, VALUE path) {
|
68
|
+
VALUE path_s = rb_funcall(path, rb_intern("to_s"), 0);
|
69
|
+
char *path_cstr = StringValueCStr(path_s);
|
70
|
+
void *lib = dlopen(path_cstr, RTLD_NOW);
|
71
|
+
const char *err = dlerror();
|
72
|
+
if (err != NULL) {
|
73
|
+
rb_raise(rb_eRuntimeError,
|
74
|
+
"Could not load shared library `%s'.\nReason: %s", path_cstr, err);
|
75
|
+
}
|
76
|
+
|
77
|
+
char buf[256];
|
78
|
+
snprintf(buf, sizeof(buf), "tree_sitter_%s", StringValueCStr(name));
|
79
|
+
tree_sitter_lang *make_ts_language = dlsym(lib, buf);
|
80
|
+
err = dlerror();
|
81
|
+
if (err != NULL) {
|
82
|
+
dlclose(lib);
|
83
|
+
rb_raise(rb_eRuntimeError,
|
84
|
+
"Could not load symbol `%s' from library `%s'.\nReason:%s",
|
85
|
+
StringValueCStr(name), StringValueCStr(path), err);
|
86
|
+
}
|
87
|
+
|
88
|
+
TSLanguage *lang = make_ts_language();
|
89
|
+
if (lang == NULL) {
|
90
|
+
dlclose(lib);
|
91
|
+
rb_raise(rb_eRuntimeError,
|
92
|
+
"TSLanguage = NULL for language `%s' in library `%s'.\nCall your "
|
93
|
+
"local TSLanguage supplier.",
|
94
|
+
StringValueCStr(name), StringValueCStr(path));
|
95
|
+
}
|
96
|
+
|
97
|
+
uint32_t version = ts_language_version(lang);
|
98
|
+
if (version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) {
|
99
|
+
rb_raise(rb_eRuntimeError,
|
100
|
+
"Language %s (v%d) from `%s' is old.\nMinimum supported ABI: "
|
101
|
+
"v%d.\nCurrent ABI: v%d.",
|
102
|
+
StringValueCStr(name), version, StringValueCStr(path),
|
103
|
+
TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
|
104
|
+
TREE_SITTER_LANGUAGE_VERSION);
|
105
|
+
}
|
106
|
+
|
107
|
+
return new_language(lang);
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE language_equal(VALUE self, VALUE other) {
|
111
|
+
TSLanguage *this = SELF;
|
112
|
+
TSLanguage *that = unwrap(other)->data;
|
113
|
+
return this == that ? Qtrue : Qfalse;
|
114
|
+
}
|
115
|
+
|
116
|
+
void init_language(void) {
|
117
|
+
cLanguage = rb_define_class_under(mTreeSitter, "Language", rb_cObject);
|
118
|
+
|
119
|
+
rb_define_alloc_func(cLanguage, language_allocate);
|
120
|
+
|
121
|
+
/* Class methods */
|
122
|
+
rb_define_method(cLanguage, "symbol_count", language_symbol_count, 0);
|
123
|
+
rb_define_method(cLanguage, "symbol_name", language_symbol_name, 1);
|
124
|
+
rb_define_method(cLanguage, "symbol_for_name", language_symbol_for_name, 2);
|
125
|
+
rb_define_method(cLanguage, "field_count", language_field_count, 0);
|
126
|
+
rb_define_method(cLanguage, "field_name_for_id", language_field_name_for_id,
|
127
|
+
1);
|
128
|
+
rb_define_method(cLanguage, "field_id_for_name", language_field_id_for_name,
|
129
|
+
1);
|
130
|
+
rb_define_method(cLanguage, "symbol_type", language_symbol_type, 1);
|
131
|
+
rb_define_method(cLanguage, "version", language_version, 0);
|
132
|
+
rb_define_module_function(cLanguage, "load", language_load, 2);
|
133
|
+
rb_define_method(cLanguage, "==", language_equal, 1);
|
134
|
+
}
|