Compare commits

..

No commits in common. "b2b8546f200a11344edc69df600c6c216901a757" and "040bb4ecb3c642077e06d9748c5c0f3edd935648" have entirely different histories.

4 changed files with 62 additions and 123 deletions

View file

@ -1,8 +1,7 @@
extern crate proc_macro; extern crate proc_macro;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote; 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)] #[proc_macro_derive(ModifierParser)]
pub fn modifier_parser(input: TokenStream) -> TokenStream { pub fn modifier_parser(input: TokenStream) -> TokenStream {
@ -32,12 +31,11 @@ fn impl_modifier_parser(ast: DeriveInput) -> TokenStream {
} else { } else {
panic!("Expected unnamed fields in enum variants"); panic!("Expected unnamed fields in enum variants");
}; };
let const_name =
Ident::new(&variant.ident.to_string().to_uppercase(), Span::call_site());
quote! { quote! {
nom::combinator::map( nom::combinator::map(
nom::sequence::preceded( 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 nom::character::complete::#variant_type
), ),
#name::#variant_name #name::#variant_name
@ -65,15 +63,15 @@ fn impl_slope_modifier_parser(ast: DeriveInput) -> TokenStream {
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());
quote! { quote! {
nom::combinator::value(#name::#variant_name, nom::character::complete::char(SlopeModifier::#const_name)) tag(#name::#variant_name)
} }
}); });
quote! { quote! {
impl lex::lexer::Parse for #name { impl lex::lexer::Parse for #name {
fn parse(input: &str) -> nom::IResult<&str, #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(( nom::branch::alt((
#(#match_arms),* #(#match_arms),*
))(input) ))(input)
@ -91,19 +89,18 @@ fn impl_quick_modifier_parser(ast: DeriveInput) -> TokenStream {
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());
quote! { quote! {
nom::combinator::map( nom::combinator::map(
nom::branch::alt( nom::branch::alt(
( (
nom::combinator::value( nom::combinator::value(
lex::MORE, true,
nom::character::complete::char(#name::#const_name.0) nom::character::complete::char(#name::#variant_name(Default::default()).token().0)
), ),
nom::combinator::value( nom::combinator::value(
lex::LESS, false,
nom::character::complete::char(#name::#const_name.1) nom::character::complete::char(#name::#variant_name(Default::default()).token().1)
) )
) )
), ),

View file

@ -2,9 +2,10 @@ use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser};
use fasteval::Instruction; use fasteval::Instruction;
mod lex; mod lex;
use lex::Token;
pub(super) enum Atom { pub(super) enum Atom {
Note(char), Note(u8),
Rest, Rest,
StartHere, StartHere,
Modifier(Modifier), Modifier(Modifier),
@ -15,30 +16,6 @@ pub(super) enum Atom {
Comment, 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)] #[derive(ModifierParser)]
pub(super) enum Modifier { pub(super) enum Modifier {
Volume(u8), Volume(u8),
@ -47,12 +24,6 @@ pub(super) enum Modifier {
Tempo(u16), Tempo(u16),
} }
impl Default for Modifier {
fn default() -> Self {
Modifier::Volume(Default::default())
}
}
#[derive(QuickModifierParser)] #[derive(QuickModifierParser)]
pub(super) enum QuickModifier { pub(super) enum QuickModifier {
Volume(bool), Volume(bool),

View file

@ -1,11 +1,11 @@
use super::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; use super::{Atom, Modifier, QuickModifier, SlopeModifier};
pub(super) mod lexer; pub(super) mod lexer;
pub(super) const MORE: bool = true; const MORE: bool = true;
pub(super) const LESS: bool = false; const LESS: bool = false;
pub(super) const ON: bool = true; const ON: bool = true;
pub(super) const OFF: bool = false; const OFF: bool = false;
struct WrappingTokens; struct WrappingTokens;
impl WrappingTokens { impl WrappingTokens {
@ -19,34 +19,51 @@ impl WrappingTokens {
const QUOTE_DEG: (char, char) = ('\'', '°'); const QUOTE_DEG: (char, char) = ('\'', '°');
} }
impl QuickModifier { pub(super) trait Token<T> {
pub(super) const VOLUME: (char, char) = WrappingTokens::PLUS_MINUS; fn token(self) -> T;
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 Modifier { impl Token<(char, char)> for QuickModifier {
pub(super) const VOLUME: char = 'v'; fn token(self) -> (char, char) {
pub(super) const OCTAVE: char = 'o'; match self {
pub(super) const LENGTH: char = 'l'; Self::Volume(_) => WrappingTokens::PLUS_MINUS,
pub(super) const TEMPO: char = 't'; Self::Octave(_) => WrappingTokens::RIGHT_LEFT,
Self::Length(_) => WrappingTokens::SLASH_BACKSLASH,
Self::Pizz(_) => WrappingTokens::QUOTE_DEG,
}
}
} }
impl SlopeModifier { impl Token<char> for Modifier {
pub(super) const NOTE: char = 'n'; fn token(self) -> char {
pub(super) const VOLUME: char = 'v'; match self {
pub(super) const OCTAVE: char = 'o'; Self::Volume(_) => 'v',
pub(super) const LENGTH: char = 'l'; Self::Octave(_) => 'o',
pub(super) const TEMPO: char = 't'; Self::Length(_) => 'l',
Self::Tempo(_) => 't',
}
}
} }
impl Atom { impl Token<char> for SlopeModifier {
pub(super) const REST: char = '.'; fn token(self) -> char {
pub(super) const START_HERE: char = ':'; match self {
pub(super) const MODIFIER: char = '!'; Self::Note => 'n',
pub(super) const LOOP: (char, char) = WrappingTokens::PARENTHESES; Self::Volume => 'v',
pub(super) const TUPLE: (char, char) = WrappingTokens::SQUARE_BRACKETS; Self::Octave => 'o',
pub(super) const SLOPE: (char, char) = WrappingTokens::BRACKETS; Self::Length => 'l',
pub(super) const COMMENT: (char, char) = WrappingTokens::SEMICOLON_COMMA; Self::Tempo => 't',
}
}
}
impl Token<char> for Atom {
fn token(self) -> char {
match self {
Atom::Rest => '.',
Atom::StartHere => ':',
Atom::Modifier(_) => '!',
_ => unimplemented!("not a singleton"),
}
}
} }

View file

@ -1,57 +1,11 @@
use std::collections::BTreeMap;
use clap::builder::TypedValueParser;
use fasteval::{Compiler, Instruction};
use nom::{ use nom::{
branch::alt, branch::alt, character::complete::char, combinator::value, sequence::delimited, IResult, Parser,
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,
}; };
use crate::bng::score::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; use crate::bng::score::QuickModifier;
use super::Token;
pub(crate) trait Parse: Sized { pub(crate) trait Parse: Sized {
fn parse(input: &str) -> IResult<&str, Self>; 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::<Instruction, nom::error::Error<&str>>::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)),
),
))
}