From 69c2869388a9a52383d65656c5584342b09564f6 Mon Sep 17 00:00:00 2001 From: Breval Ferrari Date: Wed, 21 May 2025 18:31:31 +0200 Subject: [PATCH] slope parser test, fix for longest string matching first --- src/parser.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 76ba714..2c909ef 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -189,8 +189,16 @@ impl<'s> Slope<'s> { N: AsRef + Clone, { |input| { - let iter: std::collections::hash_map::Iter<'s, String, VariableChange> = - parser.slopes.iter(); + let iter: std::iter::Rev> = { + let mut vec = parser + .slopes + .iter() + .collect::>(); + vec.sort_by_key(|(name, _)| name.len()); + vec + } + .into_iter() + .rev(); delimited( char('{'), alt(iter @@ -259,7 +267,7 @@ mod tests { use crate::{ compiler::{ - Loop, LoopCount, Marker, Note, Silence, Slope, Token, TokenVec, Tuplet, VariableChange, + Loop, LoopCount, Marker, Note, Silence, Slope, TokenVec, Tuplet, VariableChange, }, parser::expression_parser, }; @@ -531,4 +539,75 @@ 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 mut working_cases = vec![ + ( + "{normal.%}", + ( + "", + Slope( + &normal_value, + TokenVec(vec![Box::new(Silence), Box::new(Marker)]), + ), + ), + ), + ("{normal}", ("", Slope(&normal_value, TokenVec(vec![])))), + ("{nor}", ("", Slope(&very_fancy_value, TokenVec(vec![])))), + ( + "{normal do}f", + ("f", Slope(&normal_value, TokenVec(vec![Box::new(Note(0))]))), + ), + ]; + let mut not_working_cases = vec![ + "", + "{", + "}", + "{normal", + "{fancy}", + "{norma do}", + "{do}", + "{}", + ]; + for (test, expected) in working_cases.drain(..) { + let output = parser(test); + if let Ok(result) = output { + assert_eq!(expected, result, "case \"{test}\""); + } else { + panic!("result of \"{test}\" was not Ok: {output:?}"); + } + } + for test in not_working_cases.drain(..) { + let output = parser(test); + assert!( + output.is_err(), + "result of \"{test}\" was not Err: {output:?}" + ); + } + } }