inflate FlatAtoms to Atoms (garbage code) with tests (two fails)
This commit is contained in:
parent
892914256d
commit
aa512e6206
4 changed files with 288 additions and 3 deletions
|
@ -1,13 +1,16 @@
|
|||
use std::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use anyhow::Context;
|
||||
use bng_macros::{QuickModifierParser, SlopeModifierParser};
|
||||
use fasteval::Instruction;
|
||||
use strum::EnumDiscriminants;
|
||||
|
||||
mod lex;
|
||||
mod utils;
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
pub(super) enum Atom {
|
||||
Note(char),
|
||||
Note(u8),
|
||||
Rest,
|
||||
StartHere,
|
||||
Modifier(Modifier),
|
||||
|
@ -49,6 +52,7 @@ impl Clone for FlatAtom {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
pub(super) enum Modifier {
|
||||
Volume(u8),
|
||||
|
@ -63,7 +67,7 @@ impl Default for Modifier {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(QuickModifierParser)]
|
||||
#[derive(QuickModifierParser, Clone)]
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
pub(super) enum QuickModifier {
|
||||
Volume(bool),
|
||||
|
|
|
@ -9,7 +9,7 @@ use nom::{
|
|||
branch::alt,
|
||||
bytes::complete::{take_till, take_till1},
|
||||
character::complete::{anychar, char, one_of, u16, u8},
|
||||
combinator::{map_opt, map_res, opt, value},
|
||||
combinator::{map_opt, map_res, opt, value, verify},
|
||||
multi::many0,
|
||||
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
||||
Err, IResult, Parser,
|
||||
|
|
195
src/bng/score/utils.rs
Normal file
195
src/bng/score/utils.rs
Normal file
|
@ -0,0 +1,195 @@
|
|||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// TODO: replace panics with custom error type
|
||||
fn inflate(mut flat_atoms: Vec<FlatAtom>) -> Vec<Atom> {
|
||||
#[derive(EnumDiscriminants)]
|
||||
enum CurrentStack {
|
||||
Loop(NonZeroU8),
|
||||
Tuple,
|
||||
Slope(SlopeModifier, Instruction),
|
||||
}
|
||||
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<CurrentStack> = Vec::new();
|
||||
for mut atom in flat_atoms.into_iter() {
|
||||
if let Some(stack) = stack_history.last() {
|
||||
match CurrentStackDiscriminants::from(stack) {
|
||||
CurrentStackDiscriminants::Loop => match atom {
|
||||
FlatAtom::Note(n) => loop_stack.last_mut().unwrap().push(Atom::Note(n)),
|
||||
FlatAtom::Rest => loop_stack.last_mut().unwrap().push(Atom::Rest),
|
||||
FlatAtom::StartHere => loop_stack.last_mut().unwrap().push(Atom::StartHere),
|
||||
FlatAtom::Modifier(m) => loop_stack.last_mut().unwrap().push(Atom::Modifier(m)),
|
||||
FlatAtom::QuickModifier(q) => {
|
||||
loop_stack.last_mut().unwrap().push(Atom::QuickModifier(q))
|
||||
}
|
||||
FlatAtom::LoopStarts(n) => {
|
||||
loop_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Loop(n));
|
||||
}
|
||||
FlatAtom::LoopEnds => {
|
||||
let popped = loop_stack.pop().unwrap();
|
||||
if stack_history.len() > 1 {
|
||||
match CurrentStackDiscriminants::from(
|
||||
stack_history.get(stack_history.len() - 2).unwrap(),
|
||||
) {
|
||||
CurrentStackDiscriminants::Loop => &mut loop_stack,
|
||||
CurrentStackDiscriminants::Tuple => &mut tuple_stack,
|
||||
CurrentStackDiscriminants::Slope => &mut slope_stack,
|
||||
}
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.push(Atom::Loop(
|
||||
match stack_history.pop().unwrap() {
|
||||
CurrentStack::Loop(n) => n,
|
||||
_ => unreachable!("this one is proven to be a loop"),
|
||||
},
|
||||
popped,
|
||||
))
|
||||
} else {
|
||||
result.push(Atom::Loop(
|
||||
match stack_history.pop().unwrap() {
|
||||
CurrentStack::Loop(n) => n,
|
||||
_ => unreachable!("this one is proven to be a loop"),
|
||||
},
|
||||
popped,
|
||||
))
|
||||
}
|
||||
}
|
||||
FlatAtom::TupleStarts => {
|
||||
tuple_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Tuple);
|
||||
}
|
||||
FlatAtom::TupleEnds => panic!("unmatched end tuple in a loop"),
|
||||
FlatAtom::SlopeStarts(s, i) => {
|
||||
slope_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Slope(s, i));
|
||||
}
|
||||
FlatAtom::SlopeEnds => panic!("unmatched end slope in a loop"),
|
||||
FlatAtom::Comment => loop_stack.last_mut().unwrap().push(Atom::Comment),
|
||||
},
|
||||
CurrentStackDiscriminants::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) => {
|
||||
tuple_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Loop(n));
|
||||
}
|
||||
FlatAtom::LoopEnds => panic!("unmatched end loop in a tuple"),
|
||||
FlatAtom::TupleStarts => {
|
||||
tuple_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Tuple);
|
||||
}
|
||||
FlatAtom::TupleEnds => {
|
||||
let popped = loop_stack.pop().unwrap();
|
||||
if stack_history.len() > 1 {
|
||||
match CurrentStackDiscriminants::from(
|
||||
stack_history.get(stack_history.len() - 2).unwrap(),
|
||||
) {
|
||||
CurrentStackDiscriminants::Loop => &mut loop_stack,
|
||||
CurrentStackDiscriminants::Tuple => &mut tuple_stack,
|
||||
CurrentStackDiscriminants::Slope => &mut slope_stack,
|
||||
}
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.push(Atom::Tuple(popped))
|
||||
} else {
|
||||
result.push(Atom::Tuple(popped))
|
||||
}
|
||||
}
|
||||
FlatAtom::SlopeStarts(s, i) => {
|
||||
slope_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Slope(s, i));
|
||||
}
|
||||
FlatAtom::SlopeEnds => panic!("unmatched end slope in a tuple"),
|
||||
FlatAtom::Comment => tuple_stack.last_mut().unwrap().push(Atom::Comment),
|
||||
},
|
||||
CurrentStackDiscriminants::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) => {
|
||||
slope_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Loop(n));
|
||||
}
|
||||
FlatAtom::LoopEnds => panic!("unmatched end loop"),
|
||||
FlatAtom::TupleStarts => {
|
||||
tuple_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Tuple);
|
||||
}
|
||||
FlatAtom::TupleEnds => panic!("unmatched end tuple"),
|
||||
FlatAtom::SlopeStarts(s, i) => {
|
||||
slope_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Slope(s, i));
|
||||
}
|
||||
FlatAtom::SlopeEnds => {
|
||||
let popped = loop_stack.pop().unwrap();
|
||||
if stack_history.len() > 1 {
|
||||
match CurrentStackDiscriminants::from(
|
||||
stack_history.get(stack_history.len() - 2).unwrap(),
|
||||
) {
|
||||
CurrentStackDiscriminants::Loop => &mut loop_stack,
|
||||
CurrentStackDiscriminants::Tuple => &mut tuple_stack,
|
||||
CurrentStackDiscriminants::Slope => &mut slope_stack,
|
||||
}
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.push(match stack_history.pop().unwrap() {
|
||||
CurrentStack::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() {
|
||||
CurrentStack::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),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
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(CurrentStack::Loop(n));
|
||||
}
|
||||
FlatAtom::LoopEnds => panic!("unmatched end loop"),
|
||||
FlatAtom::TupleStarts => {
|
||||
tuple_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Tuple);
|
||||
}
|
||||
FlatAtom::TupleEnds => panic!("unmatched end tuple"),
|
||||
FlatAtom::SlopeStarts(s, i) => {
|
||||
slope_stack.push(Vec::new());
|
||||
stack_history.push(CurrentStack::Slope(s, i));
|
||||
}
|
||||
FlatAtom::SlopeEnds => panic!("unmatched end slope"),
|
||||
FlatAtom::Comment => result.push(Atom::Comment),
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
86
src/bng/score/utils/tests.rs
Normal file
86
src/bng/score/utils/tests.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
#[cfg(test)]
|
||||
mod inflate {
|
||||
use fasteval::Compiler;
|
||||
use lex::UP;
|
||||
|
||||
use super::{super::*, inflate};
|
||||
|
||||
const FASTEVAL_INSTRUCTION: &str = "1-cos((PI*x)/2)";
|
||||
|
||||
#[test]
|
||||
fn inflate_flat() {
|
||||
assert_eq!(
|
||||
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!(
|
||||
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!(
|
||||
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() {
|
||||
let instruction = || {
|
||||
let parser = fasteval::Parser::new();
|
||||
let mut slab = fasteval::Slab::new();
|
||||
parser
|
||||
.parse(FASTEVAL_INSTRUCTION, &mut slab.ps)
|
||||
.unwrap()
|
||||
.from(&slab.ps)
|
||||
.compile(&slab.ps, &mut slab.cs)
|
||||
};
|
||||
assert_eq!(
|
||||
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
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue