ruby_tree_sitter 0.20.6.4-x86_64-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +152 -0
  4. data/ext/tree_sitter/encoding.c +29 -0
  5. data/ext/tree_sitter/extconf.rb +172 -0
  6. data/ext/tree_sitter/input.c +126 -0
  7. data/ext/tree_sitter/input_edit.c +42 -0
  8. data/ext/tree_sitter/language.c +134 -0
  9. data/ext/tree_sitter/logger.c +212 -0
  10. data/ext/tree_sitter/macros.h +163 -0
  11. data/ext/tree_sitter/node.c +310 -0
  12. data/ext/tree_sitter/parser.c +203 -0
  13. data/ext/tree_sitter/point.c +26 -0
  14. data/ext/tree_sitter/quantifier.c +43 -0
  15. data/ext/tree_sitter/query.c +157 -0
  16. data/ext/tree_sitter/query_capture.c +28 -0
  17. data/ext/tree_sitter/query_cursor.c +103 -0
  18. data/ext/tree_sitter/query_error.c +41 -0
  19. data/ext/tree_sitter/query_match.c +44 -0
  20. data/ext/tree_sitter/query_predicate_step.c +83 -0
  21. data/ext/tree_sitter/range.c +35 -0
  22. data/ext/tree_sitter/symbol_type.c +46 -0
  23. data/ext/tree_sitter/tree.c +144 -0
  24. data/ext/tree_sitter/tree_cursor.c +97 -0
  25. data/ext/tree_sitter/tree_sitter.c +32 -0
  26. data/ext/tree_sitter/tree_sitter.h +107 -0
  27. data/lib/tree_sitter/node.rb +164 -0
  28. data/lib/tree_sitter/tree_sitter.bundle +0 -0
  29. data/lib/tree_sitter/version.rb +5 -0
  30. data/lib/tree_sitter.rb +13 -0
  31. data/test/README.md +15 -0
  32. data/test/test_helper.rb +9 -0
  33. data/test/tree_sitter/language_test.rb +68 -0
  34. data/test/tree_sitter/logger_test.rb +69 -0
  35. data/test/tree_sitter/node_test.rb +355 -0
  36. data/test/tree_sitter/parser_test.rb +140 -0
  37. data/test/tree_sitter/query_test.rb +153 -0
  38. data/test/tree_sitter/tree_cursor_test.rb +83 -0
  39. data/test/tree_sitter/tree_test.rb +51 -0
  40. data/tree_sitter.gemspec +32 -0
  41. metadata +192 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9eb61a81274ef4aac1d80c9dfc476f8d9f8909b7ba378d1215c809af7259b5c4
4
+ data.tar.gz: 14f008d70e046ea0e3e07f4f9cebd924bf52af40a40960dd1f2e7a2588973a74
5
+ SHA512:
6
+ metadata.gz: b4c67bb1d8c1efceac4d93dfb178b6b74e339823de0a0606f83c1addc9a2a7742be743f20aae40f7374e8cb2ec1101176d70d84feacc0d0499d18927304b492a
7
+ data.tar.gz: 8f096b60ffa6c11730da3491c792facb26c6f197e7b282fbbdf28e364e938def18dd453ab76065590ec32a686350edb054d86a1359db3f4d0120222712de17f7
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
+ [![ci](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/ci.yml/badge.svg)](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/ci.yml) [![valgrind](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/valgrind.yml/badge.svg)](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/valgrind.yml) [![asan/ubsan](https://github.com/Faveod/ruby-tree-sitter/actions/workflows/asan.yml/badge.svg)](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
+ }