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.
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 +145 -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.so +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: 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
+ [![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
+ }