From 9e0ead7605e2ea189c6504cbd3d0f1283b74c2e9 Mon Sep 17 00:00:00 2001 From: p6nj Date: Sat, 12 Oct 2024 16:27:27 -0400 Subject: [PATCH 1/2] replace Token trait with consts --- bng_macros/src/lib.rs | 23 +++++++----- src/bng/score/lex.rs | 75 +++++++++++++++----------------------- src/bng/score/lex/lexer.rs | 22 +++++++++-- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/bng_macros/src/lib.rs b/bng_macros/src/lib.rs index 939c7d2..e30d5c1 100644 --- a/bng_macros/src/lib.rs +++ b/bng_macros/src/lib.rs @@ -1,7 +1,8 @@ extern crate proc_macro; use proc_macro::TokenStream; +use proc_macro2::Span; use quote::quote; -use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields}; +use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields, Ident}; #[proc_macro_derive(ModifierParser)] pub fn modifier_parser(input: TokenStream) -> TokenStream { @@ -31,11 +32,12 @@ 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::#variant_name(Default::default()).token()), + nom::character::complete::char(#name::#const_name), nom::character::complete::#variant_type ), #name::#variant_name @@ -63,15 +65,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! { - tag(#name::#variant_name) + nom::combinator::value(#name::#variant_name, nom::character::complete::char(SlopeModifier::#const_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) @@ -89,18 +91,19 @@ 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( - true, - nom::character::complete::char(#name::#variant_name(Default::default()).token().0) + lex::MORE, + nom::character::complete::char(#name::#const_name.0) ), nom::combinator::value( - false, - nom::character::complete::char(#name::#variant_name(Default::default()).token().1) + lex::LESS, + nom::character::complete::char(#name::#const_name.1) ) ) ), diff --git a/src/bng/score/lex.rs b/src/bng/score/lex.rs index 6dce07a..07f561c 100644 --- a/src/bng/score/lex.rs +++ b/src/bng/score/lex.rs @@ -1,11 +1,11 @@ -use super::{Atom, Modifier, QuickModifier, SlopeModifier}; +use super::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; pub(super) mod lexer; -const MORE: bool = true; -const LESS: bool = false; -const ON: bool = true; -const OFF: bool = false; +pub(super) const MORE: bool = true; +pub(super) const LESS: bool = false; +pub(super) const ON: bool = true; +pub(super) const OFF: bool = false; struct WrappingTokens; impl WrappingTokens { @@ -19,51 +19,34 @@ impl WrappingTokens { const QUOTE_DEG: (char, char) = ('\'', '°'); } -pub(super) trait Token { - fn token(self) -> T; +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; } -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 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 for Modifier { - fn token(self) -> char { - match self { - Self::Volume(_) => 'v', - Self::Octave(_) => 'o', - Self::Length(_) => 'l', - Self::Tempo(_) => 't', - } - } +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 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"), - } - } +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; } diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index 1c9690a..77be20f 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -1,11 +1,25 @@ use nom::{ - branch::alt, character::complete::char, combinator::value, sequence::delimited, IResult, Parser, + branch::alt, + character::complete::{char, one_of, u8}, + combinator::value, + multi::many0, + sequence::{delimited, pair, preceded}, + Err, IResult, Parser, }; -use crate::bng::score::QuickModifier; - -use super::Token; +use crate::bng::score::{Atom, FlatAtom, Modifier, QuickModifier}; 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), + )) +} From b2b8546f200a11344edc69df600c6c216901a757 Mon Sep 17 00:00:00 2001 From: p6nj Date: Sat, 12 Oct 2024 17:28:33 -0400 Subject: [PATCH 2/2] atom parser --- src/bng/score.rs | 33 +++++++++++++++++++++++++++++-- src/bng/score/lex/lexer.rs | 40 ++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/bng/score.rs b/src/bng/score.rs index 94fd3af..6b7c783 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -2,10 +2,9 @@ use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser}; use fasteval::Instruction; mod lex; -use lex::Token; pub(super) enum Atom { - Note(u8), + Note(char), Rest, StartHere, Modifier(Modifier), @@ -16,6 +15,30 @@ 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), @@ -24,6 +47,12 @@ 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/lexer.rs b/src/bng/score/lex/lexer.rs index 77be20f..eeb420a 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -1,13 +1,18 @@ +use std::collections::BTreeMap; + +use clap::builder::TypedValueParser; +use fasteval::{Compiler, Instruction}; use nom::{ branch::alt, - character::complete::{char, one_of, u8}, - combinator::value, + bytes::complete::take_till1, + character::complete::{anychar, char, one_of, u8}, + combinator::{map_res, value}, multi::many0, - sequence::{delimited, pair, preceded}, + sequence::{delimited, pair, preceded, separated_pair}, Err, IResult, Parser, }; -use crate::bng::score::{Atom, FlatAtom, Modifier, QuickModifier}; +use crate::bng::score::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; pub(crate) trait Parse: Sized { fn parse(input: &str) -> IResult<&str, Self>; @@ -21,5 +26,32 @@ fn atom_parser<'a>(notes: &'a str) -> impl Parser<&str, FlatAtom, nom::error::Er 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)), + ), )) }