Add single-index filter

This commit is contained in:
NGnius (Graham) 2022-01-12 11:06:32 -05:00
parent 9df28eb69b
commit ca17313b7b
6 changed files with 197 additions and 0 deletions

View file

@ -159,6 +159,7 @@ pub(crate) fn standard_vocab(vocabulary: &mut MpsLanguageDictionary) {
.add(crate::lang::vocabulary::filters::empty_filter()) .add(crate::lang::vocabulary::filters::empty_filter())
.add(crate::lang::vocabulary::filters::field_filter()) .add(crate::lang::vocabulary::filters::field_filter())
.add(crate::lang::vocabulary::filters::field_filter_maybe()) .add(crate::lang::vocabulary::filters::field_filter_maybe())
.add(crate::lang::vocabulary::filters::index_filter())
.add(crate::lang::vocabulary::sql_function_factory()) .add(crate::lang::vocabulary::sql_function_factory())
.add(crate::lang::vocabulary::simple_sql_function_factory()) .add(crate::lang::vocabulary::simple_sql_function_factory())
.add(crate::lang::vocabulary::CommentStatementFactory) .add(crate::lang::vocabulary::CommentStatementFactory)

View file

@ -0,0 +1,74 @@
use std::collections::VecDeque;
use std::fmt::{Display, Error, Formatter};
//use super::MpsTypePrimitive;
use crate::processing::general::MpsType;
use crate::lang::{RuntimeError, SyntaxError};
use super::utility::{assert_type, assert_token, check_is_type};
use crate::tokens::MpsToken;
use crate::MpsContext;
use crate::processing::OpGetter;
#[derive(Debug)]
pub enum Lookup {
Static(MpsType),
Variable(String)
}
impl Lookup {
pub fn check_is(token: &MpsToken) -> bool {
token.is_name() || check_is_type(token)
}
pub fn parse(tokens: &mut VecDeque<MpsToken>) -> Result<Self, SyntaxError> {
if tokens.is_empty() {
Err(SyntaxError {
line: 0,
token: MpsToken::Name("Float | UInt | Int | Bool".into()),
got: None,
})
} else if check_is_type(&tokens[0]) {
Ok(Self::Static(MpsType::Primitive(assert_type(tokens)?)))
} else {
Ok(Self::Variable(assert_token(|t| match t {
MpsToken::Name(s) => Some(s),
_ => None,
}, MpsToken::Name("variable_name".into()), tokens)?))
}
}
pub fn get_mut<'a, 'b: 'a>(&'b mut self, ctx: &'a mut MpsContext, op: &mut OpGetter) -> Result<&'a mut MpsType, RuntimeError> {
match self {
Self::Static(var) => Ok(var),
Self::Variable(name) => ctx.variables.get_mut(name, op)
}
}
pub fn get<'a, 'b: 'a>(&'b self, ctx: &'a MpsContext, op: &mut OpGetter) -> Result<&'a MpsType, RuntimeError> {
match self {
Self::Static(var) => Ok(var),
Self::Variable(name) => ctx.variables.get(name, op)
}
}
}
impl Display for Lookup {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match self {
Self::Static(var) => write!(f, "{}", var),
Self::Variable(name) => write!(f, "{}", name),
}
}
}
impl std::clone::Clone for Lookup {
fn clone(&self) -> Self {
match self {
Self::Static(var) => match var {
MpsType::Primitive(p) => Self::Static(MpsType::Primitive(p.clone())),
_ => panic!("Can't clone static operator (invalid state)")
},
Self::Variable(name) => Self::Variable(name.clone()),
}
}
}

View file

@ -3,6 +3,7 @@ mod dictionary;
mod error; mod error;
mod filter; mod filter;
mod function; mod function;
mod lookup;
mod operation; mod operation;
mod pseudo_op; mod pseudo_op;
mod repeated_meme; mod repeated_meme;
@ -16,6 +17,7 @@ pub use filter::{
MpsFilterFactory, MpsFilterPredicate, MpsFilterStatement, MpsFilterStatementFactory, MpsFilterFactory, MpsFilterPredicate, MpsFilterStatement, MpsFilterStatementFactory,
}; };
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory}; pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
pub use lookup::Lookup;
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory}; pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
pub use pseudo_op::PseudoOp; pub use pseudo_op::PseudoOp;
pub use repeated_meme::{repeated_tokens, RepeatedTokens}; pub use repeated_meme::{repeated_tokens, RepeatedTokens};

View file

@ -0,0 +1,99 @@
use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter};
use crate::lang::{MpsLanguageDictionary, MpsTypePrimitive};
use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
use crate::lang::{RuntimeError, SyntaxError};
use crate::lang::Lookup;
use crate::processing::{OpGetter, general::MpsType};
use crate::tokens::MpsToken;
use crate::MpsContext;
use crate::MpsMusicItem;
#[derive(Debug, Clone)]
pub struct IndexFilter {
index: Lookup,
// state
current: u64,
complete: bool,
}
impl Display for IndexFilter {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.index)
}
}
impl MpsFilterPredicate for IndexFilter {
fn matches(
&mut self,
_item: &MpsMusicItem,
ctx: &mut MpsContext,
op: &mut OpGetter,
) -> Result<bool, RuntimeError> {
let index: u64 = match self.index.get(ctx, op)? {
MpsType::Primitive(val) => match val {
MpsTypePrimitive::Int(i) => *i as u64,
MpsTypePrimitive::UInt(u) => *u,
MpsTypePrimitive::Float(f) => *f as u64,
val => return Err(RuntimeError {
line: 0,
op: op(),
msg: format!("Cannot use {} as index", val),
})
},
val => return Err(RuntimeError {
line: 0,
op: op(),
msg: format!("Cannot use {} as index", val),
})
};
if self.current == index {
self.current += 1;
self.complete = true;
Ok(true)
} else {
self.current += 1;
Ok(false)
}
}
fn is_complete(&self) -> bool {
self.complete
}
fn reset(&mut self) -> Result<(), RuntimeError> {
self.current = 0;
self.complete = false;
Ok(())
}
}
pub struct IndexFilterFactory;
impl MpsFilterFactory<IndexFilter> for IndexFilterFactory {
fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool {
tokens.len() == 1
&& Lookup::check_is(&tokens[0])
}
fn build_filter(
&self,
tokens: &mut VecDeque<MpsToken>,
_dict: &MpsLanguageDictionary,
) -> Result<IndexFilter, SyntaxError> {
let lookup = Lookup::parse(tokens)?;
Ok(IndexFilter {
index: lookup,
current: 0,
complete: false,
})
}
}
pub type IndexFilterStatementFactory = MpsFilterStatementFactory<IndexFilter, IndexFilterFactory>;
#[inline(always)]
pub fn index_filter() -> IndexFilterStatementFactory {
IndexFilterStatementFactory::new(IndexFilterFactory)
}

View file

@ -1,6 +1,7 @@
mod empty_filter; mod empty_filter;
mod field_filter; mod field_filter;
mod field_filter_maybe; mod field_filter_maybe;
mod index_filter;
pub(crate) mod utility; pub(crate) mod utility;
pub use empty_filter::{ pub use empty_filter::{
@ -10,3 +11,4 @@ pub use field_filter::{
field_filter, FieldFilter, FieldFilterFactory, FieldFilterStatementFactory, FieldFilterErrorHandling, field_filter, FieldFilter, FieldFilterFactory, FieldFilterStatementFactory, FieldFilterErrorHandling,
}; };
pub use field_filter_maybe::{field_filter_maybe, FieldFilterMaybeFactory, FieldFilterMaybeStatementFactory}; pub use field_filter_maybe::{field_filter_maybe, FieldFilterMaybeFactory, FieldFilterMaybeStatementFactory};
pub use index_filter::{index_filter, IndexFilter, IndexFilterFactory, IndexFilterStatementFactory};

View file

@ -197,3 +197,22 @@ fn execute_files_line() -> Result<(), Box<dyn MpsLanguageError>> {
)?; )?;
execute_single_line(r"files()", false, true) execute_single_line(r"files()", false, true)
} }
#[test]
fn execute_indexfilter_line() -> Result<(), Box<dyn MpsLanguageError>> {
execute_single_line(
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).(2)",
false,
true,
)?;
execute_single_line(
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).(0)",
false,
true,
)?;
execute_single_line(
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).(200)",
true,
true,
)
}