From 2d5291c07bd392e4bc23c0b00e7ea17eb790cf40 Mon Sep 17 00:00:00 2001 From: p6nj Date: Thu, 10 Oct 2024 19:43:40 -0400 Subject: [PATCH] quick modifier parser macro --- bng_macros/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++ src/bng/score.rs | 3 ++- src/bng/score/lex.rs | 17 +++++++++++++- src/bng/score/lex/lexer.rs | 4 +++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/bng_macros/src/lib.rs b/bng_macros/src/lib.rs index bca0a42..3bd47ff 100644 --- a/bng_macros/src/lib.rs +++ b/bng_macros/src/lib.rs @@ -15,6 +15,12 @@ pub fn slope_modifier_parser(input: TokenStream) -> TokenStream { impl_slope_modifier_parser(ast) } +#[proc_macro_derive(QuickModifierParser)] +pub fn quick_modifier_parser(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + impl_quick_modifier_parser(ast) +} + fn impl_modifier_parser(ast: DeriveInput) -> TokenStream { let name = &ast.ident; if let Data::Enum(DataEnum { variants, .. }) = ast.data { @@ -77,3 +83,43 @@ fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream { panic!("this macro only works on enums") } } + +fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream { + let name = &ast.ident; + if let Data::Enum(DataEnum { variants, .. }) = ast.data { + let match_arms = variants.iter().map(|variant| { + let variant_name = &variant.ident; + + quote! { + nom::combinator::map( + nom::branch::alt( + ( + nom::combinator::value( + true, + nom::character::complete::char(#name::#variant_name(Default::default()).token()[0]) + ), + nom::combinator::value( + false, + nom::character::complete::char(#name::#variant_name(Default::default()).token()[1]) + ) + ) + ), + #name::#variant_name + ) + } + }); + + quote! { + impl lex::lexer::Parse for #name { + fn parse(input: &str) -> nom::IResult<&str, #name> { + nom::branch::alt(( + #(#match_arms),* + ))(input) + } + } + } + .into() + } else { + panic!("this macro only works on enums") + } +} diff --git a/src/bng/score.rs b/src/bng/score.rs index 27573ce..2eda638 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -1,4 +1,4 @@ -use bng_macros::{ModifierParser, SlopeModifierParser}; +use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser}; use fasteval::Instruction; mod lex; @@ -22,6 +22,7 @@ pub(super) enum Modifier { Tempo(u16), } +#[derive(QuickModifierParser)] pub(super) enum QuickModifier { Volume(bool), Octave(bool), diff --git a/src/bng/score/lex.rs b/src/bng/score/lex.rs index f8b9dfe..53f883a 100644 --- a/src/bng/score/lex.rs +++ b/src/bng/score/lex.rs @@ -1,4 +1,4 @@ -use super::{Atom, Modifier, SlopeModifier, WrapperKind}; +use super::{Atom, Modifier, QuickModifier, SlopeModifier, WrapperKind}; pub(super) mod lexer; @@ -13,6 +13,10 @@ impl WrappingTokens { const SQUARE_BRACKETS: (char, char) = ('[', ']'); const BRACKETS: (char, char) = ('{', '}'); const SEMICOLON_COMMA: (char, char) = (';', ','); + const PLUS_MINUS: (char, char) = ('+', '-'); + const RIGHT_LEFT: (char, char) = ('>', '<'); + const SLASH_BACKSLASH: (char, char) = ('/', '\\'); + const QUOTE_DEG: (char, char) = ('\'', '°'); } pub(super) trait Token { @@ -30,6 +34,17 @@ impl Token<(char, char)> for WrapperKind { } } +impl Token<(char, char)> for QuickModifier { + fn token(self) -> (char, char) { + match self { + Self::Volume(_) => WrappingTokens::PLUS_MINUS, + Self::Octave(_) => WrappingTokens::RIGHT_LEFT, + Self::Length(_) => WrappingTokens::SLASH_BACKSLASH, + Self::Pizz(_) => WrappingTokens::QUOTE_DEG, + } + } +} + impl Token for Modifier { fn token(self) -> char { match self { diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index ee3999b..2a02856 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -1,4 +1,6 @@ -use nom::IResult; +use nom::{branch::alt, character::complete::char, combinator::value, IResult, Parser}; + +use crate::bng::score::QuickModifier; pub(crate) trait Parse: Sized { fn parse(input: &str) -> IResult<&str, Self>;