no more FlatAtoms

This commit is contained in:
Breval Ferrari 2024-11-09 19:37:12 -05:00
parent 9c910b8076
commit 1c91b113fb
Signed by: breval
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 thiserror::Error;
use utils::{inflate, InflateError};
mod de;
mod lex;
mod utils;
pub use de::*;
use super::Expression as Instruction;
#[derive(Deref, From, Default)]
#[cfg_attr(debug_assertions, derive(Serialize, Debug))]
#[cfg_attr(debug_assertions, derive(Serialize, Debug, PartialEq))]
pub struct Atoms(Vec<Atom>);
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
@ -43,12 +41,21 @@ pub enum Atom {
StartHere,
Modifier(Modifier),
QuickModifier(QuickModifier),
Loop(NonZeroU8, Vec<Atom>),
Tuple(Vec<Atom>),
Slope(SlopeModifier, Instruction, Vec<Atom>),
Loop(NonZeroU8, Atoms),
Tuple(Atoms),
Slope(SlopeModifier, Instruction, Atoms),
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)]
impl Serialize for Atom {
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)]
#[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
pub enum Modifier {

View file

@ -22,18 +22,7 @@ use thiserror::Error;
use crate::bng::score::lex::lexer::root;
use super::{
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),
}
use super::{Atom, Atoms};
impl<'de> Deserialize<'de> for Atoms {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -55,16 +44,10 @@ impl<'de> Deserialize<'de> for Atoms {
if sheet.is_empty() {
Ok(Default::default())
} else {
root(&sheet, &notes)
all_consuming(root(&notes))(&sheet)
.map_err(|e| pretty_verbose_err.curry().call1(sheet.as_str()).call1(e))
.map_err(AtomsSerializeError::Parsing)
.map_err(de::Error::custom)
.and_then(|(_, v)| {
inflate(v)
.map_err(AtomsSerializeError::from)
.map_err(de::Error::custom)
})
.map(Atoms)
.map(|(i, r)| r)
}
}
}

View file

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

View file

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

View file

@ -15,7 +15,7 @@ mod flat_atom {
use nom::Parser;
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,
};
use super::*;
@ -34,7 +34,7 @@ mod flat_atom {
#[test]
fn note() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Note(2))),
Ok((SAMPLE_STR, Atom::Note(2))),
atom::<Error<&str>>("abcdefg").parse(concatcp!('c', SAMPLE_STR))
)
}
@ -42,7 +42,7 @@ mod flat_atom {
#[test]
fn rest() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Rest)),
Ok((SAMPLE_STR, Atom::Rest)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR))
)
}
@ -50,7 +50,7 @@ mod flat_atom {
#[test]
fn start_here() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::StartHere)),
Ok((SAMPLE_STR, Atom::StartHere)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR))
)
}
@ -60,7 +60,7 @@ mod flat_atom {
assert_eq!(
Ok((
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::MODIFIER,
@ -74,10 +74,7 @@ mod flat_atom {
#[test]
fn quick_modifier() {
assert_eq!(
Ok((
SAMPLE_STR,
FlatAtom::QuickModifier(QuickModifier::Length(UP))
)),
Ok((SAMPLE_STR, Atom::QuickModifier(QuickModifier::Length(UP)))),
atom::<Error<&str>>("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
)
}
@ -87,14 +84,14 @@ mod flat_atom {
assert_eq!(
Ok((
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))
);
assert_eq!(
Ok((
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))
);
@ -110,7 +107,7 @@ mod flat_atom {
#[test]
fn loop_ends() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::LoopEnds)),
Ok((SAMPLE_STR, Atom::LoopEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR))
)
}
@ -118,7 +115,7 @@ mod flat_atom {
#[test]
fn tuple_starts() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleStarts)),
Ok((SAMPLE_STR, Atom::TupleStarts)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR))
)
}
@ -126,7 +123,7 @@ mod flat_atom {
#[test]
fn tuple_ends() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::TupleEnds)),
Ok((SAMPLE_STR, Atom::TupleEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR))
)
}
@ -136,7 +133,7 @@ mod flat_atom {
assert_eq!(
Ok((
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::SLOPE.0,
@ -152,7 +149,7 @@ mod flat_atom {
#[test]
fn slope_ends() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::SlopeEnds)),
Ok((SAMPLE_STR, Atom::SlopeEnds)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR))
)
}
@ -160,7 +157,7 @@ mod flat_atom {
#[test]
fn comment() {
assert_eq!(
Ok((SAMPLE_STR, FlatAtom::Comment)),
Ok((SAMPLE_STR, Atom::Comment)),
atom::<Error<&str>>("abcdefg").parse(concatcp!(
Atom::COMMENT.0,
"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,
])
)
}
}