quick modifier parser macro

This commit is contained in:
Ponj 2024-10-10 19:43:40 -04:00
parent f9841267ec
commit 2d5291c07b
Signed by: p6nj
GPG key ID: 6FED68D87C479A59
4 changed files with 67 additions and 3 deletions

View file

@ -15,6 +15,12 @@ pub fn slope_modifier_parser(input: TokenStream) -> TokenStream {
impl_slope_modifier_parser(ast) 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 { fn impl_modifier_parser(ast: DeriveInput) -> TokenStream {
let name = &ast.ident; let name = &ast.ident;
if let Data::Enum(DataEnum { variants, .. }) = ast.data { 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") 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")
}
}

View file

@ -1,4 +1,4 @@
use bng_macros::{ModifierParser, SlopeModifierParser}; use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser};
use fasteval::Instruction; use fasteval::Instruction;
mod lex; mod lex;
@ -22,6 +22,7 @@ pub(super) enum Modifier {
Tempo(u16), Tempo(u16),
} }
#[derive(QuickModifierParser)]
pub(super) enum QuickModifier { pub(super) enum QuickModifier {
Volume(bool), Volume(bool),
Octave(bool), Octave(bool),

View file

@ -1,4 +1,4 @@
use super::{Atom, Modifier, SlopeModifier, WrapperKind}; use super::{Atom, Modifier, QuickModifier, SlopeModifier, WrapperKind};
pub(super) mod lexer; pub(super) mod lexer;
@ -13,6 +13,10 @@ impl WrappingTokens {
const SQUARE_BRACKETS: (char, char) = ('[', ']'); const SQUARE_BRACKETS: (char, char) = ('[', ']');
const BRACKETS: (char, char) = ('{', '}'); const BRACKETS: (char, char) = ('{', '}');
const SEMICOLON_COMMA: (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<T> { pub(super) trait Token<T> {
@ -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<char> for Modifier { impl Token<char> for Modifier {
fn token(self) -> char { fn token(self) -> char {
match self { match self {

View file

@ -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 { pub(crate) trait Parse: Sized {
fn parse(input: &str) -> IResult<&str, Self>; fn parse(input: &str) -> IResult<&str, Self>;