Fix error when set_included_ranges is called with an invalid range list

This commit is contained in:
Max Brunsfeld 2020-01-17 10:31:28 -08:00
parent de8877db35
commit 9f63139a10
8 changed files with 284 additions and 150 deletions

View file

@ -167,7 +167,22 @@ extern "C" {
#[doc = " The second and third parameters specify the location and length of an array"]
#[doc = " of ranges. The parser does *not* take ownership of these ranges; it copies"]
#[doc = " the data, so it doesn\'t matter how these ranges are allocated."]
pub fn ts_parser_set_included_ranges(self_: *mut TSParser, ranges: *const TSRange, length: u32);
#[doc = ""]
#[doc = " If `length` is zero, then the entire document will be parsed. Otherwise,"]
#[doc = " the given ranges must be ordered from earliest to latest in the document,"]
#[doc = " and they must not overlap. That is, the following must hold for all"]
#[doc = " `i` < `length - 1`:"]
#[doc = ""]
#[doc = " ranges[i].end_byte <= ranges[i + 1].start_byte"]
#[doc = ""]
#[doc = " If this requirement is not satisfied, the operation will fail, the ranges"]
#[doc = " will not be assigned, and this function will return `false`. On success,"]
#[doc = " this function returns `true`"]
pub fn ts_parser_set_included_ranges(
self_: *mut TSParser,
ranges: *const TSRange,
length: u32,
) -> bool;
}
extern "C" {
#[doc = " Get the ranges of text that the parser will include when parsing."]
@ -659,9 +674,11 @@ extern "C" {
) -> *const ::std::os::raw::c_char;
}
extern "C" {
#[doc = " Disable a certain capture within a query. This prevents the capture"]
#[doc = " from being returned in matches, and also avoids any resource usage"]
#[doc = " associated with recording the capture."]
#[doc = " Disable a certain capture within a query."]
#[doc = ""]
#[doc = " This prevents the capture from being returned in matches, and also avoids"]
#[doc = " any resource usage associated with recording the capture. Currently, there"]
#[doc = " is no way to undo this."]
pub fn ts_query_disable_capture(
arg1: *mut TSQuery,
arg2: *const ::std::os::raw::c_char,
@ -669,9 +686,10 @@ extern "C" {
);
}
extern "C" {
#[doc = " Disable a certain pattern within a query. This prevents the pattern"]
#[doc = " from matching and removes most of the overhead associated with the"]
#[doc = " pattern."]
#[doc = " Disable a certain pattern within a query."]
#[doc = ""]
#[doc = " This prevents the pattern from matching and removes most of the overhead"]
#[doc = " associated with the pattern. Currently, there is no way to undo this."]
pub fn ts_query_disable_pattern(arg1: *mut TSQuery, arg2: u32);
}
extern "C" {

View file

@ -142,6 +142,10 @@ pub struct LanguageError {
version: usize,
}
/// An error that occurred in `Parser::set_included_ranges`.
#[derive(Debug, PartialEq, Eq)]
pub struct IncludedRangesError(pub usize);
/// An error that occurred when trying to create a `Query`.
#[derive(Debug, PartialEq, Eq)]
pub enum QueryError {
@ -508,16 +512,41 @@ impl Parser {
/// allows you to parse only a *portion* of a document but still return a syntax
/// tree whose ranges match up with the document as a whole. You can also pass
/// multiple disjoint ranges.
pub fn set_included_ranges(&mut self, ranges: &[Range]) {
///
/// If `ranges` is empty, then the entire document will be parsed. Otherwise,
/// the given ranges must be ordered from earliest to latest in the document,
/// and they must not overlap. That is, the following must hold for all
/// `i` < `length - 1`:
///
/// ranges[i].end_byte <= ranges[i + 1].start_byte
///
/// If this requirement is not satisfied, method will panic.
pub fn set_included_ranges<'a>(
&mut self,
ranges: &'a [Range],
) -> Result<(), IncludedRangesError> {
let ts_ranges: Vec<ffi::TSRange> =
ranges.iter().cloned().map(|range| range.into()).collect();
unsafe {
let result = unsafe {
ffi::ts_parser_set_included_ranges(
self.0.as_ptr(),
ts_ranges.as_ptr(),
ts_ranges.len() as u32,
)
};
if result {
Ok(())
} else {
let mut prev_end_byte = 0;
for (i, range) in ranges.iter().enumerate() {
if range.start_byte < prev_end_byte || range.end_byte < range.start_byte {
return Err(IncludedRangesError(i));
}
prev_end_byte = range.end_byte;
}
Err(IncludedRangesError(0))
}
}
/// Get the parser's current cancellation flag pointer.