context & function names without another Parse trait

This commit is contained in:
Ponj 2024-11-09 12:53:28 -05:00
parent 78d7c493bb
commit a2566f1be3
Signed by: p6nj
GPG key ID: 6FED68D87C479A59
6 changed files with 192 additions and 104 deletions

View file

@ -7,6 +7,7 @@ edition = "2021"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
Inflector = "0.11.4"
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = { version = "2.0", features = ["full"] } syn = { version = "2.0", features = ["full"] }

View file

@ -1,8 +1,9 @@
extern crate proc_macro; extern crate proc_macro;
use inflector::Inflector;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span; use proc_macro2::Span;
use quote::quote; use quote::{quote, ToTokens};
use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Ident}; use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields, FieldsUnnamed, Ident};
#[proc_macro_derive(SlopeModifierParser)] #[proc_macro_derive(SlopeModifierParser)]
pub fn slope_modifier_parser(input: TokenStream) -> TokenStream { pub fn slope_modifier_parser(input: TokenStream) -> TokenStream {
@ -16,24 +17,49 @@ pub fn quick_modifier_parser(input: TokenStream) -> TokenStream {
impl_quick_modifier_parser(ast) impl_quick_modifier_parser(ast)
} }
#[proc_macro_derive(ModifierParser)]
pub fn modifier_parser(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
impl_modifier_parser(ast)
}
trait ToIdent: ToString {
fn to_ident(&self) -> Ident {
Ident::new(&self.to_string(), Span::call_site())
}
}
impl<S: ToString> ToIdent for S {}
fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream { fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream {
let name = &ast.ident; let name = &ast.ident;
let fn_name = name.to_string().to_snake_case().to_ident();
if let Data::Enum(DataEnum { variants, .. }) = ast.data { if let Data::Enum(DataEnum { variants, .. }) = ast.data {
let match_arms = variants.iter().map(|variant| { let match_arms = variants.iter().map(|variant| {
let variant_name = &variant.ident; let variant_name = &variant.ident;
let const_name = Ident::new(&variant.ident.to_string().to_uppercase(),Span::call_site()); let variant_name_lower = variant_name.to_string().to_lowercase().to_ident();
let const_name = &variant.ident.to_string().to_uppercase().to_ident();
quote! { quote! {
nom::combinator::value(#name::#variant_name, nom::character::complete::char(SlopeModifier::#const_name)) nom::error::context(
stringify!(#variant_name_lower),
nom::combinator::value(
#name::#variant_name,
nom::character::complete::char(SlopeModifier::#const_name)
)
)
} }
}); });
quote! { quote! {
impl lex::lexer::Parse for #name { pub fn #fn_name<'a, E: nom::error::ParseError<&'a str> + nom::error::ContextError<&'a str>>(
fn parse(input: &str) -> nom::IResult<&str, #name> { i: &'a str,
) -> nom::IResult<&'a str, #name, E> {
nom::error::context(
"slope modifier",
nom::branch::alt(( nom::branch::alt((
#(#match_arms),* #(#match_arms),*
))(input) ))
} )(i)
} }
} }
.into() .into()
@ -44,12 +70,15 @@ fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream {
fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream { fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream {
let name = &ast.ident; let name = &ast.ident;
let fn_name = name.to_string().to_snake_case().to_ident();
if let Data::Enum(DataEnum { variants, .. }) = ast.data { if let Data::Enum(DataEnum { variants, .. }) = ast.data {
let match_arms = variants.iter().map(|variant| { let match_arms = variants.iter().map(|variant| {
let variant_name = &variant.ident; let variant_name = &variant.ident;
let const_name = let variant_name_lower = variant_name.to_string().to_lowercase().to_ident();
Ident::new(&variant.ident.to_string().to_uppercase(), Span::call_site()); let const_name = &variant.ident.to_string().to_uppercase().to_ident();
quote! { quote! {
nom::error::context(
stringify!(#variant_name_lower),
nom::combinator::map( nom::combinator::map(
nom::branch::alt( nom::branch::alt(
( (
@ -65,16 +94,86 @@ fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream {
), ),
#name::#variant_name #name::#variant_name
) )
)
} }
}); });
quote! { quote! {
impl lex::lexer::Parse for #name { pub fn #fn_name<'a, E: nom::error::ParseError<&'a str> + nom::error::ContextError<&'a str>>(
fn parse(input: &str) -> nom::IResult<&str, #name> { i: &'a str,
) -> nom::IResult<&'a str, #name, E> {
nom::error::context(
"quick modifier",
nom::branch::alt(( nom::branch::alt((
#(#match_arms),* #(#match_arms),*
))(input) ))
} )(i)
}
}
.into()
} else {
panic!("this macro only works on enums")
}
}
fn impl_modifier_parser(ast: DeriveInput) -> TokenStream {
let name = &ast.ident;
let fn_name = name.to_string().to_snake_case().to_ident();
if let Data::Enum(DataEnum { variants, .. }) = ast.data {
let match_arms = variants.iter().map(|variant| {
let variant_name = &variant.ident;
let variant_name_lower = variant_name.to_string().to_lowercase().to_ident();
let const_name = &variant.ident.to_string().to_uppercase().to_ident();
if let Fields::Unnamed(FieldsUnnamed {
paren_token: _,
unnamed,
}) = &variant.fields
{
let type_name = {
let type_name = &unnamed[0].ty.to_token_stream().to_string();
match type_name.strip_prefix("NonZero") {
Some(s) => {
let lower = s.to_lowercase().to_ident();
let type_name = &unnamed[0].ty;
quote! {
nom::combinator::map_opt(
nom::character::complete::#lower,
std::num::#type_name::new
)
}
}
_ => {
let type_name = &unnamed[0].ty;
quote! {
nom::character::complete::#type_name
}
}
}
};
quote! {
nom::error::context(
stringify!(#variant_name_lower),
nom::combinator::map(
nom::sequence::preceded(nom::character::complete::char(#name::#const_name), #type_name),
#name::#variant_name
)
)
}
} else {
panic!("this macro only works on unnamed fields")
}
});
quote! {
pub fn #fn_name<'a, E: nom::error::ParseError<&'a str> + nom::error::ContextError<&'a str>>(
i: &'a str,
) -> nom::IResult<&'a str, #name, E> {
nom::error::context(
"modifier",
nom::branch::alt((
#(#match_arms),*
))
)(i)
} }
} }
.into() .into()

View file

@ -5,10 +5,10 @@ use std::{
use amplify::From; use amplify::From;
use anyhow::Context; use anyhow::Context;
use bng_macros::{QuickModifierParser, SlopeModifierParser}; use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser};
use derive_new::new; use derive_new::new;
use derived_deref::Deref; use derived_deref::Deref;
use lex::lexer::flat_atom_parser; use lex::lexer::atom;
use nom::{ use nom::{
branch::alt, branch::alt,
character::{complete::char, streaming::one_of}, character::{complete::char, streaming::one_of},
@ -91,7 +91,7 @@ impl Clone for FlatAtom {
} }
} }
#[derive(Clone)] #[derive(Clone, ModifierParser)]
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))] #[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
pub enum Modifier { pub enum Modifier {
Volume(u8), Volume(u8),

View file

@ -12,7 +12,7 @@ use serde::{
}; };
use thiserror::Error; use thiserror::Error;
use crate::bng::score::lex::lexer::flat_atom_parser; use crate::bng::score::lex::lexer::atom;
use super::{ use super::{
utils::{inflate, InflateError}, utils::{inflate, InflateError},
@ -64,7 +64,7 @@ impl<'de> Deserialize<'de> for Atoms {
if sheet.is_empty() { if sheet.is_empty() {
Ok(Default::default()) Ok(Default::default())
} else { } else {
flat_atom_parser_mapper::<D, _>(&sheet, flat_atom_parser(&notes)) atom_mapper::<D, _>(&sheet, atom(&notes))
} }
} }
} }
@ -76,7 +76,7 @@ where
many0(one_of(" \t\r")) many0(one_of(" \t\r"))
} }
fn flat_atom_parser_mapper<'a, 'de, D, P>( fn atom_mapper<'a, 'de, D, P>(
input: &'a str, input: &'a str,
parser: P, parser: P,
) -> Result<Atoms, <D as Deserializer<'de>>::Error> ) -> Result<Atoms, <D as Deserializer<'de>>::Error>

View file

@ -10,41 +10,28 @@ use nom::{
bytes::complete::{take_till, take_till1}, bytes::complete::{take_till, take_till1},
character::complete::{anychar, char, one_of, space1, u16, u8}, character::complete::{anychar, char, one_of, space1, u16, u8},
combinator::{map_opt, map_res, opt, value, verify}, combinator::{map_opt, map_res, opt, value, verify},
error::{context, ContextError, ParseError},
multi::many0, multi::many0,
sequence::{delimited, pair, preceded, separated_pair, terminated}, sequence::{delimited, pair, preceded, separated_pair, terminated},
Err, IResult, Parser, Err, IResult, Parser,
}; };
use crate::bng::score::{modifier, quick_modifier, slope_modifier};
use super::{ use super::{
super::super::Expression as Instruction, super::super::Expression as Instruction, Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier,
{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier},
}; };
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub(crate) trait Parse: Sized { pub fn atom(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> {
fn parse(input: &str) -> IResult<&str, Self>;
}
impl Parse for Modifier {
fn parse(input: &str) -> IResult<&str, Self> {
alt((
preceded(char(Modifier::VOLUME), u8).map(Modifier::Volume),
preceded(char(Modifier::OCTAVE), u8).map(Modifier::Octave),
preceded(char(Modifier::LENGTH), map_opt(u8, NonZeroU8::new)).map(Modifier::Length),
preceded(char(Modifier::TEMPO), map_opt(u16, NonZeroU16::new)).map(Modifier::Tempo),
))(input)
}
}
pub fn flat_atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> {
alt(( alt((
map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).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::Rest, char(Atom::REST)),
value(FlatAtom::StartHere, char(Atom::START_HERE)), value(FlatAtom::StartHere, char(Atom::START_HERE)),
preceded(char(Atom::MODIFIER), Modifier::parse).map(FlatAtom::Modifier), preceded(char(Atom::MODIFIER), modifier).map(FlatAtom::Modifier),
QuickModifier::parse.map(FlatAtom::QuickModifier), quick_modifier.map(FlatAtom::QuickModifier),
preceded( preceded(
char(Atom::LOOP.0), char(Atom::LOOP.0),
map_opt(opt(u8), |n| { map_opt(opt(u8), |n| {
@ -63,7 +50,7 @@ pub fn flat_atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::
preceded( preceded(
char(Atom::SLOPE.0), char(Atom::SLOPE.0),
separated_pair( separated_pair(
SlopeModifier::parse, slope_modifier,
char(' '), char(' '),
map_res(take_till1(|c| c == ','), |s: &str| { map_res(take_till1(|c| c == ','), |s: &str| {
s.parse() s.parse()

View file

@ -15,8 +15,8 @@ mod flat_atom {
use nom::Parser; use nom::Parser;
use super::super::{ use super::super::{
super::super::super::Expression as Instruction, super::UP, flat_atom_parser, Atom, super::super::super::Expression as Instruction, super::UP, atom, Atom, FlatAtom, Modifier,
FlatAtom, Modifier, QuickModifier, SlopeModifier, QuickModifier, SlopeModifier,
}; };
use super::*; use super::*;
@ -35,7 +35,7 @@ mod flat_atom {
fn note() { fn note() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Note(2))), Ok((SAMPLE_STR, FlatAtom::Note(2))),
flat_atom_parser("abcdefg").parse(concatcp!('c', SAMPLE_STR)) atom("abcdefg").parse(concatcp!('c', SAMPLE_STR))
) )
} }
@ -43,7 +43,7 @@ mod flat_atom {
fn rest() { fn rest() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Rest)), Ok((SAMPLE_STR, FlatAtom::Rest)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR))
) )
} }
@ -51,7 +51,7 @@ mod flat_atom {
fn start_here() { fn start_here() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::StartHere)), Ok((SAMPLE_STR, FlatAtom::StartHere)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR))
) )
} }
@ -62,12 +62,7 @@ mod flat_atom {
SAMPLE_STR, SAMPLE_STR,
FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) })) FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) }))
)), )),
flat_atom_parser("abcdefg").parse(concatcp!( atom("abcdefg").parse(concatcp!(Atom::MODIFIER, Modifier::LENGTH, 2u8, SAMPLE_STR))
Atom::MODIFIER,
Modifier::LENGTH,
2u8,
SAMPLE_STR
))
) )
} }
@ -78,7 +73,7 @@ mod flat_atom {
SAMPLE_STR, SAMPLE_STR,
FlatAtom::QuickModifier(QuickModifier::Length(UP)) FlatAtom::QuickModifier(QuickModifier::Length(UP))
)), )),
flat_atom_parser("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
) )
} }
@ -89,21 +84,21 @@ mod flat_atom {
SAMPLE_STR, SAMPLE_STR,
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) }) FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) })
)), )),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok(( Ok((
SAMPLE_STR, SAMPLE_STR,
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) }) FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) })
)), )),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR), concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR),
ErrorKind::Char ErrorKind::Char
))), ))),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::LOOP.0, 0u8, SAMPLE_STR))
) )
} }
@ -111,7 +106,7 @@ mod flat_atom {
fn loop_ends() { fn loop_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::LoopEnds)), Ok((SAMPLE_STR, FlatAtom::LoopEnds)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR))
) )
} }
@ -119,7 +114,7 @@ mod flat_atom {
fn tuple_starts() { fn tuple_starts() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleStarts)), Ok((SAMPLE_STR, FlatAtom::TupleStarts)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR))
) )
} }
@ -127,7 +122,7 @@ mod flat_atom {
fn tuple_ends() { fn tuple_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleEnds)), Ok((SAMPLE_STR, FlatAtom::TupleEnds)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR))
) )
} }
@ -138,7 +133,7 @@ mod flat_atom {
SAMPLE_STR, SAMPLE_STR,
FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap()) FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap())
)), )),
flat_atom_parser("abcdefg").parse(concatcp!( atom("abcdefg").parse(concatcp!(
Atom::SLOPE.0, Atom::SLOPE.0,
SlopeModifier::NOTE, SlopeModifier::NOTE,
' ', ' ',
@ -153,7 +148,7 @@ mod flat_atom {
fn slope_ends() { fn slope_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::SlopeEnds)), Ok((SAMPLE_STR, FlatAtom::SlopeEnds)),
flat_atom_parser("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR)) atom("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR))
) )
} }
@ -161,7 +156,7 @@ mod flat_atom {
fn comment() { fn comment() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Comment)), Ok((SAMPLE_STR, FlatAtom::Comment)),
flat_atom_parser("abcdefg").parse(concatcp!( atom("abcdefg").parse(concatcp!(
Atom::COMMENT.0, Atom::COMMENT.0,
"hi I'm a little pony", "hi I'm a little pony",
SAMPLE_STR, SAMPLE_STR,
@ -175,22 +170,24 @@ mod flat_atom {
mod modifier { mod modifier {
use std::num::{NonZeroU16, NonZeroU8}; use std::num::{NonZeroU16, NonZeroU8};
use const_format::concatcp;
use nom::error::{Error, ErrorKind, VerboseError};
use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR; use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR;
use super::*; use crate::bng::score::{modifier, Modifier};
use crate::bng::score::{lex::lexer::Parse, Modifier};
#[test] #[test]
fn volume() { fn volume() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, Modifier::Volume(2))), Ok((SAMPLE_STR, Modifier::Volume(2))),
Modifier::parse(concatcp!(Modifier::VOLUME, 2u8, SAMPLE_STR)) modifier::<VerboseError<&str>>(concatcp!(Modifier::VOLUME, 2u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(Modifier::VOLUME, 2556u16, SAMPLE_STR), concatcp!(Modifier::VOLUME, 2556u16, SAMPLE_STR),
ErrorKind::Char ErrorKind::Char
))), ))),
Modifier::parse(concatcp!(Modifier::VOLUME, 2556u16, SAMPLE_STR)) modifier(concatcp!(Modifier::VOLUME, 2556u16, SAMPLE_STR))
); );
} }
@ -198,14 +195,14 @@ mod modifier {
fn octave() { fn octave() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, Modifier::Octave(2))), Ok((SAMPLE_STR, Modifier::Octave(2))),
Modifier::parse(concatcp!(Modifier::OCTAVE, 2u8, SAMPLE_STR)) modifier::<VerboseError<&str>>(concatcp!(Modifier::OCTAVE, 2u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(Modifier::OCTAVE, 2556u16, SAMPLE_STR), concatcp!(Modifier::OCTAVE, 2556u16, SAMPLE_STR),
ErrorKind::Char ErrorKind::Char
))), ))),
Modifier::parse(concatcp!(Modifier::OCTAVE, 2556u16, SAMPLE_STR)) modifier(concatcp!(Modifier::OCTAVE, 2556u16, SAMPLE_STR))
); );
} }
@ -216,21 +213,21 @@ mod modifier {
SAMPLE_STR, SAMPLE_STR,
Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) }) Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) })
)), )),
Modifier::parse(concatcp!(Modifier::LENGTH, 2u8, SAMPLE_STR)) modifier::<VerboseError<&str>>(concatcp!(Modifier::LENGTH, 2u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(Modifier::LENGTH, 2556u16, SAMPLE_STR), concatcp!(Modifier::LENGTH, 2556u16, SAMPLE_STR),
ErrorKind::Char ErrorKind::Char
))), ))),
Modifier::parse(concatcp!(Modifier::LENGTH, 2556u16, SAMPLE_STR)) modifier(concatcp!(Modifier::LENGTH, 2556u16, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(Modifier::LENGTH, 0u8, SAMPLE_STR), concatcp!(Modifier::LENGTH, 0u8, SAMPLE_STR),
ErrorKind::Char ErrorKind::Char
))), ))),
Modifier::parse(concatcp!(Modifier::LENGTH, 0u8, SAMPLE_STR)) modifier(concatcp!(Modifier::LENGTH, 0u8, SAMPLE_STR))
); );
} }
@ -241,35 +238,37 @@ mod modifier {
SAMPLE_STR, SAMPLE_STR,
Modifier::Tempo(unsafe { NonZeroU16::new_unchecked(2) }) Modifier::Tempo(unsafe { NonZeroU16::new_unchecked(2) })
)), )),
Modifier::parse(concatcp!(Modifier::TEMPO, 2u8, SAMPLE_STR)) modifier::<VerboseError<&str>>(concatcp!(Modifier::TEMPO, 2u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Err(nom::Err::Error(Error::new( Err(nom::Err::Error(Error::new(
concatcp!(655353u32, SAMPLE_STR), concatcp!(655353u32, SAMPLE_STR),
ErrorKind::Digit ErrorKind::Digit
))), ))),
Modifier::parse(concatcp!(Modifier::TEMPO, 655353u32, SAMPLE_STR)) modifier(concatcp!(Modifier::TEMPO, 655353u32, SAMPLE_STR))
); );
} }
} }
mod quick_modifier { mod quick_modifier {
use const_format::concatcp;
use nom::error::VerboseError;
use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR; use super::FLATATOM_SAMPLE_STRING as SAMPLE_STR;
use super::*;
use crate::bng::score::{ use crate::bng::score::{
lex::{lexer::Parse, DOWN, OFF, ON, UP}, lex::{DOWN, OFF, ON, UP},
QuickModifier, quick_modifier, QuickModifier,
}; };
#[test] #[test]
fn volume() { fn volume() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Volume(UP))), Ok((SAMPLE_STR, QuickModifier::Volume(UP))),
QuickModifier::parse(concatcp!(QuickModifier::VOLUME.0, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::VOLUME.0, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Volume(DOWN))), Ok((SAMPLE_STR, QuickModifier::Volume(DOWN))),
QuickModifier::parse(concatcp!(QuickModifier::VOLUME.1, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::VOLUME.1, SAMPLE_STR))
); );
} }
@ -277,11 +276,11 @@ mod quick_modifier {
fn octave() { fn octave() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Octave(UP))), Ok((SAMPLE_STR, QuickModifier::Octave(UP))),
QuickModifier::parse(concatcp!(QuickModifier::OCTAVE.0, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::OCTAVE.0, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Octave(DOWN))), Ok((SAMPLE_STR, QuickModifier::Octave(DOWN))),
QuickModifier::parse(concatcp!(QuickModifier::OCTAVE.1, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::OCTAVE.1, SAMPLE_STR))
); );
} }
@ -289,11 +288,11 @@ mod quick_modifier {
fn length() { fn length() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Length(UP))), Ok((SAMPLE_STR, QuickModifier::Length(UP))),
QuickModifier::parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Length(DOWN))), Ok((SAMPLE_STR, QuickModifier::Length(DOWN))),
QuickModifier::parse(concatcp!(QuickModifier::LENGTH.1, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::LENGTH.1, SAMPLE_STR))
); );
} }
@ -301,20 +300,22 @@ mod quick_modifier {
fn pizz() { fn pizz() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Pizz(ON))), Ok((SAMPLE_STR, QuickModifier::Pizz(ON))),
QuickModifier::parse(concatcp!(QuickModifier::PIZZ.0, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::PIZZ.0, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, QuickModifier::Pizz(OFF))), Ok((SAMPLE_STR, QuickModifier::Pizz(OFF))),
QuickModifier::parse(concatcp!(QuickModifier::PIZZ.1, SAMPLE_STR)) quick_modifier::<VerboseError<&str>>(concatcp!(QuickModifier::PIZZ.1, SAMPLE_STR))
); );
} }
} }
#[cfg(test)] #[cfg(test)]
mod slope_modifier { mod slope_modifier {
use const_format::concatcp;
use nom::error::VerboseError;
use super::FLATATOM_FASTEVAL_INSTRUCTION as INSTRUCTION; use super::FLATATOM_FASTEVAL_INSTRUCTION as INSTRUCTION;
use super::*; use crate::bng::score::{slope_modifier, Atom, SlopeModifier};
use crate::bng::score::{lex::lexer::Parse, Atom, SlopeModifier};
const SAMPLE_STR: &str = concatcp!(' ', INSTRUCTION, Atom::SLOPE.1); const SAMPLE_STR: &str = concatcp!(' ', INSTRUCTION, Atom::SLOPE.1);
@ -322,7 +323,7 @@ mod slope_modifier {
fn note() { fn note() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, SlopeModifier::Note)), Ok((SAMPLE_STR, SlopeModifier::Note)),
SlopeModifier::parse(concatcp!(SlopeModifier::NOTE, SAMPLE_STR)) slope_modifier::<VerboseError<&str>>(concatcp!(SlopeModifier::NOTE, SAMPLE_STR))
) )
} }
@ -330,7 +331,7 @@ mod slope_modifier {
fn volume() { fn volume() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, SlopeModifier::Volume)), Ok((SAMPLE_STR, SlopeModifier::Volume)),
SlopeModifier::parse(concatcp!(SlopeModifier::VOLUME, SAMPLE_STR)) slope_modifier::<VerboseError<&str>>(concatcp!(SlopeModifier::VOLUME, SAMPLE_STR))
) )
} }
@ -338,7 +339,7 @@ mod slope_modifier {
fn octave() { fn octave() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, SlopeModifier::Octave)), Ok((SAMPLE_STR, SlopeModifier::Octave)),
SlopeModifier::parse(concatcp!(SlopeModifier::OCTAVE, SAMPLE_STR)) slope_modifier::<VerboseError<&str>>(concatcp!(SlopeModifier::OCTAVE, SAMPLE_STR))
) )
} }
@ -346,7 +347,7 @@ mod slope_modifier {
fn length() { fn length() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, SlopeModifier::Length)), Ok((SAMPLE_STR, SlopeModifier::Length)),
SlopeModifier::parse(concatcp!(SlopeModifier::LENGTH, SAMPLE_STR)) slope_modifier::<VerboseError<&str>>(concatcp!(SlopeModifier::LENGTH, SAMPLE_STR))
) )
} }
@ -354,7 +355,7 @@ mod slope_modifier {
fn tempo() { fn tempo() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, SlopeModifier::Tempo)), Ok((SAMPLE_STR, SlopeModifier::Tempo)),
SlopeModifier::parse(concatcp!(SlopeModifier::TEMPO, SAMPLE_STR)) slope_modifier::<VerboseError<&str>>(concatcp!(SlopeModifier::TEMPO, SAMPLE_STR))
) )
} }
} }