ruby_tree_sitter 0.20.8.2-x86_64-linux → 1.0.0-x86_64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +2 -1
- data/README.md +32 -18
- data/ext/tree_sitter/extconf.rb +1 -43
- data/ext/tree_sitter/input.c +1 -0
- data/ext/tree_sitter/language.c +131 -46
- data/ext/tree_sitter/logger.c +28 -12
- data/ext/tree_sitter/node.c +438 -130
- data/ext/tree_sitter/parser.c +232 -37
- data/ext/tree_sitter/query.c +197 -72
- data/ext/tree_sitter/query_cursor.c +140 -28
- data/ext/tree_sitter/repo.rb +121 -0
- data/ext/tree_sitter/tree.c +118 -34
- data/ext/tree_sitter/tree_cursor.c +205 -33
- data/ext/tree_sitter/tree_sitter.c +12 -0
- data/lib/tree_sitter/node.rb +43 -9
- data/lib/tree_sitter/tree_sitter.so +0 -0
- data/lib/tree_sitter/version.rb +4 -2
- data/lib/tree_sitter.rb +1 -0
- data/lib/tree_stand/ast_modifier.rb +30 -0
- data/lib/tree_stand/breadth_first_visitor.rb +54 -0
- data/lib/tree_stand/config.rb +13 -0
- data/lib/tree_stand/node.rb +224 -0
- data/lib/tree_stand/parser.rb +67 -0
- data/lib/tree_stand/range.rb +55 -0
- data/lib/tree_stand/tree.rb +123 -0
- data/lib/tree_stand/utils/printer.rb +73 -0
- data/lib/tree_stand/version.rb +7 -0
- data/lib/tree_stand/visitor.rb +127 -0
- data/lib/tree_stand/visitors/tree_walker.rb +37 -0
- data/lib/tree_stand.rb +48 -0
- data/tree_sitter.gemspec +15 -12
- metadata +37 -107
- data/test/README.md +0 -15
- data/test/test_helper.rb +0 -9
- data/test/tree_sitter/js_test.rb +0 -48
- data/test/tree_sitter/language_test.rb +0 -73
- data/test/tree_sitter/logger_test.rb +0 -70
- data/test/tree_sitter/node_test.rb +0 -355
- data/test/tree_sitter/parser_test.rb +0 -140
- data/test/tree_sitter/query_test.rb +0 -153
- data/test/tree_sitter/tree_cursor_test.rb +0 -83
- data/test/tree_sitter/tree_test.rb +0 -51
@@ -16,9 +16,39 @@ static VALUE query_cursor_allocate(VALUE klass) {
|
|
16
16
|
return res;
|
17
17
|
}
|
18
18
|
DATA_UNWRAP(query_cursor)
|
19
|
+
/**
|
20
|
+
* Create a new cursor for executing a given query.
|
21
|
+
*
|
22
|
+
* The cursor stores the state that is needed to iteratively search
|
23
|
+
* for matches. To use the query cursor, first call {QueryCursor#exec}
|
24
|
+
* to start running a given query on a given syntax node. Then, there are
|
25
|
+
* two options for consuming the results of the query:
|
26
|
+
* 1. Repeatedly call {QueryCursor#next_match} to iterate over all of the
|
27
|
+
* *matches* in the order that they were found. Each match contains the
|
28
|
+
* index of the pattern that matched, and an array of captures. Because
|
29
|
+
* multiple patterns can match the same set of nodes, one match may contain
|
30
|
+
* captures that appear *before* some of the captures from a previous match.
|
31
|
+
* 2. Repeatedly call {QueryCursor#next_capture} to iterate over all of the
|
32
|
+
* individual *captures* in the order that they appear. This is useful if
|
33
|
+
* don't care about which pattern matched, and just want a single ordered
|
34
|
+
* sequence of captures.
|
35
|
+
*
|
36
|
+
* If you don't care about consuming all of the results, you can stop calling
|
37
|
+
* {QueryCursor#next_match} or {QueryCursor#next_capture} at any point.
|
38
|
+
* You can then start executing another query on another node by calling
|
39
|
+
* {QueryCursor#exec} again.
|
40
|
+
*/
|
19
41
|
DATA_PTR_NEW(cQueryCursor, TSQueryCursor, query_cursor)
|
20
42
|
DATA_FROM_VALUE(TSQueryCursor *, query_cursor)
|
21
43
|
|
44
|
+
/**
|
45
|
+
* Start running a given query on a given node.
|
46
|
+
*
|
47
|
+
* @param query [Query]
|
48
|
+
* @param node [Node]
|
49
|
+
*
|
50
|
+
* @return [QueryCursor]
|
51
|
+
*/
|
22
52
|
static VALUE query_cursor_exec(VALUE self, VALUE query, VALUE node) {
|
23
53
|
VALUE res = query_cursor_allocate(cQueryCursor);
|
24
54
|
query_cursor_t *query_cursor = unwrap(res);
|
@@ -27,49 +57,78 @@ static VALUE query_cursor_exec(VALUE self, VALUE query, VALUE node) {
|
|
27
57
|
return res;
|
28
58
|
}
|
29
59
|
|
60
|
+
/**
|
61
|
+
* Manage the maximum number of in-progress matches allowed by this query
|
62
|
+
* cursor.
|
63
|
+
*
|
64
|
+
* Query cursors have an optional maximum capacity for storing lists of
|
65
|
+
* in-progress captures. If this capacity is exceeded, then the
|
66
|
+
* earliest-starting match will silently be dropped to make room for further
|
67
|
+
* matches. This maximum capacity is optional — by default, query cursors allow
|
68
|
+
* any number of pending matches, dynamically allocating new space for them as
|
69
|
+
* needed as the query is executed.
|
70
|
+
*/
|
30
71
|
static VALUE query_cursor_did_exceed_match_limit(VALUE self) {
|
31
72
|
return ts_query_cursor_did_exceed_match_limit(SELF) ? Qtrue : Qfalse;
|
32
73
|
}
|
33
74
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
75
|
+
/**
|
76
|
+
* @param limit [Integer]
|
77
|
+
*
|
78
|
+
* @return [nil]
|
79
|
+
*/
|
38
80
|
static VALUE query_cursor_set_match_limit(VALUE self, VALUE limit) {
|
39
81
|
ts_query_cursor_set_match_limit(SELF, NUM2UINT(limit));
|
40
82
|
return Qnil;
|
41
83
|
}
|
42
84
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
static VALUE query_cursor_set_point_range(VALUE self, VALUE from, VALUE to) {
|
49
|
-
ts_query_cursor_set_point_range(SELF, value_to_point(from),
|
50
|
-
value_to_point(to));
|
51
|
-
return Qnil;
|
85
|
+
/**
|
86
|
+
* @return [Integer]
|
87
|
+
*/
|
88
|
+
static VALUE query_cursor_get_match_limit(VALUE self) {
|
89
|
+
return UINT2NUM(ts_query_cursor_match_limit(SELF));
|
52
90
|
}
|
53
91
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
92
|
+
/**
|
93
|
+
* Set the maximum start depth for a query cursor.
|
94
|
+
*
|
95
|
+
* This prevents cursors from exploring children nodes at a certain depth.
|
96
|
+
* Note if a pattern includes many children, then they will still be checked.
|
97
|
+
*
|
98
|
+
* The zero max start depth value can be used as a special behavior and
|
99
|
+
* it helps to destructure a subtree by staying on a node and using captures
|
100
|
+
* for interested parts. Note that the zero max start depth only limit a search
|
101
|
+
* depth for a pattern's root node but other nodes that are parts of the pattern
|
102
|
+
* may be searched at any depth what defined by the pattern structure.
|
103
|
+
*
|
104
|
+
* @param max_start_depth [Integer|nil] set to nil to remove the maximum start
|
105
|
+
* depth.
|
106
|
+
*
|
107
|
+
* @return [nil]
|
108
|
+
*/
|
109
|
+
static VALUE query_cursor_set_max_start_depth(VALUE self,
|
110
|
+
VALUE max_start_depth) {
|
111
|
+
uint32_t max = UINT32_MAX;
|
112
|
+
if (!NIL_P(max_start_depth)) {
|
113
|
+
max = NUM2UINT(max_start_depth);
|
60
114
|
}
|
61
|
-
|
62
|
-
|
63
|
-
static VALUE query_cursor_remove_match(VALUE self, VALUE id) {
|
64
|
-
ts_query_cursor_remove_match(SELF, NUM2UINT(id));
|
115
|
+
ts_query_cursor_set_max_start_depth(SELF, max);
|
65
116
|
return Qnil;
|
66
117
|
}
|
67
118
|
|
68
|
-
//
|
119
|
+
// FIXME: maybe this is the limit of how "transparent" the bindings need to be.
|
69
120
|
// Pending benchmarks, this can be very inefficient because obviously
|
70
121
|
// ts_query_cursor_next_capture is intended to be used in a loop. Creating an
|
71
122
|
// array of two values and returning them, intuitively speaking, seem very
|
72
123
|
// inefficient.
|
124
|
+
// FIXME: maybe this needs to return an empty array to make for a nicer ruby
|
125
|
+
// API?
|
126
|
+
/**
|
127
|
+
* Advance to the next capture of the currently running query.
|
128
|
+
*
|
129
|
+
* @return [Array<Integer|Boolean>|nil] If there is a capture, return a tuple
|
130
|
+
* [Integer, Boolean], otherwise return +nil+.
|
131
|
+
*/
|
73
132
|
static VALUE query_cursor_next_capture(VALUE self) {
|
74
133
|
TSQueryMatch match;
|
75
134
|
uint32_t index;
|
@@ -83,21 +142,74 @@ static VALUE query_cursor_next_capture(VALUE self) {
|
|
83
142
|
}
|
84
143
|
}
|
85
144
|
|
145
|
+
/**
|
146
|
+
* Advance to the next match of the currently running query.
|
147
|
+
*
|
148
|
+
* @return [Boolean] Whether there's a match.
|
149
|
+
*/
|
150
|
+
static VALUE query_cursor_next_match(VALUE self) {
|
151
|
+
TSQueryMatch match;
|
152
|
+
if (ts_query_cursor_next_match(SELF, &match)) {
|
153
|
+
return new_query_match(&match);
|
154
|
+
} else {
|
155
|
+
return Qnil;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE query_cursor_remove_match(VALUE self, VALUE id) {
|
160
|
+
ts_query_cursor_remove_match(SELF, NUM2UINT(id));
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* @param from [Integer]
|
166
|
+
* @param to [Integer]
|
167
|
+
*
|
168
|
+
* @return [nil]
|
169
|
+
*/
|
170
|
+
static VALUE query_cursor_set_byte_range(VALUE self, VALUE from, VALUE to) {
|
171
|
+
ts_query_cursor_set_byte_range(SELF, NUM2UINT(from), NUM2UINT(to));
|
172
|
+
return Qnil;
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* @param from [Point]
|
177
|
+
* @param to [Point]
|
178
|
+
*
|
179
|
+
* @return [nil]
|
180
|
+
*/
|
181
|
+
static VALUE query_cursor_set_point_range(VALUE self, VALUE from, VALUE to) {
|
182
|
+
ts_query_cursor_set_point_range(SELF, value_to_point(from),
|
183
|
+
value_to_point(to));
|
184
|
+
return Qnil;
|
185
|
+
}
|
186
|
+
|
86
187
|
void init_query_cursor(void) {
|
87
188
|
cQueryCursor = rb_define_class_under(mTreeSitter, "QueryCursor", rb_cObject);
|
88
189
|
|
89
190
|
rb_define_alloc_func(cQueryCursor, query_cursor_allocate);
|
90
191
|
|
192
|
+
/* Module methods */
|
193
|
+
rb_define_module_function(cQueryCursor, "exec", query_cursor_exec, 2);
|
194
|
+
|
91
195
|
/* Class methods */
|
196
|
+
// Accessors
|
92
197
|
DECLARE_ACCESSOR(cQueryCursor, query_cursor, match_limit)
|
93
|
-
|
198
|
+
|
199
|
+
// Other
|
94
200
|
rb_define_method(cQueryCursor, "exceed_match_limit?",
|
95
201
|
query_cursor_did_exceed_match_limit, 0);
|
202
|
+
rb_define_method(cQueryCursor, "match_limit", query_cursor_get_match_limit,
|
203
|
+
0);
|
204
|
+
rb_define_method(cQueryCursor, "match_limit=", query_cursor_set_match_limit,
|
205
|
+
1);
|
206
|
+
rb_define_method(cQueryCursor,
|
207
|
+
"max_start_depth=", query_cursor_set_max_start_depth, 1);
|
208
|
+
rb_define_method(cQueryCursor, "next_capture", query_cursor_next_capture, 0);
|
209
|
+
rb_define_method(cQueryCursor, "next_match", query_cursor_next_match, 0);
|
210
|
+
rb_define_method(cQueryCursor, "remove_match", query_cursor_remove_match, 1);
|
96
211
|
rb_define_method(cQueryCursor, "set_byte_range", query_cursor_set_byte_range,
|
97
212
|
2);
|
98
213
|
rb_define_method(cQueryCursor, "set_point_range",
|
99
214
|
query_cursor_set_point_range, 2);
|
100
|
-
rb_define_method(cQueryCursor, "next_match", query_cursor_next_match, 0);
|
101
|
-
rb_define_method(cQueryCursor, "remove_match", query_cursor_remove_match, 1);
|
102
|
-
rb_define_method(cQueryCursor, "next_capture", query_cursor_next_capture, 0);
|
103
215
|
}
|
@@ -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
|
data/ext/tree_sitter/tree.c
CHANGED
@@ -63,40 +63,115 @@ VALUE new_tree(TSTree *ptr) {
|
|
63
63
|
|
64
64
|
DATA_FROM_VALUE(TSTree *, tree)
|
65
65
|
|
66
|
-
|
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);
|
67
87
|
|
68
|
-
|
69
|
-
|
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;
|
70
97
|
}
|
71
98
|
|
72
|
-
static VALUE
|
73
|
-
|
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;
|
74
115
|
}
|
75
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
|
+
*/
|
76
138
|
static VALUE tree_edit(VALUE self, VALUE edit) {
|
77
139
|
TSInputEdit in = value_to_input_edit(edit);
|
78
140
|
ts_tree_edit(SELF, &in);
|
79
141
|
return Qnil;
|
80
142
|
}
|
81
143
|
|
82
|
-
|
83
|
-
|
84
|
-
|
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) {
|
85
150
|
uint32_t length;
|
86
|
-
TSRange *ranges =
|
151
|
+
const TSRange *ranges = ts_tree_included_ranges(SELF, &length);
|
87
152
|
VALUE res = rb_ary_new_capa(length);
|
88
|
-
|
89
153
|
for (uint32_t i = 0; i < length; i++) {
|
90
154
|
rb_ary_push(res, new_range(&ranges[i]));
|
91
155
|
}
|
92
|
-
|
93
|
-
if (ranges) {
|
94
|
-
free(ranges);
|
95
|
-
}
|
96
|
-
|
97
156
|
return res;
|
98
157
|
}
|
99
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
|
+
*/
|
100
175
|
static VALUE tree_print_dot_graph(VALUE self, VALUE file) {
|
101
176
|
Check_Type(file, T_STRING);
|
102
177
|
char *path = StringValueCStr(file);
|
@@ -112,22 +187,26 @@ static VALUE tree_print_dot_graph(VALUE self, VALUE file) {
|
|
112
187
|
return Qnil;
|
113
188
|
}
|
114
189
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
if (val > 0) {
|
124
|
-
ts_tree_delete((TSTree *)NUM2ULONG(curr));
|
125
|
-
}
|
126
|
-
|
127
|
-
rb_hash_delete(rc, curr);
|
128
|
-
}
|
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
|
+
}
|
129
198
|
|
130
|
-
|
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));
|
131
210
|
}
|
132
211
|
|
133
212
|
void init_tree(void) {
|
@@ -135,14 +214,19 @@ void init_tree(void) {
|
|
135
214
|
|
136
215
|
rb_undef_alloc_func(cTree);
|
137
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
|
+
|
138
221
|
/* Class methods */
|
139
222
|
rb_define_method(cTree, "copy", tree_copy, 0);
|
140
|
-
rb_define_method(cTree, "root_node", tree_root_node, 0);
|
141
|
-
rb_define_method(cTree, "language", tree_language, 0);
|
142
223
|
rb_define_method(cTree, "edit", tree_edit, 1);
|
143
|
-
|
224
|
+
rb_define_method(cTree, "included_ranges", included_ranges, 0);
|
225
|
+
rb_define_method(cTree, "language", tree_language, 0);
|
144
226
|
rb_define_method(cTree, "print_dot_graph", tree_print_dot_graph, 1);
|
145
|
-
|
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);
|
146
230
|
|
147
231
|
// Reference-count created trees
|
148
232
|
VALUE rc = rb_hash_new();
|