From 892914256d772d2a65bc26605165de29dd04e64f Mon Sep 17 00:00:00 2001 From: p6nj Date: Sun, 13 Oct 2024 12:38:27 -0400 Subject: [PATCH] flat atom tests & fixes --- src/bng/score.rs | 8 +- src/bng/score/lex/lexer.rs | 65 ++++++---- src/bng/score/lex/lexer/tests.rs | 202 ++++++++++++++++++++++++++++--- 3 files changed, 232 insertions(+), 43 deletions(-) diff --git a/src/bng/score.rs b/src/bng/score.rs index 679c7db..127cf2d 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -20,7 +20,7 @@ pub(super) enum Atom { #[cfg_attr(test, derive(Debug, PartialEq))] pub(super) enum FlatAtom { - Note(char), + Note(u8), Rest, StartHere, Modifier(Modifier), @@ -38,6 +38,12 @@ impl Clone for FlatAtom { fn clone(&self) -> Self { match self { Self::Rest => Self::Rest, + Self::Comment => Self::Comment, + Self::LoopEnds => Self::LoopEnds, + Self::SlopeEnds => Self::SlopeEnds, + Self::StartHere => Self::StartHere, + Self::TupleEnds => Self::TupleEnds, + Self::TupleStarts => Self::TupleStarts, _ => unimplemented!("variant can't be cloned"), } } diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index 197e13e..41bfe95 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -7,11 +7,11 @@ use clap::builder::TypedValueParser; use fasteval::{Compiler, Instruction}; use nom::{ branch::alt, - bytes::complete::take_till1, + bytes::complete::{take_till, take_till1}, character::complete::{anychar, char, one_of, u16, u8}, - combinator::{map_opt, map_res, value}, + combinator::{map_opt, map_res, opt, value}, multi::many0, - sequence::{delimited, pair, preceded, separated_pair}, + sequence::{delimited, pair, preceded, separated_pair, terminated}, Err, IResult, Parser, }; @@ -35,40 +35,59 @@ impl Parse for Modifier { } } -fn atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> { +fn flat_atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> { alt(( - one_of(notes).map(FlatAtom::Note), + map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).map(FlatAtom::Note), value(FlatAtom::Rest, char(Atom::REST)), value(FlatAtom::StartHere, char(Atom::START_HERE)), preceded(char(Atom::MODIFIER), Modifier::parse).map(FlatAtom::Modifier), QuickModifier::parse.map(FlatAtom::QuickModifier), - preceded(char(Atom::LOOP.0), map_opt(u8, NonZeroU8::new)).map(FlatAtom::LoopStarts), + preceded( + char(Atom::LOOP.0), + map_opt(opt(u8), |n| { + if let Some(n) = n { + NonZeroU8::new(n) + } else { + unsafe { Some(NonZeroU8::new_unchecked(2)) } + } + }), + ) + .map(FlatAtom::LoopStarts), value(FlatAtom::LoopEnds, char(Atom::LOOP.1)), value(FlatAtom::TupleStarts, char(Atom::TUPLE.0)), value(FlatAtom::TupleEnds, char(Atom::TUPLE.1)), - preceded( - char(Atom::SLOPE.0), - separated_pair( - SlopeModifier::parse, - char(' '), - map_res(take_till1(|c| c == ','), |s| { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - Result::>::Ok( - parser - .parse(s, &mut slab.ps) - .map_err(|_| nom::error::Error::new(s, nom::error::ErrorKind::Verify))? - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs), - ) - }), + terminated( + preceded( + char(Atom::SLOPE.0), + separated_pair( + SlopeModifier::parse, + char(' '), + map_res(take_till1(|c| c == ','), |s| { + let parser = fasteval::Parser::new(); + let mut slab = fasteval::Slab::new(); + Result::>::Ok( + parser + .parse(s, &mut slab.ps) + .map_err(|_| { + nom::error::Error::new(s, nom::error::ErrorKind::Verify) + })? + .from(&slab.ps) + .compile(&slab.ps, &mut slab.cs), + ) + }), + ), ), + char(','), ) .map(|(sm, i)| FlatAtom::SlopeStarts(sm, i)), value(FlatAtom::SlopeEnds, char(Atom::SLOPE.1)), value( FlatAtom::Comment, - delimited(char(Atom::COMMENT.0), anychar, char(Atom::COMMENT.1)), + delimited( + char(Atom::COMMENT.0), + take_till(|c| c == Atom::COMMENT.1), + char(Atom::COMMENT.1), + ), ), )) } diff --git a/src/bng/score/lex/lexer/tests.rs b/src/bng/score/lex/lexer/tests.rs index 7b269d2..f37a4fa 100644 --- a/src/bng/score/lex/lexer/tests.rs +++ b/src/bng/score/lex/lexer/tests.rs @@ -1,14 +1,25 @@ -mod modifier { - use std::num::{NonZeroU16, NonZeroU8}; +use const_format::concatcp; +use nom::{ + error::{Error, ErrorKind}, + Err, +}; - use const_format::concatcp; - use nom::{ - error::{Error, ErrorKind}, - Err, +use flat_atom::{ + FASTEVAL_INSTRUCTION as FLATATOM_FASTEVAL_INSTRUCTION, SAMPLE_STR as FLATATOM_SAMPLE_STRING, +}; + +mod flat_atom { + use std::num::NonZeroU8; + + use fasteval::Compiler; + use nom::Parser; + + use super::*; + use crate::bng::score::{ + lex::{lexer::flat_atom_parser, UP}, + Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier, }; - use crate::bng::score::{lex::lexer::Parse, Atom, Modifier}; - pub(super) const SAMPLE_STR: &str = concatcp!( Atom::TUPLE.0, "acc", @@ -18,6 +29,164 @@ mod modifier { "hello" ); + pub(super) const FASTEVAL_INSTRUCTION: &str = "1-cos((PI*x)/2)"; + + #[test] + fn note() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::Note(2))), + flat_atom_parser("abcdefg").parse(concatcp!('c', SAMPLE_STR)) + ) + } + + #[test] + fn rest() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::Rest)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR)) + ) + } + + #[test] + fn start_here() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::StartHere)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR)) + ) + } + + #[test] + fn modifier() { + assert_eq!( + Ok(( + SAMPLE_STR, + FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) })) + )), + flat_atom_parser("abcdefg").parse(concatcp!( + Atom::MODIFIER, + Modifier::LENGTH, + 2u8, + SAMPLE_STR + )) + ) + } + + #[test] + fn quick_modifier() { + assert_eq!( + Ok(( + SAMPLE_STR, + FlatAtom::QuickModifier(QuickModifier::Length(UP)) + )), + flat_atom_parser("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR)) + ) + } + + #[test] + fn loop_starts() { + assert_eq!( + Ok(( + SAMPLE_STR, + FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) }) + )), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR)) + ); + assert_eq!( + Ok(( + SAMPLE_STR, + FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) }) + )), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR)) + ); + assert_eq!( + Err(nom::Err::Error(Error::new( + concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR), + ErrorKind::Char + ))), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR)) + ) + } + + #[test] + fn loop_ends() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::LoopEnds)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR)) + ) + } + + #[test] + fn tuple_starts() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::TupleStarts)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR)) + ) + } + + #[test] + fn tuple_ends() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::TupleEnds)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR)) + ) + } + + #[test] + fn slope_starts() { + assert_eq!( + Ok(( + SAMPLE_STR, + FlatAtom::SlopeStarts(SlopeModifier::Note, { + let parser = fasteval::Parser::new(); + let mut slab = fasteval::Slab::new(); + parser + .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) + .unwrap() + .from(&slab.ps) + .compile(&slab.ps, &mut slab.cs) + }) + )), + flat_atom_parser("abcdefg").parse(concatcp!( + Atom::SLOPE.0, + SlopeModifier::NOTE, + ' ', + FASTEVAL_INSTRUCTION, + ',', + SAMPLE_STR + )) + ) + } + + #[test] + fn slope_ends() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::SlopeEnds)), + flat_atom_parser("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR)) + ) + } + + #[test] + fn comment() { + assert_eq!( + Ok((SAMPLE_STR, FlatAtom::Comment)), + flat_atom_parser("abcdefg").parse(concatcp!( + Atom::COMMENT.0, + "hi I'm a little pony", + SAMPLE_STR, + Atom::COMMENT.1, + SAMPLE_STR + )) + ) + } +} + +mod modifier { + use std::num::{NonZeroU16, NonZeroU8}; + + use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR; + use super::*; + use crate::bng::score::{lex::lexer::Parse, Modifier}; + #[test] fn volume() { assert_eq!( @@ -92,16 +261,12 @@ mod modifier { } } -use modifier::SAMPLE_STR as MODIFIER_SAMPLE_STRING; - mod quick_modifier { - use const_format::concatcp; - use nom::{error::Error, Err}; - - use super::MODIFIER_SAMPLE_STRING as SAMPLE_STR; + use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR; + use super::*; use crate::bng::score::{ lex::{lexer::Parse, DOWN, OFF, ON, UP}, - Atom, QuickModifier, + QuickModifier, }; #[test] @@ -155,12 +320,11 @@ mod quick_modifier { #[cfg(test)] mod slope_modifier { - use const_format::concatcp; - use nom::{error::Error, Err}; - + use super::FLATATOM_FASTEVAL_INSTRUCTION as INSTRUCTION; + use super::*; use crate::bng::score::{lex::lexer::Parse, Atom, SlopeModifier}; - const SAMPLE_STR: &str = concatcp!(" 1-cos((PI*x)/2),acced", Atom::SLOPE.1); + const SAMPLE_STR: &str = concatcp!(' ', INSTRUCTION, Atom::SLOPE.1); #[test] fn note() {