tree_sitter 0.0.1

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.
@@ -0,0 +1,152 @@
1
+ use libloading::{Library, Symbol};
2
+ use magnus::{Error, Ruby};
3
+ use once_cell::sync::Lazy;
4
+ use std::collections::HashMap;
5
+ use std::sync::RwLock;
6
+ use tree_sitter_language::LanguageFn;
7
+
8
+ // Global registry of loaded languages
9
+ static LANGUAGES: Lazy<RwLock<HashMap<String, LoadedLanguage>>> =
10
+ Lazy::new(|| RwLock::new(HashMap::new()));
11
+
12
+ struct LoadedLanguage {
13
+ language: tree_sitter::Language,
14
+ #[allow(dead_code)]
15
+ library: Library, // Keep library alive!
16
+ }
17
+
18
+ // Safety: tree_sitter::Language is thread-safe
19
+ unsafe impl Send for LoadedLanguage {}
20
+ unsafe impl Sync for LoadedLanguage {}
21
+
22
+ /// Register a language from a shared library path
23
+ pub fn register_language(name: String, library_path: String) -> Result<(), Error> {
24
+ let ruby = Ruby::get().unwrap();
25
+
26
+ // Load the shared library
27
+ let library = unsafe { Library::new(&library_path) }.map_err(|e| {
28
+ Error::new(
29
+ ruby.exception_runtime_error(),
30
+ format!("Failed to load library '{}': {}", library_path, e),
31
+ )
32
+ })?;
33
+
34
+ // The symbol name follows tree-sitter convention: tree_sitter_{language}
35
+ let symbol_name = format!("tree_sitter_{}", name);
36
+ let language_fn: Symbol<LanguageFn> =
37
+ unsafe { library.get(symbol_name.as_bytes()) }.map_err(|e| {
38
+ Error::new(
39
+ ruby.exception_runtime_error(),
40
+ format!(
41
+ "Failed to find symbol '{}' in '{}': {}",
42
+ symbol_name, library_path, e
43
+ ),
44
+ )
45
+ })?;
46
+
47
+ let language: tree_sitter::Language = (*language_fn).into();
48
+
49
+ // Store language function in registry
50
+ let mut registry = LANGUAGES.write().map_err(|_| {
51
+ Error::new(
52
+ ruby.exception_runtime_error(),
53
+ "Failed to acquire language registry lock",
54
+ )
55
+ })?;
56
+
57
+ registry.insert(name, LoadedLanguage { language, library });
58
+
59
+ Ok(())
60
+ }
61
+
62
+ /// Get a registered language by name
63
+ pub fn get_language(name: String) -> Result<Language, Error> {
64
+ let ruby = Ruby::get().unwrap();
65
+
66
+ let registry = LANGUAGES.read().map_err(|_| {
67
+ Error::new(
68
+ ruby.exception_runtime_error(),
69
+ "Failed to acquire language registry lock",
70
+ )
71
+ })?;
72
+
73
+ let loaded = registry.get(&name).ok_or_else(|| {
74
+ Error::new(
75
+ ruby.exception_arg_error(),
76
+ format!(
77
+ "Language '{}' not registered. Call TreeSitter.register_language first.",
78
+ name
79
+ ),
80
+ )
81
+ })?;
82
+
83
+ Ok(Language {
84
+ name: name.clone(),
85
+ inner: loaded.language.clone(),
86
+ })
87
+ }
88
+
89
+ /// List all registered language names
90
+ pub fn list_languages() -> Result<Vec<String>, Error> {
91
+ let ruby = Ruby::get().unwrap();
92
+
93
+ let registry = LANGUAGES.read().map_err(|_| {
94
+ Error::new(
95
+ ruby.exception_runtime_error(),
96
+ "Failed to acquire language registry lock",
97
+ )
98
+ })?;
99
+
100
+ Ok(registry.keys().cloned().collect())
101
+ }
102
+
103
+ /// Get a language from the registry (internal use).
104
+ /// Returns the raw `tree_sitter::Language` instead of the wrapped `Language` struct,
105
+ /// avoiding redundant wrapping when callers just need the inner type (e.g., for
106
+ /// `parser.set_language()`). Also takes `&str` to avoid allocation.
107
+ pub fn get_language_internal(name: &str) -> Result<tree_sitter::Language, Error> {
108
+ let ruby = Ruby::get().unwrap();
109
+
110
+ let registry = LANGUAGES.read().map_err(|_| {
111
+ Error::new(
112
+ ruby.exception_runtime_error(),
113
+ "Failed to acquire language registry lock",
114
+ )
115
+ })?;
116
+
117
+ let loaded = registry.get(name).ok_or_else(|| {
118
+ Error::new(
119
+ ruby.exception_arg_error(),
120
+ format!(
121
+ "Language '{}' not registered. Call TreeSitter.register_language first.",
122
+ name
123
+ ),
124
+ )
125
+ })?;
126
+
127
+ Ok(loaded.language.clone())
128
+ }
129
+
130
+ #[magnus::wrap(class = "TreeSitter::Language")]
131
+ #[derive(Clone)]
132
+ pub struct Language {
133
+ pub name: String,
134
+ pub inner: tree_sitter::Language,
135
+ }
136
+
137
+ impl Language {
138
+ pub fn name(&self) -> &str {
139
+ &self.name
140
+ }
141
+
142
+ pub fn version(&self) -> usize {
143
+ self.inner.abi_version()
144
+ }
145
+
146
+ /// Returns the number of distinct node types (kinds) defined in this language's grammar.
147
+ /// Each node in a syntax tree has a kind like "function_definition" or "identifier".
148
+ /// Can be useful for allocation or iteration over all kinds.
149
+ pub fn node_kind_count(&self) -> usize {
150
+ self.inner.node_kind_count()
151
+ }
152
+ }
@@ -0,0 +1,140 @@
1
+ mod language;
2
+ mod node;
3
+ mod parser;
4
+ mod point;
5
+ mod query;
6
+ mod range;
7
+ mod tree;
8
+
9
+ use magnus::{function, method, prelude::*, Error, Ruby};
10
+
11
+ #[magnus::init]
12
+ fn init(ruby: &Ruby) -> Result<(), Error> {
13
+ let module = ruby.define_module("TreeSitter")?;
14
+
15
+ module.define_singleton_method(
16
+ "register_language",
17
+ function!(language::register_language, 2),
18
+ )?;
19
+ module.define_singleton_method("language", function!(language::get_language, 1))?;
20
+ module.define_singleton_method("languages", function!(language::list_languages, 0))?;
21
+
22
+ let language_class = module.define_class("Language", ruby.class_object())?;
23
+ language_class.define_method("name", method!(language::Language::name, 0))?;
24
+ language_class.define_method("version", method!(language::Language::version, 0))?;
25
+ language_class.define_method(
26
+ "node_kind_count",
27
+ method!(language::Language::node_kind_count, 0),
28
+ )?;
29
+
30
+ let parser_class = module.define_class("Parser", ruby.class_object())?;
31
+ parser_class.define_singleton_method("new", function!(parser::Parser::new, 0))?;
32
+ parser_class.define_method("language=", method!(parser::Parser::set_language, 1))?;
33
+ parser_class.define_method("language", method!(parser::Parser::language, 0))?;
34
+ parser_class.define_method("parse", method!(parser::Parser::parse, -1))?;
35
+ parser_class.define_method("timeout_micros", method!(parser::Parser::timeout_micros, 0))?;
36
+ parser_class.define_method(
37
+ "timeout_micros=",
38
+ method!(parser::Parser::set_timeout_micros, 1),
39
+ )?;
40
+ parser_class.define_method("reset", method!(parser::Parser::reset, 0))?;
41
+
42
+ let tree_class = module.define_class("Tree", ruby.class_object())?;
43
+ tree_class.define_method("root_node", method!(tree::Tree::root_node, 0))?;
44
+ tree_class.define_method("source", method!(tree::Tree::source, 0))?;
45
+ tree_class.define_method("language", method!(tree::Tree::language, 0))?;
46
+
47
+ let node_class = module.define_class("Node", ruby.class_object())?;
48
+
49
+ // Navigation
50
+ node_class.define_method("parent", method!(node::Node::parent, 0))?;
51
+ node_class.define_method("child", method!(node::Node::child, 1))?;
52
+ node_class.define_method("child_count", method!(node::Node::child_count, 0))?;
53
+ node_class.define_method("named_child", method!(node::Node::named_child, 1))?;
54
+ node_class.define_method(
55
+ "named_child_count",
56
+ method!(node::Node::named_child_count, 0),
57
+ )?;
58
+ node_class.define_method(
59
+ "child_by_field_name",
60
+ method!(node::Node::child_by_field_name, 1),
61
+ )?;
62
+ node_class.define_method("children", method!(node::Node::children, 0))?;
63
+ node_class.define_method("named_children", method!(node::Node::named_children, 0))?;
64
+ node_class.define_method("next_sibling", method!(node::Node::next_sibling, 0))?;
65
+ node_class.define_method("prev_sibling", method!(node::Node::prev_sibling, 0))?;
66
+ node_class.define_method(
67
+ "next_named_sibling",
68
+ method!(node::Node::next_named_sibling, 0),
69
+ )?;
70
+ node_class.define_method(
71
+ "prev_named_sibling",
72
+ method!(node::Node::prev_named_sibling, 0),
73
+ )?;
74
+
75
+ // Properties
76
+ node_class.define_method("kind", method!(node::Node::kind, 0))?;
77
+ node_class.define_method("type", method!(node::Node::kind, 0))?; // Alias
78
+ node_class.define_method("kind_id", method!(node::Node::kind_id, 0))?;
79
+ node_class.define_method("named?", method!(node::Node::is_named, 0))?;
80
+ node_class.define_method("missing?", method!(node::Node::is_missing, 0))?;
81
+ node_class.define_method("extra?", method!(node::Node::is_extra, 0))?;
82
+ node_class.define_method("error?", method!(node::Node::is_error, 0))?;
83
+ node_class.define_method("has_error?", method!(node::Node::has_error, 0))?;
84
+ node_class.define_method("has_changes?", method!(node::Node::has_changes, 0))?;
85
+
86
+ // Position
87
+ node_class.define_method("start_byte", method!(node::Node::start_byte, 0))?;
88
+ node_class.define_method("end_byte", method!(node::Node::end_byte, 0))?;
89
+ node_class.define_method("start_point", method!(node::Node::start_point, 0))?;
90
+ node_class.define_method("end_point", method!(node::Node::end_point, 0))?;
91
+ node_class.define_method("range", method!(node::Node::range, 0))?;
92
+
93
+ // Text
94
+ node_class.define_method("text", method!(node::Node::text, 0))?;
95
+ node_class.define_method("to_sexp", method!(node::Node::to_sexp, 0))?;
96
+ node_class.define_method("to_s", method!(node::Node::to_sexp, 0))?;
97
+ node_class.define_method("inspect", method!(node::Node::inspect, 0))?;
98
+ node_class.define_method("==", method!(node::Node::eq, 1))?;
99
+ node_class.define_method("eql?", method!(node::Node::eq, 1))?;
100
+
101
+ let point_class = module.define_class("Point", ruby.class_object())?;
102
+ point_class.define_singleton_method("new", function!(point::Point::new, 2))?;
103
+ point_class.define_method("row", method!(point::Point::row, 0))?;
104
+ point_class.define_method("column", method!(point::Point::column, 0))?;
105
+ point_class.define_method("to_a", method!(point::Point::to_a, 0))?;
106
+ point_class.define_method("inspect", method!(point::Point::inspect, 0))?;
107
+ point_class.define_method("==", method!(point::Point::eq, 1))?;
108
+
109
+ // Range class
110
+ let range_class = module.define_class("Range", ruby.class_object())?;
111
+ range_class.define_method("start_byte", method!(range::Range::start_byte, 0))?;
112
+ range_class.define_method("end_byte", method!(range::Range::end_byte, 0))?;
113
+ range_class.define_method("start_point", method!(range::Range::start_point, 0))?;
114
+ range_class.define_method("end_point", method!(range::Range::end_point, 0))?;
115
+ range_class.define_method("size", method!(range::Range::size, 0))?;
116
+ range_class.define_method("inspect", method!(range::Range::inspect, 0))?;
117
+
118
+ let query_class = module.define_class("Query", ruby.class_object())?;
119
+ query_class.define_singleton_method("new", function!(query::Query::new, 2))?;
120
+ query_class.define_method("capture_names", method!(query::Query::capture_names, 0))?;
121
+ query_class.define_method("pattern_count", method!(query::Query::pattern_count, 0))?;
122
+
123
+ let cursor_class = module.define_class("QueryCursor", ruby.class_object())?;
124
+ cursor_class.define_singleton_method("new", function!(query::QueryCursor::new, 0))?;
125
+ cursor_class.define_method("matches", method!(query::QueryCursor::matches, 3))?;
126
+ cursor_class.define_method("captures", method!(query::QueryCursor::captures, 3))?;
127
+
128
+ let match_class = module.define_class("QueryMatch", ruby.class_object())?;
129
+ match_class.define_method(
130
+ "pattern_index",
131
+ method!(query::QueryMatch::pattern_index, 0),
132
+ )?;
133
+ match_class.define_method("captures", method!(query::QueryMatch::captures, 0))?;
134
+
135
+ let capture_class = module.define_class("QueryCapture", ruby.class_object())?;
136
+ capture_class.define_method("name", method!(query::QueryCapture::name, 0))?;
137
+ capture_class.define_method("node", method!(query::QueryCapture::node, 0))?;
138
+
139
+ Ok(())
140
+ }
@@ -0,0 +1,248 @@
1
+ use crate::point::Point;
2
+ use crate::range::Range;
3
+ use magnus::{RArray, Ruby};
4
+ use std::sync::Arc;
5
+
6
+ /// Node wrapper that stores both the node data and a reference to the tree
7
+ /// This allows child navigation while keeping the tree alive
8
+ #[magnus::wrap(class = "TreeSitter::Node")]
9
+ #[derive(Clone)]
10
+ pub struct Node {
11
+ // Store the tree to keep nodes valid (public for query.rs)
12
+ pub tree: Arc<tree_sitter::Tree>,
13
+
14
+ // Source text for text extraction (public for query.rs)
15
+ pub source: Arc<String>,
16
+
17
+ // Node identification via byte range (used to relocate node in tree)
18
+ start_byte: usize,
19
+ end_byte: usize,
20
+
21
+ // Cached properties
22
+ kind: String,
23
+ kind_id: u16,
24
+ is_named: bool,
25
+ is_missing: bool,
26
+ is_extra: bool,
27
+ is_error: bool,
28
+ has_error: bool,
29
+ has_changes: bool,
30
+ start_point: Point,
31
+ end_point: Point,
32
+ child_count: usize,
33
+ named_child_count: usize,
34
+ sexp: String,
35
+ }
36
+
37
+ impl Node {
38
+ pub fn new(ts_node: tree_sitter::Node, source: Arc<String>, tree: Arc<tree_sitter::Tree>) -> Self {
39
+ Self {
40
+ tree,
41
+ source,
42
+ start_byte: ts_node.start_byte(),
43
+ end_byte: ts_node.end_byte(),
44
+ kind: ts_node.kind().to_string(),
45
+ kind_id: ts_node.kind_id(),
46
+ is_named: ts_node.is_named(),
47
+ is_missing: ts_node.is_missing(),
48
+ is_extra: ts_node.is_extra(),
49
+ is_error: ts_node.is_error(),
50
+ has_error: ts_node.has_error(),
51
+ has_changes: ts_node.has_changes(),
52
+ start_point: Point::from_ts(ts_node.start_position()),
53
+ end_point: Point::from_ts(ts_node.end_position()),
54
+ child_count: ts_node.child_count(),
55
+ named_child_count: ts_node.named_child_count(),
56
+ sexp: ts_node.to_sexp(),
57
+ }
58
+ }
59
+
60
+ /// Relocate the tree-sitter node from the stored tree
61
+ fn get_ts_node(&self) -> Option<tree_sitter::Node<'_>> {
62
+ let root = self.tree.root_node();
63
+ root.descendant_for_byte_range(self.start_byte, self.end_byte)
64
+ }
65
+
66
+ /// Public method for query.rs to access the tree-sitter node
67
+ pub fn get_ts_node_pub(&self) -> Option<tree_sitter::Node<'_>> {
68
+ let root = self.tree.root_node();
69
+ root.descendant_for_byte_range(self.start_byte, self.end_byte)
70
+ }
71
+
72
+ // Navigation methods
73
+
74
+ pub fn parent(&self) -> Option<Node> {
75
+ let ts_node = self.get_ts_node()?;
76
+ ts_node
77
+ .parent()
78
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
79
+ }
80
+
81
+ pub fn child(&self, index: usize) -> Option<Node> {
82
+ let ts_node = self.get_ts_node()?;
83
+ ts_node
84
+ .child(index)
85
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
86
+ }
87
+
88
+ pub fn child_count(&self) -> usize {
89
+ self.child_count
90
+ }
91
+
92
+ pub fn named_child(&self, index: usize) -> Option<Node> {
93
+ let ts_node = self.get_ts_node()?;
94
+ ts_node
95
+ .named_child(index)
96
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
97
+ }
98
+
99
+ pub fn named_child_count(&self) -> usize {
100
+ self.named_child_count
101
+ }
102
+
103
+ pub fn child_by_field_name(&self, name: String) -> Option<Node> {
104
+ let ts_node = self.get_ts_node()?;
105
+ ts_node
106
+ .child_by_field_name(&name)
107
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
108
+ }
109
+
110
+ pub fn children(&self) -> RArray {
111
+ let ruby = Ruby::get().unwrap();
112
+ let array = ruby.ary_new();
113
+ let Some(ts_node) = self.get_ts_node() else {
114
+ return array;
115
+ };
116
+ let mut cursor = ts_node.walk();
117
+ for n in ts_node.children(&mut cursor) {
118
+ let _ = array.push(Node::new(n, self.source.clone(), self.tree.clone()));
119
+ }
120
+ array
121
+ }
122
+
123
+ pub fn named_children(&self) -> RArray {
124
+ let ruby = Ruby::get().unwrap();
125
+ let array = ruby.ary_new();
126
+ let Some(ts_node) = self.get_ts_node() else {
127
+ return array;
128
+ };
129
+ let mut cursor = ts_node.walk();
130
+ for n in ts_node.named_children(&mut cursor) {
131
+ let _ = array.push(Node::new(n, self.source.clone(), self.tree.clone()));
132
+ }
133
+ array
134
+ }
135
+
136
+ pub fn next_sibling(&self) -> Option<Node> {
137
+ let ts_node = self.get_ts_node()?;
138
+ ts_node
139
+ .next_sibling()
140
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
141
+ }
142
+
143
+ pub fn prev_sibling(&self) -> Option<Node> {
144
+ let ts_node = self.get_ts_node()?;
145
+ ts_node
146
+ .prev_sibling()
147
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
148
+ }
149
+
150
+ pub fn next_named_sibling(&self) -> Option<Node> {
151
+ let ts_node = self.get_ts_node()?;
152
+ ts_node
153
+ .next_named_sibling()
154
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
155
+ }
156
+
157
+ pub fn prev_named_sibling(&self) -> Option<Node> {
158
+ let ts_node = self.get_ts_node()?;
159
+ ts_node
160
+ .prev_named_sibling()
161
+ .map(|n| Node::new(n, self.source.clone(), self.tree.clone()))
162
+ }
163
+
164
+ // Properties
165
+ pub fn kind(&self) -> &str {
166
+ &self.kind
167
+ }
168
+
169
+ pub fn kind_id(&self) -> u16 {
170
+ self.kind_id
171
+ }
172
+
173
+ pub fn is_named(&self) -> bool {
174
+ self.is_named
175
+ }
176
+
177
+ pub fn is_missing(&self) -> bool {
178
+ self.is_missing
179
+ }
180
+
181
+ pub fn is_extra(&self) -> bool {
182
+ self.is_extra
183
+ }
184
+
185
+ pub fn is_error(&self) -> bool {
186
+ self.is_error
187
+ }
188
+
189
+ pub fn has_error(&self) -> bool {
190
+ self.has_error
191
+ }
192
+
193
+ pub fn has_changes(&self) -> bool {
194
+ self.has_changes
195
+ }
196
+
197
+ // Position
198
+ pub fn start_byte(&self) -> usize {
199
+ self.start_byte
200
+ }
201
+
202
+ pub fn end_byte(&self) -> usize {
203
+ self.end_byte
204
+ }
205
+
206
+ pub fn start_point(&self) -> Point {
207
+ self.start_point.clone()
208
+ }
209
+
210
+ pub fn end_point(&self) -> Point {
211
+ self.end_point.clone()
212
+ }
213
+
214
+ pub fn range(&self) -> Range {
215
+ Range::new(
216
+ self.start_byte,
217
+ self.end_byte,
218
+ self.start_point.clone(),
219
+ self.end_point.clone(),
220
+ )
221
+ }
222
+
223
+ // Text
224
+ pub fn text(&self) -> &str {
225
+ if self.end_byte <= self.source.len() {
226
+ &self.source[self.start_byte..self.end_byte]
227
+ } else {
228
+ ""
229
+ }
230
+ }
231
+
232
+ pub fn to_sexp(&self) -> &str {
233
+ &self.sexp
234
+ }
235
+
236
+ pub fn inspect(&self) -> String {
237
+ format!(
238
+ "#<TreeSitter::Node kind={:?} start_byte={} end_byte={}>",
239
+ self.kind, self.start_byte, self.end_byte
240
+ )
241
+ }
242
+
243
+ pub fn eq(&self, other: &Node) -> bool {
244
+ self.start_byte == other.start_byte
245
+ && self.end_byte == other.end_byte
246
+ && self.kind == other.kind
247
+ }
248
+ }
@@ -0,0 +1,126 @@
1
+ use crate::language::{get_language_internal, Language};
2
+ use crate::tree::Tree;
3
+ use magnus::{prelude::*, Error, RString, Ruby, TryConvert, Value};
4
+ use std::cell::RefCell;
5
+ use std::time::Instant;
6
+
7
+ #[magnus::wrap(class = "TreeSitter::Parser")]
8
+ pub struct Parser {
9
+ inner: RefCell<tree_sitter::Parser>,
10
+ language_name: RefCell<Option<String>>,
11
+ timeout_micros: RefCell<u64>,
12
+ }
13
+
14
+ impl Parser {
15
+ pub fn new() -> Result<Self, Error> {
16
+ let parser = tree_sitter::Parser::new();
17
+ Ok(Self {
18
+ inner: RefCell::new(parser),
19
+ language_name: RefCell::new(None),
20
+ timeout_micros: RefCell::new(0),
21
+ })
22
+ }
23
+
24
+ pub fn set_language(&self, lang: Value) -> Result<(), Error> {
25
+ let name: String = if RString::from_value(lang).is_some() {
26
+ <String as TryConvert>::try_convert(lang)?
27
+ } else {
28
+ // Assume it's a Language object?
29
+ let language: &Language = <&Language as TryConvert>::try_convert(lang)?;
30
+ language.name.clone()
31
+ };
32
+
33
+ let ts_language = get_language_internal(&name)?;
34
+
35
+ let ruby = Ruby::get().unwrap();
36
+ let mut parser = self.inner.borrow_mut();
37
+ parser.set_language(&ts_language).map_err(|e| {
38
+ Error::new(
39
+ ruby.exception_runtime_error(),
40
+ format!("Failed to set language: {}", e),
41
+ )
42
+ })?;
43
+
44
+ *self.language_name.borrow_mut() = Some(name);
45
+ Ok(())
46
+ }
47
+
48
+ pub fn language(&self) -> Result<Option<Language>, Error> {
49
+ let name = self.language_name.borrow();
50
+ match &*name {
51
+ Some(n) => {
52
+ let ts_lang = get_language_internal(n)?;
53
+ Ok(Some(Language {
54
+ name: n.clone(),
55
+ inner: ts_lang,
56
+ }))
57
+ }
58
+ None => Ok(None),
59
+ }
60
+ }
61
+
62
+ pub fn parse(&self, args: &[Value]) -> Result<Option<Tree>, Error> {
63
+ let ruby = Ruby::get().unwrap();
64
+
65
+ if args.is_empty() {
66
+ return Err(Error::new(
67
+ ruby.exception_arg_error(),
68
+ "wrong number of arguments",
69
+ ));
70
+ }
71
+
72
+ let source: String = <String as TryConvert>::try_convert(args[0])?;
73
+ let old_tree: Option<&Tree> = if args.len() > 1 && !args[1].is_nil() {
74
+ Some(<&Tree as TryConvert>::try_convert(args[1])?)
75
+ } else {
76
+ None
77
+ };
78
+
79
+ let language_name = self.language_name.borrow().clone().ok_or_else(|| {
80
+ Error::new(
81
+ ruby.exception_runtime_error(),
82
+ "No language set. Call `parser.language = 'name'` first.",
83
+ )
84
+ })?;
85
+
86
+ let mut parser = self.inner.borrow_mut();
87
+ let old_ts_tree = old_tree.map(|t| (*t.inner).clone());
88
+
89
+ let timeout = *self.timeout_micros.borrow();
90
+ let result = if timeout > 0 {
91
+ let start = Instant::now();
92
+ let source_bytes = source.as_bytes();
93
+ let mut progress_callback =
94
+ |_: &tree_sitter::ParseState| start.elapsed().as_micros() < timeout as u128;
95
+ let options =
96
+ tree_sitter::ParseOptions::new().progress_callback(&mut progress_callback);
97
+ let mut source_callback = |offset: usize, _: tree_sitter::Point| {
98
+ if offset < source_bytes.len() {
99
+ &source_bytes[offset..]
100
+ } else {
101
+ &[]
102
+ }
103
+ };
104
+ parser.parse_with_options(&mut source_callback, old_ts_tree.as_ref(), Some(options))
105
+ } else {
106
+ parser.parse(&source, old_ts_tree.as_ref())
107
+ };
108
+
109
+ match result {
110
+ Some(tree) => Ok(Some(Tree::new(tree, source, language_name))),
111
+ None => Ok(None),
112
+ }
113
+ }
114
+
115
+ pub fn timeout_micros(&self) -> u64 {
116
+ *self.timeout_micros.borrow()
117
+ }
118
+
119
+ pub fn set_timeout_micros(&self, timeout: u64) {
120
+ *self.timeout_micros.borrow_mut() = timeout;
121
+ }
122
+
123
+ pub fn reset(&self) {
124
+ self.inner.borrow_mut().reset();
125
+ }
126
+ }