diff --git a/bng_macros/src/lib.rs b/bng_macros/src/lib.rs index e30d5c1..939c7d2 100644 --- a/bng_macros/src/lib.rs +++ b/bng_macros/src/lib.rs @@ -1,8 +1,7 @@ extern crate proc_macro; use proc_macro::TokenStream; -use proc_macro2::Span; use quote::quote; -use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields, Ident}; +use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields}; #[proc_macro_derive(ModifierParser)] pub fn modifier_parser(input: TokenStream) -> TokenStream { @@ -32,12 +31,11 @@ fn impl_modifier_parser(ast: DeriveInput) -> TokenStream { } else { panic!("Expected unnamed fields in enum variants"); }; - let const_name = - Ident::new(&variant.ident.to_string().to_uppercase(), Span::call_site()); + quote! { nom::combinator::map( nom::sequence::preceded( - nom::character::complete::char(#name::#const_name), + nom::character::complete::char(#name::#variant_name(Default::default()).token()), nom::character::complete::#variant_type ), #name::#variant_name @@ -65,15 +63,15 @@ fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream { if let Data::Enum(DataEnum { variants, .. }) = ast.data { let match_arms = variants.iter().map(|variant| { let variant_name = &variant.ident; - let const_name = Ident::new(&variant.ident.to_string().to_uppercase(),Span::call_site()); quote! { - nom::combinator::value(#name::#variant_name, nom::character::complete::char(SlopeModifier::#const_name)) + tag(#name::#variant_name) } }); quote! { impl lex::lexer::Parse for #name { fn parse(input: &str) -> nom::IResult<&str, #name> { + let tag = |sm: SlopeModifier| nom::combinator::value(sm, nom::character::complete::char(sm.token())); nom::branch::alt(( #(#match_arms),* ))(input) @@ -91,19 +89,18 @@ fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream { if let Data::Enum(DataEnum { variants, .. }) = ast.data { let match_arms = variants.iter().map(|variant| { let variant_name = &variant.ident; - let const_name = - Ident::new(&variant.ident.to_string().to_uppercase(), Span::call_site()); + quote! { nom::combinator::map( nom::branch::alt( ( nom::combinator::value( - lex::MORE, - nom::character::complete::char(#name::#const_name.0) + true, + nom::character::complete::char(#name::#variant_name(Default::default()).token().0) ), nom::combinator::value( - lex::LESS, - nom::character::complete::char(#name::#const_name.1) + false, + nom::character::complete::char(#name::#variant_name(Default::default()).token().1) ) ) ), diff --git a/src/bng/score.rs b/src/bng/score.rs index 6b7c783..94fd3af 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -2,9 +2,10 @@ use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser}; use fasteval::Instruction; mod lex; +use lex::Token; pub(super) enum Atom { - Note(char), + Note(u8), Rest, StartHere, Modifier(Modifier), @@ -15,30 +16,6 @@ pub(super) enum Atom { Comment, } -pub(super) enum FlatAtom { - Note(char), - Rest, - StartHere, - Modifier(Modifier), - QuickModifier(QuickModifier), - LoopStarts(u8), - LoopEnds, - TupleStarts, - TupleEnds, - SlopeStarts(SlopeModifier, Instruction), - SlopeEnds, - Comment, -} - -impl Clone for FlatAtom { - fn clone(&self) -> Self { - match self { - Self::Rest => Self::Rest, - _ => unimplemented!("variant can't be cloned"), - } - } -} - #[derive(ModifierParser)] pub(super) enum Modifier { Volume(u8), @@ -47,12 +24,6 @@ pub(super) enum Modifier { Tempo(u16), } -impl Default for Modifier { - fn default() -> Self { - Modifier::Volume(Default::default()) - } -} - #[derive(QuickModifierParser)] pub(super) enum QuickModifier { Volume(bool), diff --git a/src/bng/score/lex.rs b/src/bng/score/lex.rs index 07f561c..6dce07a 100644 --- a/src/bng/score/lex.rs +++ b/src/bng/score/lex.rs @@ -1,11 +1,11 @@ -use super::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; +use super::{Atom, Modifier, QuickModifier, SlopeModifier}; pub(super) mod lexer; -pub(super) const MORE: bool = true; -pub(super) const LESS: bool = false; -pub(super) const ON: bool = true; -pub(super) const OFF: bool = false; +const MORE: bool = true; +const LESS: bool = false; +const ON: bool = true; +const OFF: bool = false; struct WrappingTokens; impl WrappingTokens { @@ -19,34 +19,51 @@ impl WrappingTokens { const QUOTE_DEG: (char, char) = ('\'', '°'); } -impl QuickModifier { - pub(super) const VOLUME: (char, char) = WrappingTokens::PLUS_MINUS; - pub(super) const OCTAVE: (char, char) = WrappingTokens::RIGHT_LEFT; - pub(super) const LENGTH: (char, char) = WrappingTokens::SLASH_BACKSLASH; - pub(super) const PIZZ: (char, char) = WrappingTokens::QUOTE_DEG; +pub(super) trait Token { + fn token(self) -> T; } -impl Modifier { - pub(super) const VOLUME: char = 'v'; - pub(super) const OCTAVE: char = 'o'; - pub(super) const LENGTH: char = 'l'; - pub(super) const TEMPO: char = 't'; +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 SlopeModifier { - pub(super) const NOTE: char = 'n'; - pub(super) const VOLUME: char = 'v'; - pub(super) const OCTAVE: char = 'o'; - pub(super) const LENGTH: char = 'l'; - pub(super) const TEMPO: char = 't'; +impl Token for Modifier { + fn token(self) -> char { + match self { + Self::Volume(_) => 'v', + Self::Octave(_) => 'o', + Self::Length(_) => 'l', + Self::Tempo(_) => 't', + } + } } -impl Atom { - pub(super) const REST: char = '.'; - pub(super) const START_HERE: char = ':'; - pub(super) const MODIFIER: char = '!'; - pub(super) const LOOP: (char, char) = WrappingTokens::PARENTHESES; - pub(super) const TUPLE: (char, char) = WrappingTokens::SQUARE_BRACKETS; - pub(super) const SLOPE: (char, char) = WrappingTokens::BRACKETS; - pub(super) const COMMENT: (char, char) = WrappingTokens::SEMICOLON_COMMA; +impl Token for SlopeModifier { + fn token(self) -> char { + match self { + Self::Note => 'n', + Self::Volume => 'v', + Self::Octave => 'o', + Self::Length => 'l', + Self::Tempo => 't', + } + } +} + +impl Token for Atom { + fn token(self) -> char { + match self { + Atom::Rest => '.', + Atom::StartHere => ':', + Atom::Modifier(_) => '!', + _ => unimplemented!("not a singleton"), + } + } } diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index eeb420a..1c9690a 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -1,57 +1,11 @@ -use std::collections::BTreeMap; - -use clap::builder::TypedValueParser; -use fasteval::{Compiler, Instruction}; use nom::{ - branch::alt, - bytes::complete::take_till1, - character::complete::{anychar, char, one_of, u8}, - combinator::{map_res, value}, - multi::many0, - sequence::{delimited, pair, preceded, separated_pair}, - Err, IResult, Parser, + branch::alt, character::complete::char, combinator::value, sequence::delimited, IResult, Parser, }; -use crate::bng::score::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; +use crate::bng::score::QuickModifier; + +use super::Token; pub(crate) trait Parse: Sized { fn parse(input: &str) -> IResult<&str, Self>; } - -fn atom_parser<'a>(notes: &'a str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> { - alt(( - one_of(notes).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), u8).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), - ) - }), - ), - ) - .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)), - ), - )) -}