Skip to content

Commit 0490c9c

Browse files
committed
Migrate the parser bindings to the progress callback
1 parent 098f04f commit 0490c9c

File tree

1 file changed

+56
-33
lines changed

1 file changed

+56
-33
lines changed

bindings/src/parser.rs

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::cell::Cell;
22
use std::os::raw::c_void;
33
use std::panic::{catch_unwind, AssertUnwindSafe};
44
use std::ptr::NonNull;
5-
use std::time::Duration;
5+
use std::time::{Duration, Instant};
66
use std::{fmt, mem, ptr};
77

88
use regex_cursor::Cursor;
@@ -32,6 +32,7 @@ impl Drop for RawParser {
3232
/// source code.
3333
pub struct Parser {
3434
ptr: NonNull<ParserData>,
35+
timeout: Option<Duration>,
3536
}
3637

3738
impl Parser {
@@ -46,7 +47,7 @@ impl Parser {
4647
}
4748
None => unsafe { ts_parser_new() },
4849
};
49-
Parser { ptr }
50+
Parser { ptr, timeout: None }
5051
}
5152

5253
/// Set the language that the parser should use for parsing.
@@ -55,11 +56,7 @@ impl Parser {
5556
}
5657

5758
pub fn set_timeout(&mut self, duration: Duration) {
58-
// TODO: migrate away from timing and towards the progress API.
59-
#[allow(deprecated)]
60-
unsafe {
61-
ts_parser_set_timeout_micros(self.ptr, duration.as_micros().try_into().unwrap())
62-
}
59+
self.timeout = Some(duration);
6360
}
6461

6562
/// Set the ranges of text that the parser should include when parsing. By default, the parser
@@ -121,9 +118,25 @@ impl Parser {
121118
encoding: InputEncoding::Utf8,
122119
decode: None,
123120
};
121+
122+
let options = if let Some(timeout) = self.timeout {
123+
unsafe extern "C" fn check_timeout(state: NonNull<ParseState>) -> bool {
124+
let &(start, timeout) = state.as_ref().payload.cast().as_ref();
125+
Instant::now().duration_since(start) > timeout
126+
}
127+
128+
let start = Instant::now();
129+
ParseOptions {
130+
payload: Some(NonNull::from(&mut (start, timeout)).cast()),
131+
progress_callback: Some(check_timeout),
132+
}
133+
} else {
134+
ParseOptions::default()
135+
};
136+
124137
unsafe {
125138
let old_tree = old_tree.map(|tree| tree.as_raw());
126-
let new_tree = ts_parser_parse(self.ptr, old_tree, input);
139+
let new_tree = ts_parser_parse_with_options(self.ptr, old_tree, input, options);
127140
new_tree.map(|raw| SyntaxTree::from_raw(raw))
128141
}
129142
}
@@ -190,6 +203,26 @@ pub enum InputEncoding {
190203
Custom,
191204
}
192205

206+
#[repr(C)]
207+
#[derive(Debug)]
208+
pub struct ParseState {
209+
/// The payload passed via `ParseOptions`' `payload` field.
210+
pub payload: NonNull<c_void>,
211+
pub current_byte_offset: u32,
212+
pub has_error: bool,
213+
}
214+
215+
/// A function that accepts the current parser state and returns `true` when the parse should be
216+
/// cancelled.
217+
type ProgressCallback = unsafe extern "C" fn(state: NonNull<ParseState>) -> bool;
218+
219+
#[repr(C)]
220+
#[derive(Debug, Default)]
221+
pub struct ParseOptions {
222+
pub payload: Option<NonNull<c_void>>,
223+
pub progress_callback: Option<ProgressCallback>,
224+
}
225+
193226
extern "C" {
194227
/// Create a new parser
195228
fn ts_parser_new() -> NonNull<ParserData>;
@@ -220,41 +253,31 @@ extern "C" {
220253
count: u32,
221254
) -> bool;
222255

223-
/// Use the parser to parse some source code and create a syntax tree. If you are parsing this
224-
/// document for the first time, pass `NULL` for the `old_tree` parameter. Otherwise, if you
225-
/// have already parsed an earlier version of this document and the document has since been
226-
/// edited, pass the previous syntax tree so that the unchanged parts of it can be reused.
227-
/// This will save time and memory. For this to work correctly, you must have already edited
228-
/// the old syntax tree using the [`ts_tree_edit`] function in a way that exactly matches
229-
/// the source code changes. The [`TSInput`] parameter lets you specify how to read the text.
230-
/// It has the following three fields: 1. [`read`]: A function to retrieve a chunk of text
231-
/// at a given byte offset and (row, column) position. The function should return a pointer
232-
/// to the text and write its length to the [`bytes_read`] pointer. The parser does not
233-
/// take ownership of this buffer; it just borrows it until it has finished reading it. The
234-
/// function should write a zero value to the [`bytes_read`] pointer to indicate the end of the
235-
/// document. 2. [`payload`]: An arbitrary pointer that will be passed to each invocation of
236-
/// the [`read`] function. 3. [`encoding`]: An indication of how the text is encoded. Either
237-
/// `TSInputEncodingUTF8` or `TSInputEncodingUTF16`. This function returns a syntax tree
238-
/// on success, and `NULL` on failure. There are three possible reasons for failure: 1. The
239-
/// parser does not have a language assigned. Check for this using the [`ts_parser_language`]
240-
/// function. 2. Parsing was cancelled due to a timeout that was set by an earlier call to the
241-
/// [`ts_parser_set_timeout_micros`] function. You can resume parsing from where the parser
242-
/// left out by calling [`ts_parser_parse`] again with the same arguments. Or you can start
243-
/// parsing from scratch by first calling [`ts_parser_reset`]. 3. Parsing was cancelled using
244-
/// a cancellation flag that was set by an earlier call to [`ts_parser_set_cancellation_flag`].
245-
/// You can resume parsing from where the parser left out by calling [`ts_parser_parse`] again
246-
/// with the same arguments. [`read`]: TSInput::read [`payload`]: TSInput::payload [`encoding`]:
247-
/// TSInput::encoding [`bytes_read`]: TSInput::read
256+
/*
248257
fn ts_parser_parse(
249258
parser: NonNull<ParserData>,
250259
old_tree: Option<NonNull<SyntaxTreeData>>,
251260
input: ParserInputRaw,
252261
) -> Option<NonNull<SyntaxTreeData>>;
262+
253263
/// Set the maximum duration in microseconds that parsing should be allowed to
254264
/// take before halting.
255265
///
256266
/// If parsing takes longer than this, it will halt early, returning NULL.
257267
/// See [`ts_parser_parse`] for more information.
258268
#[deprecated = "use ts_parser_parse_with_options and pass in a calback instead, this will be removed in 0.26"]
259269
fn ts_parser_set_timeout_micros(self_: NonNull<ParserData>, timeout_micros: u64);
270+
*/
271+
272+
/// User the parser to parse some source code and create a syntax tree, with some options.
273+
///
274+
/// See `ts_parser_parse` for more details.
275+
///
276+
/// See `TSParseOptions` for more details on the options.
277+
fn ts_parser_parse_with_options(
278+
parser: NonNull<ParserData>,
279+
old_tree: Option<NonNull<SyntaxTreeData>>,
280+
input: ParserInputRaw,
281+
parse_options: ParseOptions,
282+
) -> Option<NonNull<SyntaxTreeData>>;
260283
}

0 commit comments

Comments
 (0)