chore(rust): make Query extra predicates state fully immutable
This commit is contained in:
parent
74e77b10c1
commit
52f7eaff31
6 changed files with 96 additions and 78 deletions
|
|
@ -828,8 +828,8 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
let mut all_highlight_names = self.highlight_names.lock().unwrap();
|
||||
if self.use_all_highlight_names {
|
||||
for capture_name in result.query.capture_names() {
|
||||
if !all_highlight_names.contains(capture_name) {
|
||||
all_highlight_names.push(capture_name.clone());
|
||||
if !all_highlight_names.iter().any(|x| x == capture_name) {
|
||||
all_highlight_names.push(capture_name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ fn format_captures<'a>(
|
|||
captures
|
||||
.map(|capture| {
|
||||
(
|
||||
query.capture_names()[capture.index as usize].as_str(),
|
||||
query.capture_names()[capture.index as usize],
|
||||
capture.node.utf8_text(source.as_bytes()).unwrap(),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2269,7 +2269,7 @@ fn test_query_captures_within_byte_range_assigned_after_iterating() {
|
|||
for (mat, capture_ix) in captures.by_ref().take(5) {
|
||||
let capture = mat.captures[capture_ix as usize];
|
||||
results.push((
|
||||
query.capture_names()[capture.index as usize].as_str(),
|
||||
query.capture_names()[capture.index as usize],
|
||||
&source[capture.node.byte_range()],
|
||||
));
|
||||
}
|
||||
|
|
@ -2292,7 +2292,7 @@ fn test_query_captures_within_byte_range_assigned_after_iterating() {
|
|||
for (mat, capture_ix) in captures {
|
||||
let capture = mat.captures[capture_ix as usize];
|
||||
results.push((
|
||||
query.capture_names()[capture.index as usize].as_str(),
|
||||
query.capture_names()[capture.index as usize],
|
||||
&source[capture.node.byte_range()],
|
||||
));
|
||||
}
|
||||
|
|
@ -2533,7 +2533,7 @@ fn test_query_matches_with_captured_wildcard_at_root() {
|
|||
.iter()
|
||||
.map(|c| {
|
||||
(
|
||||
query.capture_names()[c.index as usize].as_str(),
|
||||
query.capture_names()[c.index as usize],
|
||||
c.node.kind(),
|
||||
c.node.start_position().row,
|
||||
)
|
||||
|
|
@ -2934,7 +2934,8 @@ fn test_query_captures_with_predicates() {
|
|||
args: vec![
|
||||
QueryPredicateArg::Capture(0),
|
||||
QueryPredicateArg::String("omg".to_string().into_boxed_str()),
|
||||
],
|
||||
]
|
||||
.into_boxed_slice(),
|
||||
},]
|
||||
);
|
||||
assert_eq!(query.property_settings(1), &[]);
|
||||
|
|
@ -3826,7 +3827,7 @@ fn test_query_random() {
|
|||
captures: mat
|
||||
.captures
|
||||
.iter()
|
||||
.map(|c| (query.capture_names()[c.index as usize].as_str(), c.node))
|
||||
.map(|c| (query.capture_names()[c.index as usize], c.node))
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ impl HighlightConfiguration {
|
|||
let mut local_scope_capture_index = None;
|
||||
for (i, name) in query.capture_names().iter().enumerate() {
|
||||
let i = Some(i as u32);
|
||||
match name.as_str() {
|
||||
match *name {
|
||||
"injection.content" => injection_content_capture_index = i,
|
||||
"injection.language" => injection_language_capture_index = i,
|
||||
"local.definition" => local_def_capture_index = i,
|
||||
|
|
@ -353,7 +353,7 @@ impl HighlightConfiguration {
|
|||
}
|
||||
|
||||
/// Get a slice containing all of the highlight names used in the configuration.
|
||||
pub fn names(&self) -> &[String] {
|
||||
pub fn names(&self) -> &[&str] {
|
||||
self.query.capture_names()
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +399,7 @@ impl HighlightConfiguration {
|
|||
// Return the list of this configuration's capture names that are neither present in the
|
||||
// list of predefined 'canonical' names nor start with an underscore (denoting 'private' captures
|
||||
// used as part of capture internals).
|
||||
pub fn nonconformant_capture_names(&self, capture_names: &HashSet<&str>) -> Vec<&String> {
|
||||
pub fn nonconformant_capture_names(&self, capture_names: &HashSet<&str>) -> Vec<&str> {
|
||||
let capture_names = if capture_names.is_empty() {
|
||||
&*STANDARD_CAPTURE_NAMES
|
||||
} else {
|
||||
|
|
@ -407,7 +407,8 @@ impl HighlightConfiguration {
|
|||
};
|
||||
self.names()
|
||||
.iter()
|
||||
.filter(|&n| !(n.starts_with('_') || capture_names.contains(n.as_str())))
|
||||
.filter(|&n| !(n.starts_with('_') || capture_names.contains(n)))
|
||||
.map(|n| *n)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,12 +116,12 @@ pub struct TreeCursor<'cursor>(ffi::TSTreeCursor, PhantomData<&'cursor ()>);
|
|||
#[derive(Debug)]
|
||||
pub struct Query {
|
||||
ptr: NonNull<ffi::TSQuery>,
|
||||
capture_names: Vec<String>,
|
||||
capture_quantifiers: Vec<Vec<CaptureQuantifier>>,
|
||||
text_predicates: Vec<Box<[TextPredicateCapture]>>,
|
||||
property_settings: Vec<Box<[QueryProperty]>>,
|
||||
property_predicates: Vec<Box<[(QueryProperty, bool)]>>,
|
||||
general_predicates: Vec<Box<[QueryPredicate]>>,
|
||||
capture_names: Box<[&'static str]>,
|
||||
capture_quantifiers: Box<[Box<[CaptureQuantifier]>]>,
|
||||
text_predicates: Box<[Box<[TextPredicateCapture]>]>,
|
||||
property_settings: Box<[Box<[QueryProperty]>]>,
|
||||
property_predicates: Box<[Box<[(QueryProperty, bool)]>]>,
|
||||
general_predicates: Box<[Box<[QueryPredicate]>]>,
|
||||
}
|
||||
|
||||
/// A quantifier for captures
|
||||
|
|
@ -171,7 +171,7 @@ pub enum QueryPredicateArg {
|
|||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct QueryPredicate {
|
||||
pub operator: Box<str>,
|
||||
pub args: Vec<QueryPredicateArg>,
|
||||
pub args: Box<[QueryPredicateArg]>,
|
||||
}
|
||||
|
||||
/// A match of a [`Query`] to a particular set of [`Node`]s.
|
||||
|
|
@ -256,10 +256,10 @@ pub enum QueryErrorKind {
|
|||
/// The last item is a bool signifying whether or not it's meant to match
|
||||
/// any or all captures
|
||||
enum TextPredicateCapture {
|
||||
EqString(u32, String, bool, bool),
|
||||
EqString(u32, Box<str>, bool, bool),
|
||||
EqCapture(u32, u32, bool, bool),
|
||||
MatchString(u32, regex::bytes::Regex, bool, bool),
|
||||
AnyString(u32, Vec<String>, bool),
|
||||
AnyString(u32, Box<[Box<str>]>, bool),
|
||||
}
|
||||
|
||||
// TODO: Remove this struct at at some point. If `core::str::lossy::Utf8Lossy`
|
||||
|
|
@ -1643,29 +1643,37 @@ impl Query {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe fn from_raw_parts(ptr: *mut ffi::TSQuery, source: &str) -> Result<Query, QueryError> {
|
||||
let string_count = unsafe { ffi::ts_query_string_count(ptr) };
|
||||
let capture_count = unsafe { ffi::ts_query_capture_count(ptr) };
|
||||
let pattern_count = unsafe { ffi::ts_query_pattern_count(ptr) as usize };
|
||||
let mut result = Query {
|
||||
ptr: unsafe { NonNull::new_unchecked(ptr) },
|
||||
capture_names: Vec::with_capacity(capture_count as usize),
|
||||
capture_quantifiers: Vec::with_capacity(pattern_count as usize),
|
||||
text_predicates: Vec::with_capacity(pattern_count),
|
||||
property_predicates: Vec::with_capacity(pattern_count),
|
||||
property_settings: Vec::with_capacity(pattern_count),
|
||||
general_predicates: Vec::with_capacity(pattern_count),
|
||||
unsafe fn from_raw_parts(ptr: *mut ffi::TSQuery, source: &str) -> Result<Self, QueryError> {
|
||||
let ptr = {
|
||||
struct TSQueryDrop(*mut ffi::TSQuery);
|
||||
impl Drop for TSQueryDrop {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::ts_query_delete(self.0) }
|
||||
}
|
||||
}
|
||||
TSQueryDrop(ptr)
|
||||
};
|
||||
|
||||
let string_count = unsafe { ffi::ts_query_string_count(ptr.0) };
|
||||
let capture_count = unsafe { ffi::ts_query_capture_count(ptr.0) };
|
||||
let pattern_count = unsafe { ffi::ts_query_pattern_count(ptr.0) as usize };
|
||||
|
||||
let mut capture_names = Vec::with_capacity(capture_count as usize);
|
||||
let mut capture_quantifiers_vec = Vec::with_capacity(pattern_count as usize);
|
||||
let mut text_predicates_vec = Vec::with_capacity(pattern_count);
|
||||
let mut property_predicates_vec = Vec::with_capacity(pattern_count);
|
||||
let mut property_settings_vec = Vec::with_capacity(pattern_count);
|
||||
let mut general_predicates_vec = Vec::with_capacity(pattern_count);
|
||||
|
||||
// Build a vector of strings to store the capture names.
|
||||
for i in 0..capture_count {
|
||||
unsafe {
|
||||
let mut length = 0u32;
|
||||
let name =
|
||||
ffi::ts_query_capture_name_for_id(ptr, i, &mut length as *mut u32) as *const u8;
|
||||
let name = ffi::ts_query_capture_name_for_id(ptr.0, i, &mut length as *mut u32)
|
||||
as *const u8;
|
||||
let name = slice::from_raw_parts(name, length as usize);
|
||||
let name = str::from_utf8_unchecked(name);
|
||||
result.capture_names.push(name.to_string());
|
||||
capture_names.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1674,11 +1682,11 @@ impl Query {
|
|||
let mut capture_quantifiers = Vec::with_capacity(capture_count as usize);
|
||||
for j in 0..capture_count {
|
||||
unsafe {
|
||||
let quantifier = ffi::ts_query_capture_quantifier_for_id(ptr, i as u32, j);
|
||||
let quantifier = ffi::ts_query_capture_quantifier_for_id(ptr.0, i as u32, j);
|
||||
capture_quantifiers.push(quantifier.into());
|
||||
}
|
||||
}
|
||||
result.capture_quantifiers.push(capture_quantifiers);
|
||||
capture_quantifiers_vec.push(capture_quantifiers.into());
|
||||
}
|
||||
|
||||
// Build a vector of strings to represent literal values used in predicates.
|
||||
|
|
@ -1686,11 +1694,11 @@ impl Query {
|
|||
.map(|i| unsafe {
|
||||
let mut length = 0u32;
|
||||
let value =
|
||||
ffi::ts_query_string_value_for_id(ptr, i as u32, &mut length as *mut u32)
|
||||
ffi::ts_query_string_value_for_id(ptr.0, i as u32, &mut length as *mut u32)
|
||||
as *const u8;
|
||||
let value = slice::from_raw_parts(value, length as usize);
|
||||
let value = str::from_utf8_unchecked(value);
|
||||
value.to_string()
|
||||
value
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
@ -1699,13 +1707,13 @@ impl Query {
|
|||
let predicate_steps = unsafe {
|
||||
let mut length = 0u32;
|
||||
let raw_predicates =
|
||||
ffi::ts_query_predicates_for_pattern(ptr, i as u32, &mut length as *mut u32);
|
||||
ffi::ts_query_predicates_for_pattern(ptr.0, i as u32, &mut length as *mut u32);
|
||||
(length > 0)
|
||||
.then(|| slice::from_raw_parts(raw_predicates, length as usize))
|
||||
.unwrap_or_default()
|
||||
};
|
||||
|
||||
let byte_offset = unsafe { ffi::ts_query_start_byte_for_pattern(ptr, i as u32) };
|
||||
let byte_offset = unsafe { ffi::ts_query_start_byte_for_pattern(ptr.0, i as u32) };
|
||||
let row = source
|
||||
.char_indices()
|
||||
.take_while(|(i, _)| *i < byte_offset as usize)
|
||||
|
|
@ -1730,14 +1738,14 @@ impl Query {
|
|||
row,
|
||||
format!(
|
||||
"Expected predicate to start with a function name. Got @{}.",
|
||||
result.capture_names[p[0].value_id as usize],
|
||||
capture_names[p[0].value_id as usize],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Build a predicate for each of the known predicate function names.
|
||||
let operator_name = &string_values[p[0].value_id as usize];
|
||||
match operator_name.as_str() {
|
||||
let operator_name = string_values[p[0].value_id as usize];
|
||||
match operator_name {
|
||||
"eq?" | "not-eq?" | "any-eq?" | "any-not-eq?" => {
|
||||
if p.len() != 3 {
|
||||
return Err(predicate_error(
|
||||
|
|
@ -1756,7 +1764,7 @@ impl Query {
|
|||
}
|
||||
|
||||
let is_positive = operator_name == "eq?" || operator_name == "any-eq?";
|
||||
let match_all = match operator_name.as_str() {
|
||||
let match_all = match operator_name {
|
||||
"eq?" | "not-eq?" => true,
|
||||
"any-eq?" | "any-not-eq?" => false,
|
||||
_ => unreachable!(),
|
||||
|
|
@ -1771,7 +1779,7 @@ impl Query {
|
|||
} else {
|
||||
TextPredicateCapture::EqString(
|
||||
p[1].value_id,
|
||||
string_values[p[2].value_id as usize].clone(),
|
||||
string_values[p[2].value_id as usize].to_string().into(),
|
||||
is_positive,
|
||||
match_all,
|
||||
)
|
||||
|
|
@ -1794,13 +1802,13 @@ impl Query {
|
|||
if p[2].type_ == type_capture {
|
||||
return Err(predicate_error(row, format!(
|
||||
"Second argument to #match? predicate must be a literal. Got capture @{}.",
|
||||
result.capture_names[p[2].value_id as usize],
|
||||
capture_names[p[2].value_id as usize],
|
||||
)));
|
||||
}
|
||||
|
||||
let is_positive =
|
||||
operator_name == "match?" || operator_name == "any-match?";
|
||||
let match_all = match operator_name.as_str() {
|
||||
let match_all = match operator_name {
|
||||
"match?" | "not-match?" => true,
|
||||
"any-match?" | "any-not-match?" => false,
|
||||
_ => unreachable!(),
|
||||
|
|
@ -1818,8 +1826,8 @@ impl Query {
|
|||
|
||||
"set!" => property_settings.push(Self::parse_property(
|
||||
row,
|
||||
operator_name,
|
||||
&result.capture_names,
|
||||
&operator_name,
|
||||
&capture_names,
|
||||
&string_values,
|
||||
&p[1..],
|
||||
)?),
|
||||
|
|
@ -1827,8 +1835,8 @@ impl Query {
|
|||
"is?" | "is-not?" => property_predicates.push((
|
||||
Self::parse_property(
|
||||
row,
|
||||
operator_name,
|
||||
&result.capture_names,
|
||||
&operator_name,
|
||||
&capture_names,
|
||||
&string_values,
|
||||
&p[1..],
|
||||
)?,
|
||||
|
|
@ -1855,20 +1863,24 @@ impl Query {
|
|||
if arg.type_ == type_capture {
|
||||
return Err(predicate_error(row, format!(
|
||||
"Arguments to #any-of? predicate must be literals. Got capture @{}.",
|
||||
result.capture_names[arg.value_id as usize],
|
||||
capture_names[arg.value_id as usize],
|
||||
)));
|
||||
}
|
||||
values.push(string_values[arg.value_id as usize].clone());
|
||||
values.push(string_values[arg.value_id as usize]);
|
||||
}
|
||||
text_predicates.push(TextPredicateCapture::AnyString(
|
||||
p[1].value_id,
|
||||
values,
|
||||
values
|
||||
.iter()
|
||||
.map(|x| x.to_string().into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
is_positive,
|
||||
));
|
||||
}
|
||||
|
||||
_ => general_predicates.push(QueryPredicate {
|
||||
operator: operator_name.clone().into_boxed_str(),
|
||||
operator: operator_name.to_string().into(),
|
||||
args: p[1..]
|
||||
.iter()
|
||||
.map(|a| {
|
||||
|
|
@ -1876,7 +1888,7 @@ impl Query {
|
|||
QueryPredicateArg::Capture(a.value_id)
|
||||
} else {
|
||||
QueryPredicateArg::String(
|
||||
string_values[a.value_id as usize].clone().into_boxed_str(),
|
||||
string_values[a.value_id as usize].to_string().into(),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
@ -1885,20 +1897,24 @@ impl Query {
|
|||
}
|
||||
}
|
||||
|
||||
result
|
||||
.text_predicates
|
||||
.push(text_predicates.into_boxed_slice());
|
||||
result
|
||||
.property_predicates
|
||||
.push(property_predicates.into_boxed_slice());
|
||||
result
|
||||
.property_settings
|
||||
.push(property_settings.into_boxed_slice());
|
||||
result
|
||||
.general_predicates
|
||||
.push(general_predicates.into_boxed_slice());
|
||||
text_predicates_vec.push(text_predicates.into());
|
||||
property_predicates_vec.push(property_predicates.into());
|
||||
property_settings_vec.push(property_settings.into());
|
||||
general_predicates_vec.push(general_predicates.into());
|
||||
}
|
||||
|
||||
let result = Query {
|
||||
ptr: unsafe { NonNull::new_unchecked(ptr.0) },
|
||||
capture_names: capture_names.into(),
|
||||
capture_quantifiers: capture_quantifiers_vec.into(),
|
||||
text_predicates: text_predicates_vec.into(),
|
||||
property_predicates: property_predicates_vec.into(),
|
||||
property_settings: property_settings_vec.into(),
|
||||
general_predicates: general_predicates_vec.into(),
|
||||
};
|
||||
|
||||
std::mem::forget(ptr);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
|
@ -1924,7 +1940,7 @@ impl Query {
|
|||
}
|
||||
|
||||
/// Get the names of the captures used in the query.
|
||||
pub fn capture_names(&self) -> &[String] {
|
||||
pub fn capture_names(&self) -> &[&str] {
|
||||
&self.capture_names
|
||||
}
|
||||
|
||||
|
|
@ -1937,7 +1953,7 @@ impl Query {
|
|||
pub fn capture_index_for_name(&self, name: &str) -> Option<u32> {
|
||||
self.capture_names
|
||||
.iter()
|
||||
.position(|n| n == name)
|
||||
.position(|n| *n == name)
|
||||
.map(|ix| ix as u32)
|
||||
}
|
||||
|
||||
|
|
@ -2016,8 +2032,8 @@ impl Query {
|
|||
fn parse_property(
|
||||
row: usize,
|
||||
function_name: &str,
|
||||
capture_names: &[String],
|
||||
string_values: &[String],
|
||||
capture_names: &[&str],
|
||||
string_values: &[&str],
|
||||
args: &[ffi::TSQueryPredicateStep],
|
||||
) -> Result<QueryProperty, QueryError> {
|
||||
if args.len() == 0 || args.len() > 3 {
|
||||
|
|
@ -2050,7 +2066,7 @@ impl Query {
|
|||
} else if key.is_none() {
|
||||
key = Some(&string_values[arg.value_id as usize]);
|
||||
} else if value.is_none() {
|
||||
value = Some(string_values[arg.value_id as usize].as_str());
|
||||
value = Some(string_values[arg.value_id as usize]);
|
||||
} else {
|
||||
return Err(predicate_error(
|
||||
row,
|
||||
|
|
@ -2349,8 +2365,8 @@ impl QueryProperty {
|
|||
pub fn new(key: &str, value: Option<&str>, capture_id: Option<usize>) -> Self {
|
||||
QueryProperty {
|
||||
capture_id,
|
||||
key: key.to_string().into_boxed_str(),
|
||||
value: value.map(|s| s.to_string().into_boxed_str()),
|
||||
key: key.to_string().into(),
|
||||
value: value.map(|s| s.to_string().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ impl TagsConfiguration {
|
|||
let mut local_scope_capture_index = None;
|
||||
let mut local_definition_capture_index = None;
|
||||
for (i, name) in query.capture_names().iter().enumerate() {
|
||||
match name.as_str() {
|
||||
match *name {
|
||||
"" => continue,
|
||||
"name" => name_capture_index = Some(i as u32),
|
||||
"ignore" => ignore_capture_index = Some(i as u32),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue