cargo fmt

This commit is contained in:
NGnius (Graham) 2022-01-24 16:12:29 -05:00
parent 8dc571521f
commit 0a6dae930f
33 changed files with 531 additions and 323 deletions

View file

@ -3,12 +3,12 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::lang::utility::{assert_token, assert_token_raw, check_name, assert_name}; use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
use crate::lang::MpsLanguageDictionary;
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem};
use crate::lang::{RuntimeError, SyntaxError};
use crate::lang::SingleItem;
use crate::lang::MpsFilterReplaceStatement; 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::general::MpsType;
use crate::processing::OpGetter; use crate::processing::OpGetter;
use crate::tokens::MpsToken; 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> { impl<P: MpsFilterPredicate + 'static> Display for MpsFilterStatement<P> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
if let Some(other_filters) = &self.other_filters { 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 { } else {
write!(f, "{}.({})", self.iterable, self.predicate) write!(f, "{}.({})", self.iterable, self.predicate)
} }
@ -103,15 +107,19 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
} else { } else {
false false
} }
} else {true} // ASSUMPTION } else {
true
} // ASSUMPTION
} }
VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(), VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(),
VariableOrOp::Op(PseudoOp::Fake(_)) => false, VariableOrOp::Op(PseudoOp::Fake(_)) => false,
}; };
let is_other_filter_resetable = if let Some(PseudoOp::Real(other_filter)) = &self.other_filters { let is_other_filter_resetable =
other_filter.is_resetable() if let Some(PseudoOp::Real(other_filter)) = &self.other_filters {
} else {true}; other_filter.is_resetable()
} else {
true
};
is_iterable_resetable && is_other_filter_resetable is_iterable_resetable && is_other_filter_resetable
} }
@ -122,7 +130,12 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
VariableOrOp::Variable(s) => { VariableOrOp::Variable(s) => {
if self.context.as_mut().unwrap().variables.exists(s) { if self.context.as_mut().unwrap().variables.exists(s) {
let fake_getter = &mut move || fake.clone(); 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 { let result = if let MpsType::Op(var) = &mut var {
var.enter(self.context.take().unwrap()); var.enter(self.context.take().unwrap());
let result = var.reset(); 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(), 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 result
} else {Ok(())} } else {
}, Ok(())
}
}
VariableOrOp::Op(PseudoOp::Real(op)) => { VariableOrOp::Op(PseudoOp::Real(op)) => {
op.enter(self.context.take().unwrap()); op.enter(self.context.take().unwrap());
let result = op.reset(); let result = op.reset();
self.context = Some(op.escape()); self.context = Some(op.escape());
result result
}, }
VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError { VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError {
line: 0, line: 0,
op: fake, op: fake,
@ -156,7 +175,9 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
let result = other_filter.reset(); let result = other_filter.reset();
self.context = Some(other_filter.escape()); self.context = Some(other_filter.escape());
result result
} else {Ok(())} } else {
Ok(())
}
} }
} }
@ -185,7 +206,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
maybe_result = Some(Err(e)); maybe_result = Some(Err(e));
self.context = Some(ctx); self.context = Some(ctx);
break; break;
}, }
Ok(item) => { Ok(item) => {
let matches_result = let matches_result =
self.predicate.matches(&item, &mut ctx, &mut op_getter); self.predicate.matches(&item, &mut ctx, &mut op_getter);
@ -201,14 +222,18 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
// handle other filters // handle other filters
// make fake inner item // make fake inner item
let single_op = SingleItem::new_ok(item.clone()); 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, Ok(x) => x,
Err(e) => { Err(e) => {
//self.context = Some(op.escape()); //self.context = Some(op.escape());
maybe_result = Some(Err(e)); maybe_result = Some(Err(e));
self.context = Some(ctx); self.context = Some(ctx);
break; break;
}, }
}; };
let inner_real = match inner.try_real() { let inner_real = match inner.try_real() {
Ok(x) => x, Ok(x) => x,
@ -217,28 +242,34 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
maybe_result = Some(Err(e)); maybe_result = Some(Err(e));
self.context = Some(ctx); self.context = Some(ctx);
break; break;
}, }
}; };
inner_real.enter(ctx); inner_real.enter(ctx);
match inner_real.next() { match inner_real.next() {
Some(item) => { Some(item) => {
maybe_result = Some(item); maybe_result = Some(item);
ctx = inner_real.escape(); ctx = inner_real.escape();
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) { match ctx
Ok(_) => {}, .variables
.remove(INNER_VARIABLE_NAME, &mut op_getter)
{
Ok(_) => {}
Err(e) => match maybe_result { Err(e) => match maybe_result {
Some(Ok(_)) => maybe_result = Some(Err(e)), Some(Ok(_)) => maybe_result = Some(Err(e)),
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error, Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
None => {}, // impossible None => {} // impossible
} },
} }
self.context = Some(ctx); self.context = Some(ctx);
break; break;
}, }
None => { None => {
ctx = inner_real.escape(); // move ctx back to expected spot ctx = inner_real.escape(); // move ctx back to expected spot
match ctx.variables.remove(INNER_VARIABLE_NAME, &mut op_getter) { match ctx
Ok(_) => {}, .variables
.remove(INNER_VARIABLE_NAME, &mut op_getter)
{
Ok(_) => {}
Err(e) => { Err(e) => {
//self.context = Some(op.escape()); //self.context = Some(op.escape());
maybe_result = Some(Err(e)); 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]) { if tokens2.len() != 0 && check_name("if", &tokens2[0]) {
// replacement filter // replacement filter
if let Some(colon_location) = first_colon2(&tokens2) { 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) self.filter_factory.is_filter(&tokens3)
} else { } else {
false false
@ -386,9 +419,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
// regular filter // regular filter
self.filter_factory.is_filter(&tokens2) self.filter_factory.is_filter(&tokens2)
} }
} }
} }
} else { } else {
false false
@ -442,7 +473,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
tokens.extend(end_tokens); tokens.extend(end_tokens);
assert_name("else", tokens)?; assert_name("else", tokens)?;
let end_tokens = tokens.split_off(tokens.len() - 1); // up to ending close bracket 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()); else_op = Some(dict.try_build_statement(tokens)?.into());
tokens.extend(end_tokens); tokens.extend(end_tokens);
} else { } else {
@ -458,7 +489,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
context: None, context: None,
op_if: if_op, op_if: if_op,
op_else: else_op, op_else: else_op,
item_cache: super::filter_replace::item_cache_deque() item_cache: super::filter_replace::item_cache_deque(),
})) }))
} else { } else {
Err(SyntaxError { Err(SyntaxError {
@ -467,13 +498,13 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
got: None, got: None,
}) })
} }
} };
} else { } else {
let mut another_filter = None; let mut another_filter = None;
let (has_or, end_tokens) = if let Some(pipe_location) = first_double_pipe(tokens, 0) { 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 (true, tokens.split_off(pipe_location)) // parse up to OR operator
} else { } 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)?; let filter = self.filter_factory.build_filter(tokens, dict)?;
tokens.extend(end_tokens); tokens.extend(end_tokens);
@ -496,7 +527,6 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
other_filters: another_filter, 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() { for i in 0..tokens.len() {
if tokens[i].is_pipe() && inside_brackets == in_brackets { if tokens[i].is_pipe() && inside_brackets == in_brackets {
if pipe_found { if pipe_found {
return Some(i-1); return Some(i - 1);
} else { } else {
pipe_found = true; pipe_found = true;
} }

View file

@ -2,10 +2,10 @@ use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::{MpsOp, PseudoOp, MpsIteratorItem};
use crate::lang::RuntimeError; use crate::lang::RuntimeError;
use crate::lang::{MpsFilterPredicate, filter::VariableOrOp};
use crate::lang::SingleItem; use crate::lang::SingleItem;
use crate::lang::{filter::VariableOrOp, MpsFilterPredicate};
use crate::lang::{MpsIteratorItem, MpsOp, PseudoOp};
use crate::processing::general::MpsType; use crate::processing::general::MpsType;
use crate::processing::OpGetter; use crate::processing::OpGetter;
use crate::MpsContext; use crate::MpsContext;
@ -45,9 +45,17 @@ impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterReplaceStat
impl<P: MpsFilterPredicate + 'static> Display for MpsFilterReplaceStatement<P> { impl<P: MpsFilterPredicate + 'static> Display for MpsFilterReplaceStatement<P> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
if let Some(op_else) = &self.op_else { 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 { } 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 { } else {
false false
} }
} else {true} // ASSUMPTION } else {
true
} // ASSUMPTION
} }
VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(), VariableOrOp::Op(PseudoOp::Real(op)) => op.is_resetable(),
VariableOrOp::Op(PseudoOp::Fake(_)) => false, VariableOrOp::Op(PseudoOp::Fake(_)) => false,
@ -87,7 +96,12 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
VariableOrOp::Variable(s) => { VariableOrOp::Variable(s) => {
if self.context.as_mut().unwrap().variables.exists(s) { if self.context.as_mut().unwrap().variables.exists(s) {
let fake_getter = &mut move || fake.clone(); 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 { let result = if let MpsType::Op(var) = &mut var {
var.enter(self.context.take().unwrap()); var.enter(self.context.take().unwrap());
let result = var.reset(); 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(), 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 result
} else {Ok(())} } else {
}, Ok(())
}
}
VariableOrOp::Op(PseudoOp::Real(op)) => { VariableOrOp::Op(PseudoOp::Real(op)) => {
op.enter(self.context.take().unwrap()); op.enter(self.context.take().unwrap());
let result = op.reset(); let result = op.reset();
self.context = Some(op.escape()); self.context = Some(op.escape());
result result
}, }
VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError { VariableOrOp::Op(PseudoOp::Fake(_)) => Err(RuntimeError {
line: 0, line: 0,
op: fake, op: fake,
@ -171,7 +191,7 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
&mut op_getter, &mut op_getter,
) { ) {
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
Ok(_) => {}, Ok(_) => {}
} }
item item
} }
@ -180,8 +200,11 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
match next_item { match next_item {
Some(Ok(item)) => { Some(Ok(item)) => {
//println!("item is now: `{}`", &item.filename); //println!("item is now: `{}`", &item.filename);
match self.predicate.matches(&item, self.context.as_mut().unwrap(), &mut op_getter) { match self
Ok(is_match) => .predicate
.matches(&item, self.context.as_mut().unwrap(), &mut op_getter)
{
Ok(is_match) => {
if is_match { if is_match {
// unwrap inner operation // unwrap inner operation
match self.op_if.try_real() { match self.op_if.try_real() {
@ -189,7 +212,11 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
// build item variable // build item variable
let single_op = SingleItem::new_ok(item); let single_op = SingleItem::new_ok(item);
//println!("Declaring item variable"); //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, Ok(x) => x,
Err(e) => return Some(Err(e)), // probably shouldn't occur 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()); self.context = Some(real_op.escape());
// destroy item variable // destroy item variable
//println!("Removing item variable"); //println!("Removing item variable");
match remove_or_replace_item(old_item, &mut op_getter, self.context.as_mut().unwrap()) { match remove_or_replace_item(
Ok(_) => {}, old_item,
Err(e) => return Some(Err(e)) &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 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 // build item variable
let single_op = SingleItem::new_ok(item); let single_op = SingleItem::new_ok(item);
//println!("Declaring item variable"); //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, Ok(x) => x,
Err(e) => return Some(Err(e)), // probably shouldn't occur 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.item_cache.push_back(item);
} }
self.context = Some(real_op.escape()); self.context = Some(real_op.escape());
// destroy item variable // destroy item variable
//println!("Removing item variable"); //println!("Removing item variable");
match remove_or_replace_item(old_item, &mut op_getter, self.context.as_mut().unwrap()) { match remove_or_replace_item(
Ok(_) => {}, old_item,
Err(e) => return Some(Err(e)) &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 Err(e) => return Some(Err(e)), // probably shouldn't occur
@ -262,28 +301,38 @@ impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P>
} }
} else { } else {
Some(Ok(item)) Some(Ok(item))
}, }
Err(e) => return Some(Err(e)) }
Err(e) => return Some(Err(e)),
} }
}, }
Some(Err(e)) => Some(Err(e)), Some(Err(e)) => Some(Err(e)),
None => None, 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>; let old_item: Option<MpsType>;
if ctx.variables.exists(ITEM_VARIABLE_NAME) { if ctx.variables.exists(ITEM_VARIABLE_NAME) {
old_item = Some(ctx.variables.remove(ITEM_VARIABLE_NAME, op)?); old_item = Some(ctx.variables.remove(ITEM_VARIABLE_NAME, op)?);
} else { } else {
old_item = None; 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) 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)?; ctx.variables.remove(ITEM_VARIABLE_NAME, op)?;
if let Some(old_item) = old_item { if let Some(old_item) = old_item {
ctx.variables.declare(ITEM_VARIABLE_NAME, old_item, op)?; ctx.variables.declare(ITEM_VARIABLE_NAME, old_item, op)?;

View file

@ -2,17 +2,17 @@ use std::collections::VecDeque;
use std::fmt::{Display, Error, Formatter}; use std::fmt::{Display, Error, Formatter};
//use super::MpsTypePrimitive; //use super::MpsTypePrimitive;
use crate::processing::general::MpsType; use super::utility::{assert_token, assert_type, check_is_type};
use crate::lang::{RuntimeError, SyntaxError}; 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::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::processing::OpGetter;
#[derive(Debug)] #[derive(Debug)]
pub enum Lookup { pub enum Lookup {
Static(MpsType), Static(MpsType),
Variable(String) Variable(String),
} }
impl Lookup { impl Lookup {
@ -29,24 +29,36 @@ impl Lookup {
} else if check_is_type(&tokens[0]) { } else if check_is_type(&tokens[0]) {
Ok(Self::Static(MpsType::Primitive(assert_type(tokens)?))) Ok(Self::Static(MpsType::Primitive(assert_type(tokens)?)))
} else { } else {
Ok(Self::Variable(assert_token(|t| match t { Ok(Self::Variable(assert_token(
MpsToken::Name(s) => Some(s), |t| match t {
_ => None, MpsToken::Name(s) => Some(s),
}, MpsToken::Name("variable_name".into()), tokens)?)) _ => 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 { match self {
Self::Static(var) => Ok(var), 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 { match self {
Self::Static(var) => Ok(var), 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::Static(var) => write!(f, "{}", var),
Self::Variable(name) => write!(f, "{}", name), Self::Variable(name) => write!(f, "{}", name),
} }
} }
} }
@ -66,7 +77,7 @@ impl std::clone::Clone for Lookup {
match self { match self {
Self::Static(var) => match var { Self::Static(var) => match var {
MpsType::Primitive(p) => Self::Static(MpsType::Primitive(p.clone())), 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()), Self::Variable(name) => Self::Variable(name.clone()),
} }

View file

@ -22,11 +22,11 @@ pub use filter::{
pub use filter_replace::MpsFilterReplaceStatement; pub use filter_replace::MpsFilterReplaceStatement;
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory}; pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
pub use lookup::Lookup; 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 pseudo_op::PseudoOp;
pub use repeated_meme::{repeated_tokens, RepeatedTokens}; pub use repeated_meme::{repeated_tokens, RepeatedTokens};
pub use single_op::SingleItem; 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(crate) use statement::MpsStatement;
pub use type_primitives::MpsTypePrimitive; pub use type_primitives::MpsTypePrimitive;

View file

@ -1,7 +1,7 @@
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::{MpsOp, RuntimeError, MpsIteratorItem}; use crate::lang::{MpsIteratorItem, MpsOp, RuntimeError};
use crate::MpsContext; use crate::MpsContext;
use crate::MpsItem; use crate::MpsItem;
@ -34,7 +34,7 @@ impl Display for SingleItem {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match &self.item { match &self.item {
Ok(item) => write!(f, "*single item*[Ok({})]", 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),
} }
} }
} }

View file

@ -3,9 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use std::marker::PhantomData; 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::MpsLanguageDictionary;
use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem}; use crate::lang::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, PseudoOp};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
@ -13,7 +13,11 @@ use crate::MpsContext;
const SORTER_ITEM_CACHE_SIZE: usize = 8; const SORTER_ITEM_CACHE_SIZE: usize = 8;
pub trait MpsSorter: Clone + Debug + Display { 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> { pub trait MpsSorterFactory<S: MpsSorter + 'static> {
@ -62,7 +66,9 @@ impl<S: MpsSorter + 'static> MpsOp for MpsSortStatement<S> {
fn is_resetable(&self) -> bool { fn is_resetable(&self) -> bool {
if let Ok(iter) = self.iterable.try_real_ref() { if let Ok(iter) = self.iterable.try_real_ref() {
iter.is_resetable() iter.is_resetable()
} else {false} } else {
false
}
} }
fn reset(&mut self) -> Result<(), RuntimeError> { fn reset(&mut self) -> Result<(), RuntimeError> {
@ -80,7 +86,7 @@ impl<S: MpsSorter + 'static> Iterator for MpsSortStatement<S> {
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
}; };
match self.orderer.sort(real_op.as_mut(), &mut self.item_cache) { match self.orderer.sort(real_op.as_mut(), &mut self.item_cache) {
Ok(_) => {}, Ok(_) => {}
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
} }
self.item_cache.pop_front() self.item_cache.pop_front()
@ -92,9 +98,7 @@ pub struct MpsSortStatementFactory<S: MpsSorter + 'static, F: MpsSorterFactory<S
idc: PhantomData<S>, idc: PhantomData<S>,
} }
impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> impl<S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> MpsSortStatementFactory<S, F> {
MpsSortStatementFactory<S, F>
{
pub fn new(factory: F) -> Self { pub fn new(factory: F) -> Self {
Self { Self {
sort_factory: factory, 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> for MpsSortStatementFactory<S, F>
{ {
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool { fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
@ -112,18 +116,20 @@ impl <S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactor
// iterable~(sorter) // iterable~(sorter)
if tokens_len > tilde_location + 2 { if tokens_len > tilde_location + 2 {
let tokens2: VecDeque<&MpsToken> = let tokens2: VecDeque<&MpsToken> =
VecDeque::from_iter(tokens.range(tilde_location+2..tokens_len-1)); VecDeque::from_iter(tokens.range(tilde_location + 2..tokens_len - 1));
tokens[tokens_len-1].is_close_bracket() tokens[tokens_len - 1].is_close_bracket() && self.sort_factory.is_sorter(&tokens2)
&& self.sort_factory.is_sorter(&tokens2) } else {
} else {false} false
}
} else if let Some(dot_location) = last_dot_sort(tokens, 1) { } else if let Some(dot_location) = last_dot_sort(tokens, 1) {
// iterable.sort(sorter) // iterable.sort(sorter)
if tokens_len > dot_location + 3 { if tokens_len > dot_location + 3 {
let tokens2: VecDeque<&MpsToken> = let tokens2: VecDeque<&MpsToken> =
VecDeque::from_iter(tokens.range(dot_location+3..tokens_len-1)); VecDeque::from_iter(tokens.range(dot_location + 3..tokens_len - 1));
tokens[tokens_len-1].is_close_bracket() tokens[tokens_len - 1].is_close_bracket() && self.sort_factory.is_sorter(&tokens2)
&& self.sort_factory.is_sorter(&tokens2) } else {
} else {false} false
}
} else { } else {
false false
} }
@ -150,21 +156,19 @@ impl <S: MpsSorter + 'static, F: MpsSorterFactory<S> + 'static> BoxedMpsOpFactor
return Err(SyntaxError { return Err(SyntaxError {
line: 0, line: 0,
token: MpsToken::Name(".|~".into()), token: MpsToken::Name(".|~".into()),
got: tokens.pop_front() got: tokens.pop_front(),
}) });
} }
assert_token_raw(MpsToken::OpenBracket, tokens)?; 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)?; let sorter = self.sort_factory.build_sorter(tokens, dict)?;
tokens.extend(end_tokens); tokens.extend(end_tokens);
assert_token_raw(MpsToken::CloseBracket, tokens)?; assert_token_raw(MpsToken::CloseBracket, tokens)?;
Ok(Box::new( Ok(Box::new(MpsSortStatement {
MpsSortStatement { orderer: sorter,
orderer: sorter, iterable: inner_op.into(),
iterable: inner_op.into(), item_cache: VecDeque::with_capacity(SORTER_ITEM_CACHE_SIZE),
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 { } else if current_token.is_open_bracket() && bracket_depth != 0 {
bracket_depth -= 1; bracket_depth -= 1;
} else if current_token.is_tilde() && bracket_depth == target_depth { } else if current_token.is_tilde() && bracket_depth == target_depth {
return Some(i) return Some(i);
} }
} }
None None
@ -196,7 +200,7 @@ fn last_dot_sort(tokens: &VecDeque<MpsToken>, target_depth: usize) -> Option<usi
} else { } else {
None None
} }
} };
} else if bracket_found { } else if bracket_found {
if check_name("sort", current_token) { if check_name("sort", current_token) {
sort_found = true; sort_found = true;

View file

@ -1,7 +1,7 @@
//! Basic types for MPS //! Basic types for MPS
use std::cmp::{Ord, Ordering};
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::cmp::{Ordering, Ord};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum MpsTypePrimitive { pub enum MpsTypePrimitive {
@ -38,7 +38,7 @@ impl MpsTypePrimitive {
Self::UInt(x) => format!("{}", x), Self::UInt(x) => format!("{}", x),
Self::Int(x) => format!("{}", x), Self::Int(x) => format!("{}", x),
Self::Float(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 { pub fn parse(s: String) -> Self {
if let Ok(i) = s.parse::<i64>() { if let Ok(i) = s.parse::<i64>() {
Self::Int(i) Self::Int(i)
} else if let Ok(u) = s.parse::<u64>() { } else if let Ok(u) = s.parse::<u64>() {
Self::UInt(u) Self::UInt(u)
@ -117,9 +117,7 @@ impl PartialOrd for MpsTypePrimitive {
_ => None, _ => None,
}, },
Self::Float(f1) => match other { Self::Float(f1) => match other {
Self::Float(f2) => Some( Self::Float(f2) => Some(f1.partial_cmp(f2).unwrap_or(std::cmp::Ordering::Less)),
f1.partial_cmp(f2).unwrap_or(std::cmp::Ordering::Less),
),
Self::Int(f2) => Some( Self::Int(f2) => Some(
f1.partial_cmp(&(*f2 as f64)) f1.partial_cmp(&(*f2 as f64))
.unwrap_or(std::cmp::Ordering::Less), .unwrap_or(std::cmp::Ordering::Less),

View file

@ -143,7 +143,7 @@ pub fn assert_type(tokens: &mut VecDeque<MpsToken>) -> Result<MpsTypePrimitive,
match token { match token {
MpsToken::Literal(s) => Ok(MpsTypePrimitive::String(s)), MpsToken::Literal(s) => Ok(MpsTypePrimitive::String(s)),
MpsToken::Name(s) => { MpsToken::Name(s) => {
if let Ok(i) = s.parse::<i64>() { if let Ok(i) = s.parse::<i64>() {
Ok(MpsTypePrimitive::Int(i)) Ok(MpsTypePrimitive::Int(i))
} else if let Ok(u) = s.parse::<u64>() { } else if let Ok(u) = s.parse::<u64>() {
Ok(MpsTypePrimitive::UInt(u)) Ok(MpsTypePrimitive::UInt(u))

View file

@ -7,8 +7,8 @@ use crate::MpsContext;
use crate::lang::utility::assert_token; use crate::lang::utility::assert_token;
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
use crate::lang::SyntaxError; use crate::lang::SyntaxError;
use crate::lang::{BoxedMpsOpFactory, MpsIteratorItem, MpsOp, MpsOpFactory, SimpleMpsOpFactory};
#[derive(Debug)] #[derive(Debug)]
pub struct CommentStatement { pub struct CommentStatement {

View file

@ -8,7 +8,7 @@ use crate::MpsContext;
use crate::lang::repeated_tokens; use crate::lang::repeated_tokens;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; 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::lang::{RuntimeError, SyntaxError};
use crate::processing::general::FileIter; use crate::processing::general::FileIter;

View file

@ -30,8 +30,8 @@ pub struct FieldFilter {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum FieldFilterErrorHandling { pub enum FieldFilterErrorHandling {
Error, // return error Error, // return error
Ignore, // return Ok(false) when error encountered Ignore, // return Ok(false) when error encountered
Include, // return Ok(true) 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] => "<=",
[0, 1] => ">=", [0, 1] => ">=",
[-1, 1] => "!=", [-1, 1] => "!=",
_ => "??" _ => "??",
} }
} }
@ -52,7 +52,9 @@ impl Display for FieldFilter {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let comp_op = comparison_op(&self.comparison); let comp_op = comparison_op(&self.comparison);
match &self.val { 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), VariableOrValue::Value(t) => write!(f, "{} {} {}", self.field_name, comp_op, t),
} }
} }

View file

@ -1,11 +1,11 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use super::utility::assert_comparison_operator; use super::utility::assert_comparison_operator;
use super::{FieldFilter, FieldFilterErrorHandling, field_filter::VariableOrValue}; use super::{field_filter::VariableOrValue, FieldFilter, FieldFilterErrorHandling};
use crate::lang::utility::{assert_token, assert_type, check_is_type, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{MpsFilterFactory, MpsFilterStatementFactory};
use crate::lang::SyntaxError; use crate::lang::SyntaxError;
use crate::lang::{MpsFilterFactory, MpsFilterStatementFactory};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
pub struct FieldFilterMaybeFactory; 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)] #[inline(always)]
pub fn field_filter_maybe() -> FieldFilterMaybeStatementFactory { pub fn field_filter_maybe() -> FieldFilterMaybeStatementFactory {

View file

@ -1,8 +1,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use super::field_filter::{VariableOrValue, FieldFilterErrorHandling}; use super::field_filter::{FieldFilterErrorHandling, VariableOrValue};
use crate::lang::utility::{assert_token, check_name, assert_name, assert_token_raw}; use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::MpsTypePrimitive; use crate::lang::MpsTypePrimitive;
use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory}; use crate::lang::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
@ -51,7 +51,7 @@ impl MpsFilterPredicate for FieldLikeFilter {
line: 0, line: 0,
op: op(), op: op(),
msg: format!("Value is not type String"), msg: format!("Value is not type String"),
}) }),
}?; }?;
if let Some(field) = music_item_lut.field(&self.field_name) { if let Some(field) = music_item_lut.field(&self.field_name) {
let field_str = field.as_str().to_lowercase(); 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)] #[inline(always)]
pub fn field_like_filter() -> FieldLikeFilterStatementFactory { pub fn field_like_filter() -> FieldLikeFilterStatementFactory {

View file

@ -1,11 +1,11 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; 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::{MpsFilterFactory, MpsFilterPredicate, MpsFilterStatementFactory};
use crate::lang::{MpsLanguageDictionary, MpsTypePrimitive};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::{RuntimeError, SyntaxError};
use crate::lang::{Lookup, utility::assert_token_raw}; use crate::processing::{general::MpsType, OpGetter};
use crate::processing::{OpGetter, general::MpsType};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsItem; use crate::MpsItem;
@ -37,17 +37,21 @@ impl MpsFilterPredicate for IndexFilter {
MpsTypePrimitive::Int(i) => *i as u64, MpsTypePrimitive::Int(i) => *i as u64,
MpsTypePrimitive::UInt(u) => *u, MpsTypePrimitive::UInt(u) => *u,
MpsTypePrimitive::Float(f) => *f as u64, 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, line: 0,
op: op(), op: op(),
msg: format!("Cannot use {} as index", val), 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 { if self.current == index && !self.is_opposite {
self.current += 1; self.current += 1;
@ -77,14 +81,8 @@ pub struct IndexFilterFactory;
impl MpsFilterFactory<IndexFilter> for IndexFilterFactory { impl MpsFilterFactory<IndexFilter> for IndexFilterFactory {
fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool { fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool {
( (tokens.len() == 1 && Lookup::check_is(&tokens[0]))
tokens.len() == 1 || (tokens.len() == 2 && tokens[0].is_exclamation() && Lookup::check_is(&tokens[1]))
&& Lookup::check_is(&tokens[0])
) || (
tokens.len() == 2
&& tokens[0].is_exclamation()
&& Lookup::check_is(&tokens[1])
)
} }
fn build_filter( fn build_filter(
@ -95,7 +93,9 @@ impl MpsFilterFactory<IndexFilter> for IndexFilterFactory {
let is_inverted = if tokens[0].is_exclamation() { let is_inverted = if tokens[0].is_exclamation() {
assert_token_raw(MpsToken::Exclamation, tokens)?; assert_token_raw(MpsToken::Exclamation, tokens)?;
true true
} else {false}; } else {
false
};
let lookup = Lookup::parse(tokens)?; let lookup = Lookup::parse(tokens)?;
Ok(IndexFilter { Ok(IndexFilter {
index: lookup, index: lookup,

View file

@ -10,9 +10,18 @@ pub use empty_filter::{
empty_filter, EmptyFilter, EmptyFilterFactory, EmptyFilterStatementFactory, empty_filter, EmptyFilter, EmptyFilterFactory, EmptyFilterStatementFactory,
}; };
pub use field_filter::{ 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};

View file

@ -1,12 +1,12 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; 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::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::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsItem; use crate::MpsItem;
@ -23,10 +23,21 @@ pub struct RangeFilter {
impl Display for RangeFilter { impl Display for RangeFilter {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}{}{}", write!(
if let Some(start) = &self.start {format!("{}", start)} else {"".into()}, f,
if self.inclusive_end {"="} else {""}, "{}{}{}",
if let Some(end) = &self.end {format!("{}", end)} else {"".into()},) 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> { ) -> Result<bool, RuntimeError> {
let start_index = if let Some(start) = &self.start { let start_index = if let Some(start) = &self.start {
lookup_to_index(start.get(ctx, op)?, op)? lookup_to_index(start.get(ctx, op)?, op)?
} else {0}; } else {
0
};
let current = self.current; let current = self.current;
self.current += 1; self.current += 1;
if current >= start_index { if current >= start_index {
@ -87,13 +100,13 @@ fn lookup_to_index(item: &MpsType, op: &mut OpGetter) -> Result<u64, RuntimeErro
line: 0, line: 0,
op: op(), op: op(),
msg: format!("Cannot use {} as index", val), msg: format!("Cannot use {} as index", val),
}) }),
}, },
val => Err(RuntimeError { val => Err(RuntimeError {
line: 0, line: 0,
op: op(), op: op(),
msg: format!("Cannot use {} as index", val), msg: format!("Cannot use {} as index", val),
}) }),
} }
} }
@ -103,44 +116,38 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool { fn is_filter(&self, tokens: &VecDeque<&MpsToken>) -> bool {
( (
// .. // ..
tokens.len() == 2 tokens.len() == 2 && tokens[0].is_dot() && tokens[1].is_dot()
&& tokens[0].is_dot() ) || (tokens.len() == 3
&& tokens[1].is_dot()
) || (
tokens.len() == 3
&& (( && ((
// ..number // ..number
tokens[0].is_dot() tokens[0].is_dot() && tokens[1].is_dot() && Lookup::check_is(&tokens[2])
&& tokens[1].is_dot()
&& Lookup::check_is(&tokens[2])
) || ( ) || (
// number.. // number..
Lookup::check_is(&tokens[0]) Lookup::check_is(&tokens[0]) && tokens[1].is_dot() && tokens[2].is_dot()
&& tokens[1].is_dot() )))
&& tokens[2].is_dot() || (tokens.len() == 4
)) && ((
) || ( // number..number
tokens.len() == 4 Lookup::check_is(&tokens[0])
&& (( // number..number && tokens[1].is_dot()
Lookup::check_is(&tokens[0]) && tokens[2].is_dot()
&& tokens[1].is_dot() && Lookup::check_is(&tokens[3])
&& tokens[2].is_dot() ) || (
&& Lookup::check_is(&tokens[3]) // ..=number
) || ( // ..=number tokens[0].is_dot()
tokens[0].is_dot() && tokens[1].is_dot()
&& tokens[1].is_dot() && tokens[2].is_equals()
&& tokens[2].is_equals() && Lookup::check_is(&tokens[3])
&& Lookup::check_is(&tokens[3]) )))
)) || (
) || ( // number..=number
// number..=number tokens.len() == 5
tokens.len() == 5 && Lookup::check_is(&tokens[0])
&& Lookup::check_is(&tokens[0]) && tokens[1].is_dot()
&& tokens[1].is_dot() && tokens[2].is_dot()
&& tokens[2].is_dot() && tokens[3].is_equals()
&& tokens[3].is_equals() && Lookup::check_is(&tokens[4])
&& Lookup::check_is(&tokens[4]) )
)
} }
fn build_filter( fn build_filter(
@ -151,7 +158,9 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
// start index // start index
let start = if Lookup::check_is(&tokens[0]) { let start = if Lookup::check_is(&tokens[0]) {
Some(Lookup::parse(tokens)?) Some(Lookup::parse(tokens)?)
} else {None}; } else {
None
};
// .. // ..
assert_token_raw(MpsToken::Dot, tokens)?; assert_token_raw(MpsToken::Dot, tokens)?;
assert_token_raw(MpsToken::Dot, tokens)?; assert_token_raw(MpsToken::Dot, tokens)?;
@ -166,7 +175,9 @@ impl MpsFilterFactory<RangeFilter> for RangeFilterFactory {
// end index // end index
let end = if !tokens.is_empty() { let end = if !tokens.is_empty() {
Some(Lookup::parse(tokens)?) Some(Lookup::parse(tokens)?)
} else {None}; } else {
None
};
Ok(RangeFilter { Ok(RangeFilter {
start: start, start: start,

View file

@ -8,7 +8,9 @@ use crate::MpsItem;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; 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}; use crate::lang::{RuntimeError, SyntaxError};
#[derive(Debug)] #[derive(Debug)]
@ -28,7 +30,11 @@ impl Display for RepeatStatement {
if self.loop_forever { if self.loop_forever {
write!(f, "repeat({})", self.inner_statement) write!(f, "repeat({})", self.inner_statement)
} else { } else {
write!(f, "repeat({}, {})", self.inner_statement, self.original_repetitions) write!(
f,
"repeat({}, {})",
self.inner_statement, self.original_repetitions
)
} }
} }
} }

View file

@ -1,8 +1,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use crate::lang::{MpsSorter, MpsSorterFactory, MpsSortStatementFactory}; use crate::lang::{MpsIteratorItem, MpsLanguageDictionary, MpsOp};
use crate::lang::{MpsLanguageDictionary, MpsIteratorItem, MpsOp}; use crate::lang::{MpsSortStatementFactory, MpsSorter, MpsSorterFactory};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
@ -10,7 +10,11 @@ use crate::tokens::MpsToken;
pub struct EmptySorter; pub struct EmptySorter;
impl MpsSorter for 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() { if let Some(item) = iterator.next() {
item_buf.push_back(item) item_buf.push_back(item)
} }

View file

@ -1,11 +1,11 @@
use std::cmp::Ordering;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; 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::utility::assert_token;
use crate::lang::{MpsIteratorItem, MpsLanguageDictionary, MpsOp};
use crate::lang::{MpsSortStatementFactory, MpsSorter, MpsSorterFactory};
use crate::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -16,7 +16,11 @@ pub struct FieldSorter {
} }
impl MpsSorter for 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 let buf_len_old = item_buf.len(); // save buffer length before modifying buffer
if item_buf.len() < self.up_to { if item_buf.len() < self.up_to {
for item in iterator { for item in iterator {
@ -29,20 +33,18 @@ impl MpsSorter for FieldSorter {
if buf_len_old != item_buf.len() { if buf_len_old != item_buf.len() {
// when buf_len_old == item_buf.len(), iterator was already complete // 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 // 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( item_buf.make_contiguous().sort_by(|a, b| {
|a, b| { if let Ok(a) = a {
if let Ok(a) = a { if let Some(a_field) = a.field(&self.field_name) {
if let Some(a_field) = a.field(&self.field_name) { if let Ok(b) = b {
if let Ok(b) = b { if let Some(b_field) = b.field(&self.field_name) {
if let Some(b_field) = b.field(&self.field_name) { return a_field.partial_cmp(b_field).unwrap_or(self.default_order);
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); println!("Field-sorted item_buf: {:?}", item_buf);
} }
Ok(()) Ok(())
@ -67,14 +69,18 @@ impl MpsSorterFactory<FieldSorter> for FieldSorterFactory {
tokens: &mut VecDeque<MpsToken>, tokens: &mut VecDeque<MpsToken>,
_dict: &MpsLanguageDictionary, _dict: &MpsLanguageDictionary,
) -> Result<FieldSorter, SyntaxError> { ) -> Result<FieldSorter, SyntaxError> {
let name = assert_token(|t| match t { let name = assert_token(
MpsToken::Name(s) => Some(s), |t| match t {
_ => None MpsToken::Name(s) => Some(s),
}, MpsToken::Name("field_name".into()), tokens)?; _ => None,
},
MpsToken::Name("field_name".into()),
tokens,
)?;
Ok(FieldSorter { Ok(FieldSorter {
field_name: name, field_name: name,
up_to: usize::MAX, up_to: usize::MAX,
default_order: Ordering::Equal default_order: Ordering::Equal,
}) })
} }
} }

View file

@ -9,8 +9,8 @@ use crate::MpsContext;
use crate::lang::repeated_tokens; use crate::lang::repeated_tokens;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
use crate::lang::SyntaxError; use crate::lang::SyntaxError;
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsOp};
#[derive(Debug)] #[derive(Debug)]
pub struct SqlInitStatement { pub struct SqlInitStatement {

View file

@ -3,7 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::utility::assert_token; 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::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;

View file

@ -3,7 +3,9 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::utility::assert_token; 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::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;

View file

@ -7,7 +7,9 @@ use crate::MpsContext;
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type}; use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
use crate::lang::MpsLanguageDictionary; 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::lang::{RuntimeError, SyntaxError};
use crate::processing::general::MpsType; use crate::processing::general::MpsType;

View file

@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use regex::Regex; use regex::Regex;
use super::OpGetter; use super::OpGetter;
use crate::lang::{RuntimeError, MpsTypePrimitive}; use crate::lang::{MpsTypePrimitive, RuntimeError};
use crate::MpsItem; 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))$"; 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 { } else {
Vec::with_capacity(DEFAULT_VEC_CACHE_SIZE) Vec::with_capacity(DEFAULT_VEC_CACHE_SIZE)
}; };
let pattern_re = Regex::new(pattern.unwrap_or(DEFAULT_REGEX)).map_err(|e| RuntimeError { let pattern_re =
line: 0, Regex::new(pattern.unwrap_or(DEFAULT_REGEX)).map_err(|e| RuntimeError {
op: op(), line: 0,
msg: format!("Regex compile error: {}", e), op: op(),
})?; msg: format!("Regex compile error: {}", e),
})?;
Ok(Self { Ok(Self {
root: root_path, root: root_path,
pattern: pattern_re, pattern: pattern_re,
@ -182,12 +183,12 @@ impl FileIter {
} }
} }
Some(item) Some(item)
}, }
Err(_) => { Err(_) => {
let mut item = MpsItem::new(); let mut item = MpsItem::new();
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names); self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
Some(item) Some(item)
}, }
} }
} }
@ -214,7 +215,10 @@ impl FileIter {
// populates fields from named capture groups // populates fields from named capture groups
while let Some(name_maybe) = capture_names.next() { while let Some(name_maybe) = capture_names.next() {
if let Some(name) = name_maybe { 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)); item.set_field(name, MpsTypePrimitive::parse(value));
} }
} }

View file

@ -259,10 +259,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings {
} }
#[inline(always)] #[inline(always)]
fn build_mps_item( fn build_mps_item(conn: &mut rusqlite::Connection, item: DbMusicItem) -> rusqlite::Result<MpsItem> {
conn: &mut rusqlite::Connection,
item: DbMusicItem,
) -> rusqlite::Result<MpsItem> {
// query artist // query artist
let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?; let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?;
let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?; let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?;
@ -331,7 +328,6 @@ fn rows_to_item(
meta: DbMetaItem, meta: DbMetaItem,
genre: DbGenreItem, genre: DbGenreItem,
) -> MpsItem { ) -> MpsItem {
let mut item = MpsItem::new(); let mut item = MpsItem::new();
item item
// music row // music row

View file

@ -45,7 +45,9 @@ impl MpsToken {
_ => { _ => {
// name validation // name validation
let mut ok = true; let mut ok = true;
for invalid_c in ["-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", ".", "&", "|"] { for invalid_c in [
"-", "+", ",", " ", "/", "\n", "\r", "!", "?", "=", ".", "&", "|",
] {
if s.contains(invalid_c) { if s.contains(invalid_c) {
ok = false; ok = false;
break; break;

View file

@ -258,10 +258,12 @@ impl ReaderStateMachine {
'#' => Self::Octothorpe { out: input }, '#' => Self::Octothorpe { out: input },
'`' => Self::StartTickLiteral {}, '`' => Self::StartTickLiteral {},
'"' => Self::StartQuoteLiteral {}, '"' => Self::StartQuoteLiteral {},
'\n'| '\r' | '\t' | ' ' => Self::EndToken {}, '\n' | '\r' | '\t' | ' ' => Self::EndToken {},
';' => Self::EndStatement {}, ';' => Self::EndStatement {},
'\0' => Self::EndOfFile {}, '\0' => Self::EndOfFile {},
'(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' | '|' | ':' => Self::SingleCharToken { out: input }, '(' | ')' | ',' | '=' | '<' | '>' | '.' | '!' | '?' | '|' | ':' => {
Self::SingleCharToken { out: input }
}
_ => Self::Regular { out: input }, _ => Self::Regular { out: input },
}, },
Self::Escaped { inside } => match inside { Self::Escaped { inside } => match inside {

View file

@ -62,9 +62,18 @@ fn execute_single_line(
break; break;
} }
} // no need to spam the rest of the songs } // no need to spam the rest of the songs
println!("Got song `{}` (file: `{}`)", println!(
item.field("title").expect("Expected field `title` to exist").clone().to_str().expect("Expected field `title` to be String"), "Got song `{}` (file: `{}`)",
item.field("filename").expect("Expected field `filename` to exist").clone().to_str().expect("Expected field `filename` to be String") 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 { } else {
println!("!!! Got error while iterating (executing) !!!"); println!("!!! Got error while iterating (executing) !!!");
@ -109,9 +118,21 @@ fn execute_comment_line() -> Result<(), Box<dyn MpsLanguageError>> {
#[test] #[test]
fn execute_repeat_line() -> Result<(), Box<dyn MpsLanguageError>> { fn execute_repeat_line() -> Result<(), Box<dyn MpsLanguageError>> {
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`))", false, false)?; execute_single_line(
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 4)", false, true)?; "repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`))",
execute_single_line("repeat(files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`), 0)", true, true) 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] #[test]
@ -135,7 +156,11 @@ fn execute_assign_line() -> Result<(), Box<dyn MpsLanguageError>> {
#[test] #[test]
fn execute_emptyfilter_line() -> Result<(), Box<dyn MpsLanguageError>> { 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] #[test]

View file

@ -26,8 +26,14 @@ impl MpsController {
let (playback_tx, playback_rx) = channel(); let (playback_tx, playback_rx) = channel();
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone()); let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
sys_ctrl.init(playback_rx); sys_ctrl.init(playback_rx);
let handle = let handle = MpsPlayerServer::spawn(
MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, playback_tx, false); player_gen,
control_tx.clone(),
control_rx,
event_tx,
playback_tx,
false,
);
Self { Self {
control: control_tx, control: control_tx,
event: event_rx, event: event_rx,
@ -44,8 +50,14 @@ impl MpsController {
let (playback_tx, playback_rx) = channel(); let (playback_tx, playback_rx) = channel();
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone()); let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
sys_ctrl.init(playback_rx); sys_ctrl.init(playback_rx);
let handle = let handle = MpsPlayerServer::spawn(
MpsPlayerServer::spawn(player_gen, control_tx.clone(), control_rx, event_tx, playback_tx, true); player_gen,
control_tx.clone(),
control_rx,
event_tx,
playback_tx,
true,
);
Self { Self {
control: control_tx, control: control_tx,
event: event_rx, event: event_rx,

View file

@ -1,10 +1,10 @@
#[allow(unused_imports)] #[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"))] #[cfg(all(target_os = "linux", feature = "os-controls"))]
use std::thread::JoinHandle; use std::thread::JoinHandle;
#[cfg(all(target_os = "linux", feature = "os-controls"))] #[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"))] #[cfg(all(target_os = "linux", feature = "os-controls"))]
use mps_interpreter::MpsItem; use mps_interpreter::MpsItem;
@ -21,7 +21,6 @@ pub struct SystemControlWrapper {
dbus_ctrl: Option<Sender<DbusControl>>, dbus_ctrl: Option<Sender<DbusControl>>,
playback_event_handler: Option<JoinHandle<()>>, playback_event_handler: Option<JoinHandle<()>>,
playback_event_handler_killer: Option<Sender<()>>, playback_event_handler_killer: Option<Sender<()>>,
} }
/// OS-specific APIs for media controls. /// OS-specific APIs for media controls.
@ -135,27 +134,25 @@ impl SystemControlWrapper {
loop { loop {
dbus_conn.poll(5); dbus_conn.poll(5);
match dbus_ctrl.try_recv() { match dbus_ctrl.try_recv() {
Err(_) => {}, Err(_) => {}
Ok(DbusControl::Die) => break, Ok(DbusControl::Die) => break,
Ok(DbusControl::SetMetadata(meta)) => { Ok(DbusControl::SetMetadata(meta)) => {
dbus_conn.set_metadata(meta); dbus_conn.set_metadata(meta);
}, }
} }
} }
})); }));
let (tx, rx) = channel(); let (tx, rx) = channel();
self.playback_event_handler_killer = Some(tx); self.playback_event_handler_killer = Some(tx);
self.playback_event_handler = Some(std::thread::spawn(move || { self.playback_event_handler = Some(std::thread::spawn(move || loop {
loop { if let Ok(_) = rx.try_recv() {
if let Ok(_) = rx.try_recv() { break;
break; }
} match playback.recv() {
match playback.recv() { Err(_) => break,
Err(_) => break, Ok(PlaybackAction::Exit) => break,
Ok(PlaybackAction::Exit) => break, Ok(PlaybackAction::Enqueued(item)) => Self::enqueued(item, &dbus_ctrl_tx_clone),
Ok(PlaybackAction::Enqueued(item)) => Self::enqueued(item, &dbus_ctrl_tx_clone), Ok(PlaybackAction::Empty) => Self::empty(&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>) { fn enqueued(item: MpsItem, dbus_ctrl: &Sender<DbusControl>) {
//println!("Got enqueued item {}", &item.title); //println!("Got enqueued item {}", &item.title);
dbus_ctrl.send(DbusControl::SetMetadata(Metadata { dbus_ctrl
length: None, .send(DbusControl::SetMetadata(Metadata {
art_url: None, length: None,
album: item.field("album").and_then(|x| x.to_owned().to_str()), art_url: None,
album_artist: None, // TODO maybe? album: item.field("album").and_then(|x| x.to_owned().to_str()),
artist: item.field("artist").and_then(|x| x.to_owned().to_str()).map(|x| vec![x]), album_artist: None, // TODO maybe?
composer: None, artist: item
disc_number: None, .field("artist")
genre: item.field("genre").and_then(|x| x.to_owned().to_str()).map(|genre| vec![genre]), .and_then(|x| x.to_owned().to_str())
title: item.field("title").and_then(|x| x.to_owned().to_str()), .map(|x| vec![x]),
track_number: item.field("track").and_then(|x| x.to_owned().to_i64()).map(|track| track as i32), composer: None,
url: item.field("filename").and_then(|x| x.to_owned().to_str()), disc_number: None,
})).unwrap_or(()); 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>) { fn empty(dbus_ctrl: &Sender<DbusControl>) {
dbus_ctrl.send(DbusControl::SetMetadata(Metadata { dbus_ctrl
length: None, .send(DbusControl::SetMetadata(Metadata {
art_url: None, length: None,
album: None, art_url: None,
album_artist: None, // TODO maybe? album: None,
artist: None, album_artist: None, // TODO maybe?
composer: None, artist: None,
disc_number: None, composer: None,
genre: None, disc_number: None,
title: None, genre: None,
track_number: None, title: None,
url: None, track_number: None,
})).unwrap_or(()); url: None,
}))
.unwrap_or(());
} }
} }
@ -216,7 +226,7 @@ impl SystemControlWrapper {
pub fn new(control: Sender<ControlAction>) -> Self { pub fn new(control: Sender<ControlAction>) -> Self {
Self { Self {
control: control, control: control,
playback_receiver: None playback_receiver: None,
} }
} }

View file

@ -5,7 +5,7 @@ use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
use m3u8_rs::{MediaPlaylist, MediaSegment}; use m3u8_rs::{MediaPlaylist, MediaSegment};
use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsItem}; use mps_interpreter::{tokens::MpsTokenReader, MpsItem, MpsRunner};
use super::PlaybackError; use super::PlaybackError;
@ -36,14 +36,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
self.sink.sleep_until_end(); self.sink.sleep_until_end();
match item { match item {
Ok(music) => { 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 file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file); let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source); self.sink.append(source);
Ok(()) Ok(())
} else { } 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)), Err(e) => Err(PlaybackError::from_err(e)),
@ -59,14 +63,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
match item { match item {
Ok(music) => { Ok(music) => {
enqueued.push(music.clone()); 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 file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file); let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source); self.sink.append(source);
Ok(()) Ok(())
} else { } 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)), Err(e) => Err(PlaybackError::from_err(e)),
@ -85,14 +93,18 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
match item { match item {
Ok(music) => { Ok(music) => {
enqueued.push(music.clone()); 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 file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let stream = io::BufReader::new(file); let stream = io::BufReader::new(file);
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
self.sink.append(source); self.sink.append(source);
Ok(()) Ok(())
} else { } 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)), Err(e) => Err(PlaybackError::from_err(e)),
@ -139,7 +151,9 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
for item in &mut self.runner { for item in &mut self.runner {
match item { match item {
Ok(music) => { 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 { playlist.segments.push(MediaSegment {
uri: filename, uri: filename,
title: music.field("title").and_then(|x| x.to_owned().to_str()), title: music.field("title").and_then(|x| x.to_owned().to_str()),
@ -147,7 +161,9 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
}); });
Ok(()) Ok(())
} else { } 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)), Err(e) => Err(PlaybackError::from_err(e)),

View file

@ -40,9 +40,12 @@ impl<T: MpsTokenReader> MpsPlayerServer<T> {
//println!("Enqueuing up to {} items", count); //println!("Enqueuing up to {} items", count);
match self.player.enqueue(count) { match self.player.enqueue(count) {
Err(e) => self.event.send(PlayerAction::Exception(e)).unwrap(), Err(e) => self.event.send(PlayerAction::Exception(e)).unwrap(),
Ok(items) => for item in items { // notify of new items that have been enqueued Ok(items) => {
self.playback.send(PlaybackAction::Enqueued(item)).unwrap(); for item in items {
}, // notify of new items that have been enqueued
self.playback.send(PlaybackAction::Enqueued(item)).unwrap();
}
}
} }
} }

View file

@ -56,7 +56,7 @@ pub fn repl(args: CliArgs) {
while let Err(e) = player.save_m3u8(&mut playlist_writer) { while let Err(e) = player.save_m3u8(&mut playlist_writer) {
eprintln!("{}", e.message()); eprintln!("{}", e.message());
} }
}, }
} }
playlist_writer playlist_writer
.flush() .flush()
@ -111,7 +111,7 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
} else { } else {
state.in_literal = Some(read_buf[0] as char); state.in_literal = Some(read_buf[0] as char);
} }
}, }
'(' => state.bracket_depth += 1, '(' => state.bracket_depth += 1,
')' => 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(); execute();
state.statement_buf.clear(); state.statement_buf.clear();
} }
}, }
'\n' => { '\n' => {
let statement_result = std::str::from_utf8(state.statement_buf.as_slice()); let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
if statement_result.is_ok() && statement_result.unwrap().trim().starts_with("?") { 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(); state.statement_buf.clear();
} }
prompt(&mut state.line_number, args); prompt(&mut state.line_number, args);
}, }
_ => {}, _ => {}
} }
} }
} }