diff --git a/src/parser.rs b/src/parser.rs index 12b384d..549af90 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,7 +6,7 @@ use std::{ use derive_builder::Builder; use fasteval::Evaler; use nom::{ - Finish, IResult, Input, Parser as NomParser, + AsChar, Compare, Finish, IResult, Input, Parser as NomParser, branch::alt, bytes::complete::{tag, take, take_till}, character::{ @@ -43,13 +43,14 @@ impl<'i, 's> Parser<'i, '_, 's, '_> { } } -fn token_parser<'a, 's>( +fn token_parser<'a, 's, I>( parser: &Parser<'_, '_, 's, '_>, -) -> impl NomParser< - LocatedSpan<&'a str>, - Output = Vec>, - Error = nom::error::Error>, -> { +) -> impl NomParser>, Error = nom::error::Error> +where + I: Input + AsRef + for<'z> nom::Compare<&'z str>, + ::Item: AsChar, + ::Item: PartialEq, +{ let space_or_comment = || { value( (), @@ -75,58 +76,55 @@ fn into_box<'a>(token: impl Token + 'a) -> Box { Box::new(token) } -pub type TokenResult<'a, T> = IResult, T>; - impl Silence { - fn parser<'a>() -> impl NomParser< - LocatedSpan<&'a str>, - Output = Self, - Error = nom::error::Error>, - > { + fn parser() -> impl NomParser> + where + I: Input, + ::Item: AsChar, + { value(Self, char('.')) } } impl Marker { - fn parser<'a>() -> impl NomParser< - LocatedSpan<&'a str>, - Output = Self, - Error = nom::error::Error>, - > { + fn parser() -> impl NomParser> + where + I: Input, + ::Item: AsChar, + { value(Marker, char('%')) } } impl Note { - fn parser<'a, 'n>( + fn parser<'n, I>( notes: &'n [String], - ) -> impl NomParser< - LocatedSpan<&'a str>, - Output = Self, - Error = nom::error::Error>, - > { - |input: LocatedSpan<&'a str>| { - let mut parsers: Vec) -> TokenResult<'a, Self>>> = - notes - .iter() - .enumerate() - .map(|(i, t)| { - Box::new(move |input: LocatedSpan<&'a str>| { - value(Note(i as u8), tag(t.clone().as_str())).parse(input) - }) - as Box) -> TokenResult<'a, Self>> - }) - .collect(); + ) -> impl NomParser> + where + I: Input + for<'z> Compare<&'z str>, + { + |input: I| { + let mut parsers: Vec IResult>> = notes + .iter() + .enumerate() + .map(|(i, t)| { + Box::new(move |input: I| { + value(Note(i as u8), tag(t.clone().as_str())).parse(input) + }) as Box IResult> + }) + .collect(); alt(parsers.as_mut_slice()).parse(input) } } } impl VariableChange { - fn parser( - variables: &[char], - ) -> impl for<'a> Fn(LocatedSpan<&'a str>) -> TokenResult<'a, Self> { - move |i: LocatedSpan<&str>| { + fn parser(variables: &[char]) -> impl Fn(I) -> IResult + where + I: Input + AsRef, + ::Item: AsChar, + { + move |i: I| { preceded(char('$'), one_of(variables)) .and(expression_parser(variables)) .map(|(name, change)| VariableChange(name, change)) @@ -136,9 +134,12 @@ impl VariableChange { } impl<'s> Loop<'s> { - fn parser<'i, 'n, 'v>( - parser: &Parser<'i, 'n, 's, 'v>, - ) -> impl Fn(LocatedSpan<&str>) -> TokenResult { + fn parser<'i, 'n, 'v, I>(parser: &Parser<'i, 'n, 's, 'v>) -> impl Fn(I) -> IResult + where + I: Input + AsRef + for<'z> nom::Compare<&'z str>, + ::Item: AsChar, + ::Item: PartialEq, + { |input| { delimited( char('('), @@ -156,9 +157,12 @@ impl<'s> Loop<'s> { } impl<'s> Tuplet<'s> { - fn parser<'i, 'n, 'v>( - parser: &Parser<'i, 'n, 's, 'v>, - ) -> impl Fn(LocatedSpan<&str>) -> TokenResult { + fn parser<'i, 'n, 'v, I>(parser: &Parser<'i, 'n, 's, 'v>) -> impl Fn(I) -> IResult + where + I: Input + for<'z> Compare<&'z str> + AsRef, + ::Item: AsChar, + ::Item: PartialEq, + { |input| { delimited(char('['), token_parser(parser), char(']')) .map(Self) @@ -168,34 +172,24 @@ impl<'s> Tuplet<'s> { } impl<'s> Slope<'s> { - fn parser<'a, 'i, 'n, 'v>( - parser: &Parser<'i, 'n, 's, 'v>, - ) -> impl Fn(LocatedSpan<&'a str>) -> TokenResult<'a, Self> { + fn parser<'i, 'n, 'v, I>(parser: &Parser<'i, 'n, 's, 'v>) -> impl Fn(I) -> IResult + where + I: Input + for<'z> Compare<&'z str> + AsRef, + ::Item: AsChar, + ::Item: PartialEq, + { |input| { let iter: std::collections::hash_map::Iter<'s, String, VariableChange> = parser.slopes.iter(); delimited( char('{'), - alt( - iter - .map(|(k, v)| { - Box::new(move|input: LocatedSpan<&'a str>| { - value(v, tag(k.as_str())).parse(input) - }) - as Box< - dyn 's + Fn( - LocatedSpan<&'a str>, - ) - -> TokenResult<'a, &'s VariableChange>, - > - }) - .collect::) -> TokenResult<'a, &'s VariableChange>, - >, - >>() - .as_mut_slice(), - ) + alt(iter + .map(|(k, v)| { + Box::new(move |input: I| value(v, tag(k.as_str())).parse(input)) + as Box IResult> + }) + .collect:: IResult>>>() + .as_mut_slice()) .and(token_parser(parser)), char('}'), ) @@ -206,14 +200,14 @@ impl<'s> Slope<'s> { } /// Will return the longest valid fasteval expression -fn expression_parser + Ord + Display>( +fn expression_parser<'a, I: Input + AsRef, C: Into + Ord + Display>( variables: &[C], -) -> impl Fn(LocatedSpan<&str>) -> TokenResult { - |input: LocatedSpan<&str>| { +) -> impl Fn(I) -> IResult { + |input: I| { let mut end_index = 0; let mut current_expression = None; while input.input_len() > end_index { - if let Some(e) = input[..end_index + 1] + if let Some(e) = input.as_ref()[..end_index + 1] .parse::() .ok() .and_then(|e| { @@ -241,9 +235,7 @@ fn expression_parser + Ord + Display>( } } if let Some(e) = current_expression { - Ok::<(LocatedSpan<&str>, Expression), nom::Err>>>(( - input, e, - )) + Ok((input, e)) } else { Err(nom::Err::Incomplete(nom::Needed::Unknown)) } @@ -252,13 +244,14 @@ fn expression_parser + Ord + Display>( #[cfg(test)] mod tests { + use nom::Parser; use nom_locate::LocatedSpan; - use crate::parser::expression_parser; + use crate::{compiler::Silence, parser::expression_parser}; #[test] fn expression_parser_test() { - let parser = expression_parser::(&['x']); + let parser = expression_parser(&['x']); let mut working_test_cases = vec![ "1", "1x", @@ -276,13 +269,32 @@ mod tests { ]; for test in working_test_cases.drain(..) { - let output = parser(LocatedSpan::new(test)); + let output = parser(test); assert!(output.is_ok(), "result was not Ok: {output:?}"); } for test in not_working_test_cases.drain(..) { - let output = parser(LocatedSpan::new(test)); + let output = parser(test); assert!(output.is_err(), "result was not Err: {output:?}"); } } + + // #[test] + // fn silence() { + // let parser = |input: &'static str| Silence::parser().parse(input.into()); + // let mut working_cases = vec![(".", ()), ".dd", ".."]; + // let mut not_working_cases = vec![]; + // for (test, expected) in working_cases.drain(..) { + // let output = parser(test); + // if let Ok((result)) = output { + // assert_eq!(expected, result); + // } else { + // panic!("result was not Ok: {output:?}"); + // } + // } + // for test in not_working_cases.drain(..) { + // let output = parser(test); + // assert!(output.is_err(), "result was not Err: {output:?}"); + // } + // } }