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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +152 -0
- data/ext/tree_sitter/encoding.c +29 -0
- data/ext/tree_sitter/extconf.rb +172 -0
- data/ext/tree_sitter/input.c +126 -0
- data/ext/tree_sitter/input_edit.c +42 -0
- data/ext/tree_sitter/language.c +134 -0
- data/ext/tree_sitter/logger.c +212 -0
- data/ext/tree_sitter/macros.h +163 -0
- data/ext/tree_sitter/node.c +310 -0
- data/ext/tree_sitter/parser.c +203 -0
- data/ext/tree_sitter/point.c +26 -0
- data/ext/tree_sitter/quantifier.c +43 -0
- data/ext/tree_sitter/query.c +157 -0
- data/ext/tree_sitter/query_capture.c +28 -0
- data/ext/tree_sitter/query_cursor.c +103 -0
- data/ext/tree_sitter/query_error.c +41 -0
- data/ext/tree_sitter/query_match.c +44 -0
- data/ext/tree_sitter/query_predicate_step.c +83 -0
- data/ext/tree_sitter/range.c +35 -0
- data/ext/tree_sitter/symbol_type.c +46 -0
- data/ext/tree_sitter/tree.c +145 -0
- data/ext/tree_sitter/tree_cursor.c +97 -0
- data/ext/tree_sitter/tree_sitter.c +32 -0
- data/ext/tree_sitter/tree_sitter.h +107 -0
- data/lib/tree_sitter/node.rb +164 -0
- data/lib/tree_sitter/tree_sitter.so +0 -0
- data/lib/tree_sitter/version.rb +5 -0
- data/lib/tree_sitter.rb +13 -0
- data/test/README.md +15 -0
- data/test/test_helper.rb +9 -0
- data/test/tree_sitter/language_test.rb +68 -0
- data/test/tree_sitter/logger_test.rb +69 -0
- data/test/tree_sitter/node_test.rb +355 -0
- data/test/tree_sitter/parser_test.rb +140 -0
- data/test/tree_sitter/query_test.rb +153 -0
- data/test/tree_sitter/tree_cursor_test.rb +83 -0
- data/test/tree_sitter/tree_test.rb +51 -0
- data/tree_sitter.gemspec +32 -0
- metadata +192 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TreeSitter
|
4
|
+
class Node
|
5
|
+
def fields
|
6
|
+
return @fields if @fields
|
7
|
+
|
8
|
+
@fields = Set.new
|
9
|
+
child_count.times do |i|
|
10
|
+
name = field_name_for_child(i)
|
11
|
+
@fields << name.to_sym if name
|
12
|
+
end
|
13
|
+
|
14
|
+
@fields
|
15
|
+
end
|
16
|
+
|
17
|
+
def field?(field)
|
18
|
+
fields.include?(field)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Access node's named children.
|
22
|
+
#
|
23
|
+
# It's similar to {#fetch}, but differes in input type, return values, and
|
24
|
+
# the internal implementation.
|
25
|
+
#
|
26
|
+
# Both of these methods exist for separate use cases, but also because
|
27
|
+
# sometime tree-sitter does some monkey business and having both separate
|
28
|
+
# implementations can help.
|
29
|
+
#
|
30
|
+
# Comparison with {#fetch}:
|
31
|
+
#
|
32
|
+
# [] | fetch
|
33
|
+
# ------------------------------+----------------------
|
34
|
+
# input types Integer, String, Symbol | Array<String, Symbol>
|
35
|
+
# Array<Integer, String, Symbol>|
|
36
|
+
# ------------------------------+----------------------
|
37
|
+
# returns 1-to-1 correspondance with | unique nodes
|
38
|
+
# input |
|
39
|
+
# ------------------------------+----------------------
|
40
|
+
# uses named_child | field_name_for_child
|
41
|
+
# child_by_field_name | via each_node
|
42
|
+
# ------------------------------+----------------------
|
43
|
+
#
|
44
|
+
# @param keys [Integer | String | Symbol | Array<Integer, String, Symbol>, #read]
|
45
|
+
#
|
46
|
+
# @return [Node | Array<Node>]
|
47
|
+
def [](*keys)
|
48
|
+
case keys.length
|
49
|
+
when 0 then raise "#{self.class.name}##{__method__} requires a key."
|
50
|
+
when 1
|
51
|
+
case k = keys.first
|
52
|
+
when Numeric then named_child(k)
|
53
|
+
when String, Symbol
|
54
|
+
if fields.include?(k.to_sym)
|
55
|
+
child_by_field_name(k.to_s)
|
56
|
+
else
|
57
|
+
raise "Cannot find field #{k}"
|
58
|
+
end
|
59
|
+
else raise <<~ERR
|
60
|
+
#{self.class.name}##{__method__} accepts Integer and returns named child at given index,
|
61
|
+
or a (String | Symbol) and returns the child by given field name.
|
62
|
+
ERR
|
63
|
+
end
|
64
|
+
else
|
65
|
+
keys.map { |key| self[key] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Allows access to child_by_field_name without using [].
|
70
|
+
def method_missing(method_name, *_args, &_block)
|
71
|
+
if fields.include?(method_name)
|
72
|
+
child_by_field_name(method_name.to_s)
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def respond_to_missing?(*args)
|
79
|
+
init_fields
|
80
|
+
args.length == 1 && fields.include?(args[0])
|
81
|
+
end
|
82
|
+
|
83
|
+
# Iterate over a node's children.
|
84
|
+
#
|
85
|
+
# @yieldparam child [Node] the child
|
86
|
+
def each
|
87
|
+
return enum_for __method__ if !block_given?
|
88
|
+
|
89
|
+
(0...(child_count)).each do |i|
|
90
|
+
yield child(i)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Iterate over a node's children assigned to a field.
|
95
|
+
#
|
96
|
+
# @yieldparam name [NilClass | String] field name.
|
97
|
+
# @yieldparam child [Node] the child.
|
98
|
+
def each_field
|
99
|
+
return enum_for __method__ if !block_given?
|
100
|
+
|
101
|
+
each.with_index do |c, i|
|
102
|
+
f = field_name_for_child(i)
|
103
|
+
next if f.nil? || f.empty?
|
104
|
+
|
105
|
+
yield f, c
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Iterate over a node's named children
|
110
|
+
#
|
111
|
+
# @yieldparam child [Node] the child
|
112
|
+
def each_named
|
113
|
+
return enum_for __method__ if !block_given?
|
114
|
+
|
115
|
+
(0...(named_child_count)).each do |i|
|
116
|
+
yield named_child(i)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_a
|
121
|
+
each.to_a
|
122
|
+
end
|
123
|
+
|
124
|
+
# Access node's named children.
|
125
|
+
#
|
126
|
+
# It's similar to {#fetch}, but differes in input type, return values, and
|
127
|
+
# the internal implementation.
|
128
|
+
#
|
129
|
+
# Both of these methods exist for separate use cases, but also because
|
130
|
+
# sometime tree-sitter does some monkey business and having both separate
|
131
|
+
# implementations can help.
|
132
|
+
#
|
133
|
+
# Comparison with {#fetch}:
|
134
|
+
#
|
135
|
+
# [] | fetch
|
136
|
+
# ------------------------------+----------------------
|
137
|
+
# input types Integer, String, Symbol | String, Symbol
|
138
|
+
# Array<Integer, String, Symbol>| Array<String, Symbol>
|
139
|
+
# ------------------------------+----------------------
|
140
|
+
# returns 1-to-1 correspondance with | unique nodes
|
141
|
+
# input |
|
142
|
+
# ------------------------------+----------------------
|
143
|
+
# uses named_child | field_name_for_child
|
144
|
+
# child_by_field_name | via each_node
|
145
|
+
# ------------------------------+----------------------
|
146
|
+
def fetch(*keys)
|
147
|
+
dict = {}
|
148
|
+
keys.each.with_index do |k, i|
|
149
|
+
dict[k.to_s] = i
|
150
|
+
end
|
151
|
+
|
152
|
+
res = {}
|
153
|
+
each_field do |f, c|
|
154
|
+
if dict.key?(f)
|
155
|
+
res[dict[f]] = c
|
156
|
+
dict.delete(f)
|
157
|
+
end
|
158
|
+
break if dict.empty?
|
159
|
+
end
|
160
|
+
|
161
|
+
res.sort.map { |_, v| v }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
Binary file
|
data/lib/tree_sitter.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TreeSitter
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
require 'tree_sitter/version'
|
9
|
+
|
10
|
+
require 'tree_sitter/tree_sitter'
|
11
|
+
require 'tree_sitter/node'
|
12
|
+
|
13
|
+
ObjectSpace.define_finalizer(TreeSitter::Tree.class, proc { TreeSitter::Tree.finalizer })
|
data/test/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Unit testing
|
2
|
+
|
3
|
+
Since we don't have languages bundled in ruby gems, we have to load the dynamic
|
4
|
+
libraries from disk.
|
5
|
+
|
6
|
+
We're using the `bin/get` scripts to do so.
|
7
|
+
|
8
|
+
Since not all languages have a Makefile in their root dir, and we don't want to
|
9
|
+
mess with copying Makefiles, we're going to rely on languages that do have a
|
10
|
+
Makefile in their root.
|
11
|
+
|
12
|
+
So for the time being we're sticking with `ruby`.
|
13
|
+
|
14
|
+
We might need to change this strategy in the future if we're to test some
|
15
|
+
multilang parsing.
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,68 @@
|
|
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
|
+
# NOTE: one should be weary of testing with data structures that are owned by
|
21
|
+
# parsers. They are not reliable and we should expect them to break when these
|
22
|
+
# parsers evolve.
|
23
|
+
|
24
|
+
describe 'language' do
|
25
|
+
it 'must be able to load a library from `Pathname` (or any object that has `to_s`)' do
|
26
|
+
path =
|
27
|
+
if p = ENV.fetch('TREE_SITTER_PARSERS', nil)
|
28
|
+
Pathname(p) / "libtree-sitter-ruby.#{TreeSitter.ext}"
|
29
|
+
else
|
30
|
+
Pathname('tree-sitter-parsers') / 'ruby' / "libtree-sitter-ruby.#{TreeSitter.ext}"
|
31
|
+
end
|
32
|
+
ll = TreeSitter::Language.load('ruby', path)
|
33
|
+
assert ll.field_count.positive?
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'must return symbol count' do
|
37
|
+
assert ruby.symbol_count.positive?
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'must return symbol name' do
|
41
|
+
assert_equal 'end', ruby.symbol_name(0)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'must return symbol id for string name' do
|
45
|
+
assert ruby.symbol_for_name(root.type, root.named?).positive?
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'must return field count' do
|
49
|
+
assert ruby.field_count.positive?
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'must return field name for id' do
|
53
|
+
assert_equal 'alias', ruby.field_name_for_id(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'must return field name for id' do
|
57
|
+
assert_equal 1, ruby.field_id_for_name('alias')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'must return field symbol type' do
|
61
|
+
assert_equal TreeSitter::SymbolType::AUXILIARY, ruby.symbol_type(0)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'must be of correct version' do
|
65
|
+
assert ruby.version <= TreeSitter::LANGUAGE_VERSION \
|
66
|
+
&& ruby.version >= TreeSitter::MIN_COMPATIBLE_LANGUAGE_VERSION
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../test_helper'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
ruby = TreeSitter.lang('ruby')
|
7
|
+
parser = TreeSitter::Parser.new
|
8
|
+
parser.language = ruby
|
9
|
+
|
10
|
+
program = <<~RUBY
|
11
|
+
def mul(a, b)
|
12
|
+
res = a * b
|
13
|
+
puts res.inspect
|
14
|
+
return res
|
15
|
+
end
|
16
|
+
RUBY
|
17
|
+
|
18
|
+
# Use with fork.
|
19
|
+
#
|
20
|
+
# Minitest on ruby 2.7 was failing sometimes for no particular reason,
|
21
|
+
# complaining about some random number not having a `write` method.
|
22
|
+
#
|
23
|
+
# My assumption is that the global var $stderr is not playing nice when
|
24
|
+
# we try to replace it and other minitest stuff are going alongside.
|
25
|
+
#
|
26
|
+
# If this theory holds, then forking should solve any race conditions that
|
27
|
+
# minitest could introduce. Let's wait and see.
|
28
|
+
def capture_stderr
|
29
|
+
# The output stream must be an IO-like object. In this case we capture it in
|
30
|
+
# an in-memory IO object so we can return the string value. You can assign any
|
31
|
+
# IO object here.
|
32
|
+
previous_stderr = $stderr
|
33
|
+
$stderr = StringIO.new
|
34
|
+
yield
|
35
|
+
$stderr.string
|
36
|
+
ensure
|
37
|
+
# Restore the previous value of stderr (typically equal to STDERR).
|
38
|
+
$stderr = previous_stderr
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'logging' do
|
42
|
+
it 'should log to stderr by default' do
|
43
|
+
fork do
|
44
|
+
captured_output = capture_stderr do
|
45
|
+
# Does not output anything directly.
|
46
|
+
parser.logger = TreeSitter::Logger.new
|
47
|
+
parser.parse_string(nil, program)
|
48
|
+
end
|
49
|
+
refute_equal 0, captured_output.length
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should log to IO objects' do
|
54
|
+
backend = StringIO.new
|
55
|
+
parser.logger = TreeSitter::Logger.new(backend)
|
56
|
+
parser.parse_string(nil, program)
|
57
|
+
refute_equal 0, backend.length
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should format output when a format string is passed' do
|
61
|
+
delim = '~~~~~'
|
62
|
+
backend = StringIO.new
|
63
|
+
parser.logger = TreeSitter::Logger.new(backend, "%s#{delim}%s")
|
64
|
+
parser.parse_string(nil, program)
|
65
|
+
backend.each_line do |l|
|
66
|
+
assert (/#{delim}/ =~ l), 'delimiter must be in every single line'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,355 @@
|
|
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
|
+
end
|