cargo fmt
This commit is contained in:
parent
8dc571521f
commit
0a6dae930f
33 changed files with 531 additions and 323 deletions
|
@ -3,12 +3,12 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, check_name, assert_name};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::SingleItem;
|
||||
use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
|
||||
use crate::lang::MpsFilterReplaceStatement;
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::SingleItem;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, PseudoOp};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::general::MpsType;
|
||||
use crate::processing::OpGetter;
|
||||
use crate::tokens::MpsToken;
|
||||
|
@ -77,7 +77,11 @@ impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterStatement<P
|
|||
impl<P: MpsFilterPredicate + 'static> Display for MpsFilterStatement<P> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
if let Some(other_filters) = &self.other_filters {
|
||||
write!(f, "{}.({} || (like) {})", self.iterable, self.predicate, other_filters)
|
||||
write!(
|
||||
f,
|
||||
"{}.({} || (like) {})",
|
||||
self.iterable, self.predicate, other_filters
|
||||
)
|
||||
} else {
|
||||
write!(f, "{}.({})", self.iterable, self.predicate)
|
||||
}
|
||||
|
@ -103,15 +107,19 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
|
|||
} else {
|
||||
false
|
||||
}
|
||||
} else {true} // ASSUMPTION
|
||||
|
||||
} else {
|
||||
true
|
||||
} // ASSUMPTION
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(),
|
||||
VariableOrOp::Op(PseudoOp::Fake(_)) => false,
|
||||
};
|
||||
let is_other_filter_resetable = if let Some(PseudoOp::Real(other_filter)) = &self.other_filters {
|
||||
other_filter.is_resetable()
|
||||
} else {true};
|
||||
let is_other_filter_resetable =
|
||||
if let Some(PseudoOp::Real(other_filter)) = &self.other_filters {
|
||||
other_filter.is_resetable()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
is_iterable_resetable && is_other_filter_resetable
|
||||
}
|
||||
|
||||
|
@ -122,7 +130,12 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
|
|||
VariableOrOp::Variable(s) => {
|
||||
if self.context.as_mut().unwrap().variables.exists(s) {
|
||||
let fake_getter = &mut move || fake.clone();
|
||||
let mut var = self.context.as_mut().unwrap().variables.remove(s, fake_getter)?;
|
||||
let mut var = self
|
||||
.context
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.variables
|
||||
.remove(s, fake_getter)?;
|
||||
let result = if let MpsType::Op(var) = &mut var {
|
||||
var.enter(self.context.take().unwrap());
|
||||
let result = var.reset();
|
||||
|
@ -135,16 +148,22 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
|
|||
msg: "Cannot reset non-iterable filter variable".to_string(),
|
||||
})
|
||||
};
|
||||
self.context.as_mut().unwrap().variables.declare(s, var, fake_getter)?;
|
||||
self.context
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.variables
|
||||
.declare(s, var, fake_getter)?;
|
||||
result
|
||||
} else {Ok(())}
|
||||
},
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Real(op)) => {
|
||||
op.enter(self.context.take().unwrap());
|
||||
let result = op.reset();
|
||||
self.context = Some(op.escape());
|
||||
result
|
||||
},
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError {
|
||||
line: 0,
|
||||
op: fake,
|
||||
|
@ -156,7 +175,9 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
|
|||
let result = other_filter.reset();
|
||||
self.context = Some(other_filter.escape());
|
||||
result
|
||||
} else {Ok(())}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +206,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
|||
maybe_result = Some(Err(e));
|
||||
self.context = Some(ctx);
|
||||
break;
|
||||
},
|
||||
}
|
||||
Ok(item) => {
|
||||
let matches_result =
|
||||
self.predicate.matches(&item, &mut ctx, &mut op_getter);
|
||||
|
@ -201,14 +222,18 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
|||
// handle other filters
|
||||
// make fake inner item
|
||||
let single_op = SingleItem::new_ok(item.clone());
|
||||
match ctx.variables.declare(INNER_VARIABLE_NAME, MpsType::Op(Box::new(single_op)), &mut op_getter) {
|
||||
match ctx.variables.declare(
|
||||
INNER_VARIABLE_NAME,
|
||||
MpsType::Op(Box::new(single_op)),
|
||||
&mut op_getter,
|
||||
) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
//self.context = Some(op.escape());
|
||||
maybe_result = Some(Err(e));
|
||||
self.context = Some(ctx);
|
||||
break;
|
||||
},
|
||||
}
|
||||
};
|
||||
let inner_real = match inner.try_real() {
|
||||
Ok(x) => x,
|
||||
|
@ -217,28 +242,34 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
|
|||
maybe_result = Some(Err(e));
|
||||
self.context = Some(ctx);
|
||||
break;
|
||||
},
|
||||
}
|
||||
};
|
||||
inner_real.enter(ctx);
|
||||
match inner_real.next() {
|
||||
Some(item) => {
|
||||
maybe_result = Some(item);
|
||||
ctx = inner_real.escape();
|
||||
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) {
|
||||
Ok(_) => {},
|
||||
match ctx
|
||||
.variables
|
||||
.remove(INNER_VARIABLE_NAME, &mut op_getter)
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => match maybe_result {
|
||||
Some(Ok(_)) => maybe_result = Some(Err(e)),
|
||||
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
|
||||
None => {}, // impossible
|
||||
}
|
||||
None => {} // impossible
|
||||
},
|
||||
}
|
||||
self.context = Some(ctx);
|
||||
break;
|
||||
},
|
||||
}
|
||||
None => {
|
||||
ctx = inner_real.escape(); // move ctx back to expected spot
|
||||
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) {
|
||||
Ok(_) => {},
|
||||
match ctx
|
||||
.variables
|
||||
.remove(INNER_VARIABLE_NAME, &mut op_getter)
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
//self.context = Some(op.escape());
|
||||
maybe_result = Some(Err(e));
|
||||
|
@ -377,7 +408,9 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
if tokens2.len() != 0 && check_name("if", &tokens2[0]) {
|
||||
// replacement filter
|
||||
if let Some(colon_location) = first_colon2(&tokens2) {
|
||||
let tokens3 = VecDeque::from_iter(tokens.range(start_of_predicate+1..start_of_predicate+colon_location));
|
||||
let tokens3 = VecDeque::from_iter(tokens.range(
|
||||
start_of_predicate + 1..start_of_predicate + colon_location,
|
||||
));
|
||||
self.filter_factory.is_filter(&tokens3)
|
||||
} else {
|
||||
false
|
||||
|
@ -386,9 +419,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
// regular filter
|
||||
self.filter_factory.is_filter(&tokens2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -442,7 +473,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
tokens.extend(end_tokens);
|
||||
assert_name("else", tokens)?;
|
||||
let end_tokens = tokens.split_off(tokens.len() - 1); // up to ending close bracket
|
||||
// build replacement system
|
||||
// build replacement system
|
||||
else_op = Some(dict.try_build_statement(tokens)?.into());
|
||||
tokens.extend(end_tokens);
|
||||
} else {
|
||||
|
@ -458,7 +489,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
context: None,
|
||||
op_if: if_op,
|
||||
op_else: else_op,
|
||||
item_cache: super::filter_replace::item_cache_deque()
|
||||
item_cache: super::filter_replace::item_cache_deque(),
|
||||
}))
|
||||
} else {
|
||||
Err(SyntaxError {
|
||||
|
@ -467,13 +498,13 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
got: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
let mut another_filter = None;
|
||||
let (has_or, end_tokens) = if let Some(pipe_location) = first_double_pipe(tokens, 0) {
|
||||
(true, tokens.split_off(pipe_location)) // parse up to OR operator
|
||||
} else {
|
||||
(false, tokens.split_off(tokens.len()-1)) // don't parse closing bracket in filter
|
||||
(false, tokens.split_off(tokens.len() - 1)) // don't parse closing bracket in filter
|
||||
};
|
||||
let filter = self.filter_factory.build_filter(tokens, dict)?;
|
||||
tokens.extend(end_tokens);
|
||||
|
@ -496,7 +527,6 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
|
|||
other_filters: another_filter,
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,7 +582,7 @@ fn first_double_pipe(tokens: &VecDeque<MpsToken>, in_brackets: usize) -> Option<
|
|||
for i in 0..tokens.len() {
|
||||
if tokens[i].is_pipe() && inside_brackets == in_brackets {
|
||||
if pipe_found {
|
||||
return Some(i-1);
|
||||
return Some(i - 1);
|
||||
} else {
|
||||
pipe_found = true;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::VecDeque;
|
|||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::{MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::RuntimeError;
|
||||
use crate::lang::{MpsFilterPredicate, filter::VariableOrOp};
|
||||
use crate::lang::SingleItem;
|
||||
use crate::lang::{filter::VariableOrOp, MpsFilterPredicate};
|
||||
use crate::lang::{MpsIteratorItem, MpsOp, PseudoOp};
|
||||
use crate::processing::general::MpsType;
|
||||
use crate::processing::OpGetter;
|
||||
use crate::MpsContext;
|
||||
|
@ -45,9 +45,17 @@ impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterReplaceStat
|
|||
impl<P: MpsFilterPredicate + 'static> Display for MpsFilterReplaceStatement<P> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
if let Some(op_else) = &self.op_else {
|
||||
write!(f, "{}.(if {}: {} else {})", self.iterable, self.predicate, self.op_if, op_else)
|
||||
write!(
|
||||
f,
|
||||
"{}.(if {}: {} else {})",
|
||||
self.iterable, self.predicate, self.op_if, op_else
|
||||
)
|
||||
} else {
|
||||
write!(f, "{}.(if {}: {})", self.iterable, self.predicate, self.op_if)
|
||||
write!(
|
||||
f,
|
||||
"{}.(if {}: {})",
|
||||
self.iterable, self.predicate, self.op_if
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +79,9 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
|
|||
} else {
|
||||
false
|
||||
}
|
||||
} else {true} // ASSUMPTION
|
||||
|
||||
} else {
|
||||
true
|
||||
} // ASSUMPTION
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(),
|
||||
VariableOrOp::Op(PseudoOp::Fake(_)) => false,
|
||||
|
@ -87,7 +96,12 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
|
|||
VariableOrOp::Variable(s) => {
|
||||
if self.context.as_mut().unwrap().variables.exists(s) {
|
||||
let fake_getter = &mut move || fake.clone();
|
||||
let mut var = self.context.as_mut().unwrap().variables.remove(s, fake_getter)?;
|
||||
let mut var = self
|
||||
.context
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.variables
|
||||
.remove(s, fake_getter)?;
|
||||
let result = if let MpsType::Op(var) = &mut var {
|
||||
var.enter(self.context.take().unwrap());
|
||||
let result = var.reset();
|
||||
|
@ -100,16 +114,22 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
|
|||
msg: "Cannot reset non-iterable filter variable".to_string(),
|
||||
})
|
||||
};
|
||||
self.context.as_mut().unwrap().variables.declare(s, var, fake_getter)?;
|
||||
self.context
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.variables
|
||||
.declare(s, var, fake_getter)?;
|
||||
result
|
||||
} else {Ok(())}
|
||||
},
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Real(op)) => {
|
||||
op.enter(self.context.take().unwrap());
|
||||
let result = op.reset();
|
||||
self.context = Some(op.escape());
|
||||
result
|
||||
},
|
||||
}
|
||||
VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError {
|
||||
line: 0,
|
||||
op: fake,
|
||||
|
@ -171,7 +191,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
&mut op_getter,
|
||||
) {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
}
|
||||
item
|
||||
}
|
||||
|
@ -180,8 +200,11 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
match next_item {
|
||||
Some(Ok(item)) => {
|
||||
//println!("item is now: `{}`", &item.filename);
|
||||
match self.predicate.matches(&item, self.context.as_mut().unwrap(), &mut op_getter) {
|
||||
Ok(is_match) =>
|
||||
match self
|
||||
.predicate
|
||||
.matches(&item, self.context.as_mut().unwrap(), &mut op_getter)
|
||||
{
|
||||
Ok(is_match) => {
|
||||
if is_match {
|
||||
// unwrap inner operation
|
||||
match self.op_if.try_real() {
|
||||
|
@ -189,7 +212,11 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
// build item variable
|
||||
let single_op = SingleItem::new_ok(item);
|
||||
//println!("Declaring item variable");
|
||||
let old_item = match declare_or_replace_item(single_op, &mut op_getter, self.context.as_mut().unwrap()) {
|
||||
let old_item = match declare_or_replace_item(
|
||||
single_op,
|
||||
&mut op_getter,
|
||||
self.context.as_mut().unwrap(),
|
||||
) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return Some(Err(e)), // probably shouldn't occur
|
||||
};
|
||||
|
@ -207,9 +234,13 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
self.context = Some(real_op.escape());
|
||||
// destroy item variable
|
||||
//println!("Removing item variable");
|
||||
match remove_or_replace_item(old_item, &mut op_getter, self.context.as_mut().unwrap()) {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Some(Err(e))
|
||||
match remove_or_replace_item(
|
||||
old_item,
|
||||
&mut op_getter,
|
||||
self.context.as_mut().unwrap(),
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
}
|
||||
Err(e) => return Some(Err(e)), // probably shouldn't occur
|
||||
|
@ -228,7 +259,11 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
// build item variable
|
||||
let single_op = SingleItem::new_ok(item);
|
||||
//println!("Declaring item variable");
|
||||
let old_item = match declare_or_replace_item(single_op, &mut op_getter, self.context.as_mut().unwrap()) {
|
||||
let old_item = match declare_or_replace_item(
|
||||
single_op,
|
||||
&mut op_getter,
|
||||
self.context.as_mut().unwrap(),
|
||||
) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return Some(Err(e)), // probably shouldn't occur
|
||||
};
|
||||
|
@ -244,11 +279,15 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
self.item_cache.push_back(item);
|
||||
}
|
||||
self.context = Some(real_op.escape());
|
||||
// destroy item variable
|
||||
// destroy item variable
|
||||
//println!("Removing item variable");
|
||||
match remove_or_replace_item(old_item, &mut op_getter, self.context.as_mut().unwrap()) {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Some(Err(e))
|
||||
match remove_or_replace_item(
|
||||
old_item,
|
||||
&mut op_getter,
|
||||
self.context.as_mut().unwrap(),
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
}
|
||||
Err(e) => return Some(Err(e)), // probably shouldn't occur
|
||||
|
@ -262,28 +301,38 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
|
|||
}
|
||||
} else {
|
||||
Some(Ok(item))
|
||||
},
|
||||
Err(e) => return Some(Err(e))
|
||||
}
|
||||
}
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
},
|
||||
}
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn declare_or_replace_item(single: SingleItem, op: &mut OpGetter, ctx: &mut MpsContext) -> Result<Option<MpsType>, RuntimeError> {
|
||||
fn declare_or_replace_item(
|
||||
single: SingleItem,
|
||||
op: &mut OpGetter,
|
||||
ctx: &mut MpsContext,
|
||||
) -> Result<Option<MpsType>, RuntimeError> {
|
||||
let old_item: Option<MpsType>;
|
||||
if ctx.variables.exists(ITEM_VARIABLE_NAME) {
|
||||
old_item = Some(ctx.variables.remove(ITEM_VARIABLE_NAME, op)?);
|
||||
} else {
|
||||
old_item = None;
|
||||
}
|
||||
ctx.variables.declare(ITEM_VARIABLE_NAME, MpsType::Op(Box::new(single)), op)?;
|
||||
ctx.variables
|
||||
.declare(ITEM_VARIABLE_NAME, MpsType::Op(Box::new(single)), op)?;
|
||||
Ok(old_item)
|
||||
}
|
||||
|
||||
fn remove_or_replace_item(old_item: Option<MpsType>, op: &mut OpGetter, ctx: &mut MpsContext) -> Result<(), RuntimeError> {
|
||||
fn remove_or_replace_item(
|
||||
old_item: Option<MpsType>,
|
||||
op: &mut OpGetter,
|
||||
ctx: &mut MpsContext,
|
||||
) -> Result<(), RuntimeError> {
|
||||
ctx.variables.remove(ITEM_VARIABLE_NAME, op)?;
|
||||
if let Some(old_item) = old_item {
|
||||
ctx.variables.declare(ITEM_VARIABLE_NAME, old_item, op)?;
|
||||
|
|
|
@ -2,17 +2,17 @@ use std::collections::VecDeque;
|
|||
use std::fmt::{Display, Error, Formatter};
|
||||
|
||||
//use super::MpsTypePrimitive;
|
||||
use crate::processing::general::MpsType;
|
||||
use super::utility::{assert_token, assert_type, check_is_type};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use super::utility::{assert_type, assert_token, check_is_type};
|
||||
use crate::processing::general::MpsType;
|
||||
use crate::processing::OpGetter;
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::processing::OpGetter;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Lookup {
|
||||
Static(MpsType),
|
||||
Variable(String)
|
||||
Variable(String),
|
||||
}
|
||||
|
||||
impl Lookup {
|
||||
|
@ -29,24 +29,36 @@ impl Lookup {
|
|||
} 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)?))
|
||||
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> {
|
||||
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)
|
||||
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> {
|
||||
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)
|
||||
Self::Variable(name) => ctx.variables.get(name, op),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +69,6 @@ impl Display for Lookup {
|
|||
Self::Static(var) => write!(f, "{}", var),
|
||||
Self::Variable(name) => write!(f, "{}", name),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +77,7 @@ impl std::clone::Clone for Lookup {
|
|||
match self {
|
||||
Self::Static(var) => match var {
|
||||
MpsType::Primitive(p) => Self::Static(MpsType::Primitive(p.clone())),
|
||||
_ => panic!("Can't clone static operator (invalid state)")
|
||||
_ => panic!("Can't clone static operator (invalid state)"),
|
||||
},
|
||||
Self::Variable(name) => Self::Variable(name.clone()),
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@ pub use filter::{
|
|||
pub use filter_replace::MpsFilterReplaceStatement;
|
||||
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
|
||||
pub use lookup::Lookup;
|
||||
pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
|
||||
pub use operation::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||
pub use pseudo_op::PseudoOp;
|
||||
pub use repeated_meme::{repeated_tokens, RepeatedTokens};
|
||||
pub use single_op::SingleItem;
|
||||
pub use sorter::{MpsSorterFactory, MpsSorter, MpsSortStatement, MpsSortStatementFactory};
|
||||
pub use sorter::{MpsSortStatement, MpsSortStatementFactory, MpsSorter, MpsSorterFactory};
|
||||
//pub(crate) use statement::MpsStatement;
|
||||
pub use type_primitives::MpsTypePrimitive;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::{MpsOp, RuntimeError, MpsIteratorItem};
|
||||
use crate::lang::{MpsIteratorItem, MpsOp, RuntimeError};
|
||||
use crate::MpsContext;
|
||||
use crate::MpsItem;
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl Display for SingleItem {
|
|||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
match &self.item {
|
||||
Ok(item) => write!(f, "*single item*[Ok({})]", item),
|
||||
Err(e) => write!(f, "*single-item*[Err({})]", e)
|
||||
Err(e) => write!(f, "*single-item*[Err({})]", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::lang::utility::{assert_token_raw, check_name, assert_name};
|
||||
use crate::lang::utility::{assert_name, assert_token_raw, check_name};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, PseudoOp};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
|
@ -13,7 +13,11 @@ use crate::MpsContext;
|
|||
const SORTER_ITEM_CACHE_SIZE: usize = 8;
|
||||
|
||||
pub trait MpsSorter: Clone + Debug + Display {
|
||||
fn sort(&mut self, iterator: &mut dyn MpsOp, item_buf: &mut VecDeque<MpsIteratorItem>) -> Result<(), RuntimeError>;
|
||||
fn sort(
|
||||
&mut self,
|
||||
iterator: &mut dyn MpsOp,
|
||||
item_buf: &mut VecDeque<MpsIteratorItem>,
|
||||
) -> Result<(), RuntimeError>;
|
||||
}
|
||||
|
||||
pub trait MpsSorterFactory<S: MpsSorter + 'static> {
|
||||
|
@ -62,7 +66,9 @@ impl<S: MpsSorter + 'static> MpsOp for MpsSortStatement<S> {
|
|||
fn is_resetable(&self) -> bool {
|
||||
if let Ok(iter) = self.iterable.try_real_ref() {
|
||||
iter.is_resetable()
|
||||
} else {false}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<(), RuntimeError> {
|
||||
|
@ -80,7 +86,7 @@ impl<S: MpsSorter + 'static> Iterator for MpsSortStatement<S> {
|
|||
Err(e) => return Some(Err(e)),
|
||||
};
|
||||
match self.orderer.sort(real_op.as_mut(), &mut self.item_cache) {
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
self.item_cache.pop_front()
|
||||
|
@ -92,9 +98,7 @@ pub struct MpsSortStatementFactory<S: MpsSorter + 'static, F: MpsSorterFactory<S
|
|||
idc: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static>
|
||||
MpsSortStatementFactory<S, F>
|
||||
{
|
||||
impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> MpsSortStatementFactory<S, F> {
|
||||
pub fn new(factory: F) -> Self {
|
||||
Self {
|
||||
sort_factory: factory,
|
||||
|
@ -103,7 +107,7 @@ impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static>
|
|||
}
|
||||
}
|
||||
|
||||
impl <S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactory
|
||||
impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactory
|
||||
for MpsSortStatementFactory<S, F>
|
||||
{
|
||||
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
|
||||
|
@ -112,18 +116,20 @@ impl <S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactor
|
|||
// iterable~(sorter)
|
||||
if tokens_len > tilde_location + 2 {
|
||||
let tokens2: VecDeque<&MpsToken> =
|
||||
VecDeque::from_iter(tokens.range(tilde_location+2..tokens_len-1));
|
||||
tokens[tokens_len-1].is_close_bracket()
|
||||
&& self.sort_factory.is_sorter(&tokens2)
|
||||
} else {false}
|
||||
VecDeque::from_iter(tokens.range(tilde_location + 2..tokens_len - 1));
|
||||
tokens[tokens_len - 1].is_close_bracket() && self.sort_factory.is_sorter(&tokens2)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if let Some(dot_location) = last_dot_sort(tokens, 1) {
|
||||
// iterable.sort(sorter)
|
||||
if tokens_len > dot_location + 3 {
|
||||
let tokens2: VecDeque<&MpsToken> =
|
||||
VecDeque::from_iter(tokens.range(dot_location+3..tokens_len-1));
|
||||
tokens[tokens_len-1].is_close_bracket()
|
||||
&& self.sort_factory.is_sorter(&tokens2)
|
||||
} else {false}
|
||||
VecDeque::from_iter(tokens.range(dot_location + 3..tokens_len - 1));
|
||||
tokens[tokens_len - 1].is_close_bracket() && self.sort_factory.is_sorter(&tokens2)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -150,21 +156,19 @@ impl <S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactor
|
|||
return Err(SyntaxError {
|
||||
line: 0,
|
||||
token: MpsToken::Name(".|~".into()),
|
||||
got: tokens.pop_front()
|
||||
})
|
||||
got: tokens.pop_front(),
|
||||
});
|
||||
}
|
||||
assert_token_raw(MpsToken::OpenBracket, tokens)?;
|
||||
let end_tokens = tokens.split_off(tokens.len()-1);
|
||||
let end_tokens = tokens.split_off(tokens.len() - 1);
|
||||
let sorter = self.sort_factory.build_sorter(tokens, dict)?;
|
||||
tokens.extend(end_tokens);
|
||||
assert_token_raw(MpsToken::CloseBracket, tokens)?;
|
||||
Ok(Box::new(
|
||||
MpsSortStatement {
|
||||
orderer: sorter,
|
||||
iterable: inner_op.into(),
|
||||
item_cache: VecDeque::with_capacity(SORTER_ITEM_CACHE_SIZE),
|
||||
}
|
||||
))
|
||||
Ok(Box::new(MpsSortStatement {
|
||||
orderer: sorter,
|
||||
iterable: inner_op.into(),
|
||||
item_cache: VecDeque::with_capacity(SORTER_ITEM_CACHE_SIZE),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +181,7 @@ fn last_tilde(tokens: &VecDeque<MpsToken>, target_depth: usize) -> Option<usize>
|
|||
} else if current_token.is_open_bracket() && bracket_depth != 0 {
|
||||
bracket_depth -= 1;
|
||||
} else if current_token.is_tilde() && bracket_depth == target_depth {
|
||||
return Some(i)
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -196,7 +200,7 @@ fn last_dot_sort(tokens: &VecDeque<MpsToken>, target_depth: usize) -> Option<usi
|
|||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if bracket_found {
|
||||
if check_name("sort", current_token) {
|
||||
sort_found = true;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Basic types for MPS
|
||||
|
||||
use std::cmp::{Ord, Ordering};
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::cmp::{Ordering, Ord};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum MpsTypePrimitive {
|
||||
|
@ -38,7 +38,7 @@ impl MpsTypePrimitive {
|
|||
Self::UInt(x) => format!("{}", x),
|
||||
Self::Int(x) => format!("{}", x),
|
||||
Self::Float(x) => format!("{}", x),
|
||||
Self::Bool(x) => format!("{}", x)
|
||||
Self::Bool(x) => format!("{}", x),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ impl MpsTypePrimitive {
|
|||
}
|
||||
|
||||
pub fn parse(s: String) -> Self {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
Self::Int(i)
|
||||
} else if let Ok(u) = s.parse::<u64>() {
|
||||
Self::UInt(u)
|
||||
|
@ -117,9 +117,7 @@ impl PartialOrd for MpsTypePrimitive {
|
|||
_ => None,
|
||||
},
|
||||
Self::Float(f1) => match other {
|
||||
Self::Float(f2) => Some(
|
||||
f1.partial_cmp(f2).unwrap_or(std::cmp::Ordering::Less),
|
||||
),
|
||||
Self::Float(f2) => Some(f1.partial_cmp(f2).unwrap_or(std::cmp::Ordering::Less)),
|
||||
Self::Int(f2) => Some(
|
||||
f1.partial_cmp(&(*f2 as f64))
|
||||
.unwrap_or(std::cmp::Ordering::Less),
|
||||
|
|
|
@ -143,7 +143,7 @@ pub fn assert_type(tokens: &mut VecDeque<MpsToken>) -> Result<MpsTypePrimitive,
|
|||
match token {
|
||||
MpsToken::Literal(s) => Ok(MpsTypePrimitive::String(s)),
|
||||
MpsToken::Name(s) => {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
Ok(MpsTypePrimitive::Int(i))
|
||||
} else if let Ok(u) = s.parse::<u64>() {
|
||||
Ok(MpsTypePrimitive::UInt(u))
|
||||
|
|
|
@ -7,8 +7,8 @@ use crate::MpsContext;
|
|||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
|
||||
use crate::lang::SyntaxError;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommentStatement {
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::MpsContext;
|
|||
use crate::lang::repeated_tokens;
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsOp};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::general::FileIter;
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ pub struct FieldFilter {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FieldFilterErrorHandling {
|
||||
Error, // return error
|
||||
Ignore, // return Ok(false) when error encountered
|
||||
Error, // return error
|
||||
Ignore, // return Ok(false) when error encountered
|
||||
Include, // return Ok(true) when error encountered
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ fn comparison_op(c: &[i8; 2]) -> &str {
|
|||
[0, -1] => "<=",
|
||||
[0, 1] => ">=",
|
||||
[-1, 1] => "!=",
|
||||
_ => "??"
|
||||
_ => "??",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,9 @@ impl Display for FieldFilter {
|
|||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
let comp_op = comparison_op(&self.comparison);
|
||||
match &self.val {
|
||||
VariableOrValue::Variable(name) => write!(f, "{} {} {}", self.field_name, comp_op, name),
|
||||
VariableOrValue::Variable(name) => {
|
||||
write!(f, "{} {} {}", self.field_name, comp_op, name)
|
||||
}
|
||||
VariableOrValue::Value(t) => write!(f, "{} {} {}", self.field_name, comp_op, t),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use super::utility::assert_comparison_operator;
|
||||
use super::{FieldFilter, FieldFilterErrorHandling, field_filter::VariableOrValue};
|
||||
use crate::lang::utility::{assert_token, assert_type, check_is_type, assert_token_raw};
|
||||
use super::{field_filter::VariableOrValue, FieldFilter, FieldFilterErrorHandling};
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFilterFactory, MpsFilterStatementFactory};
|
||||
use crate::lang::SyntaxError;
|
||||
use crate::lang::{MpsFilterFactory, MpsFilterStatementFactory};
|
||||
use crate::tokens::MpsToken;
|
||||
|
||||
pub struct FieldFilterMaybeFactory;
|
||||
|
@ -80,7 +80,8 @@ impl MpsFilterFactory<FieldFilter> for FieldFilterMaybeFactory {
|
|||
}
|
||||
}
|
||||
|
||||
pub type FieldFilterMaybeStatementFactory = MpsFilterStatementFactory<FieldFilter, FieldFilterMaybeFactory>;
|
||||
pub type FieldFilterMaybeStatementFactory =
|
||||
MpsFilterStatementFactory<FieldFilter, FieldFilterMaybeFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_filter_maybe() -> FieldFilterMaybeStatementFactory {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use super::field_filter::{VariableOrValue, FieldFilterErrorHandling};
|
||||
use crate::lang::utility::{assert_token, check_name, assert_name, assert_token_raw};
|
||||
use super::field_filter::{FieldFilterErrorHandling, VariableOrValue};
|
||||
use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::MpsTypePrimitive;
|
||||
use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
|
||||
|
@ -51,7 +51,7 @@ impl MpsFilterPredicate for FieldLikeFilter {
|
|||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Value is not type String"),
|
||||
})
|
||||
}),
|
||||
}?;
|
||||
if let Some(field) = music_item_lut.field(&self.field_name) {
|
||||
let field_str = field.as_str().to_lowercase();
|
||||
|
@ -150,7 +150,8 @@ impl MpsFilterFactory<FieldLikeFilter> for FieldLikeFilterFactory {
|
|||
}
|
||||
}
|
||||
|
||||
pub type FieldLikeFilterStatementFactory = MpsFilterStatementFactory<FieldLikeFilter, FieldLikeFilterFactory>;
|
||||
pub type FieldLikeFilterStatementFactory =
|
||||
MpsFilterStatementFactory<FieldLikeFilter, FieldLikeFilterFactory>;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn field_like_filter() -> FieldLikeFilterStatementFactory {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use crate::lang::{MpsLanguageDictionary, MpsTypePrimitive};
|
||||
use crate::lang::{utility::assert_token_raw, Lookup};
|
||||
use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
|
||||
use crate::lang::{MpsLanguageDictionary, MpsTypePrimitive};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::{Lookup, utility::assert_token_raw};
|
||||
use crate::processing::{OpGetter, general::MpsType};
|
||||
use crate::processing::{general::MpsType, OpGetter};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsItem;
|
||||
|
@ -37,17 +37,21 @@ impl MpsFilterPredicate for IndexFilter {
|
|||
MpsTypePrimitive::Int(i) => *i as u64,
|
||||
MpsTypePrimitive::UInt(u) => *u,
|
||||
MpsTypePrimitive::Float(f) => *f as u64,
|
||||
val => return Err(RuntimeError {
|
||||
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),
|
||||
})
|
||||
},
|
||||
val => return Err(RuntimeError {
|
||||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Cannot use {} as index", val),
|
||||
})
|
||||
}
|
||||
};
|
||||
if self.current == index && !self.is_opposite {
|
||||
self.current += 1;
|
||||
|
@ -77,14 +81,8 @@ pub struct IndexFilterFactory;
|
|||
|
||||
impl MpsFilterFactory<IndexFilter> for IndexFilterFactory {
|
||||
fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool {
|
||||
(
|
||||
tokens.len() == 1
|
||||
&& Lookup::check_is(&tokens[0])
|
||||
) || (
|
||||
tokens.len() == 2
|
||||
&& tokens[0].is_exclamation()
|
||||
&& Lookup::check_is(&tokens[1])
|
||||
)
|
||||
(tokens.len() == 1 && Lookup::check_is(&tokens[0]))
|
||||
|| (tokens.len() == 2 && tokens[0].is_exclamation() && Lookup::check_is(&tokens[1]))
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
|
@ -95,7 +93,9 @@ impl MpsFilterFactory<IndexFilter> for IndexFilterFactory {
|
|||
let is_inverted = if tokens[0].is_exclamation() {
|
||||
assert_token_raw(MpsToken::Exclamation, tokens)?;
|
||||
true
|
||||
} else {false};
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let lookup = Lookup::parse(tokens)?;
|
||||
Ok(IndexFilter {
|
||||
index: lookup,
|
||||
|
|
|
@ -10,9 +10,18 @@ pub use empty_filter::{
|
|||
empty_filter, EmptyFilter, EmptyFilterFactory, EmptyFilterStatementFactory,
|
||||
};
|
||||
pub use field_filter::{
|
||||
field_filter, FieldFilter, FieldFilterFactory, FieldFilterStatementFactory, FieldFilterErrorHandling,
|
||||
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 index_filter::{
|
||||
index_filter, IndexFilter, IndexFilterFactory, IndexFilterStatementFactory,
|
||||
};
|
||||
pub use range_filter::{
|
||||
range_filter, RangeFilter, RangeFilterFactory, RangeFilterStatementFactory,
|
||||
};
|
||||
pub use field_filter_maybe::{field_filter_maybe, FieldFilterMaybeFactory, FieldFilterMaybeStatementFactory};
|
||||
pub use field_like_filter::{field_like_filter, FieldLikeFilterFactory, FieldLikeFilterStatementFactory};
|
||||
pub use index_filter::{index_filter, IndexFilter, IndexFilterFactory, IndexFilterStatementFactory};
|
||||
pub use range_filter::{range_filter, RangeFilter, RangeFilterFactory, RangeFilterStatementFactory};
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
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::lang::utility::assert_token_raw;
|
||||
use crate::processing::{OpGetter, general::MpsType};
|
||||
use crate::lang::Lookup;
|
||||
use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
|
||||
use crate::lang::{MpsLanguageDictionary, MpsTypePrimitive};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::{general::MpsType, OpGetter};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
use crate::MpsItem;
|
||||
|
@ -23,10 +23,21 @@ pub struct RangeFilter {
|
|||
|
||||
impl Display for RangeFilter {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "{}{}{}",
|
||||
if let Some(start) = &self.start {format!("{}", start)} else {"".into()},
|
||||
if self.inclusive_end {"="} else {""},
|
||||
if let Some(end) = &self.end {format!("{}", end)} else {"".into()},)
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}",
|
||||
if let Some(start) = &self.start {
|
||||
format!("{}", start)
|
||||
} else {
|
||||
"".into()
|
||||
},
|
||||
if self.inclusive_end { "=" } else { "" },
|
||||
if let Some(end) = &self.end {
|
||||
format!("{}", end)
|
||||
} else {
|
||||
"".into()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +50,9 @@ impl MpsFilterPredicate for RangeFilter {
|
|||
) -> Result<bool, RuntimeError> {
|
||||
let start_index = if let Some(start) = &self.start {
|
||||
lookup_to_index(start.get(ctx, op)?, op)?
|
||||
} else {0};
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let current = self.current;
|
||||
self.current += 1;
|
||||
if current >= start_index {
|
||||
|
@ -87,13 +100,13 @@ fn lookup_to_index(item: &MpsType, op: &mut OpGetter) -> Result<u64, RuntimeErro
|
|||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Cannot use {} as index", val),
|
||||
})
|
||||
}),
|
||||
},
|
||||
val => Err(RuntimeError {
|
||||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Cannot use {} as index", val),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,44 +116,38 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
|
|||
fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool {
|
||||
(
|
||||
// ..
|
||||
tokens.len() == 2
|
||||
&& tokens[0].is_dot()
|
||||
&& tokens[1].is_dot()
|
||||
) || (
|
||||
tokens.len() == 3
|
||||
tokens.len() == 2 && tokens[0].is_dot() && tokens[1].is_dot()
|
||||
) || (tokens.len() == 3
|
||||
&& ((
|
||||
// ..number
|
||||
tokens[0].is_dot()
|
||||
&& tokens[1].is_dot()
|
||||
&& Lookup::check_is(&tokens[2])
|
||||
tokens[0].is_dot() && tokens[1].is_dot() && Lookup::check_is(&tokens[2])
|
||||
) || (
|
||||
// number..
|
||||
Lookup::check_is(&tokens[0])
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_dot()
|
||||
))
|
||||
) || (
|
||||
tokens.len() == 4
|
||||
&& (( // number..number
|
||||
Lookup::check_is(&tokens[0])
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_dot()
|
||||
&& Lookup::check_is(&tokens[3])
|
||||
) || ( // ..=number
|
||||
tokens[0].is_dot()
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_equals()
|
||||
&& Lookup::check_is(&tokens[3])
|
||||
))
|
||||
) || (
|
||||
// number..=number
|
||||
tokens.len() == 5
|
||||
&& Lookup::check_is(&tokens[0])
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_dot()
|
||||
&& tokens[3].is_equals()
|
||||
&& Lookup::check_is(&tokens[4])
|
||||
)
|
||||
Lookup::check_is(&tokens[0]) && tokens[1].is_dot() && tokens[2].is_dot()
|
||||
)))
|
||||
|| (tokens.len() == 4
|
||||
&& ((
|
||||
// number..number
|
||||
Lookup::check_is(&tokens[0])
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_dot()
|
||||
&& Lookup::check_is(&tokens[3])
|
||||
) || (
|
||||
// ..=number
|
||||
tokens[0].is_dot()
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_equals()
|
||||
&& Lookup::check_is(&tokens[3])
|
||||
)))
|
||||
|| (
|
||||
// number..=number
|
||||
tokens.len() == 5
|
||||
&& Lookup::check_is(&tokens[0])
|
||||
&& tokens[1].is_dot()
|
||||
&& tokens[2].is_dot()
|
||||
&& tokens[3].is_equals()
|
||||
&& Lookup::check_is(&tokens[4])
|
||||
)
|
||||
}
|
||||
|
||||
fn build_filter(
|
||||
|
@ -151,7 +158,9 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
|
|||
// start index
|
||||
let start = if Lookup::check_is(&tokens[0]) {
|
||||
Some(Lookup::parse(tokens)?)
|
||||
} else {None};
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// ..
|
||||
assert_token_raw(MpsToken::Dot, tokens)?;
|
||||
assert_token_raw(MpsToken::Dot, tokens)?;
|
||||
|
@ -166,7 +175,9 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
|
|||
// end index
|
||||
let end = if !tokens.is_empty() {
|
||||
Some(Lookup::parse(tokens)?)
|
||||
} else {None};
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(RangeFilter {
|
||||
start: start,
|
||||
|
|
|
@ -8,7 +8,9 @@ use crate::MpsItem;
|
|||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{
|
||||
MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsOp, PseudoOp,
|
||||
};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -28,7 +30,11 @@ impl Display for RepeatStatement {
|
|||
if self.loop_forever {
|
||||
write!(f, "repeat({})", self.inner_statement)
|
||||
} else {
|
||||
write!(f, "repeat({}, {})", self.inner_statement, self.original_repetitions)
|
||||
write!(
|
||||
f,
|
||||
"repeat({}, {})",
|
||||
self.inner_statement, self.original_repetitions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use crate::lang::{MpsSorter, MpsSorterFactory, MpsSortStatementFactory};
|
||||
use crate::lang::{MpsLanguageDictionary, MpsIteratorItem, MpsOp};
|
||||
use crate::lang::{MpsIteratorItem, MpsLanguageDictionary, MpsOp};
|
||||
use crate::lang::{MpsSortStatementFactory, MpsSorter, MpsSorterFactory};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
|
||||
|
@ -10,7 +10,11 @@ use crate::tokens::MpsToken;
|
|||
pub struct EmptySorter;
|
||||
|
||||
impl MpsSorter for EmptySorter {
|
||||
fn sort(&mut self, iterator: &mut dyn MpsOp, item_buf: &mut VecDeque<MpsIteratorItem>) -> Result<(), RuntimeError> {
|
||||
fn sort(
|
||||
&mut self,
|
||||
iterator: &mut dyn MpsOp,
|
||||
item_buf: &mut VecDeque<MpsIteratorItem>,
|
||||
) -> Result<(), RuntimeError> {
|
||||
if let Some(item) = iterator.next() {
|
||||
item_buf.push_back(item)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::lang::{MpsSorter, MpsSorterFactory, MpsSortStatementFactory};
|
||||
use crate::lang::{MpsLanguageDictionary, MpsIteratorItem, MpsOp};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::{MpsIteratorItem, MpsLanguageDictionary, MpsOp};
|
||||
use crate::lang::{MpsSortStatementFactory, MpsSorter, MpsSorterFactory};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -16,7 +16,11 @@ pub struct FieldSorter {
|
|||
}
|
||||
|
||||
impl MpsSorter for FieldSorter {
|
||||
fn sort(&mut self, iterator: &mut dyn MpsOp, item_buf: &mut VecDeque<MpsIteratorItem>) -> Result<(), RuntimeError> {
|
||||
fn sort(
|
||||
&mut self,
|
||||
iterator: &mut dyn MpsOp,
|
||||
item_buf: &mut VecDeque<MpsIteratorItem>,
|
||||
) -> Result<(), RuntimeError> {
|
||||
let buf_len_old = item_buf.len(); // save buffer length before modifying buffer
|
||||
if item_buf.len() < self.up_to {
|
||||
for item in iterator {
|
||||
|
@ -29,20 +33,18 @@ impl MpsSorter for FieldSorter {
|
|||
if buf_len_old != item_buf.len() {
|
||||
// when buf_len_old == item_buf.len(), iterator was already complete
|
||||
// no need to sort in that case, since buffer was sorted in last call to sort or buffer never had any items to sort
|
||||
item_buf.make_contiguous().sort_by(
|
||||
|a, b| {
|
||||
if let Ok(a) = a {
|
||||
if let Some(a_field) = a.field(&self.field_name) {
|
||||
if let Ok(b) = b {
|
||||
if let Some(b_field) = b.field(&self.field_name) {
|
||||
return a_field.partial_cmp(b_field).unwrap_or(self.default_order);
|
||||
}
|
||||
item_buf.make_contiguous().sort_by(|a, b| {
|
||||
if let Ok(a) = a {
|
||||
if let Some(a_field) = a.field(&self.field_name) {
|
||||
if let Ok(b) = b {
|
||||
if let Some(b_field) = b.field(&self.field_name) {
|
||||
return a_field.partial_cmp(b_field).unwrap_or(self.default_order);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.default_order
|
||||
}
|
||||
);
|
||||
self.default_order
|
||||
});
|
||||
println!("Field-sorted item_buf: {:?}", item_buf);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -67,14 +69,18 @@ impl MpsSorterFactory<FieldSorter> for FieldSorterFactory {
|
|||
tokens: &mut VecDeque<MpsToken>,
|
||||
_dict: &MpsLanguageDictionary,
|
||||
) -> Result<FieldSorter, SyntaxError> {
|
||||
let name = assert_token(|t| match t {
|
||||
MpsToken::Name(s) => Some(s),
|
||||
_ => None
|
||||
}, MpsToken::Name("field_name".into()), tokens)?;
|
||||
let name = assert_token(
|
||||
|t| match t {
|
||||
MpsToken::Name(s) => Some(s),
|
||||
_ => None,
|
||||
},
|
||||
MpsToken::Name("field_name".into()),
|
||||
tokens,
|
||||
)?;
|
||||
Ok(FieldSorter {
|
||||
field_name: name,
|
||||
up_to: usize::MAX,
|
||||
default_order: Ordering::Equal
|
||||
default_order: Ordering::Equal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ use crate::MpsContext;
|
|||
use crate::lang::repeated_tokens;
|
||||
use crate::lang::utility::{assert_token, assert_token_raw};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::SyntaxError;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsOp};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SqlInitStatement {
|
||||
|
|
|
@ -3,7 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{
|
||||
MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsLanguageDictionary, MpsOp,
|
||||
};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
|
|
|
@ -3,7 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
|
|||
use std::iter::Iterator;
|
||||
|
||||
use crate::lang::utility::assert_token;
|
||||
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem};
|
||||
use crate::lang::{
|
||||
MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsLanguageDictionary, MpsOp,
|
||||
};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::tokens::MpsToken;
|
||||
use crate::MpsContext;
|
||||
|
|
|
@ -7,7 +7,9 @@ use crate::MpsContext;
|
|||
|
||||
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
|
||||
use crate::lang::MpsLanguageDictionary;
|
||||
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp, MpsIteratorItem};
|
||||
use crate::lang::{
|
||||
BoxedMpsOpFactory, MpsIteratorItem, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp,
|
||||
};
|
||||
use crate::lang::{RuntimeError, SyntaxError};
|
||||
use crate::processing::general::MpsType;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
|
|||
use regex::Regex;
|
||||
|
||||
use super::OpGetter;
|
||||
use crate::lang::{RuntimeError, MpsTypePrimitive};
|
||||
use crate::lang::{MpsTypePrimitive, RuntimeError};
|
||||
use crate::MpsItem;
|
||||
|
||||
const DEFAULT_REGEX: &str = r"/(?P<artist>[^/]+)/(?P<album>[^/]+)/(?:(?:(?P<disc>\d+)\s+)?(?P<track>\d+)\.?\s+)?(?P<title>[^/]+)\.(?P<format>(?:mp3)|(?:wav)|(?:ogg)|(?:flac)|(?:mp4)|(?:aac))$";
|
||||
|
@ -100,11 +100,12 @@ impl FileIter {
|
|||
} else {
|
||||
Vec::with_capacity(DEFAULT_VEC_CACHE_SIZE)
|
||||
};
|
||||
let pattern_re = Regex::new(pattern.unwrap_or(DEFAULT_REGEX)).map_err(|e| RuntimeError {
|
||||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Regex compile error: {}", e),
|
||||
})?;
|
||||
let pattern_re =
|
||||
Regex::new(pattern.unwrap_or(DEFAULT_REGEX)).map_err(|e| RuntimeError {
|
||||
line: 0,
|
||||
op: op(),
|
||||
msg: format!("Regex compile error: {}", e),
|
||||
})?;
|
||||
Ok(Self {
|
||||
root: root_path,
|
||||
pattern: pattern_re,
|
||||
|
@ -182,12 +183,12 @@ impl FileIter {
|
|||
}
|
||||
}
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
let mut item = MpsItem::new();
|
||||
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +215,10 @@ impl FileIter {
|
|||
// populates fields from named capture groups
|
||||
while let Some(name_maybe) = capture_names.next() {
|
||||
if let Some(name) = name_maybe {
|
||||
if let Some(value) = captures.name(name).and_then(|m| Some(m.as_str().to_string())) {
|
||||
if let Some(value) = captures
|
||||
.name(name)
|
||||
.and_then(|m| Some(m.as_str().to_string()))
|
||||
{
|
||||
item.set_field(name, MpsTypePrimitive::parse(value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -259,10 +259,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn build_mps_item(
|
||||
conn: &mut rusqlite::Connection,
|
||||
item: DbMusicItem,
|
||||
) -> rusqlite::Result<MpsItem> {
|
||||
fn build_mps_item(conn: &mut rusqlite::Connection, item: DbMusicItem) -> rusqlite::Result<MpsItem> {
|
||||
// query artist
|
||||
let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?;
|
||||
let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?;
|
||||
|
@ -331,7 +328,6 @@ fn rows_to_item(
|
|||
meta: DbMetaItem,
|
||||
genre: DbGenreItem,
|
||||
) -> MpsItem {
|
||||
|
||||
let mut item = MpsItem::new();
|
||||
item
|
||||
// music row
|
||||
|
|
|
@ -45,7 +45,9 @@ impl MpsToken {
|
|||
_ => {
|
||||
// name validation
|
||||
let mut ok = true;
|
||||
for invalid_c in ["-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", ".", "&", "|"] {
|
||||
for invalid_c in [
|
||||
"-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", ".", "&", "|",
|
||||
] {
|
||||
if s.contains(invalid_c) {
|
||||
ok = false;
|
||||
break;
|
||||
|
|
|
@ -258,10 +258,12 @@ impl ReaderStateMachine {
|
|||
'#' => Self::Octothorpe { out: input },
|
||||
'`' => Self::StartTickLiteral {},
|
||||
'"' => Self::StartQuoteLiteral {},
|
||||
'\n'| '\r' | '\t' | ' ' => Self::EndToken {},
|
||||
'\n' | '\r' | '\t' | ' ' => Self::EndToken {},
|
||||
';' => Self::EndStatement {},
|
||||
'\0' => Self::EndOfFile {},
|
||||
'(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' | '|' | ':' => Self::SingleCharToken { out: input },
|
||||
'(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' | '|' | ':' => {
|
||||
Self::SingleCharToken { out: input }
|
||||
}
|
||||
_ => Self::Regular { out: input },
|
||||
},
|
||||
Self::Escaped { inside } => match inside {
|
||||
|
|
|
@ -62,9 +62,18 @@ fn execute_single_line(
|
|||
break;
|
||||
}
|
||||
} // no need to spam the rest of the songs
|
||||
println!("Got song `{}` (file: `{}`)",
|
||||
item.field("title").expect("Expected field `title` to exist").clone().to_str().expect("Expected field `title` to be String"),
|
||||
item.field("filename").expect("Expected field `filename` to exist").clone().to_str().expect("Expected field `filename` to be String")
|
||||
println!(
|
||||
"Got song `{}` (file: `{}`)",
|
||||
item.field("title")
|
||||
.expect("Expected field `title` to exist")
|
||||
.clone()
|
||||
.to_str()
|
||||
.expect("Expected field `title` to be String"),
|
||||
item.field("filename")
|
||||
.expect("Expected field `filename` to exist")
|
||||
.clone()
|
||||
.to_str()
|
||||
.expect("Expected field `filename` to be String")
|
||||
);
|
||||
} else {
|
||||
println!("!!! Got error while iterating (executing) !!!");
|
||||
|
@ -109,9 +118,21 @@ fn execute_comment_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
|||
|
||||
#[test]
|
||||
fn execute_repeat_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
||||
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`))", false, false)?;
|
||||
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 4)", false, true)?;
|
||||
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 0)", true, true)
|
||||
execute_single_line(
|
||||
"repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`))",
|
||||
false,
|
||||
false,
|
||||
)?;
|
||||
execute_single_line(
|
||||
"repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 4)",
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
execute_single_line(
|
||||
"repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 0)",
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -135,7 +156,11 @@ fn execute_assign_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
|||
|
||||
#[test]
|
||||
fn execute_emptyfilter_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
||||
execute_single_line("files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).().().()", false, true)
|
||||
execute_single_line(
|
||||
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).().().()",
|
||||
false,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -26,8 +26,14 @@ impl MpsController {
|
|||
let (playback_tx, playback_rx) = channel();
|
||||
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
|
||||
sys_ctrl.init(playback_rx);
|
||||
let handle =
|
||||
MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, playback_tx, false);
|
||||
let handle = MpsPlayerServer::spawn(
|
||||
player_gen,
|
||||
control_tx.clone(),
|
||||
control_rx,
|
||||
event_tx,
|
||||
playback_tx,
|
||||
false,
|
||||
);
|
||||
Self {
|
||||
control: control_tx,
|
||||
event: event_rx,
|
||||
|
@ -44,8 +50,14 @@ impl MpsController {
|
|||
let (playback_tx, playback_rx) = channel();
|
||||
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
|
||||
sys_ctrl.init(playback_rx);
|
||||
let handle =
|
||||
MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, playback_tx, true);
|
||||
let handle = MpsPlayerServer::spawn(
|
||||
player_gen,
|
||||
control_tx.clone(),
|
||||
control_rx,
|
||||
event_tx,
|
||||
playback_tx,
|
||||
true,
|
||||
);
|
||||
Self {
|
||||
control: control_tx,
|
||||
event: event_rx,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#[allow(unused_imports)]
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls"))]
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls"))]
|
||||
use mpris_player::{MprisPlayer, PlaybackStatus, Metadata};
|
||||
use mpris_player::{Metadata, MprisPlayer, PlaybackStatus};
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls"))]
|
||||
use mps_interpreter::MpsItem;
|
||||
|
@ -21,7 +21,6 @@ pub struct SystemControlWrapper {
|
|||
dbus_ctrl: Option<Sender<DbusControl>>,
|
||||
playback_event_handler: Option<JoinHandle<()>>,
|
||||
playback_event_handler_killer: Option<Sender<()>>,
|
||||
|
||||
}
|
||||
|
||||
/// OS-specific APIs for media controls.
|
||||
|
@ -135,27 +134,25 @@ impl SystemControlWrapper {
|
|||
loop {
|
||||
dbus_conn.poll(5);
|
||||
match dbus_ctrl.try_recv() {
|
||||
Err(_) => {},
|
||||
Err(_) => {}
|
||||
Ok(DbusControl::Die) => break,
|
||||
Ok(DbusControl::SetMetadata(meta)) => {
|
||||
dbus_conn.set_metadata(meta);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
let (tx, rx) = channel();
|
||||
self.playback_event_handler_killer = Some(tx);
|
||||
self.playback_event_handler = Some(std::thread::spawn(move || {
|
||||
loop {
|
||||
if let Ok(_) = rx.try_recv() {
|
||||
break;
|
||||
}
|
||||
match playback.recv() {
|
||||
Err(_) => break,
|
||||
Ok(PlaybackAction::Exit) => break,
|
||||
Ok(PlaybackAction::Enqueued(item)) => Self::enqueued(item, &dbus_ctrl_tx_clone),
|
||||
Ok(PlaybackAction::Empty) => Self::empty(&dbus_ctrl_tx_clone),
|
||||
}
|
||||
self.playback_event_handler = Some(std::thread::spawn(move || loop {
|
||||
if let Ok(_) = rx.try_recv() {
|
||||
break;
|
||||
}
|
||||
match playback.recv() {
|
||||
Err(_) => break,
|
||||
Ok(PlaybackAction::Exit) => break,
|
||||
Ok(PlaybackAction::Enqueued(item)) => Self::enqueued(item, &dbus_ctrl_tx_clone),
|
||||
Ok(PlaybackAction::Empty) => Self::empty(&dbus_ctrl_tx_clone),
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -179,35 +176,48 @@ impl SystemControlWrapper {
|
|||
|
||||
fn enqueued(item: MpsItem, dbus_ctrl: &Sender<DbusControl>) {
|
||||
//println!("Got enqueued item {}", &item.title);
|
||||
dbus_ctrl.send(DbusControl::SetMetadata(Metadata {
|
||||
length: None,
|
||||
art_url: None,
|
||||
album: item.field("album").and_then(|x| x.to_owned().to_str()),
|
||||
album_artist: None, // TODO maybe?
|
||||
artist: item.field("artist").and_then(|x| x.to_owned().to_str()).map(|x| vec![x]),
|
||||
composer: None,
|
||||
disc_number: None,
|
||||
genre: item.field("genre").and_then(|x| x.to_owned().to_str()).map(|genre| vec![genre]),
|
||||
title: item.field("title").and_then(|x| x.to_owned().to_str()),
|
||||
track_number: item.field("track").and_then(|x| x.to_owned().to_i64()).map(|track| track as i32),
|
||||
url: item.field("filename").and_then(|x| x.to_owned().to_str()),
|
||||
})).unwrap_or(());
|
||||
dbus_ctrl
|
||||
.send(DbusControl::SetMetadata(Metadata {
|
||||
length: None,
|
||||
art_url: None,
|
||||
album: item.field("album").and_then(|x| x.to_owned().to_str()),
|
||||
album_artist: None, // TODO maybe?
|
||||
artist: item
|
||||
.field("artist")
|
||||
.and_then(|x| x.to_owned().to_str())
|
||||
.map(|x| vec![x]),
|
||||
composer: None,
|
||||
disc_number: None,
|
||||
genre: item
|
||||
.field("genre")
|
||||
.and_then(|x| x.to_owned().to_str())
|
||||
.map(|genre| vec![genre]),
|
||||
title: item.field("title").and_then(|x| x.to_owned().to_str()),
|
||||
track_number: item
|
||||
.field("track")
|
||||
.and_then(|x| x.to_owned().to_i64())
|
||||
.map(|track| track as i32),
|
||||
url: item.field("filename").and_then(|x| x.to_owned().to_str()),
|
||||
}))
|
||||
.unwrap_or(());
|
||||
}
|
||||
|
||||
fn empty(dbus_ctrl: &Sender<DbusControl>) {
|
||||
dbus_ctrl.send(DbusControl::SetMetadata(Metadata {
|
||||
length: None,
|
||||
art_url: None,
|
||||
album: None,
|
||||
album_artist: None, // TODO maybe?
|
||||
artist: None,
|
||||
composer: None,
|
||||
disc_number: None,
|
||||
genre: None,
|
||||
title: None,
|
||||
track_number: None,
|
||||
url: None,
|
||||
})).unwrap_or(());
|
||||
dbus_ctrl
|
||||
.send(DbusControl::SetMetadata(Metadata {
|
||||
length: None,
|
||||
art_url: None,
|
||||
album: None,
|
||||
album_artist: None, // TODO maybe?
|
||||
artist: None,
|
||||
composer: None,
|
||||
disc_number: None,
|
||||
genre: None,
|
||||
title: None,
|
||||
track_number: None,
|
||||
url: None,
|
||||
}))
|
||||
.unwrap_or(());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,7 +226,7 @@ impl SystemControlWrapper {
|
|||
pub fn new(control: Sender<ControlAction>) -> Self {
|
||||
Self {
|
||||
control: control,
|
||||
playback_receiver: None
|
||||
playback_receiver: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
|
|||
|
||||
use m3u8_rs::{MediaPlaylist, MediaSegment};
|
||||
|
||||
use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsItem};
|
||||
use mps_interpreter::{tokens::MpsTokenReader, MpsItem, MpsRunner};
|
||||
|
||||
use super::PlaybackError;
|
||||
|
||||
|
@ -36,14 +36,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
self.sink.sleep_until_end();
|
||||
match item {
|
||||
Ok(music) => {
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
if let Some(filename) =
|
||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||
{
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
Err(PlaybackError::from_err(
|
||||
"Field `filename` does not exist on item",
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
|
@ -59,14 +63,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
match item {
|
||||
Ok(music) => {
|
||||
enqueued.push(music.clone());
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
if let Some(filename) =
|
||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||
{
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
Err(PlaybackError::from_err(
|
||||
"Field `filename` does not exist on item",
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
|
@ -85,14 +93,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
match item {
|
||||
Ok(music) => {
|
||||
enqueued.push(music.clone());
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
if let Some(filename) =
|
||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||
{
|
||||
let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
|
||||
let stream = io::BufReader::new(file);
|
||||
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
|
||||
self.sink.append(source);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
Err(PlaybackError::from_err(
|
||||
"Field `filename` does not exist on item",
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
|
@ -139,7 +151,9 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
for item in &mut self.runner {
|
||||
match item {
|
||||
Ok(music) => {
|
||||
if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
|
||||
if let Some(filename) =
|
||||
music.field("filename").and_then(|x| x.to_owned().to_str())
|
||||
{
|
||||
playlist.segments.push(MediaSegment {
|
||||
uri: filename,
|
||||
title: music.field("title").and_then(|x| x.to_owned().to_str()),
|
||||
|
@ -147,7 +161,9 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
|
|||
});
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
|
||||
Err(PlaybackError::from_err(
|
||||
"Field `filename` does not exist on item",
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(PlaybackError::from_err(e)),
|
||||
|
|
|
@ -40,9 +40,12 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
|
|||
//println!("Enqueuing up to {} items", count);
|
||||
match self.player.enqueue(count) {
|
||||
Err(e) => self.event.send(PlayerAction::Exception(e)).unwrap(),
|
||||
Ok(items) => for item in items { // notify of new items that have been enqueued
|
||||
self.playback.send(PlaybackAction::Enqueued(item)).unwrap();
|
||||
},
|
||||
Ok(items) => {
|
||||
for item in items {
|
||||
// notify of new items that have been enqueued
|
||||
self.playback.send(PlaybackAction::Enqueued(item)).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
src/repl.rs
10
src/repl.rs
|
@ -56,7 +56,7 @@ pub fn repl(args: CliArgs) {
|
|||
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
|
||||
eprintln!("{}", e.message());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
playlist_writer
|
||||
.flush()
|
||||
|
@ -111,7 +111,7 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
|
|||
} else {
|
||||
state.in_literal = Some(read_buf[0] as char);
|
||||
}
|
||||
},
|
||||
}
|
||||
'(' => state.bracket_depth += 1,
|
||||
')' => state.bracket_depth -= 1,
|
||||
';' => {
|
||||
|
@ -123,7 +123,7 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
|
|||
execute();
|
||||
state.statement_buf.clear();
|
||||
}
|
||||
},
|
||||
}
|
||||
'\n' => {
|
||||
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
|
||||
if statement_result.is_ok() && statement_result.unwrap().trim().starts_with("?") {
|
||||
|
@ -140,8 +140,8 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
|
|||
state.statement_buf.clear();
|
||||
}
|
||||
prompt(&mut state.line_number, args);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue