Class: TreeSitter::Node
- Inherits:
-
Object
- Object
- TreeSitter::Node
- Defined in:
- lib/tree_sitter/node.rb,
ext/tree_sitter/node.c
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#[](*keys) ⇒ Node | Array<Node>
Access node’s named children.
- #changed? ⇒ Boolean
- #child(idx) ⇒ Object
- #child_by_field_id(field_id) ⇒ Object
- #child_by_field_name(field_name) ⇒ Object
- #child_count ⇒ Object
- #descendant_for_byte_range(from, to) ⇒ Object
- #descendant_for_point_range(from, to) ⇒ Object
-
#each {|child| ... } ⇒ Object
Iterate over a node’s children.
-
#each_field {|name, child| ... } ⇒ Object
Iterate over a node’s children assigned to a field.
-
#each_named {|child| ... } ⇒ Object
Iterate over a node’s named children.
- #edit(input_edit) ⇒ Object
- #end_byte ⇒ Object
- #end_point ⇒ Object
- #eq?(other) ⇒ Boolean
- #error? ⇒ Boolean
- #extra? ⇒ Boolean
-
#fetch(*keys) ⇒ Object
Access node’s named children.
- #field?(field) ⇒ Boolean
- #field_name_for_child(idx) ⇒ Object
- #fields ⇒ Object
- #first_child_for_byte(byte) ⇒ Object
- #first_named_child_for_byte(byte) ⇒ Object
- #inspect ⇒ Object
-
#method_missing(method_name, *_args, &_block) ⇒ Object
Allows access to child_by_field_name without using [].
- #missing? ⇒ Boolean
- #named? ⇒ Boolean
- #named_child(idx) ⇒ Object
- #named_child_count ⇒ Object
- #named_descendant_for_byte_range(from, to) ⇒ Object
- #named_descendant_for_point_range(from, to) ⇒ Object
- #next_named_sibling ⇒ Object
- #next_sibling ⇒ Object
- #null? ⇒ Boolean
- #parent ⇒ Object
- #prev_named_sibling ⇒ Object
- #prev_sibling ⇒ Object
- #respond_to_missing?(*args) ⇒ Boolean
- #start_byte ⇒ Object
- #start_point ⇒ Object
- #symbol ⇒ Object
- #to_a ⇒ Object
- #to_s ⇒ Object
- #to_str ⇒ Object
-
#type ⇒ Object
Class methods.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *_args, &_block) ⇒ Object
Allows access to child_by_field_name without using [].
70 71 72 73 74 75 76 |
# File 'lib/tree_sitter/node.rb', line 70 def method_missing(method_name, *_args, &_block) if fields.include?(method_name) child_by_field_name(method_name.to_s) else super end end |
Instance Method Details
#==(other) ⇒ Object
259 260 261 |
# File 'ext/tree_sitter/node.c', line 259
static VALUE node_eq(VALUE self, VALUE other) {
return ts_node_eq(SELF, unwrap(other)->data) ? Qtrue : Qfalse;
}
|
#[](*keys) ⇒ Node | Array<Node>
Access node’s named children.
It’s similar to #fetch, but differes in input type, return values, and the internal implementation.
Both of these methods exist for separate use cases, but also because sometime tree-sitter does some monkey business and having both separate implementations can help.
Comparison with #fetch:
[] | fetch
------------------------------+----------------------
input types Integer, String, Symbol | Array<String, Symbol>
Array<Integer, String, Symbol>|
------------------------------+----------------------
returns 1-to-1 correspondance with | unique nodes
input |
------------------------------+----------------------
uses named_child | field_name_for_child
child_by_field_name | via each_node
------------------------------+----------------------
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/tree_sitter/node.rb', line 47 def [](*keys) case keys.length when 0 then raise "#{self.class.name}##{__method__} requires a key." when 1 case k = keys.first when Numeric then named_child(k) when String, Symbol if fields.include?(k.to_sym) child_by_field_name(k.to_s) else raise "Cannot find field #{k}" end else raise <<~ERR #{self.class.name}##{__method__} accepts Integer and returns named child at given index, or a (String | Symbol) and returns the child by given field name. ERR end else keys.map { |key| self[key] } end end |
#changed? ⇒ Boolean
86 87 88 |
# File 'ext/tree_sitter/node.c', line 86 static VALUE node_has_changes(VALUE self) { return ts_node_has_changes(SELF) ? Qtrue : Qfalse; } |
#child(idx) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'ext/tree_sitter/node.c', line 98
static VALUE node_child(VALUE self, VALUE idx) {
TSNode node = SELF;
uint32_t index = NUM2UINT(idx);
uint32_t range = ts_node_child_count(node);
if (index < range) {
return new_node_by_val(ts_node_child(node, index));
} else {
rb_raise(rb_eIndexError, "Index %d is out of range (len = %d)", index,
range);
}
}
|
#child_by_field_id(field_id) ⇒ Object
157 158 159 |
# File 'ext/tree_sitter/node.c', line 157
static VALUE node_child_by_field_id(VALUE self, VALUE field_id) {
return new_node_by_val(ts_node_child_by_field_id(SELF, NUM2UINT(field_id)));
}
|
#child_by_field_name(field_name) ⇒ Object
151 152 153 154 155 |
# File 'ext/tree_sitter/node.c', line 151
static VALUE node_child_by_field_name(VALUE self, VALUE field_name) {
const char *name = StringValuePtr(field_name);
uint32_t length = (uint32_t)RSTRING_LEN(field_name);
return new_node_by_val(ts_node_child_by_field_name(SELF, name, length));
}
|
#child_count ⇒ Object
124 125 126 127 128 129 130 131 132 |
# File 'ext/tree_sitter/node.c', line 124
static VALUE node_child_count(VALUE self) {
TSNode node = SELF;
const char *type = ts_node_type(node);
if (strcmp(type, "end") == 0) {
return UINT2NUM(0);
} else {
return UINT2NUM(ts_node_child_count(SELF));
}
}
|
#descendant_for_byte_range(from, to) ⇒ Object
186 187 188 189 190 191 192 193 194 195 196 |
# File 'ext/tree_sitter/node.c', line 186
static VALUE node_descendant_for_byte_range(VALUE self, VALUE from, VALUE to) {
uint32_t from_b = NUM2UINT(from);
uint32_t to_b = NUM2UINT(to);
if (from_b > to_b) {
rb_raise(rb_eIndexError, "From > To: %d > %d", from_b, to_b);
} else {
return new_node_by_val(
ts_node_descendant_for_byte_range(SELF, from_b, to_b));
}
}
|
#descendant_for_point_range(from, to) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'ext/tree_sitter/node.c', line 198
static VALUE node_descendant_for_point_range(VALUE self, VALUE from, VALUE to) {
TSNode node = SELF;
TSPoint start = ts_node_start_point(node);
TSPoint end = ts_node_end_point(node);
TSPoint f = value_to_point(from);
TSPoint t = value_to_point(to);
if ((f.row < start.row) || (t.row > end.row) ||
(f.row == start.row && (f.column < start.column)) ||
(t.row == end.row && (t.column > end.column))) {
rb_raise(rb_eIndexError,
"Invalid point range: [%+" PRIsVALUE ", %+" PRIsVALUE
"] is not in [%+" PRIsVALUE ", %+" PRIsVALUE "].",
from, to, new_point(&start), new_point(&end));
} else {
return new_node_by_val(ts_node_descendant_for_point_range(node, f, t));
}
}
|
#each {|child| ... } ⇒ Object
Iterate over a node’s children.
86 87 88 89 90 91 92 |
# File 'lib/tree_sitter/node.rb', line 86 def each return enum_for __method__ if !block_given? (0...(child_count)).each do |i| yield child(i) end end |
#each_field {|name, child| ... } ⇒ Object
Iterate over a node’s children assigned to a field.
98 99 100 101 102 103 104 105 106 107 |
# File 'lib/tree_sitter/node.rb', line 98 def each_field return enum_for __method__ if !block_given? each.with_index do |c, i| f = field_name_for_child(i) next if f.nil? || f.empty? yield f, c end end |
#each_named {|child| ... } ⇒ Object
Iterate over a node’s named children
112 113 114 115 116 117 118 |
# File 'lib/tree_sitter/node.rb', line 112 def each_named return enum_for __method__ if !block_given? (0...(named_child_count)).each do |i| yield named_child(i) end end |
#edit(input_edit) ⇒ Object
251 252 253 254 255 256 257 |
# File 'ext/tree_sitter/node.c', line 251
static VALUE node_edit(VALUE self, VALUE input_edit) {
TSNode node = SELF;
TSInputEdit edit = value_to_input_edit(input_edit);
ts_node_edit(&node, &edit);
return Qnil;
}
|
#end_byte ⇒ Object
53 54 55 |
# File 'ext/tree_sitter/node.c', line 53 static VALUE node_end_byte(VALUE self) { return UINT2NUM(ts_node_end_byte(SELF)); } |
#end_point ⇒ Object
57 58 59 |
# File 'ext/tree_sitter/node.c', line 57 static VALUE node_end_point(VALUE self) { return new_point_by_val(ts_node_end_point(SELF)); } |
#eq?(other) ⇒ Boolean
259 260 261 |
# File 'ext/tree_sitter/node.c', line 259
static VALUE node_eq(VALUE self, VALUE other) {
return ts_node_eq(SELF, unwrap(other)->data) ? Qtrue : Qfalse;
}
|
#error? ⇒ Boolean
90 91 92 |
# File 'ext/tree_sitter/node.c', line 90 static VALUE node_has_error(VALUE self) { return ts_node_has_error(SELF) ? Qtrue : Qfalse; } |
#extra? ⇒ Boolean
82 83 84 |
# File 'ext/tree_sitter/node.c', line 82 static VALUE node_is_extra(VALUE self) { return ts_node_is_extra(SELF) ? Qtrue : Qfalse; } |
#fetch(*keys) ⇒ Object
Access node’s named children.
It’s similar to #fetch, but differes in input type, return values, and the internal implementation.
Both of these methods exist for separate use cases, but also because sometime tree-sitter does some monkey business and having both separate implementations can help.
Comparison with #fetch:
[] | fetch
------------------------------+----------------------
input types Integer, String, Symbol | String, Symbol
Array<Integer, String, Symbol>| Array<String, Symbol>
------------------------------+----------------------
returns 1-to-1 correspondance with | unique nodes
input |
------------------------------+----------------------
uses named_child | field_name_for_child
child_by_field_name | via each_node
------------------------------+----------------------
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/tree_sitter/node.rb', line 146 def fetch(*keys) dict = {} keys.each.with_index do |k, i| dict[k.to_s] = i end res = {} each_field do |f, c| if dict.key?(f) res[dict[f]] = c dict.delete(f) end break if dict.empty? end res.sort.map { |_, v| v } end |
#field?(field) ⇒ Boolean
17 18 19 |
# File 'lib/tree_sitter/node.rb', line 17 def field?(field) fields.include?(field) end |
#field_name_for_child(idx) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'ext/tree_sitter/node.c', line 111
static VALUE node_field_name_for_child(VALUE self, VALUE idx) {
TSNode node = SELF;
uint32_t index = NUM2UINT(idx);
uint32_t range = ts_node_child_count(node);
if (index < range) {
return safe_str(ts_node_field_name_for_child(node, index));
} else {
rb_raise(rb_eIndexError, "Index %d is out of range (len = %d)", index,
range);
}
}
|
#fields ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/tree_sitter/node.rb', line 5 def fields return @fields if @fields @fields = Set.new child_count.times do |i| name = field_name_for_child(i) @fields << name.to_sym if name end @fields end |
#first_child_for_byte(byte) ⇒ Object
177 178 179 |
# File 'ext/tree_sitter/node.c', line 177
static VALUE node_first_child_for_byte(VALUE self, VALUE byte) {
return new_node_by_val(ts_node_first_child_for_byte(SELF, NUM2UINT(byte)));
}
|
#first_named_child_for_byte(byte) ⇒ Object
181 182 183 184 |
# File 'ext/tree_sitter/node.c', line 181
static VALUE node_first_named_child_for_byte(VALUE self, VALUE byte) {
return new_node_by_val(
ts_node_first_named_child_for_byte(SELF, NUM2UINT(byte)));
}
|
#inspect ⇒ Object
61 62 63 64 65 66 67 68 |
# File 'ext/tree_sitter/node.c', line 61
static VALUE node_string(VALUE self) {
char *str = ts_node_string(SELF);
VALUE res = safe_str(str);
if (str) {
free(str);
}
return res;
}
|
#missing? ⇒ Boolean
78 79 80 |
# File 'ext/tree_sitter/node.c', line 78 static VALUE node_is_missing(VALUE self) { return ts_node_is_missing(SELF) ? Qtrue : Qfalse; } |
#named? ⇒ Boolean
74 75 76 |
# File 'ext/tree_sitter/node.c', line 74 static VALUE node_is_named(VALUE self) { return ts_node_is_named(SELF) ? Qtrue : Qfalse; } |
#named_child(idx) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'ext/tree_sitter/node.c', line 134
static VALUE node_named_child(VALUE self, VALUE idx) {
TSNode node = SELF;
uint32_t index = NUM2UINT(idx);
uint32_t range = ts_node_named_child_count(node);
if (index < range) {
return new_node_by_val(ts_node_named_child(node, index));
} else {
rb_raise(rb_eIndexError, "Index %d is out of range (len = %d)", index,
range);
}
}
|
#named_child_count ⇒ Object
147 148 149 |
# File 'ext/tree_sitter/node.c', line 147 static VALUE node_named_child_count(VALUE self) { return UINT2NUM(ts_node_named_child_count(SELF)); } |
#named_descendant_for_byte_range(from, to) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'ext/tree_sitter/node.c', line 217
static VALUE node_named_descendant_for_byte_range(VALUE self, VALUE from,
VALUE to) {
uint32_t from_b = NUM2UINT(from);
uint32_t to_b = NUM2UINT(to);
if (from_b > to_b) {
rb_raise(rb_eIndexError, "From > To: %d > %d", from_b, to_b);
} else {
return new_node_by_val(
ts_node_named_descendant_for_byte_range(SELF, from_b, to_b));
}
}
|
#named_descendant_for_point_range(from, to) ⇒ Object
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'ext/tree_sitter/node.c', line 230
static VALUE node_named_descendant_for_point_range(VALUE self, VALUE from,
VALUE to) {
TSNode node = SELF;
TSPoint start = ts_node_start_point(node);
TSPoint end = ts_node_end_point(node);
TSPoint f = value_to_point(from);
TSPoint t = value_to_point(to);
if ((f.row < start.row) || (t.row > end.row) ||
(f.row == start.row && (f.column < start.column)) ||
(t.row == end.row && (t.column > end.column))) {
rb_raise(rb_eIndexError,
"Invalid point range: [%+" PRIsVALUE ", %+" PRIsVALUE
"] is not in [%+" PRIsVALUE ", %+" PRIsVALUE "].",
from, to, new_point(&start), new_point(&end));
} else {
return new_node_by_val(
ts_node_named_descendant_for_point_range(node, f, t));
}
}
|
#next_named_sibling ⇒ Object
169 170 171 |
# File 'ext/tree_sitter/node.c', line 169 static VALUE node_next_named_sibling(VALUE self) { return new_node_by_val(ts_node_next_named_sibling(SELF)); } |
#next_sibling ⇒ Object
161 162 163 |
# File 'ext/tree_sitter/node.c', line 161 static VALUE node_next_sibling(VALUE self) { return new_node_by_val(ts_node_next_sibling(SELF)); } |
#null? ⇒ Boolean
70 71 72 |
# File 'ext/tree_sitter/node.c', line 70 static VALUE node_is_null(VALUE self) { return ts_node_is_null(SELF) ? Qtrue : Qfalse; } |
#parent ⇒ Object
94 95 96 |
# File 'ext/tree_sitter/node.c', line 94 static VALUE node_parent(VALUE self) { return new_node_by_val(ts_node_parent(SELF)); } |
#prev_named_sibling ⇒ Object
173 174 175 |
# File 'ext/tree_sitter/node.c', line 173 static VALUE node_prev_named_sibling(VALUE self) { return new_node_by_val(ts_node_prev_named_sibling(SELF)); } |
#prev_sibling ⇒ Object
165 166 167 |
# File 'ext/tree_sitter/node.c', line 165 static VALUE node_prev_sibling(VALUE self) { return new_node_by_val(ts_node_prev_sibling(SELF)); } |
#respond_to_missing?(*args) ⇒ Boolean
78 79 80 81 |
# File 'lib/tree_sitter/node.rb', line 78 def respond_to_missing?(*args) init_fields args.length == 1 && fields.include?(args[0]) end |
#start_byte ⇒ Object
45 46 47 |
# File 'ext/tree_sitter/node.c', line 45 static VALUE node_start_byte(VALUE self) { return UINT2NUM(ts_node_start_byte(SELF)); } |
#start_point ⇒ Object
49 50 51 |
# File 'ext/tree_sitter/node.c', line 49 static VALUE node_start_point(VALUE self) { return new_point_by_val(ts_node_start_point(SELF)); } |
#symbol ⇒ Object
43 |
# File 'ext/tree_sitter/node.c', line 43 static VALUE node_symbol(VALUE self) { return UINT2NUM(ts_node_symbol(SELF)); } |
#to_a ⇒ Object
120 121 122 |
# File 'lib/tree_sitter/node.rb', line 120 def to_a each.to_a end |
#to_s ⇒ Object
61 62 63 64 65 66 67 68 |
# File 'ext/tree_sitter/node.c', line 61
static VALUE node_string(VALUE self) {
char *str = ts_node_string(SELF);
VALUE res = safe_str(str);
if (str) {
free(str);
}
return res;
}
|
#to_str ⇒ Object
61 62 63 64 65 66 67 68 |
# File 'ext/tree_sitter/node.c', line 61
static VALUE node_string(VALUE self) {
char *str = ts_node_string(SELF);
VALUE res = safe_str(str);
if (str) {
free(str);
}
return res;
}
|
#type ⇒ Object
Class methods