test setup, silence & expression tests

This commit is contained in:
Breval Ferrari 2025-05-21 12:00:35 +02:00
parent 16f79c302a
commit fa49625f7f
2 changed files with 64 additions and 26 deletions

View file

@ -1,37 +1,61 @@
use std::{collections::HashMap, str::FromStr}; use std::{collections::HashMap, fmt::Debug, str::FromStr};
use derive_new::new; use derive_new::new;
use derive_wrapper::{AsRef, From};
use fasteval::{Compiler, Instruction, Slab}; use fasteval::{Compiler, Instruction, Slab};
pub type TokenVec<'a> = Vec<Box<dyn Token + 'a>>; #[derive(From, AsRef)]
#[cfg_attr(test, derive(Debug))]
pub struct TokenVec<'a>(Vec<Box<dyn Token + 'a>>);
#[cfg(not(test))]
pub trait Token { pub trait Token {
fn apply(&self, context: Context) -> Context { fn apply(&self, context: Context) -> Context {
todo!() todo!()
} }
} }
#[cfg(test)]
pub trait Token: Debug {
fn apply(&self, context: Context) -> Context {
todo!()
}
}
#[cfg(test)]
impl PartialEq for TokenVec<'_> {
fn eq(&self, other: &Self) -> bool {
format!("{self:?}") == format!("{other:?}")
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Silence; pub struct Silence;
impl Token for Silence {} impl Token for Silence {}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Marker; pub struct Marker;
impl Token for Marker {} impl Token for Marker {}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Note(pub u8); pub struct Note(pub u8);
impl Token for Note {} impl Token for Note {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct VariableChange(pub char, pub Expression); pub struct VariableChange(pub char, pub Expression);
impl Token for VariableChange {} impl Token for VariableChange {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>); pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>);
#[cfg_attr(test, derive(Debug, PartialEq))]
pub enum LoopCount { pub enum LoopCount {
Litteral(usize), Litteral(usize),
Variable(char), Variable(char),
@ -45,16 +69,18 @@ impl Default for LoopCount {
impl Token for Loop<'_> {} impl Token for Loop<'_> {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Tuplet<'a>(pub TokenVec<'a>); pub struct Tuplet<'a>(pub TokenVec<'a>);
impl Token for Tuplet<'_> {} impl Token for Tuplet<'_> {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>); pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>);
impl Token for Slope<'_> {} impl Token for Slope<'_> {}
#[derive(new)] #[derive(new)]
#[cfg_attr(debug_assertions, derive(Debug))] #[cfg_attr(any(debug_assertions, test), derive(Debug))]
pub struct Expression { pub struct Expression {
pub(crate) instruction: Instruction, pub(crate) instruction: Instruction,
pub(crate) slab: Slab, pub(crate) slab: Slab,
@ -66,6 +92,13 @@ impl Clone for Expression {
} }
} }
#[cfg(test)]
impl PartialEq for Expression {
fn eq(&self, other: &Self) -> bool {
format!("{self:?}") == format!("{other:?}")
}
}
impl FromStr for Expression { impl FromStr for Expression {
type Err = fasteval::Error; type Err = fasteval::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -78,6 +111,7 @@ impl FromStr for Expression {
} }
} }
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Context { pub struct Context {
pub result: Vec<f64>, pub result: Vec<f64>,
pub variables: HashMap<char, f64>, pub variables: HashMap<char, f64>,

View file

@ -21,7 +21,8 @@ use nom::{
use nom_locate::LocatedSpan; use nom_locate::LocatedSpan;
use crate::compiler::{ use crate::compiler::{
Expression, Loop, LoopCount, Marker, Note, Silence, Slope, Token, Tuplet, VariableChange, Expression, Loop, LoopCount, Marker, Note, Silence, Slope, Token, TokenVec, Tuplet,
VariableChange,
}; };
#[derive(Builder)] #[derive(Builder)]
@ -33,9 +34,7 @@ pub struct Parser<'i, 'n, 's, 'v> {
} }
impl<'i, 's> Parser<'i, '_, 's, '_> { impl<'i, 's> Parser<'i, '_, 's, '_> {
pub fn parse_all( pub fn parse_all(&self) -> Result<TokenVec<'s>, Error<nom_locate::LocatedSpan<&'i str>>> {
&self,
) -> Result<Vec<Box<dyn Token + 's>>, Error<nom_locate::LocatedSpan<&'i str>>> {
token_parser(self) token_parser(self)
.parse_complete(LocatedSpan::new(self.input)) .parse_complete(LocatedSpan::new(self.input))
.finish() .finish()
@ -45,7 +44,7 @@ impl<'i, 's> Parser<'i, '_, 's, '_> {
fn token_parser<'a, 's, I>( fn token_parser<'a, 's, I>(
parser: &Parser<'_, '_, 's, '_>, parser: &Parser<'_, '_, 's, '_>,
) -> impl NomParser<I, Output = Vec<Box<dyn Token + 's>>, Error = nom::error::Error<I>> ) -> impl NomParser<I, Output = TokenVec<'s>, Error = nom::error::Error<I>>
where where
I: Input + AsRef<str> + for<'z> nom::Compare<&'z str>, I: Input + AsRef<str> + for<'z> nom::Compare<&'z str>,
<I as Input>::Item: AsChar, <I as Input>::Item: AsChar,
@ -70,6 +69,7 @@ where
)), )),
space_or_comment(), space_or_comment(),
)) ))
.map(Into::into)
} }
fn into_box<'a>(token: impl Token + 'a) -> Box<dyn Token + 'a> { fn into_box<'a>(token: impl Token + 'a) -> Box<dyn Token + 'a> {
@ -279,22 +279,26 @@ mod tests {
} }
} }
// #[test] #[test]
// fn silence() { fn silence() {
// let parser = |input: &'static str| Silence::parser().parse(input.into()); let parser = |input| Silence::parser().parse(input);
// let mut working_cases = vec![(".", ()), ".dd", ".."]; let mut working_cases = vec![
// let mut not_working_cases = vec![]; (".", ("", Silence)),
// for (test, expected) in working_cases.drain(..) { (".dd", ("dd", Silence)),
// let output = parser(test); ("..", (".", Silence)),
// if let Ok((result)) = output { ];
// assert_eq!(expected, result); let mut not_working_cases = vec!["", ",", "d.", " "];
// } else { for (test, expected) in working_cases.drain(..) {
// panic!("result was not Ok: {output:?}"); let output = parser(test);
// } if let Ok(result) = output {
// } assert_eq!(expected, result);
// for test in not_working_cases.drain(..) { } else {
// let output = parser(test); panic!("result was not Ok: {output:?}");
// assert!(output.is_err(), "result was not Err: {output:?}"); }
// } }
// } for test in not_working_cases.drain(..) {
let output = parser(test);
assert!(output.is_err(), "result was not Err: {output:?}");
}
}
} }