ruby_tree_sitter 0.20.8.3-x86_64-linux → 1.1.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -1
  3. data/README.md +32 -18
  4. data/ext/tree_sitter/extconf.rb +1 -1
  5. data/ext/tree_sitter/input.c +1 -0
  6. data/ext/tree_sitter/language.c +131 -46
  7. data/ext/tree_sitter/logger.c +28 -12
  8. data/ext/tree_sitter/node.c +438 -130
  9. data/ext/tree_sitter/parser.c +232 -37
  10. data/ext/tree_sitter/query.c +197 -72
  11. data/ext/tree_sitter/query_cursor.c +140 -28
  12. data/ext/tree_sitter/repo.rb +1 -1
  13. data/ext/tree_sitter/tree.c +118 -34
  14. data/ext/tree_sitter/tree_cursor.c +205 -33
  15. data/ext/tree_sitter/tree_sitter.c +12 -0
  16. data/lib/tree_sitter/node.rb +23 -6
  17. data/lib/tree_sitter/tree_sitter.so +0 -0
  18. data/lib/tree_sitter/version.rb +4 -2
  19. data/lib/tree_sitter.rb +1 -0
  20. data/lib/tree_stand/ast_modifier.rb +30 -0
  21. data/lib/tree_stand/breadth_first_visitor.rb +54 -0
  22. data/lib/tree_stand/config.rb +13 -0
  23. data/lib/tree_stand/node.rb +224 -0
  24. data/lib/tree_stand/parser.rb +67 -0
  25. data/lib/tree_stand/range.rb +55 -0
  26. data/lib/tree_stand/tree.rb +123 -0
  27. data/lib/tree_stand/utils/printer.rb +73 -0
  28. data/lib/tree_stand/version.rb +7 -0
  29. data/lib/tree_stand/visitor.rb +127 -0
  30. data/lib/tree_stand/visitors/tree_walker.rb +37 -0
  31. data/lib/tree_stand.rb +48 -0
  32. data/tree_sitter.gemspec +14 -11
  33. metadata +36 -107
  34. data/test/README.md +0 -15
  35. data/test/test_helper.rb +0 -9
  36. data/test/tree_sitter/js_test.rb +0 -48
  37. data/test/tree_sitter/language_test.rb +0 -73
  38. data/test/tree_sitter/logger_test.rb +0 -70
  39. data/test/tree_sitter/node_test.rb +0 -411
  40. data/test/tree_sitter/parser_test.rb +0 -140
  41. data/test/tree_sitter/query_test.rb +0 -153
  42. data/test/tree_sitter/tree_cursor_test.rb +0 -83
  43. data/test/tree_sitter/tree_test.rb +0 -51
@@ -1,411 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
-
5
- ruby = TreeSitter.lang('ruby')
6
- parser = TreeSitter::Parser.new
7
- parser.language = ruby
8
-
9
- program = <<~RUBY
10
- def mul(a, b)
11
- res = a * b
12
- puts res.inspect
13
- return res
14
- end
15
- RUBY
16
-
17
- tree = parser.parse_string(nil, program)
18
- root = tree.root_node
19
-
20
- describe 'type' do
21
- it 'must be a Symbol' do
22
- assert_instance_of Symbol, root.type
23
- end
24
-
25
- it 'must be "program" on root' do
26
- assert_equal :program, root.type
27
- end
28
- end
29
-
30
- describe 'symbol' do
31
- it 'must be an Integer' do
32
- assert_instance_of Integer, root.symbol
33
- end
34
- end
35
-
36
- describe 'start_byte' do
37
- it 'must be an Integer' do
38
- assert_instance_of Integer, root.start_byte
39
- end
40
-
41
- it 'must be an 0' do
42
- assert_equal 0, root.start_byte
43
- end
44
- end
45
-
46
- describe 'end_byte' do
47
- it 'must be an Integer' do
48
- assert_instance_of Integer, root.end_byte
49
- end
50
-
51
- it 'must not be 0' do
52
- refute_equal 0, root.end_byte
53
- end
54
- end
55
-
56
- describe 'start_point' do
57
- it 'must be an instance of point' do
58
- assert_instance_of TreeSitter::Point, root.start_point
59
- end
60
-
61
- it 'must be at row 0' do
62
- assert_equal 0, root.start_point.row
63
- end
64
-
65
- it 'must be at column 0' do
66
- assert_equal 0, root.start_point.row
67
- end
68
- end
69
-
70
- describe 'end_point' do
71
- it 'must be an instance of point' do
72
- assert_instance_of TreeSitter::Point, root.end_point
73
- end
74
-
75
- it 'must not be at row 0' do
76
- refute_equal 0, root.end_point.row
77
- end
78
-
79
- it 'must not be at column 0' do
80
- refute_equal 0, root.end_point.row
81
- end
82
- end
83
-
84
- describe 'string' do
85
- it 'must be an instance of string' do
86
- assert_instance_of String, root.to_s
87
- end
88
-
89
- it 'must be non-empty' do
90
- refute root.to_s.empty?
91
- end
92
- end
93
-
94
- describe 'predicates' do
95
- it 'must not be null' do
96
- refute_nil root.null?
97
- end
98
-
99
- it 'must be named' do
100
- assert root.named?
101
- end
102
-
103
- it 'must not be missing' do
104
- refute root.missing?
105
- end
106
-
107
- it 'must not be extra' do
108
- refute root.extra?
109
- end
110
-
111
- it 'must not have any changes' do
112
- # TODO: needs a more elaborate test to check for true changes?
113
- refute root.changed?
114
- end
115
-
116
- it 'must not have no errors' do
117
- refute root.error?
118
- end
119
- end
120
-
121
- describe 'parent' do
122
- # NOTE: never call parent on root. It will segfault.
123
- #
124
- # tree-sitter does not provide a way to check if a node has a parent.
125
-
126
- it 'must never be nil' do
127
- refute_nil root.child(0).parent
128
- end
129
-
130
- it 'must be root for its children' do
131
- assert_equal root, root.child(0).parent
132
- end
133
- end
134
-
135
- describe 'child' do
136
- before do
137
- @child = root.child(0)
138
- end
139
-
140
- it 'must return proper children count' do
141
- assert_equal 1, root.child_count
142
- end
143
-
144
- it 'must return proper name child count' do
145
- assert_equal 5, @child.named_child_count
146
- end
147
-
148
- it 'must return proper name child' do
149
- assert_equal @child.child(1), @child.named_child(0)
150
- end
151
-
152
- it 'must return proper child by field name' do
153
- assert_equal @child.child(1), @child.child_by_field_name('name')
154
- end
155
-
156
- it 'must return proper child by field id' do
157
- assert_equal @child.child(1), @child.child_by_field_id(ruby.field_id_for_name('name'))
158
- end
159
-
160
- it 'must return proper child for byte' do
161
- child = @child.child(0)
162
- assert_equal child, @child.first_child_for_byte(child.start_byte)
163
- end
164
-
165
- it 'must return proper named child for byte' do
166
- child = @child.child(1)
167
- assert_equal child, @child.first_named_child_for_byte(child.start_byte)
168
- end
169
-
170
- it 'must return proper descendant for byte range' do
171
- child = @child.child(1)
172
- assert_equal child, @child.descendant_for_byte_range(child.start_byte, child.end_byte)
173
- end
174
-
175
- it 'must return proper descendant for point range' do
176
- child = @child.child(1)
177
- assert_equal child, @child.descendant_for_point_range(child.start_point, child.end_point)
178
- end
179
-
180
- it 'must return proper named descendant for byte range' do
181
- child = @child.child(1)
182
- assert_equal child, @child.named_descendant_for_byte_range(child.start_byte, child.end_byte)
183
- end
184
-
185
- it 'must return proper named descendant for point range' do
186
- child = @child.child(1)
187
- assert_equal child, @child.named_descendant_for_point_range(child.start_point, child.end_point)
188
- end
189
-
190
- it 'must raise an exception for wrong ranges' do
191
- child = @child.child(0)
192
- assert_raises IndexError do
193
- @child.descendant_for_byte_range(child.end_byte, child.start_byte)
194
- end
195
- assert_raises IndexError do
196
- @child.named_descendant_for_byte_range(child.end_byte, child.start_byte)
197
- end
198
- assert_raises IndexError do
199
- p1 = TreeSitter::Point.new
200
- p1.row = @child.end_point.row
201
- p1.column = @child.end_point.column + 1
202
- @child.named_descendant_for_point_range(@child.start_point, p1)
203
- end
204
- assert_raises IndexError do
205
- p1 = TreeSitter::Point.new
206
- p1.row = @child.end_point.row
207
- p1.column = @child.end_point.column + 1
208
- @child.named_descendant_for_point_range(@child.start_point, p1)
209
- end
210
- end
211
- end
212
-
213
- describe 'field_name' do
214
- before do
215
- @child = root.child(0)
216
- end
217
-
218
- it 'must return proper field name' do
219
- assert_equal 'name', @child.field_name_for_child(1)
220
- end
221
- end
222
-
223
- describe 'siblings' do
224
- before do
225
- @child = root.child(0).child(0)
226
- end
227
-
228
- it 'must return proper next/previous siblings' do
229
- assert_equal @child, @child.next_sibling.prev_sibling
230
- end
231
-
232
- it 'must return proper next/previous named siblings' do
233
- assert_equal @child.parent.child(1), @child.next_named_sibling
234
- end
235
- end
236
-
237
- # TODO: edit
238
-
239
- # Tese are High-Level Ruby APIs that we designed.
240
- # They rely on the bindings.
241
-
242
- describe '[]' do
243
- before do
244
- @child = root.child(0)
245
- end
246
-
247
- it 'must return a named child by index when index is an Integer' do
248
- assert_equal @child.named_child(0), @child[0]
249
- end
250
-
251
- it 'must return a child by field name when index is a (String | Symbol)' do
252
- assert_equal @child.named_child(0), @child[:name]
253
- assert_equal @child.named_child(0), @child['name']
254
- end
255
-
256
- it 'must return an array of nodes when index is an Array' do
257
- arr = [@child.named_child(0)] * 3
258
- assert_equal arr, @child[0, :name, 'name']
259
- end
260
-
261
- it 'must throw an exception when out of index' do
262
- assert_raises { @child[255] }
263
- end
264
-
265
- it 'must throw an exception when field is not found (NO SIGSEGV ANYMORE!)' do
266
- assert_raises { @child[:randomzes] }
267
- end
268
- end
269
-
270
- describe 'each' do
271
- before do
272
- @child = root.child(0)
273
- end
274
-
275
- it 'must iterate over all children' do
276
- i = 0
277
- @child.each do |_|
278
- i += 1
279
- end
280
- assert @child.child_count, i
281
- end
282
-
283
- it 'must iterate ove named children attached to fields only' do
284
- @child.each_field do |f, c|
285
- refute f.nil?
286
- refute f.empty?
287
- assert_equal @child[f], c
288
- end
289
- end
290
-
291
- it 'must iterate over named children when `each_named_child`' do
292
- i = 0
293
- @child.each_named do |c|
294
- assert c.named?
295
- i += 1
296
- end
297
- assert @child.named_child_count, i
298
- end
299
- end
300
-
301
- describe 'method_missing' do
302
- before do
303
- @child = root.child(0)
304
- end
305
-
306
- it 'should act like the [] method when we pass (String | Symbol)' do
307
- assert_equal @child[:name], @child.name
308
- end
309
- end
310
-
311
- describe 'to_a' do
312
- before do
313
- @child = root.child(0)
314
- end
315
-
316
- it 'should return the list from each' do
317
- ll = @child.to_a
318
-
319
- refute ll.empty?
320
-
321
- @child.each.with_index do |c, i|
322
- assert_equal @child.child(i), c
323
- end
324
- end
325
- end
326
-
327
- describe 'fetch' do
328
- before do
329
- @child = root.child(0).child(4)
330
- end
331
-
332
- it 'should return all requested keys by order' do
333
- method = @child.child(0)
334
- arguments = @child.child(1)
335
-
336
- m, a = @child.fetch(:method, :arguments)
337
-
338
- assert_equal method, m
339
- assert_equal arguments, a
340
-
341
- a, m = @child.fetch(:arguments, :method)
342
-
343
- assert_equal method, m
344
- assert_equal arguments, a
345
- end
346
-
347
- it 'should return unique keys' do
348
- method = @child.child(0)
349
-
350
- m = @child.fetch(:method, :method)
351
-
352
- assert_equal 1, m.length
353
- assert_equal method, m.first
354
- end
355
-
356
- it 'should return an empty array when asked for non-existent fields' do
357
- b = @child.fetch(:a)
358
- assert_empty b
359
-
360
- b = @child.fetch(:b, :focus)
361
- assert_empty b
362
- end
363
-
364
- it 'should return an array of `nil` values when asked for non-existent fields with `all: true`' do
365
- b = @child.fetch(:d, all: true)
366
- refute_empty b
367
- assert b.all?(&:nil?)
368
-
369
- b = @child.fetch(:e, :f, all: true)
370
- refute_empty b
371
- assert b.all?(&:nil?)
372
- end
373
-
374
- it 'should return values, even if `nil`, for all keys when `all: true`' do
375
- method = @child.child(0)
376
- arguments = @child.child(1)
377
-
378
- m, a, f = @child.fetch(:method, :arguments, :fake, all: true)
379
-
380
- assert_equal method, m
381
- assert_equal arguments, a
382
- assert_nil f
383
- end
384
- end
385
-
386
- describe 'fetch_all' do
387
- before do
388
- @child = root.child(0).child(4)
389
- end
390
-
391
- it 'should return an array of `nil` values when asked for non-existent fields' do
392
- b = @child.fetch_all(:d)
393
- refute_empty b
394
- assert b.all?(&:nil?)
395
-
396
- b = @child.fetch_all(:e, :f)
397
- refute_empty b
398
- assert b.all?(&:nil?)
399
- end
400
-
401
- it 'should return values, even if `nil`, for all keys' do
402
- method = @child.child(0)
403
- arguments = @child.child(1)
404
-
405
- m, a, f = @child.fetch_all(:method, :arguments, :fake)
406
-
407
- assert_equal method, m
408
- assert_equal arguments, a
409
- assert_nil f
410
- end
411
- end
@@ -1,140 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
-
5
- ruby = TreeSitter.lang('ruby')
6
- parser = TreeSitter::Parser.new
7
- parser.language = ruby
8
-
9
- program = <<~RUBY
10
- def mul(a, b)
11
- res = a * b
12
- puts res.inspect
13
- return res
14
- end
15
- RUBY
16
-
17
- # NOTE: I was trying to parse invalid programs and see what happens.
18
- #
19
- # What happens = undefined behavior with the ruby parsers.
20
- #
21
- # Sometimes it would parse normally and return an instance of Tree, and
22
- # sometimes it would return nil. That goes for both `parse_string` and
23
- # `parse_string_encoded`.
24
- #
25
- # I suspect the same thing would happen with `parse`
26
-
27
- # margorp = <<~YBUR
28
- # fibfast n = fib' 0 1 n
29
- # where fib' a b n | n <= 1 = b
30
- # | otherwise = fib' b (a+b) (n-1)
31
- # YBUR
32
-
33
- program16 = program.encode('utf-16')
34
- # margorp_16 = margorp.encode('utf-16')
35
-
36
- describe 'loading a language' do
37
- before do
38
- parser.reset
39
- end
40
-
41
- it 'must set/get the same language' do
42
- parser.language = ruby
43
- assert_equal ruby, parser.language
44
- end
45
- end
46
-
47
- describe 'parse_string' do
48
- before do
49
- parser.reset
50
- end
51
-
52
- it 'must parse nil' do
53
- res = parser.parse_string(nil, nil)
54
- assert_nil res
55
- end
56
-
57
- [
58
- ['empty', '', 0],
59
- ['valid', program, 1],
60
- # ['invalid', margorp, 3]
61
- ].each do |q, p, c|
62
- it "must parse #{q} programs" do
63
- res = parser.parse_string(nil, p)
64
- assert_instance_of TreeSitter::Tree, res
65
-
66
- root = res.root_node
67
- assert_instance_of TreeSitter::Node, root
68
- assert_equal c, root.child_count
69
- end
70
- end
71
- end
72
-
73
- describe 'parse_string_encoding' do
74
- before do
75
- parser.reset
76
- end
77
-
78
- it 'must parse nil' do
79
- res = parser.parse_string_encoding(nil, nil, :utf8)
80
- assert_nil res
81
- res = parser.parse_string_encoding(nil, nil, :utf16)
82
- assert_nil res
83
- end
84
-
85
- [
86
- ['empty', '', 0, :utf8],
87
- ['valid', program, 1, :utf8],
88
- # ['invalid', margorp, 3, :utf8],
89
- ['empty', ''.encode('utf-16'), 0, :utf16],
90
- ['valid', program16, 1, :utf16],
91
- # ['invalid', margorp_16, 1, :utf16]
92
- ].each do |q, p, c, e|
93
- it "must parse #{q} programs in #{e}" do
94
- res = parser.parse_string_encoding(nil, p, e)
95
- assert_instance_of TreeSitter::Tree, res
96
-
97
- root = res.root_node
98
- assert_instance_of TreeSitter::Node, root
99
- assert_equal c, root.child_count
100
- end
101
- end
102
- end
103
-
104
- describe 'print_dot_graphs' do
105
- before do
106
- parser.reset
107
- end
108
-
109
- it 'must save its debug info to a file' do
110
- dot = File.expand_path('tmp/debug-dot.gv', FileUtils.getwd)
111
- parser.print_dot_graphs(dot)
112
- parser.parse_string(nil, program)
113
-
114
- assert File.exist?(dot), 'dot file must be exist'
115
- assert File.file?(dot), 'dot file must be a file'
116
- refute_equal 0, File.size(dot)
117
- end
118
- end
119
-
120
- describe 'canecalation_flags' do
121
- it 'must get/set cancellation_flah' do
122
- parser.cancellation_flag = 1
123
- assert_equal 1, parser.cancellation_flag
124
- end
125
- end
126
-
127
- describe 'timeout_micros' do
128
- it 'must get/set timeout_micros' do
129
- parser.timeout_micros = 1
130
- assert_equal 1, parser.timeout_micros
131
- end
132
- end
133
-
134
- # TODO: included_ranges for parsing partial documents.
135
-
136
- # TODO: parsing with non-nil tree.
137
-
138
- # TODO: parsing Input streams. We're currently just hading the callback from
139
- # C-space to Ruby-space At some point we might need to implement a
140
- # buffered input reader and we should test it here.
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
-
5
- ruby = TreeSitter.lang('ruby')
6
- parser = TreeSitter::Parser.new
7
- parser.language = ruby
8
-
9
- program = <<~RUBY
10
- def mul(a, b)
11
- res = a * b
12
- puts res.inspect
13
- return res
14
- end
15
- RUBY
16
-
17
- tree = parser.parse_string(nil, program)
18
- root = tree.root_node
19
-
20
- pattern = '(method_parameters)'
21
- capture = '(method_parameters (_)+ @args)'
22
- predicate = '(method_parameters (_)+ @args (#match? @args "\w"))'
23
- combined = "#{pattern} #{capture}"
24
- # string = '(method_parameters (_)+ @args)'
25
-
26
- # NOTE: It' still unclear to me what a captured string is.
27
-
28
- describe 'pattern/capture/string' do
29
- it 'must return an Integer for pattern count' do
30
- query = TreeSitter::Query.new(ruby, pattern)
31
- assert_equal 1, query.pattern_count
32
- assert_equal 0, query.capture_count
33
- assert_equal 0, query.string_count
34
- end
35
-
36
- it 'must return an Integer for pattern count' do
37
- query = TreeSitter::Query.new(ruby, capture)
38
- assert_equal 1, query.pattern_count
39
- assert_equal 1, query.capture_count
40
- assert_equal 0, query.string_count
41
- end
42
-
43
- it 'must return an Integer for combined patterns' do
44
- query = TreeSitter::Query.new(ruby, combined)
45
- assert_equal 2, query.pattern_count
46
- assert_equal 1, query.capture_count
47
- assert_equal 0, query.string_count
48
- end
49
-
50
- it 'must return an Integer for pattern start byte' do
51
- query = TreeSitter::Query.new(ruby, combined)
52
- assert_equal 0, query.start_byte_for_pattern(0)
53
- assert_equal pattern.bytesize + 1, query.start_byte_for_pattern(1)
54
- end
55
-
56
- it 'must return an array of predicates for a pattern' do
57
- query = TreeSitter::Query.new(ruby, combined)
58
-
59
- preds0 = query.predicates_for_pattern(0)
60
- assert_instance_of Array, preds0
61
- assert_equal 0, preds0.size
62
-
63
- preds1 = query.predicates_for_pattern(1)
64
- assert_instance_of Array, preds1
65
- assert_equal 0, preds1.size
66
-
67
- query = TreeSitter::Query.new(ruby, predicate)
68
- preds2 = query.predicates_for_pattern(0)
69
- assert_instance_of Array, preds2
70
- assert_equal 4, preds2.size
71
- end
72
-
73
- it 'must return string names, quanitfier, and string value for capture id' do
74
- query = TreeSitter::Query.new(ruby, predicate)
75
- query.predicates_for_pattern(0).each do |step|
76
- next if step.type != TreeSitter::QueryPredicateStep::CAPTURE
77
-
78
- assert_equal 'args', query.capture_name_for_id(step.value_id)
79
- assert_equal TreeSitter::Quantifier::ONE_OR_MORE, query.capture_quantifier_for_id(0, step.value_id)
80
- assert_equal 'match?', query.string_value_for_id(step.value_id)
81
- end
82
- end
83
-
84
- it 'must disable captures but keep it in count' do
85
- query = TreeSitter::Query.new(ruby, capture)
86
- query.disable_capture('@args')
87
- assert_equal 1, query.capture_count
88
- end
89
-
90
- it 'must disable captures but keep it in count' do
91
- query = TreeSitter::Query.new(ruby, capture)
92
- query.disable_pattern(0)
93
- assert_equal 1, query.pattern_count
94
- end
95
- # TODO: pattern guaranteed at step
96
- end
97
-
98
- describe 'query_cursor' do
99
- before do
100
- @query = TreeSitter::Query.new(ruby, capture)
101
- @cursor = TreeSitter::QueryCursor.exec(@query, root)
102
- end
103
-
104
- it 'must work with limits' do
105
- @cursor.match_limit = 1
106
- assert_equal 1, @cursor.match_limit
107
- refute @cursor.exceed_match_limit?
108
- refute_nil @cursor.next_capture
109
- assert @cursor.exceed_match_limit?
110
- end
111
-
112
- it 'must work with byte range' do
113
- child = root.child(0).child(0)
114
- @cursor.set_byte_range(child.start_byte, child.end_byte)
115
- assert_nil @cursor.next_capture
116
- end
117
-
118
- it 'must work with point range' do
119
- child = root.child(0).child(0)
120
- @cursor.set_point_range(child.start_point, child.end_point)
121
- assert_nil @cursor.next_capture
122
- end
123
-
124
- it 'must work with next/remove' do
125
- assert_equal 0, @cursor.next_match.id
126
- @cursor.remove_match(1)
127
- assert_nil @cursor.next_match
128
- end
129
- end
130
-
131
- describe 'querying anonymous nodes' do
132
- it 'must match & capture the correct nodes' do
133
- binary = '(binary left: (identifier) operator: "*" right: (identifier)) @binary'
134
- prog = <<~RUBY
135
- c + d
136
- a * b
137
- e / f
138
- RUBY
139
- prog_tree = parser.parse_string(nil, prog)
140
- prog_root = prog_tree.root_node
141
- query = TreeSitter::Query.new(ruby, binary)
142
- cursor = TreeSitter::QueryCursor.exec(query, prog_root)
143
-
144
- while match = cursor.next_match
145
- refute_nil(match)
146
- assert_equal(1, match.captures.size)
147
-
148
- node = match.captures.first.node
149
- assert_equal 'a * b', prog[node.start_byte...node.end_byte]
150
- end
151
- assert_nil(match)
152
- end
153
- end