Add single-index filter
This commit is contained in:
parent
9df28eb69b
commit
ca17313b7b
6 changed files with 197 additions and 0 deletions
|
@ -159,6 +159,7 @@ pub(crate) fn standard_vocab(vocabulary: &mut MpsLanguageDictionary) {
|
|||
.add(crate::lang::vocabulary::filters::empty_filter())
|
||||
.add(crate::lang::vocabulary::filters::field_filter())
|
||||
.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::simple_sql_function_factory())
|
||||
.add(crate::lang::vocabulary::CommentStatementFactory)
|
||||
|
|
74
mps-interpreter/src/lang/lookup.rs
Normal file
74
mps-interpreter/src/lang/lookup.rs
Normal 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()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ mod dictionary;
|
|||
mod error;
|
||||
mod filter;
|
||||
mod function;
|
||||
mod lookup;
|
||||
mod operation;
|
||||
mod pseudo_op;
|
||||
mod repeated_meme;
|
||||
|
@ -16,6 +17,7 @@ pub use filter::{
|
|||
MpsFilterFactory, MpsFilterPredicate, MpsFilterStatement, MpsFilterStatementFactory,
|
||||
};
|
||||
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||
pub use lookup::Lookup;
|
||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||
pub use pseudo_op::PseudoOp;
|
||||
pub use repeated_meme::{repeated_tokens, RepeatedTokens};
|
||||
|
|
99
mps-interpreter/src/lang/vocabulary/filters/index_filter.rs
Normal file
99
mps-interpreter/src/lang/vocabulary/filters/index_filter.rs
Normal 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)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
mod empty_filter;
|
||||
mod field_filter;
|
||||
mod field_filter_maybe;
|
||||
mod index_filter;
|
||||
pub(crate) mod utility;
|
||||
|
||||
pub use empty_filter::{
|
||||
|
@ -10,3 +11,4 @@ pub use field_filter::{
|
|||
field_filter, FieldFilter, FieldFilterFactory, FieldFilterStatementFactory, FieldFilterErrorHandling,
|
||||
};
|
||||
pub use field_filter_maybe::{field_filter_maybe, FieldFilterMaybeFactory, FieldFilterMaybeStatementFactory};
|
||||
pub use index_filter::{index_filter, IndexFilter, IndexFilterFactory, IndexFilterStatementFactory};
|
||||
|
|
|
@ -197,3 +197,22 @@ fn execute_files_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
|||
)?;
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue