Refactor field filters to share same base parse node
This commit is contained in:
parent
00812bb3a3
commit
7dbd896348
9 changed files with 247 additions and 151 deletions
|
@ -6,21 +6,25 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) {
|
|||
// filters
|
||||
.add(crate::lang::vocabulary::filters::empty_filter())
|
||||
.add(crate::lang::vocabulary::filters::unique_filter()) // accepts .(unique)
|
||||
.add(crate::lang::vocabulary::filters::field_filter()) // accepts any .(something)
|
||||
.add(crate::lang::vocabulary::filters::field_filter_maybe())
|
||||
.add(crate::lang::vocabulary::filters::index_filter())
|
||||
.add(crate::lang::vocabulary::filters::range_filter())
|
||||
.add(crate::lang::vocabulary::filters::field_like_filter())
|
||||
.add(crate::lang::vocabulary::filters::field_re_filter())
|
||||
.add( // accepts any .(.something)
|
||||
crate::lang::vocabulary::filters::field::FieldFilterBlockFactory::new()
|
||||
.push(crate::lang::vocabulary::filters::field::FieldFilterComparisonFactory)
|
||||
.push(crate::lang::vocabulary::filters::field::FieldFilterMaybeFactory)
|
||||
.push(crate::lang::vocabulary::filters::field::FieldLikeFilterFactory)
|
||||
.push(crate::lang::vocabulary::filters::field::FieldRegexFilterFactory)
|
||||
.to_statement_factory()
|
||||
)
|
||||
.add(crate::lang::vocabulary::filters::index_filter())
|
||||
.add(crate::lang::vocabulary::filters::unique_field_filter())
|
||||
.add(crate::lang::vocabulary::filters::nonempty_filter())
|
||||
// sorters
|
||||
.add(crate::lang::vocabulary::sorters::empty_sort())
|
||||
.add(crate::lang::vocabulary::sorters::shuffle_sort()) // accepts ~(shuffle)
|
||||
.add(crate::lang::vocabulary::sorters::shuffle_sort()) // accepts ~(~shuffle)
|
||||
.add(crate::lang::vocabulary::sorters::bliss_sort())
|
||||
.add(crate::lang::vocabulary::sorters::bliss_next_sort())
|
||||
.add(crate::lang::vocabulary::sorters::radio_sort())
|
||||
.add(crate::lang::vocabulary::sorters::field_sort()) // accepts any ~(name)
|
||||
.add(crate::lang::vocabulary::sorters::field_sort()) // accepts any ~(.name)
|
||||
// iter blocks
|
||||
.add(
|
||||
crate::lang::ItemBlockFactory::new()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use super::utility::{assert_comparison_operator, comparison_op};
|
||||
use crate::lang::utility::{assert_token, assert_type, check_is_type, assert_token_raw};
|
||||
use super::super::utility::{assert_comparison_operator, comparison_op};
|
||||
use super::{FieldFilterFactory, FieldFilterPredicate};
|
||||
use crate::lang::utility::{assert_token, assert_type, check_is_type};
|
||||
use crate::lang::LanguageDictionary;
|
||||
use crate::lang::TypePrimitive;
|
||||
use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory};
|
||||
use crate::lang::{RuntimeMsg, SyntaxError};
|
||||
use crate::processing::general::Type;
|
||||
use crate::tokens::Token;
|
||||
|
@ -46,7 +46,7 @@ impl Display for FieldFilter {
|
|||
}
|
||||
}
|
||||
|
||||
impl FilterPredicate for FieldFilter {
|
||||
impl FieldFilterPredicate for FieldFilter {
|
||||
fn matches(&mut self, music_item_lut: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||
let variable = match &self.val {
|
||||
VariableOrValue::Variable(name) => match ctx.variables.get(name)? {
|
||||
|
@ -93,41 +93,33 @@ impl FilterPredicate for FieldFilter {
|
|||
fn reset(&mut self) -> Result<(), RuntimeMsg> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<dyn FieldFilterPredicate + 'static> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldFilterFactory;
|
||||
pub struct FieldFilterComparisonFactory;
|
||||
|
||||
impl FilterFactory<FieldFilter> for FieldFilterFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||
impl FieldFilterFactory<FieldFilter> for FieldFilterComparisonFactory {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool {
|
||||
let tokens_len = tokens.len();
|
||||
(tokens_len >= 3
|
||||
(tokens_len >= 1
|
||||
// .field > variable OR .field < variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_open_angle_bracket() || tokens[2].is_close_angle_bracket()))
|
||||
|| (tokens_len >= 4 // .field >= variable OR .field <= variable OR .field != variable OR .field == variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_open_angle_bracket() || tokens[2].is_close_angle_bracket() || tokens[2].is_equals() || tokens[2].is_exclamation())
|
||||
&& tokens[3].is_equals()
|
||||
&& !(tokens_len > 4 && tokens[4].is_equals())
|
||||
&& (tokens[0].is_open_angle_bracket() || tokens[0].is_close_angle_bracket()))
|
||||
|| (tokens_len >= 2 // .field >= variable OR .field <= variable OR .field != variable OR .field == variable
|
||||
&& (tokens[0].is_open_angle_bracket() || tokens[0].is_close_angle_bracket() || tokens[0].is_equals() || tokens[0].is_exclamation())
|
||||
&& tokens[1].is_equals()
|
||||
&& !(tokens_len > 2 && tokens[2].is_equals())
|
||||
)
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
_dict: &LanguageDictionary,
|
||||
) -> Result<FieldFilter, SyntaxError> {
|
||||
assert_token_raw(Token::Dot, tokens)?;
|
||||
let field = assert_token(
|
||||
|t| match t {
|
||||
Token::Name(n) => Some(n),
|
||||
_ => None,
|
||||
},
|
||||
Token::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
let compare_operator = assert_comparison_operator(tokens)?;
|
||||
if check_is_type(&tokens[0]) {
|
||||
let value = VariableOrValue::Value(assert_type(tokens)?);
|
||||
|
@ -159,10 +151,3 @@ impl FilterFactory<FieldFilter> for FieldFilterFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type FieldFilterStatementFactory = FilterStatementFactory<FieldFilter, FieldFilterFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_filter() -> FieldFilterStatementFactory {
|
||||
FieldFilterStatementFactory::new(FieldFilterFactory)
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory};
|
||||
use crate::tokens::Token;
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::LanguageDictionary;
|
||||
use crate::lang::{RuntimeMsg, SyntaxError};
|
||||
use crate::Context;
|
||||
use crate::Item;
|
||||
|
||||
pub trait FieldFilterFactory<T: FieldFilterPredicate + 'static>: Send + Sync {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool;
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
dict: &LanguageDictionary,
|
||||
) -> Result<T, SyntaxError>;
|
||||
}
|
||||
|
||||
pub trait FieldFilterPredicate: Send + Sync + Debug + Display {
|
||||
fn matches(&mut self, item: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg>;
|
||||
|
||||
fn is_complete(&self) -> bool;
|
||||
|
||||
fn reset(&mut self) -> Result<(), RuntimeMsg>;
|
||||
|
||||
fn box_clone(&self) -> Box<dyn FieldFilterPredicate + 'static>;
|
||||
}
|
||||
|
||||
pub struct FieldFilterFactoryBoxer<T: FieldFilterPredicate + 'static> {
|
||||
inner: Box<dyn FieldFilterFactory<T>>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BoxedFilterPredicate {
|
||||
inner: Box<dyn FieldFilterPredicate + 'static>
|
||||
}
|
||||
|
||||
impl Clone for BoxedFilterPredicate {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.box_clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BoxedFilterPredicate {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
(&self.inner as &dyn Display).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterPredicate for BoxedFilterPredicate {
|
||||
fn matches(&mut self, item: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||
self.inner.matches(item, ctx)
|
||||
}
|
||||
|
||||
fn is_complete(&self) -> bool {
|
||||
self.inner.is_complete()
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<(), RuntimeMsg> {
|
||||
self.inner.reset()
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldFilterPredicate for BoxedFilterPredicate {
|
||||
fn matches(&mut self, item: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||
self.inner.matches(item, ctx)
|
||||
}
|
||||
|
||||
fn is_complete(&self) -> bool {
|
||||
self.inner.is_complete()
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<(), RuntimeMsg> {
|
||||
self.inner.reset()
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<dyn FieldFilterPredicate + 'static> {
|
||||
self.inner.box_clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: FieldFilterPredicate + 'static> FieldFilterFactory<BoxedFilterPredicate> for FieldFilterFactoryBoxer<T> {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool {
|
||||
self.inner.is_filter(tokens)
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
dict: &LanguageDictionary,
|
||||
) -> Result<BoxedFilterPredicate, SyntaxError> {
|
||||
self.inner.build_filter(tokens, field, dict).map(|x| BoxedFilterPredicate { inner: Box::new(x) })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldFilterBlockFactory {
|
||||
field_filters: Vec<Box<dyn FieldFilterFactory<BoxedFilterPredicate>>>,
|
||||
}
|
||||
|
||||
impl FieldFilterBlockFactory {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
field_filters: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push<T: FieldFilterPredicate + 'static, F: FieldFilterFactory<T> + 'static>(mut self, factory: F) -> Self {
|
||||
self.field_filters.push(
|
||||
Box::new(FieldFilterFactoryBoxer { inner: Box::new(factory) })
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_statement_factory(self) -> FieldFilterStatementFactory {
|
||||
FieldFilterStatementFactory::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterFactory<BoxedFilterPredicate> for FieldFilterBlockFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||
tokens.len() > 1 && tokens[0].is_dot()
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
dict: &LanguageDictionary,
|
||||
) -> Result<BoxedFilterPredicate, SyntaxError> {
|
||||
assert_token_raw(Token::Dot, tokens)?;
|
||||
let field = assert_token(
|
||||
|t| match t {
|
||||
Token::Name(n) => Some(n),
|
||||
_ => None,
|
||||
},
|
||||
Token::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
for filter in &self.field_filters {
|
||||
if filter.is_filter(tokens.make_contiguous()) {
|
||||
return filter.build_filter(tokens, field, dict);
|
||||
}
|
||||
}
|
||||
Err(SyntaxError {
|
||||
got: tokens.front().cloned(),
|
||||
token: Token::Name("<comparison op>".into()),
|
||||
line: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub type FieldFilterStatementFactory =
|
||||
FilterStatementFactory<BoxedFilterPredicate, FieldFilterBlockFactory>;
|
|
@ -1,45 +1,34 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use super::utility::assert_comparison_operator;
|
||||
use super::super::utility::assert_comparison_operator;
|
||||
use super::{field_filter::VariableOrValue, FieldFilter, FieldFilterErrorHandling};
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
|
||||
use crate::lang::LanguageDictionary;
|
||||
use crate::lang::SyntaxError;
|
||||
use crate::lang::{FilterFactory, FilterStatementFactory};
|
||||
//use crate::lang::{FilterFactory, FilterStatementFactory};
|
||||
use super::FieldFilterFactory;
|
||||
use crate::tokens::Token;
|
||||
|
||||
pub struct FieldFilterMaybeFactory;
|
||||
|
||||
impl FilterFactory<FieldFilter> for FieldFilterMaybeFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||
impl FieldFilterFactory<FieldFilter> for FieldFilterMaybeFactory {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool {
|
||||
let tokens_len = tokens.len();
|
||||
(tokens_len >= 4 // .field > variable OR .field < variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_interrogation() || tokens[2].is_exclamation())
|
||||
&& (tokens[3].is_open_angle_bracket() || tokens[3].is_close_angle_bracket()))
|
||||
|| (tokens_len >= 5 // .field >= variable OR .field <= variable OR .field != variable OR .field == variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_interrogation() || tokens[2].is_exclamation())
|
||||
&& (tokens[3].is_open_angle_bracket() || tokens[3].is_close_angle_bracket() || tokens[3].is_equals() || tokens[3].is_exclamation())
|
||||
&& tokens[4].is_equals())
|
||||
(tokens_len >= 2 // .field > variable OR .field < variable
|
||||
&& (tokens[0].is_interrogation() || tokens[0].is_exclamation())
|
||||
&& (tokens[1].is_open_angle_bracket() || tokens[1].is_close_angle_bracket()))
|
||||
|| (tokens_len >= 3 // .field >= variable OR .field <= variable OR .field != variable OR .field == variable
|
||||
&& (tokens[0].is_interrogation() || tokens[0].is_exclamation())
|
||||
&& (tokens[1].is_open_angle_bracket() || tokens[1].is_close_angle_bracket() || tokens[1].is_equals() || tokens[1].is_exclamation())
|
||||
&& tokens[2].is_equals())
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
_dict: &LanguageDictionary,
|
||||
) -> Result<FieldFilter, SyntaxError> {
|
||||
assert_token_raw(Token::Dot, tokens)?;
|
||||
let field = assert_token(
|
||||
|t| match t {
|
||||
Token::Name(n) => Some(n),
|
||||
_ => None,
|
||||
},
|
||||
Token::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
let error_f;
|
||||
let error_c;
|
||||
if tokens[0].is_interrogation() {
|
||||
|
@ -82,11 +71,3 @@ impl FilterFactory<FieldFilter> for FieldFilterMaybeFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type FieldFilterMaybeStatementFactory =
|
||||
FilterStatementFactory<FieldFilter, FieldFilterMaybeFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_filter_maybe() -> FieldFilterMaybeStatementFactory {
|
||||
FieldFilterMaybeStatementFactory::new(FieldFilterMaybeFactory)
|
||||
}
|
|
@ -5,7 +5,7 @@ use super::field_filter::{FieldFilterErrorHandling, VariableOrValue};
|
|||
use crate::lang::utility::{assert_token, assert_token_raw, check_name};
|
||||
use crate::lang::LanguageDictionary;
|
||||
use crate::lang::TypePrimitive;
|
||||
use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory};
|
||||
use super::{FieldFilterFactory, FieldFilterPredicate};
|
||||
use crate::lang::{RuntimeMsg, SyntaxError};
|
||||
use crate::processing::general::Type;
|
||||
use crate::tokens::Token;
|
||||
|
@ -22,7 +22,7 @@ pub struct FieldLikeFilter {
|
|||
|
||||
impl FieldLikeFilter {
|
||||
fn sanitise_string(s: &str) -> String {
|
||||
super::utility::sanitise_string(s)
|
||||
super::super::utility::sanitise_string(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ impl Display for FieldLikeFilter {
|
|||
}
|
||||
}
|
||||
|
||||
impl FilterPredicate for FieldLikeFilter {
|
||||
impl FieldFilterPredicate for FieldLikeFilter {
|
||||
fn matches(&mut self, music_item_lut: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||
let variable = match &self.val {
|
||||
VariableOrValue::Variable(name) => match ctx.variables.get(name)? {
|
||||
|
@ -74,38 +74,30 @@ impl FilterPredicate for FieldLikeFilter {
|
|||
fn reset(&mut self) -> Result<(), RuntimeMsg> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<dyn FieldFilterPredicate + 'static> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldLikeFilterFactory;
|
||||
|
||||
impl FilterFactory<FieldLikeFilter> for FieldLikeFilterFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||
impl FieldFilterFactory<FieldLikeFilter> for FieldLikeFilterFactory {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool {
|
||||
let tokens_len = tokens.len();
|
||||
(tokens_len >= 3 // field like variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (check_name("like", tokens[2]) || check_name("unlike", tokens[2])))
|
||||
|| (tokens_len >= 4 // field? like variable OR field! like variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_interrogation() || tokens[2].is_exclamation())
|
||||
&& (check_name("like", tokens[3]) || check_name("unlike", tokens[3])))
|
||||
(tokens_len >= 1 // field like variable
|
||||
&& (check_name("like", &tokens[0]) || check_name("unlike", &tokens[0])))
|
||||
|| (tokens_len >= 2 // field? like variable OR field! like variable
|
||||
&& (tokens[0].is_interrogation() || tokens[0].is_exclamation())
|
||||
&& (check_name("like", &tokens[1]) || check_name("unlike", &tokens[1])))
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
_dict: &LanguageDictionary,
|
||||
) -> Result<FieldLikeFilter, SyntaxError> {
|
||||
assert_token_raw(Token::Dot, tokens)?;
|
||||
let field = assert_token(
|
||||
|t| match t {
|
||||
Token::Name(n) => Some(n),
|
||||
_ => None,
|
||||
},
|
||||
Token::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
let error_handling = if tokens[0].is_interrogation() {
|
||||
assert_token_raw(Token::Interrogation, tokens)?;
|
||||
FieldFilterErrorHandling::Ignore
|
||||
|
@ -164,11 +156,3 @@ impl FilterFactory<FieldLikeFilter> for FieldLikeFilterFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type FieldLikeFilterStatementFactory =
|
||||
FilterStatementFactory<FieldLikeFilter, FieldLikeFilterFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_like_filter() -> FieldLikeFilterStatementFactory {
|
||||
FieldLikeFilterStatementFactory::new(FieldLikeFilterFactory)
|
||||
}
|
|
@ -7,7 +7,7 @@ use super::field_filter::{FieldFilterErrorHandling, VariableOrValue};
|
|||
use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
|
||||
use crate::lang::LanguageDictionary;
|
||||
use crate::lang::TypePrimitive;
|
||||
use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory};
|
||||
use super::{FieldFilterFactory, FieldFilterPredicate};
|
||||
use crate::lang::{RuntimeMsg, SyntaxError};
|
||||
use crate::processing::general::Type;
|
||||
use crate::tokens::Token;
|
||||
|
@ -32,7 +32,7 @@ impl Display for FieldRegexFilter {
|
|||
}
|
||||
}
|
||||
|
||||
impl FilterPredicate for FieldRegexFilter {
|
||||
impl FieldFilterPredicate for FieldRegexFilter {
|
||||
fn matches(&mut self, music_item_lut: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||
let variable = match &self.val {
|
||||
VariableOrValue::Variable(name) => match ctx.variables.get(name)? {
|
||||
|
@ -83,38 +83,30 @@ impl FilterPredicate for FieldRegexFilter {
|
|||
//self.regex_cache = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<dyn FieldFilterPredicate + 'static> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldRegexFilterFactory;
|
||||
|
||||
impl FilterFactory<FieldRegexFilter> for FieldRegexFilterFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||
impl FieldFilterFactory<FieldRegexFilter> for FieldRegexFilterFactory {
|
||||
fn is_filter(&self, tokens: &[Token]) -> bool {
|
||||
let tokens_len = tokens.len();
|
||||
(tokens_len >= 3 // .field like variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& check_name("matches", tokens[2]))
|
||||
|| (tokens_len >= 4 // .field? like variable OR .field! like variable
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_name()
|
||||
&& (tokens[2].is_interrogation() || tokens[2].is_exclamation())
|
||||
&& check_name("matches", tokens[3]))
|
||||
(tokens_len >= 1 // .field like variable
|
||||
&& check_name("matches", &tokens[0]))
|
||||
|| (tokens_len >= 2 // .field? like variable OR .field! like variable
|
||||
&& (tokens[0].is_interrogation() || tokens[0].is_exclamation())
|
||||
&& check_name("matches", &tokens[1]))
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
&self,
|
||||
tokens: &mut VecDeque<Token>,
|
||||
field: String,
|
||||
_dict: &LanguageDictionary,
|
||||
) -> Result<FieldRegexFilter, SyntaxError> {
|
||||
assert_token_raw(Token::Dot, tokens)?;
|
||||
let field = assert_token(
|
||||
|t| match t {
|
||||
Token::Name(n) => Some(n),
|
||||
_ => None,
|
||||
},
|
||||
Token::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
let error_handling = if tokens[0].is_interrogation() {
|
||||
assert_token_raw(Token::Interrogation, tokens)?;
|
||||
FieldFilterErrorHandling::Ignore
|
||||
|
@ -220,11 +212,3 @@ fn build_regex(pattern: &str, flags: u8) -> Result<Regex, regex::Error> {
|
|||
.ignore_whitespace((flags & (1 << 5)) != 0)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub type FieldRegexFilterStatementFactory =
|
||||
FilterStatementFactory<FieldRegexFilter, FieldRegexFilterFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_re_filter() -> FieldRegexFilterStatementFactory {
|
||||
FieldRegexFilterStatementFactory::new(FieldRegexFilterFactory)
|
||||
}
|
14
interpreter/src/lang/vocabulary/filters/field/mod.rs
Normal file
14
interpreter/src/lang/vocabulary/filters/field/mod.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
mod field_filter;
|
||||
mod field_filter_factory;
|
||||
mod field_filter_maybe;
|
||||
mod field_like_filter;
|
||||
mod field_match_filter;
|
||||
|
||||
pub use field_filter::{
|
||||
FieldFilter, FieldFilterErrorHandling, FieldFilterComparisonFactory,
|
||||
};
|
||||
pub use field_filter_maybe::FieldFilterMaybeFactory;
|
||||
pub use field_like_filter::FieldLikeFilterFactory;
|
||||
pub use field_match_filter::FieldRegexFilterFactory;
|
||||
|
||||
pub use field_filter_factory::*;
|
|
@ -1,8 +1,5 @@
|
|||
mod empty_filter;
|
||||
mod field_filter;
|
||||
mod field_filter_maybe;
|
||||
mod field_like_filter;
|
||||
mod field_match_filter;
|
||||
pub mod field;
|
||||
mod index_filter;
|
||||
mod nonempty_filter;
|
||||
mod range_filter;
|
||||
|
@ -12,19 +9,6 @@ pub(crate) mod utility;
|
|||
pub use empty_filter::{
|
||||
empty_filter, EmptyFilter, EmptyFilterFactory, EmptyFilterStatementFactory,
|
||||
};
|
||||
pub use field_filter::{
|
||||
field_filter, FieldFilter, FieldFilterErrorHandling, FieldFilterFactory,
|
||||
FieldFilterStatementFactory,
|
||||
};
|
||||
pub use field_filter_maybe::{
|
||||
field_filter_maybe, FieldFilterMaybeFactory, FieldFilterMaybeStatementFactory,
|
||||
};
|
||||
pub use field_like_filter::{
|
||||
field_like_filter, FieldLikeFilterFactory, FieldLikeFilterStatementFactory,
|
||||
};
|
||||
pub use field_match_filter::{
|
||||
field_re_filter, FieldRegexFilterFactory, FieldRegexFilterStatementFactory,
|
||||
};
|
||||
pub use index_filter::{
|
||||
index_filter, IndexFilter, IndexFilterFactory, IndexFilterStatementFactory,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{HashSet, VecDeque};
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use super::field_filter::FieldFilterErrorHandling;
|
||||
use super::field::FieldFilterErrorHandling;
|
||||
use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
|
||||
use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory};
|
||||
use crate::lang::{LanguageDictionary, TypePrimitive};
|
||||
|
|
Loading…
Reference in a new issue