tree_stump 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,311 @@
1
+ use magnus::{function, method, prelude::*, typed_data, value::Lazy, Error, RClass, Ruby};
2
+
3
+ use libloading::Library;
4
+ use tree_sitter::ffi::TSLanguage;
5
+
6
+ use std::collections::HashMap;
7
+ use std::sync::Mutex;
8
+ use std::sync::OnceLock;
9
+
10
+ mod data;
11
+ mod language;
12
+ mod parser;
13
+ mod query;
14
+ mod tree;
15
+ mod util;
16
+
17
+ use crate::language::{LanguageRef, LookaheadIterator};
18
+ use crate::parser::Parser;
19
+ use crate::query::{Query, QueryCursor, QueryMatch};
20
+ use crate::tree::{Node, Tree, TreeCursor};
21
+
22
+ pub static LANG_LIBRARIES: OnceLock<Mutex<HashMap<String, Library>>> = OnceLock::new();
23
+ pub static LANG_LANGUAGES: OnceLock<Mutex<HashMap<String, tree_sitter::Language>>> =
24
+ OnceLock::new();
25
+
26
+ pub static QUERY_CAPTURE_CLASS: Lazy<RClass> =
27
+ Lazy::new(|ruby| ruby.define_struct(None, ("node", "index")).unwrap());
28
+
29
+ fn register_lang(lang: String, path: String) -> () {
30
+ let func_name = String::from("tree_sitter_") + &lang;
31
+ let language;
32
+
33
+ let libraries = LANG_LIBRARIES.get_or_init(|| Mutex::new(HashMap::new()));
34
+ let languages = LANG_LANGUAGES.get_or_init(|| Mutex::new(HashMap::new()));
35
+
36
+ unsafe {
37
+ let mut libraries = libraries.lock().unwrap();
38
+ let lib = libraries.entry(lang.clone()).or_insert_with(|| {
39
+ let loaded = Library::new(path).expect("Failed to load library");
40
+ loaded
41
+ });
42
+
43
+ let func: libloading::Symbol<unsafe extern "C" fn() -> *const TSLanguage> =
44
+ lib.get(func_name.as_bytes()).unwrap();
45
+
46
+ language = tree_sitter::Language::from_raw(func());
47
+
48
+ let mut languages = languages.lock().unwrap();
49
+ languages.insert(lang.to_string(), language);
50
+ };
51
+ }
52
+
53
+ fn available_langs() -> Vec<String> {
54
+ let languages = LANG_LANGUAGES.get_or_init(|| Mutex::new(HashMap::new()));
55
+ let languages = languages.lock().unwrap();
56
+ languages.keys().cloned().collect()
57
+ }
58
+
59
+ #[magnus::init]
60
+ fn init(ruby: &Ruby) -> Result<(), Error> {
61
+ let namespace = ruby.define_module("TreeStump")?;
62
+ namespace.define_singleton_method("register_lang", function!(register_lang, 2))?;
63
+ namespace.define_singleton_method("available_langs", function!(available_langs, 0))?;
64
+
65
+ let parser_class = namespace.define_class("Parser", ruby.class_object())?;
66
+ parser_class.define_singleton_method("new", function!(Parser::new, 0))?;
67
+ parser_class.define_method("set_language", method!(Parser::set_language, 1))?;
68
+ parser_class.define_method("parse", method!(Parser::parse, 1))?;
69
+ parser_class.define_method("reset", method!(Parser::reset, 0))?;
70
+ parser_class.define_method("timeout_micros", method!(Parser::timeout_micros, 0))?;
71
+ parser_class.define_method("set_timeout_micros", method!(Parser::set_timeout_micros, 1))?;
72
+ parser_class.define_method("build_query", method!(Parser::build_query, 1))?;
73
+
74
+ let tree_class = namespace.define_class("Tree", ruby.class_object())?;
75
+ tree_class.define_method("root_node", method!(Tree::root_node, 0))?;
76
+ tree_class.define_method("language", method!(Tree::language, 0))?;
77
+ tree_class.define_method("walk", method!(Tree::walk, 0))?;
78
+ tree_class.define_method("print_dot_graph", method!(Tree::print_dot_graph, 1))?;
79
+ tree_class.define_method("inspect", method!(Tree::inspect, 0))?;
80
+
81
+ let tree_cursor_class = namespace.define_class("TreeCursor", ruby.class_object())?;
82
+ tree_cursor_class.define_method("node", method!(TreeCursor::node, 0))?;
83
+ tree_cursor_class.define_method("field_id", method!(TreeCursor::field_id, 0))?;
84
+ tree_cursor_class
85
+ .define_method("goto_first_child", method!(TreeCursor::goto_first_child, 0))?;
86
+ tree_cursor_class.define_method("goto_last_child", method!(TreeCursor::goto_last_child, 0))?;
87
+ tree_cursor_class.define_method("goto_parent", method!(TreeCursor::goto_parent, 0))?;
88
+ tree_cursor_class.define_method(
89
+ "goto_next_sibling",
90
+ method!(TreeCursor::goto_next_sibling, 0),
91
+ )?;
92
+ tree_cursor_class.define_method("goto_descendant", method!(TreeCursor::goto_descendant, 1))?;
93
+ tree_cursor_class.define_method(
94
+ "goto_previous_sibling",
95
+ method!(TreeCursor::goto_previous_sibling, 0),
96
+ )?;
97
+ tree_cursor_class.define_method(
98
+ "goto_first_child_for_byte",
99
+ method!(TreeCursor::goto_first_child_for_byte, 1),
100
+ )?;
101
+ tree_cursor_class.define_method("reset", method!(TreeCursor::reset, 1))?;
102
+ tree_cursor_class.define_method("reset_to", method!(TreeCursor::reset_to, 1))?;
103
+
104
+ let node_class = namespace.define_class("Node", ruby.class_object())?;
105
+ node_class.define_method("hash", method!(<Node as typed_data::Hash>::hash, 0))?;
106
+ node_class.define_method("==", method!(<Node as typed_data::IsEql>::is_eql, 1))?;
107
+ node_class.define_method("eql?", method!(<Node as typed_data::IsEql>::is_eql, 1))?;
108
+ node_class.define_method("id", method!(Node::id, 0))?;
109
+ node_class.define_method("kind", method!(Node::kind, 0))?;
110
+ node_class.define_method("kind_id", method!(Node::kind_id, 0))?;
111
+ node_class.define_method("grammar_id", method!(Node::grammar_id, 0))?;
112
+ node_class.define_method("grammar_name", method!(Node::grammar_name, 0))?;
113
+ node_class.define_method("language", method!(Node::language, 0))?;
114
+ node_class.define_method("is_named?", method!(Node::is_named, 0))?;
115
+ node_class.define_method("is_extra?", method!(Node::is_extra, 0))?;
116
+ node_class.define_method("has_changes?", method!(Node::has_changes, 0))?;
117
+ node_class.define_method("has_error?", method!(Node::has_error, 0))?;
118
+ node_class.define_method("is_error?", method!(Node::is_error, 0))?;
119
+ node_class.define_method("parse_state", method!(Node::parse_state, 0))?;
120
+ node_class.define_method("next_parse_state", method!(Node::next_parse_state, 0))?;
121
+ node_class.define_method("start_byte", method!(Node::start_byte, 0))?;
122
+ node_class.define_method("end_byte", method!(Node::end_byte, 0))?;
123
+ node_class.define_method("byte_range", method!(Node::byte_range, 0))?;
124
+ node_class.define_method("range", method!(Node::range, 0))?;
125
+ node_class.define_method("start_position", method!(Node::start_position, 0))?;
126
+ node_class.define_method("end_position", method!(Node::end_position, 0))?;
127
+ node_class.define_method("child", method!(Node::child, 1))?;
128
+ node_class.define_method("child_count", method!(Node::child_count, 0))?;
129
+ node_class.define_method("named_child", method!(Node::named_child, 1))?;
130
+ node_class.define_method("named_child_count", method!(Node::named_child_count, 0))?;
131
+ node_class.define_method("child_by_field_name", method!(Node::child_by_field_name, 1))?;
132
+ node_class.define_method("child_by_field_id", method!(Node::child_by_field_id, 1))?;
133
+ node_class.define_method(
134
+ "field_name_for_child",
135
+ method!(Node::field_name_for_child, 1),
136
+ )?;
137
+ node_class.define_method("parent", method!(Node::parent, 0))?;
138
+ node_class.define_method("children", method!(Node::children, 0))?;
139
+ node_class.define_method(
140
+ "children_with_cursor",
141
+ method!(Node::children_with_cursor, 1),
142
+ )?;
143
+ node_class.define_method(
144
+ "named_children_with_cursor",
145
+ method!(Node::named_children_with_cursor, 1),
146
+ )?;
147
+ node_class.define_method(
148
+ "children_by_field_name_with_cursor",
149
+ method!(Node::children_by_field_name_with_cursor, 2),
150
+ )?;
151
+ node_class.define_method(
152
+ "children_by_field_id_with_cursor",
153
+ method!(Node::children_by_field_id_with_cursor, 2),
154
+ )?;
155
+ node_class.define_method(
156
+ "child_containing_descendant",
157
+ method!(Node::child_containing_descendant, 1),
158
+ )?;
159
+ node_class.define_method("next_sibling", method!(Node::next_sibling, 0))?;
160
+ node_class.define_method("prev_sibling", method!(Node::prev_sibling, 0))?;
161
+ node_class.define_method("next_named_sibling", method!(Node::next_named_sibling, 0))?;
162
+ node_class.define_method("prev_named_sibling", method!(Node::prev_named_sibling, 0))?;
163
+ node_class.define_method("descendant_count", method!(Node::descendant_count, 0))?;
164
+ node_class.define_method(
165
+ "descendant_for_byte_range",
166
+ method!(Node::descendant_for_byte_range, 2),
167
+ )?;
168
+ node_class.define_method(
169
+ "named_descendant_for_byte_range",
170
+ method!(Node::named_descendant_for_byte_range, 2),
171
+ )?;
172
+ node_class.define_method(
173
+ "descendant_for_point_range",
174
+ method!(Node::descendant_for_point_range, 2),
175
+ )?;
176
+ node_class.define_method(
177
+ "named_descendant_for_point_range",
178
+ method!(Node::named_descendant_for_point_range, 2),
179
+ )?;
180
+
181
+ node_class.define_method("to_sexp", method!(Node::to_sexp, 0))?;
182
+ node_class.define_method("utf8_text", method!(Node::utf8_text, 1))?;
183
+ node_class.define_method("walk", method!(Node::walk, 0))?;
184
+
185
+ node_class.define_method("inspect", method!(Node::inspect, 0))?;
186
+ node_class.define_method("to_s", method!(Node::to_s, 0))?;
187
+
188
+ let point_class = namespace.define_class("Point", ruby.class_object())?;
189
+ point_class.define_singleton_method("new", function!(data::Point::new, 2))?;
190
+ point_class.define_method("hash", method!(<data::Point as typed_data::Hash>::hash, 0))?;
191
+ point_class.define_method("==", method!(<data::Point as typed_data::IsEql>::is_eql, 1))?;
192
+ point_class.define_method(
193
+ "eql?",
194
+ method!(<data::Point as typed_data::IsEql>::is_eql, 1),
195
+ )?;
196
+ point_class.define_method("row", method!(data::Point::get_row, 0))?;
197
+ point_class.define_method("column", method!(data::Point::get_column, 0))?;
198
+ point_class.define_method("inspect", method!(data::Point::inspect, 0))?;
199
+ point_class.define_method("to_s", method!(data::Point::to_s, 0))?;
200
+
201
+ let range_class = namespace.define_class("Range", ruby.class_object())?;
202
+ range_class.define_singleton_method("new", function!(data::Range::new, 4))?;
203
+ range_class.define_method("hash", method!(<data::Range as typed_data::Hash>::hash, 0))?;
204
+ range_class.define_method("==", method!(<data::Range as typed_data::IsEql>::is_eql, 1))?;
205
+ range_class.define_method(
206
+ "eql?",
207
+ method!(<data::Range as typed_data::IsEql>::is_eql, 1),
208
+ )?;
209
+ range_class.define_method("start_byte", method!(data::Range::get_start_byte, 0))?;
210
+ range_class.define_method("end_byte", method!(data::Range::get_end_byte, 0))?;
211
+ range_class.define_method("start_point", method!(data::Range::get_start_point, 0))?;
212
+ range_class.define_method("end_point", method!(data::Range::get_end_point, 0))?;
213
+ range_class.define_method("inspect", method!(data::Range::inspect, 0))?;
214
+ range_class.define_method("to_s", method!(data::Range::to_s, 0))?;
215
+
216
+ let language_class = namespace.define_class("LanguageRef", ruby.class_object())?;
217
+ language_class.define_method("version", method!(LanguageRef::version, 0))?;
218
+ language_class.define_method("node_kind_count", method!(LanguageRef::node_kind_count, 0))?;
219
+ language_class.define_method(
220
+ "parse_state_count",
221
+ method!(LanguageRef::parse_state_count, 0),
222
+ )?;
223
+ language_class.define_method(
224
+ "node_kind_for_id",
225
+ method!(LanguageRef::node_kind_for_id, 1),
226
+ )?;
227
+ language_class.define_method(
228
+ "id_for_node_kind",
229
+ method!(LanguageRef::id_for_node_kind, 2),
230
+ )?;
231
+ language_class.define_method(
232
+ "node_kind_is_named",
233
+ method!(LanguageRef::node_kind_is_named, 1),
234
+ )?;
235
+ language_class.define_method(
236
+ "node_kind_is_visible",
237
+ method!(LanguageRef::node_kind_is_visible, 1),
238
+ )?;
239
+ language_class.define_method(
240
+ "field_name_for_id",
241
+ method!(LanguageRef::field_name_for_id, 1),
242
+ )?;
243
+ language_class.define_method(
244
+ "field_id_for_name",
245
+ method!(LanguageRef::field_id_for_name, 1),
246
+ )?;
247
+ language_class.define_method("next_state", method!(LanguageRef::next_state, 2))?;
248
+ language_class.define_method(
249
+ "lookahead_iterator",
250
+ method!(LanguageRef::lookahead_iterator, 1),
251
+ )?;
252
+
253
+ let lookahead_iterator_class =
254
+ namespace.define_class("LookaheadIterator", ruby.class_object())?;
255
+ lookahead_iterator_class.define_method("next", method!(LookaheadIterator::next, 0))?;
256
+ lookahead_iterator_class.define_method(
257
+ "current_symbol_name",
258
+ method!(LookaheadIterator::current_symbol_name, 0),
259
+ )?;
260
+
261
+ let query_class = namespace.define_class("Query", ruby.class_object())?;
262
+ query_class.define_method(
263
+ "start_byte_for_pattern",
264
+ method!(Query::start_byte_for_pattern, 1),
265
+ )?;
266
+ query_class.define_method("pattern_count", method!(Query::pattern_count, 0))?;
267
+ query_class.define_method("capture_names", method!(Query::capture_names, 0))?;
268
+ query_class.define_method(
269
+ "capture_quantifiers",
270
+ method!(Query::capture_quantifiers, 1),
271
+ )?;
272
+ query_class.define_method(
273
+ "capture_index_for_name",
274
+ method!(Query::capture_index_for_name, 1),
275
+ )?;
276
+ query_class.define_method("disable_capture", method!(Query::disable_capture, 1))?;
277
+ query_class.define_method("disable_pattern", method!(Query::disable_pattern, 1))?;
278
+ query_class.define_method("is_pattern_rooted", method!(Query::is_pattern_rooted, 1))?;
279
+ query_class.define_method(
280
+ "is_pattern_guaranteed_at_step",
281
+ method!(Query::is_pattern_guaranteed_at_step, 1),
282
+ )?;
283
+
284
+ Lazy::force(&QUERY_CAPTURE_CLASS, ruby);
285
+ let struct_class = Lazy::try_get_inner(&QUERY_CAPTURE_CLASS).unwrap();
286
+ namespace.const_set("QueryCapture", struct_class)?;
287
+
288
+ let query_match_class = namespace.define_class("QueryMatch", ruby.class_object())?;
289
+ query_match_class.define_method("pattern_index", method!(QueryMatch::pattern_index, 0))?;
290
+ query_match_class.define_method("captures", method!(QueryMatch::captures, 0))?;
291
+
292
+ let query_cursor_class = namespace.define_class("QueryCursor", ruby.class_object())?;
293
+ query_cursor_class.define_singleton_method("new", function!(QueryCursor::new, 0))?;
294
+ query_cursor_class.define_method("match_limit", method!(QueryCursor::match_limit, 0))?;
295
+ query_cursor_class
296
+ .define_method("set_match_limit", method!(QueryCursor::set_match_limit, 1))?;
297
+ query_cursor_class.define_method(
298
+ "did_exceed_match_limit",
299
+ method!(QueryCursor::did_exceed_match_limit, 0),
300
+ )?;
301
+ query_cursor_class.define_method("matches", method!(QueryCursor::matches, 3))?;
302
+ query_cursor_class.define_method("set_byte_range", method!(QueryCursor::set_byte_range, 1))?;
303
+ query_cursor_class
304
+ .define_method("set_point_range", method!(QueryCursor::set_point_range, 1))?;
305
+ query_cursor_class.define_method(
306
+ "set_max_start_depth",
307
+ method!(QueryCursor::set_max_start_depth, 1),
308
+ )?;
309
+
310
+ Ok(())
311
+ }
@@ -0,0 +1,67 @@
1
+ use crate::query::Query;
2
+ use crate::tree::Tree;
3
+ use crate::util::build_error;
4
+ use crate::LANG_LANGUAGES;
5
+
6
+ use std::cell::RefCell;
7
+ use std::collections::HashMap;
8
+ use std::sync::{Arc, Mutex};
9
+
10
+ #[magnus::wrap(class = "TreeStump::Parser")]
11
+ pub struct Parser {
12
+ raw_parser: RefCell<tree_sitter::Parser>,
13
+ }
14
+
15
+ impl Parser {
16
+ pub fn new() -> Self {
17
+ Self {
18
+ raw_parser: RefCell::new(tree_sitter::Parser::new()),
19
+ }
20
+ }
21
+
22
+ pub fn set_language(&self, lang: String) -> Result<bool, magnus::Error> {
23
+ let languages = LANG_LANGUAGES.get_or_init(|| Mutex::new(HashMap::new()));
24
+ let languages = languages.lock().unwrap();
25
+ let language = languages.get(&lang);
26
+ match language {
27
+ Some(language) => {
28
+ let result = self.raw_parser.borrow_mut().set_language(language);
29
+ result.map_or_else(|e| Err(build_error(e.to_string())), |_| Ok(true))
30
+ }
31
+ None => Err(build_error(format!("Language {} is not registered", lang))),
32
+ }
33
+ }
34
+
35
+ pub fn parse(&self, source: String) -> Result<Tree, magnus::Error> {
36
+ let tree = self.raw_parser.borrow_mut().parse(source, None);
37
+
38
+ match tree {
39
+ Some(tree) => Ok(Tree::from(Arc::new(tree))),
40
+ None => Err(build_error("Failed to parse")),
41
+ }
42
+ }
43
+
44
+ pub fn reset(&self) {
45
+ self.raw_parser.borrow_mut().reset();
46
+ }
47
+
48
+ pub fn timeout_micros(&self) -> u64 {
49
+ self.raw_parser.borrow().timeout_micros()
50
+ }
51
+
52
+ pub fn set_timeout_micros(&self, timeout: u64) {
53
+ self.raw_parser.borrow_mut().set_timeout_micros(timeout);
54
+ }
55
+
56
+ fn language(&self) -> Option<tree_sitter::Language> {
57
+ self.raw_parser.borrow().language()
58
+ }
59
+
60
+ pub fn build_query(&self, source: String) -> Result<Query, magnus::Error> {
61
+ let lang = self.language();
62
+ lang.map_or_else(
63
+ || Err(build_error("Failed to get language from parser")),
64
+ |lang| Query::new(&lang, source),
65
+ )
66
+ }
67
+ }
@@ -0,0 +1,209 @@
1
+ use std::{cell::RefCell, sync::Arc};
2
+
3
+ use magnus::{
4
+ block::Yield,
5
+ symbol::IntoSymbol,
6
+ typed_data,
7
+ value::{InnerRef, Opaque, ReprValue},
8
+ Class, Error, IntoValue, RArray, RStruct, RTypedData, Ruby, Value,
9
+ };
10
+
11
+ use crate::{data::Point, tree::Node, util::build_error, QUERY_CAPTURE_CLASS};
12
+
13
+ #[magnus::wrap(class = "TreeStump::Query", free_immediately)]
14
+ #[derive(Debug)]
15
+ pub struct Query {
16
+ pub raw_query: RefCell<tree_sitter::Query>,
17
+ }
18
+
19
+ impl Query {
20
+ pub fn new(language: &tree_sitter::Language, source: String) -> Result<Self, magnus::Error> {
21
+ let raw_query = tree_sitter::Query::new(language, source.as_str());
22
+ let raw_query = raw_query.map_err(|e| build_error(e.to_string()));
23
+ raw_query.map(|q| Self {
24
+ raw_query: RefCell::new(q),
25
+ })
26
+ }
27
+
28
+ pub fn start_byte_for_pattern(&self, pattern_index: usize) -> usize {
29
+ self.raw_query
30
+ .borrow()
31
+ .start_byte_for_pattern(pattern_index)
32
+ }
33
+
34
+ pub fn pattern_count(&self) -> usize {
35
+ self.raw_query.borrow().pattern_count()
36
+ }
37
+
38
+ pub fn capture_names(&self) -> Vec<String> {
39
+ self.raw_query
40
+ .borrow()
41
+ .capture_names()
42
+ .iter()
43
+ .map(|s| s.to_string())
44
+ .collect()
45
+ }
46
+
47
+ pub fn capture_quantifiers(&self, index: usize) -> Result<RArray, Error> {
48
+ let raw_query = self.raw_query.borrow();
49
+ let quantifiers = raw_query
50
+ .capture_quantifiers(index)
51
+ .iter()
52
+ .map(|q| format!("{:?}", q).into_symbol());
53
+ let ruby = Ruby::get().expect("Ruby is not initialized");
54
+ let array = ruby.ary_from_iter(quantifiers);
55
+ Ok(array)
56
+ }
57
+
58
+ pub fn capture_index_for_name(&self, name: String) -> Option<u32> {
59
+ self.raw_query
60
+ .borrow()
61
+ .capture_index_for_name(name.as_str())
62
+ }
63
+
64
+ pub fn disable_capture(&self, name: String) {
65
+ self.raw_query.borrow_mut().disable_capture(&name);
66
+ }
67
+
68
+ pub fn disable_pattern(&self, index: usize) {
69
+ self.raw_query.borrow_mut().disable_pattern(index);
70
+ }
71
+
72
+ pub fn is_pattern_rooted(&self, index: usize) -> bool {
73
+ self.raw_query.borrow().is_pattern_rooted(index)
74
+ }
75
+
76
+ pub fn is_pattern_guaranteed_at_step(&self, index: usize) -> bool {
77
+ self.raw_query.borrow().is_pattern_guaranteed_at_step(index)
78
+ }
79
+ }
80
+
81
+ #[magnus::wrap(class = "TreeStump::QueryMatch", free_immediately)]
82
+ pub struct QueryMatch {
83
+ pattern_index: usize,
84
+ captures: Opaque<RArray>,
85
+ }
86
+
87
+ impl QueryMatch {
88
+ pub fn pattern_index(&self) -> usize {
89
+ self.pattern_index
90
+ }
91
+
92
+ pub fn captures(ruby: &Ruby, rb_self: typed_data::Obj<Self>) -> Result<RArray, Error> {
93
+ Ok(ruby.get_inner(rb_self.captures))
94
+ }
95
+ }
96
+
97
+ #[magnus::wrap(class = "TreeStump::QueryCursor", free_immediately)]
98
+ pub struct QueryCursor {
99
+ raw_cursor: RefCell<tree_sitter::QueryCursor>,
100
+ }
101
+
102
+ impl QueryCursor {
103
+ pub fn new() -> Self {
104
+ Self {
105
+ raw_cursor: RefCell::new(tree_sitter::QueryCursor::new()),
106
+ }
107
+ }
108
+
109
+ pub fn match_limit(&self) -> u32 {
110
+ self.raw_cursor.borrow().match_limit()
111
+ }
112
+
113
+ pub fn set_match_limit(&self, limit: u32) {
114
+ self.raw_cursor.borrow_mut().set_match_limit(limit);
115
+ }
116
+
117
+ pub fn did_exceed_match_limit(&self) -> bool {
118
+ self.raw_cursor.borrow().did_exceed_match_limit()
119
+ }
120
+
121
+ pub fn matches<'tree>(
122
+ ruby: &Ruby,
123
+ rb_self: typed_data::Obj<Self>,
124
+ query: typed_data::Obj<Query>,
125
+ node: typed_data::Obj<Node<'tree>>,
126
+ source: String,
127
+ ) -> Result<Yield<impl Iterator<Item = Value>>, Error> {
128
+ let mut cursor = rb_self.raw_cursor.borrow_mut();
129
+ let raw_query = query.raw_query.borrow();
130
+
131
+ let matches = cursor.matches(&raw_query, node.get_raw_node(), source.as_bytes());
132
+ let struct_class = QUERY_CAPTURE_CLASS.get_inner_ref_with(ruby);
133
+ let array = ruby.ary_new();
134
+
135
+ for m in matches {
136
+ let captures = ruby.ary_new();
137
+ for c in m.captures {
138
+ let r_struct = RStruct::from_value(
139
+ struct_class
140
+ .new_instance((Node::new(Arc::clone(&node.raw_tree), c.node), c.index))?,
141
+ );
142
+ captures.push(r_struct)?
143
+ }
144
+ let query_match = QueryMatch {
145
+ pattern_index: m.pattern_index,
146
+ captures: Opaque::from(captures),
147
+ };
148
+ array.push(query_match)?
149
+ }
150
+
151
+ if ruby.block_given() {
152
+ Ok(Yield::Iter(array.into_iter()))
153
+ } else {
154
+ Ok(Yield::Enumerator(rb_self.enumeratorize(
155
+ "matches",
156
+ (query, node, source.into_value()),
157
+ )))
158
+ }
159
+ }
160
+
161
+ pub fn set_byte_range(
162
+ _ruby: &Ruby,
163
+ rb_self: typed_data::Obj<Self>,
164
+ range: magnus::Range,
165
+ ) -> Result<typed_data::Obj<Self>, Error> {
166
+ let mut cursor = rb_self.raw_cursor.borrow_mut();
167
+ let len = range.funcall("size", ())?;
168
+ let std_range = range.to_range_with_len(len)?;
169
+ cursor.set_byte_range(std_range);
170
+ Ok(rb_self)
171
+ }
172
+
173
+ pub fn set_point_range(
174
+ _ruby: &Ruby,
175
+ rb_self: typed_data::Obj<Self>,
176
+ range: magnus::Range,
177
+ ) -> Result<typed_data::Obj<Self>, Error> {
178
+ let excl = range.excl();
179
+
180
+ if excl {
181
+ return Err(build_error("Point range must be inclusive"));
182
+ }
183
+
184
+ let start: Value = range.beg()?;
185
+ let end: Value = range.end()?;
186
+
187
+ let start_typed_data = RTypedData::from_value(start).expect("Expected typed data");
188
+ let start = start_typed_data.get::<Point>()?;
189
+
190
+ let end_typed_data = RTypedData::from_value(end).expect("Expected typed data");
191
+ let end = end_typed_data.get::<Point>()?;
192
+
193
+ let point_range = start.into_raw()..end.into_raw();
194
+
195
+ let mut cursor = rb_self.raw_cursor.borrow_mut();
196
+ cursor.set_point_range(point_range);
197
+ Ok(rb_self)
198
+ }
199
+
200
+ pub fn set_max_start_depth(
201
+ _ruby: &Ruby,
202
+ rb_self: typed_data::Obj<Self>,
203
+ depth: Option<u32>,
204
+ ) -> Result<typed_data::Obj<Self>, Error> {
205
+ let mut cursor = rb_self.raw_cursor.borrow_mut();
206
+ cursor.set_max_start_depth(depth);
207
+ Ok(rb_self)
208
+ }
209
+ }