feat: add any-of predicate

This commit is contained in:
Amaan Qureshi 2023-07-20 04:41:47 -04:00
parent 8eb92d1c64
commit 458b5de0fc
No known key found for this signature in database
GPG key ID: E67890ADC4227273
2 changed files with 61 additions and 0 deletions

View file

@ -2842,6 +2842,14 @@ fn test_query_captures_with_text_conditions() {
((identifier) @function.builtin
(#eq? @function.builtin "require"))
((identifier) @variable.builtin
(#any-of? @variable.builtin
"arguments"
"module"
"console"
"window"
"document"))
((identifier) @variable
(#not-match? @variable "^(lambda|load)$"))
"#,
@ -2855,6 +2863,9 @@ fn test_query_captures_with_text_conditions() {
lambda
const ab = require('./ab');
new Cd(EF);
document;
module;
console;
";
let mut parser = Parser::new();
@ -2876,6 +2887,12 @@ fn test_query_captures_with_text_conditions() {
("constant", "EF"),
("constructor", "EF"),
("variable", "EF"),
("variable.builtin", "document"),
("variable", "document"),
("variable.builtin", "module"),
("variable", "module"),
("variable.builtin", "console"),
("variable", "console"),
],
);
});

View file

@ -251,6 +251,7 @@ enum TextPredicate {
CaptureEqString(u32, String, bool),
CaptureEqCapture(u32, u32, bool),
CaptureMatchString(u32, regex::bytes::Regex, bool),
CaptureAnyString(u32, Vec<String>, bool),
}
// TODO: Remove this struct at at some point. If `core::str::lossy::Utf8Lossy`
@ -1811,6 +1812,38 @@ impl Query {
operator_name == "is?",
)),
"any-of?" | "not-any-of?" => {
if p.len() < 2 {
return Err(predicate_error(row, format!(
"Wrong number of arguments to #any-of? predicate. Expected at least 1, got {}.",
p.len() - 1
)));
}
if p[1].type_ != type_capture {
return Err(predicate_error(row, format!(
"First argument to #any-of? predicate must be a capture name. Got literal \"{}\".",
string_values[p[1].value_id as usize],
)));
}
let is_positive = operator_name == "any-of?";
let mut values = Vec::new();
for arg in &p[2..] {
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],
)));
}
values.push(string_values[arg.value_id as usize].clone());
}
text_predicates.push(TextPredicate::CaptureAnyString(
p[1].value_id,
values,
is_positive,
));
}
_ => general_predicates.push(QueryPredicate {
operator: operator_name.clone().into_boxed_str(),
args: p[1..]
@ -2265,6 +2298,17 @@ impl<'tree> QueryMatch<'_, 'tree> {
None => true,
}
}
TextPredicate::CaptureAnyString(i, v, is_positive) => {
let node = self.nodes_for_capture_index(*i).next();
match node {
Some(node) => {
let mut text = text_provider.text(node);
let text = node_text1.get_text(&mut text);
v.iter().any(|s| text == s.as_bytes()) == *is_positive
}
None => true,
}
}
})
}
}