ruby_tree_sitter 1.1.0-arm64-darwin-22

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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +199 -0
  4. data/ext/tree_sitter/encoding.c +29 -0
  5. data/ext/tree_sitter/extconf.rb +149 -0
  6. data/ext/tree_sitter/input.c +127 -0
  7. data/ext/tree_sitter/input_edit.c +42 -0
  8. data/ext/tree_sitter/language.c +219 -0
  9. data/ext/tree_sitter/logger.c +228 -0
  10. data/ext/tree_sitter/macros.h +163 -0
  11. data/ext/tree_sitter/node.c +618 -0
  12. data/ext/tree_sitter/parser.c +398 -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 +282 -0
  16. data/ext/tree_sitter/query_capture.c +28 -0
  17. data/ext/tree_sitter/query_cursor.c +215 -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/repo.rb +121 -0
  23. data/ext/tree_sitter/symbol_type.c +46 -0
  24. data/ext/tree_sitter/tree.c +234 -0
  25. data/ext/tree_sitter/tree_cursor.c +269 -0
  26. data/ext/tree_sitter/tree_sitter.c +44 -0
  27. data/ext/tree_sitter/tree_sitter.h +107 -0
  28. data/lib/tree_sitter/node.rb +197 -0
  29. data/lib/tree_sitter/tree_sitter.bundle +0 -0
  30. data/lib/tree_sitter/version.rb +8 -0
  31. data/lib/tree_sitter.rb +14 -0
  32. data/lib/tree_stand/ast_modifier.rb +30 -0
  33. data/lib/tree_stand/breadth_first_visitor.rb +54 -0
  34. data/lib/tree_stand/config.rb +13 -0
  35. data/lib/tree_stand/node.rb +224 -0
  36. data/lib/tree_stand/parser.rb +67 -0
  37. data/lib/tree_stand/range.rb +55 -0
  38. data/lib/tree_stand/tree.rb +123 -0
  39. data/lib/tree_stand/utils/printer.rb +73 -0
  40. data/lib/tree_stand/version.rb +7 -0
  41. data/lib/tree_stand/visitor.rb +127 -0
  42. data/lib/tree_stand/visitors/tree_walker.rb +37 -0
  43. data/lib/tree_stand.rb +48 -0
  44. data/tree_sitter.gemspec +35 -0
  45. metadata +124 -0
@@ -0,0 +1,35 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cRange;
6
+
7
+ DATA_WRAP(Range, range)
8
+ DATA_DEFINE_ACCESSOR(range, start_point, new_point_by_val, value_to_point)
9
+ DATA_DEFINE_ACCESSOR(range, end_point, new_point_by_val, value_to_point)
10
+ DATA_DEFINE_ACCESSOR(range, start_byte, UINT2NUM, NUM2UINT)
11
+ DATA_DEFINE_ACCESSOR(range, end_byte, UINT2NUM, NUM2UINT)
12
+
13
+ static VALUE range_inspect(VALUE self) {
14
+ range_t *range = unwrap(self);
15
+ return rb_sprintf("{start_point= %+" PRIsVALUE ", end_point=%+" PRIsVALUE
16
+ ", start_byte=%i, end_byte=%i}",
17
+ new_point_by_val(range->data.start_point),
18
+ new_point_by_val(range->data.end_point),
19
+ range->data.start_byte, range->data.end_byte);
20
+ }
21
+
22
+ void init_range(void) {
23
+ cRange = rb_define_class_under(mTreeSitter, "Range", rb_cObject);
24
+
25
+ rb_define_alloc_func(cRange, range_allocate);
26
+
27
+ /* Class methods */
28
+ DECLARE_ACCESSOR(cRange, range, start_point)
29
+ DECLARE_ACCESSOR(cRange, range, end_point)
30
+ DECLARE_ACCESSOR(cRange, range, start_byte)
31
+ DECLARE_ACCESSOR(cRange, range, end_byte)
32
+
33
+ rb_define_method(cRange, "inspect", range_inspect, 0);
34
+ rb_define_method(cRange, "to_s", range_inspect, 0);
35
+ }
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/tree_sitter/version'
4
+
5
+ module TreeSitter
6
+ # Fetches tree-sitter sources.
7
+ class Repo
8
+ attr_reader :exe, :src, :url, :version
9
+
10
+ def initialize
11
+ @version = TREESITTER_VERSION
12
+
13
+ # `tree-sitter-@version` is the name produced by tagged releases of sources
14
+ # by git, so we use it everywhere, including when cloning from git.
15
+ @src = Pathname.pwd / "tree-sitter-#{@version}"
16
+
17
+ @url = {
18
+ git: 'https://github.com/tree-sitter/tree-sitter',
19
+ tar: "https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{@version}.tar.gz",
20
+ zip: "https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{@version}.zip",
21
+ }
22
+
23
+ @exe = {}
24
+ %i[curl git tar wget zip].each do |cmd|
25
+ @exe[cmd] = find_executable(cmd.to_s)
26
+ end
27
+ end
28
+
29
+ def compile
30
+ # We need to clean because the same folder is used over and over
31
+ # by rake-compiler-dock
32
+ sh "cd #{src} && make clean && make"
33
+ end
34
+
35
+ def exe?(name)
36
+ @exe[name]
37
+ end
38
+
39
+ def extract?
40
+ !exe.filter { |k, v| %i[tar zip].include?(k) && v }.empty?
41
+ end
42
+
43
+ def download
44
+ # TODO: should we force re-download? Maybe with a flag?
45
+ return true if Dir.exist? src
46
+
47
+ res = false
48
+ %w[git curl wget].each do |cmd|
49
+ res =
50
+ if find_executable(cmd)
51
+ send("sources_from_#{cmd}")
52
+ else
53
+ false
54
+ end
55
+ break if res
56
+ end
57
+
58
+ res
59
+ end
60
+
61
+ def include_and_lib_dirs
62
+ [[src / 'lib' / 'include'], [src.to_s]]
63
+ end
64
+
65
+ def keep_static_lib
66
+ src
67
+ .children
68
+ .filter { |f| /\.(dylib|so)/ =~ f.basename.to_s }
69
+ .each(&:unlink)
70
+ end
71
+
72
+ def sh(cmd)
73
+ return if system(cmd)
74
+
75
+ abort <<~MSG
76
+
77
+ Failed to run: #{cmd}
78
+
79
+ exiting …
80
+
81
+ MSG
82
+ end
83
+
84
+ def sources_from_curl
85
+ return false if !exe?(:curl) || !extract?
86
+
87
+ if exe?(:tar)
88
+ sh "curl -L #{url[:tar]} -o tree-sitter-v#{version}.tar.gz"
89
+ sh "tar -xf tree-sitter-v#{version}.tar.gz"
90
+ elsif exe?(:zip)
91
+ sh "curl -L #{url[:zip]} -o tree-sitter-v#{version}.zip"
92
+ sh "unzip -q tree-sitter-v#{version}.zip"
93
+ end
94
+
95
+ true
96
+ end
97
+
98
+ def sources_from_git
99
+ return false if !exe?(:git)
100
+
101
+ sh "git clone #{url[:git]} #{src}"
102
+ sh "cd #{src} && git checkout tags/v#{version}"
103
+
104
+ true
105
+ end
106
+
107
+ def sources_from_wget
108
+ return false if !exe?(:wget) || !extract?
109
+
110
+ if exe?(:tar)
111
+ sh "wget #{url[:tar]} -O tree-sitter-v#{version}.tar.gz"
112
+ sh "tar -xf tree-sitter-v#{version}.tar.gz"
113
+ elsif exe?(:zip)
114
+ sh "wget #{url[:zip]} -O tree-sitter-v#{version}.zip"
115
+ sh "unzip -q tree-sitter-v#{version}.zip"
116
+ end
117
+
118
+ true
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,46 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE mSymbolType;
6
+
7
+ const char *regular = "regular";
8
+ const char *anonymous = "anonymous";
9
+ const char *auxiliary = "auxiliary";
10
+
11
+ TSSymbolType value_to_symbol_type(VALUE symbol_type) {
12
+ VALUE sym = SYM2ID(symbol_type);
13
+ VALUE anon = rb_const_get_at(mSymbolType, rb_intern(anonymous));
14
+ VALUE aux = rb_const_get_at(mSymbolType, rb_intern(auxiliary));
15
+
16
+ // NOTE: should we emit a warning instead of defaulting to regular?
17
+ if (sym == anon) {
18
+ return TSSymbolTypeAnonymous;
19
+ } else if (sym == aux) {
20
+ return TSSymbolTypeAuxiliary;
21
+ } else {
22
+ return TSSymbolTypeRegular;
23
+ }
24
+ }
25
+
26
+ VALUE new_symbol_type(TSSymbolType symbol_type) {
27
+ switch (symbol_type) {
28
+ case TSSymbolTypeRegular:
29
+ return ID2SYM(rb_intern(regular));
30
+ case TSSymbolTypeAnonymous:
31
+ return ID2SYM(rb_intern(anonymous));
32
+ case TSSymbolTypeAuxiliary:
33
+ return ID2SYM(rb_intern(auxiliary));
34
+ default:
35
+ return ID2SYM(rb_intern("this_should_never_get_reached"));
36
+ }
37
+ }
38
+
39
+ void init_symbol_type(void) {
40
+ mSymbolType = rb_define_module_under(mTreeSitter, "SymbolType");
41
+
42
+ /* Constants */
43
+ rb_define_const(mSymbolType, "REGULAR", ID2SYM(rb_intern(regular)));
44
+ rb_define_const(mSymbolType, "ANONYMOUS", ID2SYM(rb_intern(anonymous)));
45
+ rb_define_const(mSymbolType, "AUXILIARY", ID2SYM(rb_intern(auxiliary)));
46
+ }
@@ -0,0 +1,234 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cTree;
6
+
7
+ int tree_rc_free(const TSTree *tree) {
8
+ VALUE ptr = ULONG2NUM((uintptr_t)tree);
9
+ VALUE rc = rb_cv_get(cTree, "@@rc");
10
+ VALUE val = rb_hash_lookup(rc, ptr);
11
+
12
+ if (!NIL_P(val)) {
13
+ unsigned int count = NUM2UINT(val);
14
+ --count;
15
+ if (count < 1) {
16
+ rb_hash_delete(rc, ptr);
17
+ ts_tree_delete((TSTree *)tree);
18
+ return 1;
19
+ } else {
20
+ rb_hash_aset(rc, ptr, ULONG2NUM(count));
21
+ return 0;
22
+ }
23
+ } else {
24
+ return 1;
25
+ }
26
+ }
27
+
28
+ void tree_rc_new(const TSTree *tree) {
29
+ VALUE ptr = ULONG2NUM((uintptr_t)tree);
30
+ VALUE rc = rb_cv_get(cTree, "@@rc");
31
+ VALUE val = rb_hash_lookup(rc, ptr);
32
+
33
+ if (NIL_P(val)) {
34
+ rb_hash_aset(rc, ptr, UINT2NUM(1));
35
+ } else {
36
+ rb_hash_aset(rc, ptr, UINT2NUM(NUM2UINT(val) + 1));
37
+ }
38
+ }
39
+
40
+ DATA_TYPE(TSTree *, tree)
41
+ static void tree_free(void *ptr) {
42
+ tree_t *type = (tree_t *)ptr;
43
+ if (tree_rc_free(type->data)) {
44
+ xfree(ptr);
45
+ }
46
+ }
47
+
48
+ DATA_MEMSIZE(tree)
49
+ DATA_DECLARE_DATA_TYPE(tree)
50
+ DATA_ALLOCATE(tree)
51
+ DATA_UNWRAP(tree)
52
+
53
+ VALUE new_tree(TSTree *ptr) {
54
+ if (ptr == NULL) {
55
+ return Qnil;
56
+ }
57
+ VALUE res = tree_allocate(cTree);
58
+ tree_t *type = unwrap(res);
59
+ type->data = ptr;
60
+ tree_rc_new(ptr);
61
+ return res;
62
+ }
63
+
64
+ DATA_FROM_VALUE(TSTree *, tree)
65
+
66
+ /**
67
+ * Compare an old edited syntax tree to a new syntax tree representing the same
68
+ * document, returning an array of ranges whose syntactic structure has changed.
69
+ *
70
+ * For this to work correctly, the old syntax tree must have been edited such
71
+ * that its ranges match up to the new tree. Generally, you'll want to call
72
+ * this function right after calling one of the {Parser#parse} functions.
73
+ * You need to pass the old tree that was passed to parse, as well as the new
74
+ * tree that was returned from that function.
75
+ *
76
+ * @param old_tree [Tree]
77
+ * @param new_tree [Tree]
78
+ *
79
+ * @return [Array<Range>]
80
+ */
81
+ static VALUE tree_changed_ranges(VALUE _self, VALUE old_tree, VALUE new_tree) {
82
+ TSTree *old = unwrap(old_tree)->data;
83
+ TSTree *new = unwrap(new_tree)->data;
84
+ uint32_t length;
85
+ TSRange *ranges = ts_tree_get_changed_ranges(old, new, &length);
86
+ VALUE res = rb_ary_new_capa(length);
87
+
88
+ for (uint32_t i = 0; i < length; i++) {
89
+ rb_ary_push(res, new_range(&ranges[i]));
90
+ }
91
+
92
+ if (ranges) {
93
+ free(ranges);
94
+ }
95
+
96
+ return res;
97
+ }
98
+
99
+ static VALUE tree_finalizer(VALUE _self) {
100
+ VALUE rc = rb_cv_get(cTree, "@@rc");
101
+ VALUE keys = rb_funcall(rc, rb_intern("keys"), 0);
102
+ long len = RARRAY_LEN(keys);
103
+
104
+ for (long i = 0; i < len; ++i) {
105
+ VALUE curr = RARRAY_AREF(keys, i);
106
+ unsigned int val = NUM2UINT(rb_hash_lookup(rc, curr));
107
+ if (val > 0) {
108
+ ts_tree_delete((TSTree *)NUM2ULONG(curr));
109
+ }
110
+
111
+ rb_hash_delete(rc, curr);
112
+ }
113
+
114
+ return Qnil;
115
+ }
116
+
117
+ /**
118
+ * Create a shallow copy of the syntax tree. This is very fast.
119
+ *
120
+ * You need to copy a syntax tree in order to use it on more than one thread at
121
+ * a time, as syntax trees are not thread safe.
122
+ *
123
+ * @return [Tree]
124
+ */
125
+ static VALUE tree_copy(VALUE self) { return new_tree(ts_tree_copy(SELF)); }
126
+
127
+ /**
128
+ * Edit the syntax tree to keep it in sync with source code that has been
129
+ * edited.
130
+ *
131
+ * You must describe the edit both in terms of byte offsets and in terms of
132
+ * (row, column) coordinates.
133
+ *
134
+ * @param edit [InputEdit]
135
+ *
136
+ * @return [nil]
137
+ */
138
+ static VALUE tree_edit(VALUE self, VALUE edit) {
139
+ TSInputEdit in = value_to_input_edit(edit);
140
+ ts_tree_edit(SELF, &in);
141
+ return Qnil;
142
+ }
143
+
144
+ /**
145
+ * Get the array of included ranges that was used to parse the syntax tree.
146
+ *
147
+ * @return [Array<Range>]
148
+ */
149
+ static VALUE included_ranges(VALUE self) {
150
+ uint32_t length;
151
+ const TSRange *ranges = ts_tree_included_ranges(SELF, &length);
152
+ VALUE res = rb_ary_new_capa(length);
153
+ for (uint32_t i = 0; i < length; i++) {
154
+ rb_ary_push(res, new_range(&ranges[i]));
155
+ }
156
+ return res;
157
+ }
158
+
159
+ /**
160
+ * Get the language that was used to parse the syntax tree.
161
+ *
162
+ * @return [Language]
163
+ */
164
+ static VALUE tree_language(VALUE self) {
165
+ return new_language(ts_tree_language(SELF));
166
+ }
167
+
168
+ /**
169
+ * Write a DOT graph describing the syntax tree to the given file.
170
+ *
171
+ * @param file [String]
172
+ *
173
+ * @return [nil]
174
+ */
175
+ static VALUE tree_print_dot_graph(VALUE self, VALUE file) {
176
+ Check_Type(file, T_STRING);
177
+ char *path = StringValueCStr(file);
178
+ int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC,
179
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
180
+ if (fd < 0) {
181
+ rb_raise(rb_eRuntimeError, "Could not open file `%s'.\nReason:\n%s", path,
182
+ strerror(fd));
183
+ return Qnil;
184
+ }
185
+ ts_tree_print_dot_graph(SELF, fd);
186
+ close(fd);
187
+ return Qnil;
188
+ }
189
+
190
+ /**
191
+ * Get the root node of the syntax tree.
192
+ *
193
+ * @return [Node]
194
+ */
195
+ static VALUE tree_root_node(VALUE self) {
196
+ return new_node_by_val(ts_tree_root_node(SELF));
197
+ }
198
+
199
+ /**
200
+ * Get the root node of the syntax tree, but with its position
201
+ * shifted forward by the given offset.
202
+ *
203
+ * @return [Node]
204
+ */
205
+ static VALUE tree_root_node_with_offset(VALUE self, VALUE offset_bytes,
206
+ VALUE offset_extent) {
207
+ uint32_t bytes = NUM2UINT(offset_bytes);
208
+ TSPoint extent = value_to_point(offset_extent);
209
+ return new_node_by_val(ts_tree_root_node_with_offset(SELF, bytes, extent));
210
+ }
211
+
212
+ void init_tree(void) {
213
+ cTree = rb_define_class_under(mTreeSitter, "Tree", rb_cObject);
214
+
215
+ rb_undef_alloc_func(cTree);
216
+
217
+ /* Module methods */
218
+ rb_define_module_function(cTree, "changed_ranges", tree_changed_ranges, 2);
219
+ rb_define_module_function(cTree, "finalizer", tree_finalizer, 0);
220
+
221
+ /* Class methods */
222
+ rb_define_method(cTree, "copy", tree_copy, 0);
223
+ rb_define_method(cTree, "edit", tree_edit, 1);
224
+ rb_define_method(cTree, "included_ranges", included_ranges, 0);
225
+ rb_define_method(cTree, "language", tree_language, 0);
226
+ rb_define_method(cTree, "print_dot_graph", tree_print_dot_graph, 1);
227
+ rb_define_method(cTree, "root_node", tree_root_node, 0);
228
+ rb_define_method(cTree, "root_node_with_offset", tree_root_node_with_offset,
229
+ 2);
230
+
231
+ // Reference-count created trees
232
+ VALUE rc = rb_hash_new();
233
+ rb_cv_set(cTree, "@@rc", rc);
234
+ }
@@ -0,0 +1,269 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cTreeCursor;
6
+
7
+ DATA_TYPE(TSTreeCursor, tree_cursor)
8
+ static void tree_cursor_free(void *ptr) {
9
+ tree_cursor_t *type = (tree_cursor_t *)ptr;
10
+ ts_tree_cursor_delete(&type->data);
11
+ xfree(ptr);
12
+ }
13
+ DATA_MEMSIZE(tree_cursor)
14
+ DATA_DECLARE_DATA_TYPE(tree_cursor)
15
+ DATA_ALLOCATE(tree_cursor)
16
+ DATA_UNWRAP(tree_cursor)
17
+ DATA_NEW(cTreeCursor, TSTreeCursor, tree_cursor)
18
+ DATA_FROM_VALUE(TSTreeCursor, tree_cursor)
19
+
20
+ /**
21
+ * Safely copy a tree cursor.
22
+ *
23
+ * @return [TreeCursor]
24
+ */
25
+ static VALUE tree_cursor_copy(VALUE self) {
26
+ VALUE res = tree_cursor_allocate(cTreeCursor);
27
+ tree_cursor_t *ptr = unwrap(res);
28
+ ptr->data = ts_tree_cursor_copy(&SELF);
29
+ return res;
30
+ }
31
+
32
+ /**
33
+ * Get the depth of the cursor's current node relative to the original
34
+ * node that the cursor was constructed with.
35
+ *
36
+ * @return [Integer]
37
+ */
38
+ static VALUE tree_cursor_current_depth(VALUE self) {
39
+ return UINT2NUM(ts_tree_cursor_current_depth(&SELF));
40
+ }
41
+
42
+ /**
43
+ * Get the index of the cursor's current node out of all of the
44
+ * descendants of the original node that the cursor was constructed with.
45
+ *
46
+ * @return [Integer]
47
+ */
48
+ static VALUE tree_cursor_current_descendant_index(VALUE self) {
49
+ return UINT2NUM(ts_tree_cursor_current_descendant_index(&SELF));
50
+ }
51
+
52
+ /**
53
+ * Get the field id of the tree cursor's current node.
54
+ *
55
+ * This returns zero if the current node doesn't have a field.
56
+ *
57
+ * @see Node#child_by_field_id
58
+ * @see Node#field_id_for_name
59
+ *
60
+ * @return [Integer]
61
+ */
62
+ static VALUE tree_cursor_current_field_id(VALUE self) {
63
+ return UINT2NUM(ts_tree_cursor_current_field_id(&SELF));
64
+ }
65
+
66
+ /**
67
+ * Get the field name of the tree cursor's current node.
68
+ *
69
+ * This returns +nil+ if the current node doesn't have a field.
70
+ *
71
+ * @see Node#child_by_field_name
72
+ *
73
+ * @return [String]
74
+ */
75
+ static VALUE tree_cursor_current_field_name(VALUE self) {
76
+ return safe_str(ts_tree_cursor_current_field_name(&SELF));
77
+ }
78
+
79
+ /**
80
+ * Get the tree cursor's current node.
81
+ *
82
+ * @return [Node]
83
+ */
84
+ static VALUE tree_cursor_current_node(VALUE self) {
85
+ TSNode node = ts_tree_cursor_current_node(&SELF);
86
+ return new_node(&node);
87
+ }
88
+
89
+ /**
90
+ * Move the cursor to the node that is the nth descendant of
91
+ * the original node that the cursor was constructed with, where
92
+ * zero represents the original node itself.
93
+ *
94
+ * @return [nil]
95
+ */
96
+ static VALUE tree_cursor_goto_descendant(VALUE self, VALUE descendant_idx) {
97
+ uint32_t idx = NUM2UINT(descendant_idx);
98
+ ts_tree_cursor_goto_descendant(&SELF, idx);
99
+ return Qnil;
100
+ }
101
+
102
+ /**
103
+ * Move the cursor to the first child of its current node.
104
+ *
105
+ * This returns +true+ if the cursor successfully moved, and returns +false+
106
+ * if there were no children.
107
+ *
108
+ * @return [Boolean]
109
+ */
110
+ static VALUE tree_cursor_goto_first_child(VALUE self) {
111
+ return ts_tree_cursor_goto_first_child(&SELF) ? Qtrue : Qfalse;
112
+ }
113
+
114
+ /**
115
+ * Move the cursor to the first child of its current node that extends beyond
116
+ * the given byte offset.
117
+ *
118
+ * This returns the index of the child node if one was found, and returns -1
119
+ * if no such child was found.
120
+ *
121
+ * @return [Integer]
122
+ */
123
+ static VALUE tree_cursor_goto_first_child_for_byte(VALUE self, VALUE byte) {
124
+ return LL2NUM(
125
+ ts_tree_cursor_goto_first_child_for_byte(&SELF, NUM2UINT(byte)));
126
+ }
127
+
128
+ /**
129
+ * Move the cursor to the first child of its current node that extends beyond
130
+ * the given or point.
131
+ *
132
+ * This returns the index of the child node if one was found, and returns -1
133
+ * if no such child was found.
134
+ *
135
+ * @return [Integer]
136
+ */
137
+ static VALUE tree_cursor_goto_first_child_for_point(VALUE self, VALUE point) {
138
+ return LL2NUM(
139
+ ts_tree_cursor_goto_first_child_for_point(&SELF, value_to_point(point)));
140
+ }
141
+
142
+ /**
143
+ * Move the cursor to the last child of its current node.
144
+ *
145
+ * This returns +true+ if the cursor successfully moved, and returns +false+ if
146
+ * there were no children.
147
+ *
148
+ * Note that this function may be slower than {#goto_first_child}
149
+ * because it needs to iterate through all the children to compute the child's
150
+ * position.
151
+ */
152
+ static VALUE tree_cursor_goto_last_child(VALUE self) {
153
+ return ts_tree_cursor_goto_last_child(&SELF) ? Qtrue : Qfalse;
154
+ }
155
+
156
+ /**
157
+ * Move the cursor to the next sibling of its current node.
158
+ *
159
+ * This returns +true+ if the cursor successfully moved, and returns +false+
160
+ * if there was no next sibling node.
161
+ *
162
+ * @return Boolean
163
+ */
164
+ static VALUE tree_cursor_goto_next_sibling(VALUE self) {
165
+ return ts_tree_cursor_goto_next_sibling(&SELF) ? Qtrue : Qfalse;
166
+ }
167
+
168
+ /**
169
+ * Move the cursor to the parent of its current node.
170
+ *
171
+ * This returns +true+ if the cursor successfully moved, and returns +false+
172
+ * if there was no parent node (the cursor was already on the root node).
173
+ *
174
+ * @return [Boolean]
175
+ */
176
+ static VALUE tree_cursor_goto_parent(VALUE self) {
177
+ return ts_tree_cursor_goto_parent(&SELF) ? Qtrue : Qfalse;
178
+ }
179
+
180
+ /**
181
+ * Move the cursor to the previous sibling of its current node.
182
+ *
183
+ * This returns +true+ if the cursor successfully moved, and returns +false+ if
184
+ * there was no previous sibling node.
185
+ *
186
+ * Note, that this function may be slower than
187
+ * {#goto_next_sibling} due to how node positions are stored. In
188
+ * the worst case, this will need to iterate through all the children upto the
189
+ * previous sibling node to recalculate its position.
190
+ *
191
+ * @return [Boolean]
192
+ */
193
+ static VALUE tree_cursor_goto_previous_sibling(VALUE self) {
194
+ return ts_tree_cursor_goto_previous_sibling(&SELF) ? Qtrue : Qfalse;
195
+ }
196
+
197
+ /**
198
+ * Create a new tree cursor starting from the given node.
199
+ *
200
+ * A tree cursor allows you to walk a syntax tree more efficiently than is
201
+ * possible using the {Node} functions. It is a mutable object that is always
202
+ * on a certain syntax node, and can be moved imperatively to different nodes.
203
+ *
204
+ * @return [TreeCursor]
205
+ */
206
+ static VALUE tree_cursor_initialize(VALUE self, VALUE node) {
207
+ TSNode n = value_to_node(node);
208
+ tree_cursor_t *ptr = unwrap(self);
209
+ ptr->data = ts_tree_cursor_new(n);
210
+ return self;
211
+ }
212
+
213
+ /**
214
+ * Re-initialize a tree cursor to start at a different node.
215
+ *
216
+ * @return [nil]
217
+ */
218
+ static VALUE tree_cursor_reset(VALUE self, VALUE node) {
219
+ ts_tree_cursor_reset(&SELF, value_to_node(node));
220
+ return Qnil;
221
+ }
222
+
223
+ /**
224
+ * Re-initialize a tree cursor to the same position as another cursor.
225
+ *
226
+ * Unlike {#reset}, this will not lose parent information and allows reusing
227
+ * already created cursors.
228
+ *
229
+ * @return [nil]
230
+ */
231
+ VALUE tree_cursor_reset_to(VALUE self, VALUE src) {
232
+ ts_tree_cursor_reset_to(&SELF, &unwrap(src)->data);
233
+ return Qnil;
234
+ }
235
+
236
+ void init_tree_cursor(void) {
237
+ cTreeCursor = rb_define_class_under(mTreeSitter, "TreeCursor", rb_cObject);
238
+
239
+ rb_define_alloc_func(cTreeCursor, tree_cursor_allocate);
240
+
241
+ /* Class methods */
242
+ rb_define_method(cTreeCursor, "copy", tree_cursor_copy, 0);
243
+ rb_define_method(cTreeCursor, "current_depth", tree_cursor_current_depth, 0);
244
+ rb_define_method(cTreeCursor, "current_descendant_index",
245
+ tree_cursor_current_descendant_index, 0);
246
+ rb_define_method(cTreeCursor, "current_field_id",
247
+ tree_cursor_current_field_id, 0);
248
+ rb_define_method(cTreeCursor, "current_field_name",
249
+ tree_cursor_current_field_name, 0);
250
+ rb_define_method(cTreeCursor, "current_node", tree_cursor_current_node, 0);
251
+ rb_define_method(cTreeCursor, "goto_descendant", tree_cursor_goto_descendant,
252
+ 1);
253
+ rb_define_method(cTreeCursor, "goto_first_child",
254
+ tree_cursor_goto_first_child, 0);
255
+ rb_define_method(cTreeCursor, "goto_first_child_for_byte",
256
+ tree_cursor_goto_first_child_for_byte, 1);
257
+ rb_define_method(cTreeCursor, "goto_first_child_for_point",
258
+ tree_cursor_goto_first_child_for_point, 1);
259
+ rb_define_method(cTreeCursor, "goto_last_child", tree_cursor_goto_last_child,
260
+ 0);
261
+ rb_define_method(cTreeCursor, "goto_next_sibling",
262
+ tree_cursor_goto_next_sibling, 0);
263
+ rb_define_method(cTreeCursor, "goto_parent", tree_cursor_goto_parent, 0);
264
+ rb_define_method(cTreeCursor, "goto_previous_sibling",
265
+ tree_cursor_goto_previous_sibling, 0);
266
+ rb_define_method(cTreeCursor, "initialize", tree_cursor_initialize, 1);
267
+ rb_define_method(cTreeCursor, "reset", tree_cursor_reset, 1);
268
+ rb_define_method(cTreeCursor, "reset_to", tree_cursor_reset_to, 1);
269
+ }