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::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)
|
||||||
|
|
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 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};
|
||||||
|
|
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 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};
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue