diff --git a/src/compiler.rs b/src/compiler.rs index 71556ce..26893cf 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,12 +1,15 @@ use std::{ - any::{Any, TypeId}, collections::{BTreeMap, HashMap}, f64, fmt::Debug, str::FromStr + any::{Any, TypeId}, + collections::{BTreeMap, HashMap}, + f64, + fmt::Debug, + str::FromStr, }; use cfg_if::cfg_if; use derive_new::new; use derive_wrapper::{AsRef, From}; use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab}; -use lazy_static::lazy_static; use thiserror::Error; cfg_if! { @@ -19,30 +22,19 @@ cfg_if! { #[derive(From, AsRef, Default)] #[cfg_attr(test, derive(Debug))] -pub struct TokenVec<'a>(pub(crate) Vec>); +pub struct TokenVec(pub(crate) Vec>); pub trait Type { fn type_id(&self) -> TypeId; } -macro_rules! impl_type { - ($name:ty) => { - impl Type for $name { - fn type_id(&self) -> std::any::TypeId { - ::type_id(self) - } - } - }; -} - -macro_rules! impl_type_life { - ($name:ty) => { - impl Type for $name { - fn type_id(&self) -> TypeId { - <$name as Any>::type_id(&Default::default()) - } - } - }; +impl Type for T +where + T: Default + 'static, +{ + fn type_id(&self) -> TypeId { + ::type_id(&Default::default()) + } } #[cfg(not(test))] @@ -56,7 +48,7 @@ pub trait Token: Debug + Type { } #[cfg(test)] -impl PartialEq for TokenVec<'_> { +impl PartialEq for TokenVec { fn eq(&self, other: &Self) -> bool { format!("{self:?}") == format!("{other:?}") } @@ -66,8 +58,6 @@ impl PartialEq for TokenVec<'_> { #[cfg_attr(test, derive(Debug, PartialEq))] pub struct Silence; -impl_type!(Silence); - impl Token for Silence { fn apply(&self, mut context: Context) -> Result { let mut next = context.render(None)?; @@ -80,8 +70,6 @@ impl Token for Silence { #[cfg_attr(test, derive(Debug, PartialEq))] pub struct Marker; -impl_type!(Marker); - impl Token for Marker { fn apply(&self, mut context: Context) -> Result { context.result.clear(); @@ -93,8 +81,6 @@ impl Token for Marker { #[cfg_attr(test, derive(Debug, PartialEq))] pub struct Note(pub u8); -impl_type!(Note); - impl Token for Note { fn apply(&self, mut context: Context) -> Result { let mut next = context.render(Some(self.0))?; @@ -107,20 +93,22 @@ impl Token for Note { #[cfg_attr(test, derive(Debug, PartialEq))] pub struct VariableChange(pub char, pub Expression); -impl_type!(VariableChange); +impl AsRef for VariableChange { + fn as_ref(&self) -> &VariableChange { + self + } +} impl Token for VariableChange { fn apply(&self, mut context: Context) -> Result { - *context.get_mut(self.0)? = context.eval(&self.1)?; + *context.get_mut(self.0)? = context.eval(self.1.as_ref())?; Ok(context) } } #[derive(Default)] #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>); - -impl_type_life!(Loop<'_>); +pub struct Loop(pub LoopCount, pub TokenVec); #[cfg_attr(test, derive(Debug, PartialEq))] pub enum LoopCount { @@ -134,7 +122,7 @@ impl Default for LoopCount { } } -impl Token for Loop<'_> { +impl Token for Loop { fn apply(&self, mut context: Context) -> Result { let mut old_result = context.result.clone(); let count = match self.0 { @@ -157,11 +145,9 @@ impl Token for Loop<'_> { #[derive(Default)] #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct Tuplet<'a>(pub TokenVec<'a>); +pub struct Tuplet(pub TokenVec); -impl_type_life!(Tuplet<'_>); - -impl Token for Tuplet<'_> { +impl Token for Tuplet { fn apply(&self, mut context: Context) -> Result { let mut old_result = context.result.clone(); context.result.clear(); @@ -194,22 +180,15 @@ impl Token for Tuplet<'_> { } } +#[derive(new, Default)] #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>); +pub struct Slope(pub VariableChange, pub TokenVec); -lazy_static! { - static ref VARIABLE_CHANGE_DEFAULT: VariableChange = Default::default(); -} - -impl Type for Slope<'_> { - fn type_id(&self) -> TypeId { - ::type_id(&Slope(&VARIABLE_CHANGE_DEFAULT, Default::default())) - } -} - -impl Token for Slope<'_> { +impl Token for Slope { fn apply(&self, mut context: Context) -> Result { - context.slopes.push((self.0.0, self.0.1.clone())); + context + .slopes + .push((self.0.as_ref().0, self.0.as_ref().1.as_ref().clone())); context = self .1 .0 @@ -228,6 +207,12 @@ pub struct Expression { pub(crate) slab: Slab, } +impl AsRef for Expression { + fn as_ref(&self) -> &Expression { + self + } +} + impl Clone for Expression { fn clone(&self) -> Self { self.from diff --git a/src/parser.rs b/src/parser.rs index 2c909ef..9b64364 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,9 +1,6 @@ -use std::{ - collections::{BTreeMap, HashMap}, - fmt::Display, -}; +use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData}; -use derive_builder::Builder; +use derive_new::new; use fasteval::Evaler; use nom::{ AsChar, Compare, Finish, IResult, Input, Parser as NomParser, @@ -25,18 +22,35 @@ use crate::compiler::{ VariableChange, }; -#[derive(Builder)] -pub struct Parser<'n, 's, 'v, N: AsRef + Clone> { - notes: &'n [N], - slopes: &'s HashMap, - variables: &'v [char], +#[derive(new)] +pub struct Parser +where + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, +{ + notes: N, + slopes: S, + variables: V, + phantom: PhantomData<(NS, SS)>, } -impl<'a, 's, N: AsRef + Clone> Parser<'_, 's, '_, N> { +impl<'a, N, NS, S, SS, SV, V> Parser +where + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator + Clone, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, +{ pub fn parse_all( &self, input: &'a str, - ) -> Result, Error>> { + ) -> Result>> { token_parser(self) .parse_complete(LocatedSpan::new(input)) .finish() @@ -44,14 +58,19 @@ impl<'a, 's, N: AsRef + Clone> Parser<'_, 's, '_, N> { } } -fn token_parser<'a, 's, I, N>( - parser: &Parser<'_, 's, '_, N>, -) -> impl NomParser, Error = nom::error::Error> +fn token_parser<'a, I, N, NS, S, SS, SV, V>( + parser: &Parser, +) -> impl NomParser> where I: Input + AsRef + for<'z> nom::Compare<&'z str> + Copy, ::Item: AsChar, ::Item: PartialEq, - N: AsRef + Clone, + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator + Clone, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, { let space_or_comment = || { value( @@ -64,8 +83,8 @@ where alt(( Silence::parser().map(into_box), Marker::parser().map(into_box), - Note::parser(parser.notes).map(into_box), - VariableChange::parser(parser.variables).map(into_box), + Note::parser(parser.notes.as_ref()).map(into_box), + VariableChange::parser(&parser.variables).map(into_box), Loop::parser(parser).map(into_box), Tuplet::parser(parser).map(into_box), Slope::parser(parser).map(into_box), @@ -100,60 +119,87 @@ impl Marker { } impl Note { - fn parser<'n, N, I>( - notes: &'n [N], - ) -> impl NomParser> + fn parser<'a, N, NS, I>( + notes: N, + ) -> impl NomParser> + 'a where - N: AsRef + Clone, + N: IntoIterator, + NS: AsRef, I: Input + for<'z> Compare<&'z str>, { - |input: I| { - let mut parsers: Vec IResult>> = { - let mut sorted = notes.iter().enumerate().collect::>(); - sorted.sort_by_key(|(_, n)| n.as_ref().len()); - sorted - } - .drain(..) - .rev() - .map(|(i, t)| { - Box::new(move |input: I| value(Note(i as u8), tag(t.clone().as_ref())).parse(input)) - as Box IResult> - }) - .collect(); + let notes = { + let mut sorted = notes + .into_iter() + .map(|s| s.as_ref().to_string()) + .enumerate() + .collect::>(); + sorted.sort_by_key(|(_, n)| n.len()); + sorted + }; + move |input: I| { + let mut parsers: Vec IResult>> = notes + .clone() + .drain(..) + .rev() + .map(|(i, t)| { + Box::new(move |input: I| { + value(Note(i as u8), tag(t.clone().as_ref())).parse(input) + }) as Box IResult> + }) + .collect(); alt(parsers.as_mut_slice()).parse(input) } } } impl VariableChange { - fn parser(variables: &[char]) -> impl Fn(I) -> IResult + fn parser(variables: V) -> impl Fn(I) -> IResult where I: Input + AsRef + Copy, ::Item: AsChar, + V: AsRef<[char]>, { move |i: I| { - preceded(char('$'), one_of(variables)) - .and(expression_parser(variables)) - .map(|(name, change)| VariableChange(name, change)) - .parse(i) + preceded( + char('$'), + one_of(variables.as_ref().iter().collect::().as_str()), + ) + .and(expression_parser(variables.as_ref())) + .map(|(name, change)| VariableChange(name, change)) + .parse(i) } } } -impl<'s> Loop<'s> { - fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult +impl Loop { + fn parser( + parser: &Parser, + ) -> impl Fn(I) -> IResult where I: Input + AsRef + for<'z> nom::Compare<&'z str> + Copy, ::Item: AsChar, ::Item: PartialEq, - N: AsRef + Clone, + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator + Clone, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, { - |input| { + move |input| { delimited( char('('), opt(alt(( usize.map(LoopCount::Litteral), - one_of(parser.variables).map(LoopCount::Variable), + one_of( + parser + .variables + .as_ref() + .iter() + .collect::() + .as_str(), + ) + .map(LoopCount::Variable), ))) .and(token_parser(parser)), char(')'), @@ -164,13 +210,20 @@ impl<'s> Loop<'s> { } } -impl<'s> Tuplet<'s> { - fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult +impl Tuplet { + fn parser( + parser: &Parser, + ) -> impl Fn(I) -> IResult where I: Input + for<'z> Compare<&'z str> + AsRef + Copy, ::Item: AsChar, ::Item: PartialEq, - N: AsRef + Clone, + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator + Clone, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, { |input| { delimited(char('['), token_parser(parser), char(']')) @@ -180,54 +233,70 @@ impl<'s> Tuplet<'s> { } } -impl<'s> Slope<'s> { - fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult +impl Slope { + fn parser<'p, I, N, NS, S, SS, SV, V>( + parser: &'p Parser, + ) -> impl Fn(I) -> IResult where I: Input + for<'z> Compare<&'z str> + AsRef + Copy, ::Item: AsChar, ::Item: PartialEq, - N: AsRef + Clone, + N: AsRef<[NS]>, + NS: AsRef, + S: IntoIterator + Clone, + SS: AsRef, + SV: Borrow, + V: AsRef<[char]>, { - |input| { - let iter: std::iter::Rev> = { + move |input| { + let slopes = { let mut vec = parser .slopes - .iter() - .collect::>(); + .clone() + .into_iter() + .map(|(s1, s2)| (s1.as_ref().to_string(), s2.borrow().clone())) + .collect::>(); vec.sort_by_key(|(name, _)| name.len()); vec - } - .into_iter() - .rev(); + }; + let iter: std::iter::Rev> = + slopes.into_iter().rev(); delimited( char('{'), alt(iter .map(|(k, v)| { - Box::new(move |input: I| value(v, tag(k.as_str())).parse(input)) - as Box IResult> + Box::new(move |input: I| value(v.clone(), tag(k.as_str())).parse(input)) + as Box IResult> }) - .collect:: IResult>>>() + .collect:: IResult>>>() .as_mut_slice()) .and(token_parser(parser)), char('}'), ) - .map(|(i, v)| Self(i, v)) + .map(|(i, v)| Self::new(i, v)) .parse(input) } } } /// Will return the longest valid fasteval expression -fn expression_parser + Copy, C: Into + Ord + Display>( - variables: &[C], -) -> impl Fn(I) -> IResult { - |input: I| { +fn expression_parser<'v, I, V, C>(variables: V) -> impl 'v + Fn(I) -> IResult +where + I: Input + AsRef + Copy, + V: IntoIterator, + C: Borrow, +{ + let variables: Vec<(String, f64)> = variables + .into_iter() + .map(|v| (v.borrow().to_string(), 0.0)) + .collect(); + move |input: I| { take_while_map(|i: I| { i.as_ref().parse::().ok().and_then(|e| { e.instruction .eval( &e.slab, - &mut BTreeMap::from_iter(variables.iter().map(|v| (v.to_string(), 0.0))), + &mut BTreeMap::from_iter(variables.clone().drain(..)), ) .ok() .is_some() @@ -261,9 +330,11 @@ where #[cfg(test)] mod tests { + use super::Parser; + use std::collections::HashMap; - use nom::{IResult, Parser}; + use nom::{IResult, Parser as _}; use crate::{ compiler::{ @@ -272,7 +343,31 @@ mod tests { parser::expression_parser, }; - use super::ParserBuilder; + fn very_fancy_slope() -> VariableChange { + VariableChange('n', "1+1".parse().unwrap()) + } + + fn normal_slope() -> VariableChange { + VariableChange('n', "1".parse().unwrap()) + } + + fn parser_generator() -> Parser< + [&'static str; 3], + &'static str, + HashMap, + String, + VariableChange, + [char; 1], + > { + Parser::new( + ["do", "ré", "mi"], + HashMap::from([ + ("nor".to_string(), very_fancy_slope()), + ("normal".to_string(), normal_slope()), + ]), + ['n'], + ) + } #[test] fn expression_parser_test() { @@ -435,17 +530,9 @@ mod tests { let slopes = Default::default(); fn parser_builder<'s>( slopes: &'s HashMap, - ) -> impl Fn(&str) -> IResult<&str, Loop<'s>> { + ) -> impl Fn(&str) -> IResult<&str, Loop> { move |input: &str| { - Loop::parser( - &ParserBuilder::create_empty() - .notes(&["do", "ré", "mi"]) - .slopes(slopes) - .variables(&['n']) - .build() - .unwrap(), - ) - .parse(input) + Loop::parser(&Parser::new(["do", "ré", "mi"], slopes, ['n'])).parse(input) } } let parser = parser_builder(&slopes); @@ -497,17 +584,9 @@ mod tests { let slopes = Default::default(); fn parser_builder<'s>( slopes: &'s HashMap, - ) -> impl Fn(&str) -> IResult<&str, Tuplet<'s>> { + ) -> impl Fn(&str) -> IResult<&str, Tuplet> { move |input: &str| { - Tuplet::parser( - &ParserBuilder::create_empty() - .notes(&["do", "ré", "mi"]) - .slopes(slopes) - .variables(&['n']) - .build() - .unwrap(), - ) - .parse(input) + Tuplet::parser(&Parser::new(["do", "ré", "mi"], slopes, ['n'])).parse(input) } } let parser = parser_builder(&slopes); @@ -542,46 +621,30 @@ mod tests { #[test] fn slope() { - let normal = || VariableChange('n', "1".parse().unwrap()); - let very_fancy = || VariableChange('n', "1+1".parse().unwrap()); - let slopes = HashMap::from([ - ("nor".to_string(), very_fancy()), - ("normal".to_string(), normal()), - ]); - fn parser_builder<'s>( - slopes: &'s HashMap, - ) -> impl Fn(&str) -> IResult<&str, Slope<'s>> { - move |input: &str| { - Slope::parser( - &ParserBuilder::create_empty() - .notes(&["do", "ré", "mi"]) - .slopes(slopes) - .variables(&['n']) - .build() - .unwrap(), - ) - .parse(input) - } - } - let parser = parser_builder(&slopes); - let normal_value = normal(); - let very_fancy_value = very_fancy(); + let p = parser_generator(); + let parser_builder = || Slope::parser(&p); + let parser = parser_builder(); + let normal_value = normal_slope(); + let very_fancy_value = very_fancy_slope(); let mut working_cases = vec![ ( "{normal.%}", ( "", Slope( - &normal_value, + normal_value.clone(), TokenVec(vec![Box::new(Silence), Box::new(Marker)]), ), ), ), - ("{normal}", ("", Slope(&normal_value, TokenVec(vec![])))), - ("{nor}", ("", Slope(&very_fancy_value, TokenVec(vec![])))), + ( + "{normal}", + ("", Slope(normal_value.clone(), TokenVec(vec![]))), + ), + ("{nor}", ("", Slope(very_fancy_value, TokenVec(vec![])))), ( "{normal do}f", - ("f", Slope(&normal_value, TokenVec(vec![Box::new(Note(0))]))), + ("f", Slope(normal_value, TokenVec(vec![Box::new(Note(0))]))), ), ]; let mut not_working_cases = vec![