no more FlatAtoms

This commit is contained in:
Breval Ferrari 2024-11-09 19:37:12 -05:00
parent 9c910b8076
commit 1c91b113fb
No known key found for this signature in database
GPG key ID: 6FED68D87C479A59
7 changed files with 105 additions and 603 deletions

View file

@ -23,17 +23,15 @@ use serde::{
}; };
use strum::EnumDiscriminants; use strum::EnumDiscriminants;
use thiserror::Error; use thiserror::Error;
use utils::{inflate, InflateError};
mod de; mod de;
mod lex; mod lex;
mod utils;
pub use de::*; pub use de::*;
use super::Expression as Instruction; use super::Expression as Instruction;
#[derive(Deref, From, Default)] #[derive(Deref, From, Default)]
#[cfg_attr(debug_assertions, derive(Serialize, Debug))] #[cfg_attr(debug_assertions, derive(Serialize, Debug, PartialEq))]
pub struct Atoms(Vec<Atom>); pub struct Atoms(Vec<Atom>);
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))] #[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
@ -43,12 +41,21 @@ pub enum Atom {
StartHere, StartHere,
Modifier(Modifier), Modifier(Modifier),
QuickModifier(QuickModifier), QuickModifier(QuickModifier),
Loop(NonZeroU8, Vec<Atom>), Loop(NonZeroU8, Atoms),
Tuple(Vec<Atom>), Tuple(Atoms),
Slope(SlopeModifier, Instruction, Vec<Atom>), Slope(SlopeModifier, Instruction, Atoms),
Comment, Comment,
} }
impl Clone for Atom {
fn clone(&self) -> Self {
match self {
Self::Rest => Self::Rest,
_ => unimplemented!("variant can't be cloned right now"),
}
}
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
impl Serialize for Atom { impl Serialize for Atom {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -59,37 +66,6 @@ impl Serialize for Atom {
} }
} }
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
pub(super) enum FlatAtom {
Note(u8),
Rest,
StartHere,
Modifier(Modifier),
QuickModifier(QuickModifier),
LoopStarts(NonZeroU8),
LoopEnds,
TupleStarts,
TupleEnds,
SlopeStarts(SlopeModifier, Instruction),
SlopeEnds,
Comment,
}
impl Clone for FlatAtom {
fn clone(&self) -> Self {
match self {
Self::Rest => Self::Rest,
Self::Comment => Self::Comment,
Self::LoopEnds => Self::LoopEnds,
Self::SlopeEnds => Self::SlopeEnds,
Self::StartHere => Self::StartHere,
Self::TupleEnds => Self::TupleEnds,
Self::TupleStarts => Self::TupleStarts,
_ => unimplemented!("variant can't be cloned"),
}
}
}
#[derive(Clone, ModifierParser)] #[derive(Clone, ModifierParser)]
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))] #[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
pub enum Modifier { pub enum Modifier {

View file

@ -22,18 +22,7 @@ use thiserror::Error;
use crate::bng::score::lex::lexer::root; use crate::bng::score::lex::lexer::root;
use super::{ use super::{Atom, Atoms};
utils::{inflate, InflateError},
Atoms, FlatAtom,
};
#[derive(Debug, Error)]
enum AtomsSerializeError {
#[error("sheet parsing error:\n{0}")]
Parsing(String),
#[error("sheet semantics: {0}")]
Inflation(#[from] InflateError),
}
impl<'de> Deserialize<'de> for Atoms { impl<'de> Deserialize<'de> for Atoms {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -55,16 +44,10 @@ impl<'de> Deserialize<'de> for Atoms {
if sheet.is_empty() { if sheet.is_empty() {
Ok(Default::default()) Ok(Default::default())
} else { } else {
root(&sheet, &notes) all_consuming(root(&notes))(&sheet)
.map_err(|e| pretty_verbose_err.curry().call1(sheet.as_str()).call1(e)) .map_err(|e| pretty_verbose_err.curry().call1(sheet.as_str()).call1(e))
.map_err(AtomsSerializeError::Parsing)
.map_err(de::Error::custom) .map_err(de::Error::custom)
.and_then(|(_, v)| { .map(|(i, r)| r)
inflate(v)
.map_err(AtomsSerializeError::from)
.map_err(de::Error::custom)
})
.map(Atoms)
} }
} }
} }

View file

@ -1,4 +1,4 @@
use super::{Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}; use super::{Atom, Modifier, QuickModifier, SlopeModifier};
pub(super) mod lexer; pub(super) mod lexer;

View file

@ -16,12 +16,14 @@ use nom::{
Err, IResult, Parser, Err, IResult, Parser,
}; };
use crate::bng::score::Atoms;
use super::{ use super::{
super::super::Expression as Instruction, Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier, super::super::Expression as Instruction, Atom, Modifier, QuickModifier, SlopeModifier,
}; };
#[cfg(test)] // #[cfg(test)]
mod tests; // mod tests;
fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec<char>, E> fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec<char>, E>
where where
@ -30,76 +32,81 @@ where
context("yml white space", many0(one_of(" \t\r\n"))) context("yml white space", many0(one_of(" \t\r\n")))
} }
pub fn root<'a, E>(i: &'a str, notes: &'a str) -> IResult<&'a str, Vec<FlatAtom>, E> pub fn root<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atoms, E>
where where
E: ParseError<&'a str> E: ParseError<&'a str>
+ ContextError<&'a str> + ContextError<&'a str>
+ FromExternalError<&'a str, TryFromIntError> + FromExternalError<&'a str, TryFromIntError>
+ FromExternalError<&'a str, E>, + FromExternalError<&'a str, E>,
{ {
all_consuming(terminated( terminated(
many1(preceded(maybe_yml_str_space(), atom(notes))), many1(preceded(maybe_yml_str_space(), atom(notes))),
maybe_yml_str_space(), maybe_yml_str_space(),
))(i) )
.map(Atoms)
} }
fn note<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> fn note<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str> + FromExternalError<&'a str, TryFromIntError>, E: ParseError<&'a str> + ContextError<&'a str> + FromExternalError<&'a str, TryFromIntError>,
{ {
context( context(
"note", "note",
map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).map(FlatAtom::Note), map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from),
) )
.map(Atom::Note)
} }
fn rest<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn rest<'a, E>(i: &'a str) -> IResult<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str> + ContextError<&'a str>,
{ {
context("rest", value(FlatAtom::Rest, char(Atom::REST)))(i) value(Atom::Rest, context("rest", char(Atom::REST))).parse(i)
} }
fn start_here<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn start_here<'a, E>(i: &'a str) -> IResult<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str> + ContextError<&'a str>,
{ {
context( value(
"start_here", Atom::StartHere,
value(FlatAtom::StartHere, char(Atom::START_HERE)), context("start_here", char(Atom::START_HERE)),
)(i) )
.parse(i)
} }
fn modifier<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn modifier<'a, E>(i: &'a str) -> IResult<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str> + ContextError<&'a str>,
{ {
use super::super::modifier; use super::super::modifier;
context( context("modifier", preceded(char(Atom::MODIFIER), modifier))
"modifier", .map(Atom::Modifier)
preceded(char(Atom::MODIFIER), modifier).map(FlatAtom::Modifier), .parse(i)
)(i)
} }
fn quick_modifier<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn quick_modifier<'a, E>(i: &'a str) -> IResult<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str> + ContextError<&'a str>,
{ {
use super::super::quick_modifier; use super::super::quick_modifier;
context( context("quick_modifier", quick_modifier)
"quick_modifier", .map(Atom::QuickModifier)
quick_modifier.map(FlatAtom::QuickModifier), .parse(i)
)(i)
} }
fn loop_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn r#loop<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str>
+ ContextError<&'a str>
+ FromExternalError<&'a str, TryFromIntError>
+ FromExternalError<&'a str, E>,
{ {
context( context(
"loop_starts", "loop",
preceded( delimited(
char(Atom::LOOP.0), char(Atom::LOOP.0),
pair(
map_opt(opt(u8), |n| { map_opt(opt(u8), |n| {
if let Some(n) = n { if let Some(n) = n {
NonZeroU8::new(n) NonZeroU8::new(n)
@ -107,46 +114,39 @@ where
unsafe { Some(NonZeroU8::new_unchecked(2)) } unsafe { Some(NonZeroU8::new_unchecked(2)) }
} }
}), }),
root(notes),
),
char(Atom::LOOP.1),
),
) )
.map(FlatAtom::LoopStarts), .map(|(n, v)| Atom::Loop(n, v))
)(i)
} }
fn loop_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn tuple<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str>
{ + ContextError<&'a str>
context("loop_ends", value(FlatAtom::LoopEnds, char(Atom::LOOP.1)))(i) + FromExternalError<&'a str, TryFromIntError>
} + FromExternalError<&'a str, E>,
fn tuple_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E>
where
E: ParseError<&'a str> + ContextError<&'a str>,
{ {
context( context(
"tuple_starts", "tuple",
value(FlatAtom::TupleStarts, char(Atom::TUPLE.0)), delimited(char(Atom::TUPLE.0), root(notes), char(Atom::TUPLE.1)),
)(i) )
.map(Atom::Tuple)
} }
fn tuple_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn slope<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str>
{ + ContextError<&'a str>
context( + FromExternalError<&'a str, TryFromIntError>
"tuple_ends", + FromExternalError<&'a str, E>,
value(FlatAtom::TupleEnds, char(Atom::TUPLE.1)),
)(i)
}
fn slope_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E>
where
E: ParseError<&'a str> + ContextError<&'a str> + FromExternalError<&'a str, E>,
{ {
use super::super::slope_modifier; use super::super::slope_modifier;
context( context(
"slope_starts", "slope_starts",
terminated( separated_pair(
preceded( preceded(
char(Atom::SLOPE.0), char(Atom::SLOPE.0),
separated_pair( separated_pair(
@ -159,29 +159,20 @@ where
), ),
), ),
char(','), char(','),
root(notes),
),
) )
.map(|(sm, i)| FlatAtom::SlopeStarts(sm, i)), .map(|((sm, i), v)| Atom::Slope(sm, i, v))
)(i)
} }
fn slope_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> fn comment<'a, E>(i: &'a str) -> IResult<&'a str, Atom, E>
where
E: ParseError<&'a str> + ContextError<&'a str>,
{
context(
"slope_ends",
value(FlatAtom::SlopeEnds, char(Atom::SLOPE.1)),
)(i)
}
fn comment<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E>
where where
E: ParseError<&'a str> + ContextError<&'a str>, E: ParseError<&'a str> + ContextError<&'a str>,
{ {
context( context(
"comment", "comment",
value( value(
FlatAtom::Comment, Atom::Comment,
delimited( delimited(
char(Atom::COMMENT.0), char(Atom::COMMENT.0),
take_till(|c| c == Atom::COMMENT.1), take_till(|c| c == Atom::COMMENT.1),
@ -191,7 +182,7 @@ where
)(i) )(i)
} }
fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, Atom, E>
where where
E: ParseError<&'a str> E: ParseError<&'a str>
+ ContextError<&'a str> + ContextError<&'a str>
@ -206,12 +197,9 @@ where
start_here, start_here,
modifier, modifier,
quick_modifier, quick_modifier,
loop_starts, r#loop(&notes),
loop_ends, tuple(&notes),
tuple_starts, slope(&notes),
tuple_ends,
slope_starts,
slope_ends,
comment, comment,
)), )),
) )

View file

@ -15,7 +15,7 @@ mod flat_atom {
use nom::Parser; use nom::Parser;
use super::super::{ use super::super::{
super::super::super::Expression as Instruction, super::UP, atom, Atom, FlatAtom, Modifier, super::super::super::Expression as Instruction, super::UP, atom, Atom, Modifier,
QuickModifier, SlopeModifier, QuickModifier, SlopeModifier,
}; };
use super::*; use super::*;
@ -34,7 +34,7 @@ mod flat_atom {
#[test] #[test]
fn note() { fn note() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Note(2))), Ok((SAMPLE_STR, Atom::Note(2))),
atom::<Error<&str>>("abcdefg").parse(concatcp!('c', SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!('c', SAMPLE_STR))
) )
} }
@ -42,7 +42,7 @@ mod flat_atom {
#[test] #[test]
fn rest() { fn rest() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Rest)), Ok((SAMPLE_STR, Atom::Rest)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR))
) )
} }
@ -50,7 +50,7 @@ mod flat_atom {
#[test] #[test]
fn start_here() { fn start_here() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::StartHere)), Ok((SAMPLE_STR, Atom::StartHere)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR))
) )
} }
@ -60,7 +60,7 @@ mod flat_atom {
assert_eq!( assert_eq!(
Ok(( Ok((
SAMPLE_STR, SAMPLE_STR,
FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) })) Atom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) }))
)), )),
atom::<Error<&str>>("abcdefg").parse(concatcp!( atom::<Error<&str>>("abcdefg").parse(concatcp!(
Atom::MODIFIER, Atom::MODIFIER,
@ -74,10 +74,7 @@ mod flat_atom {
#[test] #[test]
fn quick_modifier() { fn quick_modifier() {
assert_eq!( assert_eq!(
Ok(( Ok((SAMPLE_STR, Atom::QuickModifier(QuickModifier::Length(UP)))),
SAMPLE_STR,
FlatAtom::QuickModifier(QuickModifier::Length(UP))
)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
) )
} }
@ -87,14 +84,14 @@ mod flat_atom {
assert_eq!( assert_eq!(
Ok(( Ok((
SAMPLE_STR, SAMPLE_STR,
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) }) Atom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) })
)), )),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR))
); );
assert_eq!( assert_eq!(
Ok(( Ok((
SAMPLE_STR, SAMPLE_STR,
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) }) Atom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) })
)), )),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR))
); );
@ -110,7 +107,7 @@ mod flat_atom {
#[test] #[test]
fn loop_ends() { fn loop_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::LoopEnds)), Ok((SAMPLE_STR, Atom::LoopEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR))
) )
} }
@ -118,7 +115,7 @@ mod flat_atom {
#[test] #[test]
fn tuple_starts() { fn tuple_starts() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleStarts)), Ok((SAMPLE_STR, Atom::TupleStarts)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR))
) )
} }
@ -126,7 +123,7 @@ mod flat_atom {
#[test] #[test]
fn tuple_ends() { fn tuple_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleEnds)), Ok((SAMPLE_STR, Atom::TupleEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR))
) )
} }
@ -136,7 +133,7 @@ mod flat_atom {
assert_eq!( assert_eq!(
Ok(( Ok((
SAMPLE_STR, SAMPLE_STR,
FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap()) Atom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap())
)), )),
atom::<Error<&str>>("abcdefg").parse(concatcp!( atom::<Error<&str>>("abcdefg").parse(concatcp!(
Atom::SLOPE.0, Atom::SLOPE.0,
@ -152,7 +149,7 @@ mod flat_atom {
#[test] #[test]
fn slope_ends() { fn slope_ends() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::SlopeEnds)), Ok((SAMPLE_STR, Atom::SlopeEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR)) atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR))
) )
} }
@ -160,7 +157,7 @@ mod flat_atom {
#[test] #[test]
fn comment() { fn comment() {
assert_eq!( assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Comment)), Ok((SAMPLE_STR, Atom::Comment)),
atom::<Error<&str>>("abcdefg").parse(concatcp!( atom::<Error<&str>>("abcdefg").parse(concatcp!(
Atom::COMMENT.0, Atom::COMMENT.0,
"hi I'm a little pony", "hi I'm a little pony",

View file

@ -1,236 +0,0 @@
use super::*;
use strum::Display;
use thiserror::Error;
#[cfg(test)]
mod tests;
#[derive(Debug, EnumDiscriminants)]
#[strum_discriminants(derive(Display))]
pub enum Wrapper {
Loop(NonZeroU8),
Tuple,
Slope(SlopeModifier, Instruction),
}
#[derive(Debug, Error)]
#[cfg_attr(test, derive(PartialEq))]
pub enum InflateError {
#[error("misplaced {0} end symbol")]
MismatchedEnd(WrapperDiscriminants),
}
pub fn inflate(mut flat_atoms: Vec<FlatAtom>) -> Result<Vec<Atom>, InflateError> {
type Error = InflateError;
let mut result = Vec::with_capacity(flat_atoms.len());
let mut loop_stack: Vec<Vec<Atom>> = Vec::new();
let mut tuple_stack: Vec<Vec<Atom>> = Vec::new();
let mut slope_stack: Vec<Vec<Atom>> = Vec::new();
let mut stack_history: Vec<Wrapper> = Vec::new();
for mut atom in flat_atoms.into_iter() {
#[cfg(test)]
{
dbg!(&atom);
dbg!(&loop_stack);
dbg!(&tuple_stack);
dbg!(&slope_stack);
dbg!(&stack_history);
}
match stack_history.last().map(WrapperDiscriminants::from) {
Some(WrapperDiscriminants::Loop) => match atom {
FlatAtom::Note(n) => {
unsafe { loop_stack.last_mut().unwrap_unchecked() }.push(Atom::Note(n))
}
FlatAtom::Rest => {
unsafe { loop_stack.last_mut().unwrap_unchecked() }.push(Atom::Rest)
}
FlatAtom::StartHere => {
unsafe { loop_stack.last_mut().unwrap_unchecked() }.push(Atom::StartHere)
}
FlatAtom::Modifier(m) => {
unsafe { loop_stack.last_mut().unwrap_unchecked() }.push(Atom::Modifier(m))
}
FlatAtom::QuickModifier(q) => {
unsafe { loop_stack.last_mut().unwrap_unchecked() }.push(Atom::QuickModifier(q))
}
FlatAtom::LoopStarts(n) => {
loop_stack.push(Vec::new());
stack_history.push(Wrapper::Loop(n));
}
FlatAtom::LoopEnds => {
let popped = unsafe { loop_stack.pop().unwrap_unchecked() };
if stack_history.len() > 1 {
match WrapperDiscriminants::from(
stack_history.get(stack_history.len() - 2).unwrap(),
) {
WrapperDiscriminants::Loop => &mut loop_stack,
WrapperDiscriminants::Tuple => &mut tuple_stack,
WrapperDiscriminants::Slope => &mut slope_stack,
}
.last_mut()
.unwrap()
.push(Atom::Loop(
match stack_history.pop().unwrap() {
Wrapper::Loop(n) => n,
_ => unreachable!("this one is proven to be a loop"),
},
popped,
))
} else {
result.push(Atom::Loop(
match stack_history.pop().unwrap() {
Wrapper::Loop(n) => n,
_ => unreachable!("this one is proven to be a loop"),
},
popped,
))
}
}
FlatAtom::TupleStarts => {
tuple_stack.push(Vec::new());
stack_history.push(Wrapper::Tuple);
}
FlatAtom::TupleEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Tuple));
}
FlatAtom::SlopeStarts(s, i) => {
slope_stack.push(Vec::new());
stack_history.push(Wrapper::Slope(s, i));
}
FlatAtom::SlopeEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Slope));
}
FlatAtom::Comment => loop_stack.last_mut().unwrap().push(Atom::Comment),
},
Some(WrapperDiscriminants::Tuple) => match atom {
FlatAtom::Note(n) => tuple_stack.last_mut().unwrap().push(Atom::Note(n)),
FlatAtom::Rest => tuple_stack.last_mut().unwrap().push(Atom::Rest),
FlatAtom::StartHere => tuple_stack.last_mut().unwrap().push(Atom::StartHere),
FlatAtom::Modifier(m) => tuple_stack.last_mut().unwrap().push(Atom::Modifier(m)),
FlatAtom::QuickModifier(q) => {
tuple_stack.last_mut().unwrap().push(Atom::QuickModifier(q))
}
FlatAtom::LoopStarts(n) => {
loop_stack.push(Vec::new());
stack_history.push(Wrapper::Loop(n));
}
FlatAtom::LoopEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Loop));
}
FlatAtom::TupleStarts => {
tuple_stack.push(Vec::new());
stack_history.push(Wrapper::Tuple);
}
FlatAtom::TupleEnds => {
let popped = tuple_stack.pop().unwrap();
if stack_history.len() > 1 {
match WrapperDiscriminants::from(
stack_history.get(stack_history.len() - 2).unwrap(),
) {
WrapperDiscriminants::Loop => &mut loop_stack,
WrapperDiscriminants::Tuple => &mut tuple_stack,
WrapperDiscriminants::Slope => &mut slope_stack,
}
.last_mut()
.unwrap()
.push({
stack_history.pop();
Atom::Tuple(popped)
})
} else {
result.push(Atom::Tuple(popped))
}
}
FlatAtom::SlopeStarts(s, i) => {
slope_stack.push(Vec::new());
stack_history.push(Wrapper::Slope(s, i));
}
FlatAtom::SlopeEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Slope));
}
FlatAtom::Comment => tuple_stack.last_mut().unwrap().push(Atom::Comment),
},
Some(WrapperDiscriminants::Slope) => match atom {
FlatAtom::Note(n) => slope_stack.last_mut().unwrap().push(Atom::Note(n)),
FlatAtom::Rest => slope_stack.last_mut().unwrap().push(Atom::Rest),
FlatAtom::StartHere => slope_stack.last_mut().unwrap().push(Atom::StartHere),
FlatAtom::Modifier(m) => slope_stack.last_mut().unwrap().push(Atom::Modifier(m)),
FlatAtom::QuickModifier(q) => {
slope_stack.last_mut().unwrap().push(Atom::QuickModifier(q))
}
FlatAtom::LoopStarts(n) => {
loop_stack.push(Vec::new());
stack_history.push(Wrapper::Loop(n));
}
FlatAtom::LoopEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Loop));
}
FlatAtom::TupleStarts => {
tuple_stack.push(Vec::new());
stack_history.push(Wrapper::Tuple);
}
FlatAtom::TupleEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Tuple));
}
FlatAtom::SlopeStarts(s, i) => {
slope_stack.push(Vec::new());
stack_history.push(Wrapper::Slope(s, i));
}
FlatAtom::SlopeEnds => {
let popped = slope_stack.pop().unwrap();
if stack_history.len() > 1 {
match WrapperDiscriminants::from(
stack_history.get(stack_history.len() - 2).unwrap(),
) {
WrapperDiscriminants::Loop => &mut loop_stack,
WrapperDiscriminants::Tuple => &mut tuple_stack,
WrapperDiscriminants::Slope => &mut slope_stack,
}
.last_mut()
.unwrap()
.push(match stack_history.pop().unwrap() {
Wrapper::Slope(m, i) => Atom::Slope(m, i, popped),
_ => unreachable!("this one is proven to be a slope"),
})
} else {
result.push(match stack_history.pop().unwrap() {
Wrapper::Slope(m, i) => Atom::Slope(m, i, popped),
_ => unreachable!("this one is proven to be a slope"),
})
}
}
FlatAtom::Comment => slope_stack.last_mut().unwrap().push(Atom::Comment),
},
None => match atom {
FlatAtom::Note(n) => result.push(Atom::Note(n)),
FlatAtom::Rest => result.push(Atom::Rest),
FlatAtom::StartHere => result.push(Atom::StartHere),
FlatAtom::Modifier(m) => result.push(Atom::Modifier(m)),
FlatAtom::QuickModifier(q) => result.push(Atom::QuickModifier(q)),
FlatAtom::LoopStarts(n) => {
loop_stack.push(Vec::new());
stack_history.push(Wrapper::Loop(n));
}
FlatAtom::LoopEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Loop));
}
FlatAtom::TupleStarts => {
tuple_stack.push(Vec::new());
stack_history.push(Wrapper::Tuple);
}
FlatAtom::TupleEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Tuple));
}
FlatAtom::SlopeStarts(s, i) => {
slope_stack.push(Vec::new());
stack_history.push(Wrapper::Slope(s, i));
}
FlatAtom::SlopeEnds => {
return Err(Error::MismatchedEnd(WrapperDiscriminants::Slope));
}
FlatAtom::Comment => result.push(Atom::Comment),
},
}
}
Ok(result)
}

View file

@ -1,206 +0,0 @@
#[cfg(test)]
mod inflate {
use fasteval::Compiler;
use lex::{ON, UP};
use super::{super::*, inflate};
const FASTEVAL_INSTRUCTION: &str = "1-cos((PI*x)/2)";
fn instruction() -> Instruction {
FASTEVAL_INSTRUCTION.parse().unwrap()
}
#[test]
fn inflate_flat() {
assert_eq!(
Ok(vec![
Atom::Note(2),
Atom::Rest,
Atom::StartHere,
Atom::Modifier(Modifier::Volume(2)),
Atom::QuickModifier(QuickModifier::Volume(UP)),
Atom::Comment
]),
inflate(vec![
FlatAtom::Note(2),
FlatAtom::Rest,
FlatAtom::StartHere,
FlatAtom::Modifier(Modifier::Volume(2)),
FlatAtom::QuickModifier(QuickModifier::Volume(UP)),
FlatAtom::Comment
])
)
}
#[test]
fn inflate_loop_l1() {
assert_eq!(
Ok(vec![Atom::Loop(
unsafe { NonZeroU8::new_unchecked(3) },
vec![Atom::Note(2), Atom::Note(3)]
)]),
inflate(vec![
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) }),
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::LoopEnds
])
)
}
#[test]
fn inflate_tuple_l1() {
assert_eq!(
Ok(vec![Atom::Tuple(vec![Atom::Note(2), Atom::Note(3)])]),
inflate(vec![
FlatAtom::TupleStarts,
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::TupleEnds
])
)
}
#[test]
fn inflate_slope_l1() {
assert_eq!(
Ok(vec![Atom::Slope(
SlopeModifier::Note,
instruction(),
vec![Atom::Note(2), Atom::Note(3)]
)]),
inflate(vec![
FlatAtom::SlopeStarts(SlopeModifier::Note, instruction()),
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::SlopeEnds
])
)
}
#[test]
fn inflate_loop_l2() {
assert_eq!(
Ok(vec![Atom::Loop(
unsafe { NonZeroU8::new_unchecked(2) },
vec![Atom::Loop(
unsafe { NonZeroU8::new_unchecked(3) },
vec![Atom::Note(2), Atom::Note(3)]
)]
)]),
inflate(vec![
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) }),
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) }),
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::LoopEnds,
FlatAtom::LoopEnds
])
)
}
#[test]
fn inflate_tuple_l2() {
assert_eq!(
Ok(vec![Atom::Tuple(vec![Atom::Tuple(vec![
Atom::Note(2),
Atom::Note(3)
])])]),
inflate(vec![
FlatAtom::TupleStarts,
FlatAtom::TupleStarts,
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::TupleEnds,
FlatAtom::TupleEnds
])
)
}
#[test]
fn inflate_slope_l2() {
assert_eq!(
Ok(vec![Atom::Slope(
SlopeModifier::Note,
instruction(),
vec![Atom::Slope(
SlopeModifier::Length,
instruction(),
vec![Atom::Note(2), Atom::Note(3)]
)]
)]),
inflate(vec![
FlatAtom::SlopeStarts(SlopeModifier::Note, instruction()),
FlatAtom::SlopeStarts(SlopeModifier::Length, instruction()),
FlatAtom::Note(2),
FlatAtom::Note(3),
FlatAtom::SlopeEnds,
FlatAtom::SlopeEnds
])
)
}
#[test]
fn mixed() {
assert_eq!(
Ok(vec![Atom::Slope(
SlopeModifier::Note,
instruction(),
vec![Atom::Slope(
SlopeModifier::Length,
instruction(),
vec![
Atom::Note(2),
Atom::Tuple(vec![Atom::Rest, Atom::Note(6)]),
Atom::Note(3),
Atom::Loop(
unsafe { NonZeroU8::new_unchecked(9) },
vec![Atom::QuickModifier(QuickModifier::Pizz(ON)), Atom::Note(0)]
)
]
)]
)]),
inflate(vec![
FlatAtom::SlopeStarts(SlopeModifier::Note, instruction()),
FlatAtom::SlopeStarts(SlopeModifier::Length, instruction()),
FlatAtom::Note(2),
FlatAtom::TupleStarts,
FlatAtom::Rest,
FlatAtom::Note(6),
FlatAtom::TupleEnds,
FlatAtom::Note(3),
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(9) }),
FlatAtom::QuickModifier(QuickModifier::Pizz(ON)),
FlatAtom::Note(0),
FlatAtom::LoopEnds,
FlatAtom::SlopeEnds,
FlatAtom::SlopeEnds
])
)
}
#[test]
fn mixed_mismatched_end() {
assert_eq!(
Err(InflateError::MismatchedEnd(WrapperDiscriminants::Slope)),
inflate(vec![
FlatAtom::SlopeStarts(SlopeModifier::Note, instruction()),
FlatAtom::SlopeStarts(SlopeModifier::Length, instruction()),
FlatAtom::Note(2),
FlatAtom::TupleStarts,
FlatAtom::Rest,
FlatAtom::SlopeEnds, // mismatched slope end while in a tuple
FlatAtom::Note(6),
FlatAtom::TupleEnds,
FlatAtom::Note(3),
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(9) }),
FlatAtom::QuickModifier(QuickModifier::Pizz(ON)),
FlatAtom::Note(0),
FlatAtom::LoopEnds,
FlatAtom::SlopeEnds,
FlatAtom::SlopeEnds,
])
)
}
}