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_wrapper::{AsRef, From};
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 {
fn apply(&self, context: Context) -> Context {
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)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Silence;
impl Token for Silence {}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Marker;
impl Token for Marker {}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Note(pub u8);
impl Token for Note {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct VariableChange(pub char, pub Expression);
impl Token for VariableChange {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>);
#[cfg_attr(test, derive(Debug, PartialEq))]
pub enum LoopCount {
Litteral(usize),
Variable(char),
@ -45,16 +69,18 @@ impl Default for LoopCount {
impl Token for Loop<'_> {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Tuplet<'a>(pub TokenVec<'a>);
impl Token for Tuplet<'_> {}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>);
impl Token for Slope<'_> {}
#[derive(new)]
#[cfg_attr(debug_assertions, derive(Debug))]
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
pub struct Expression {
pub(crate) instruction: Instruction,
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 {
type Err = fasteval::Error;
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 result: Vec<f64>,
pub variables: HashMap<char, f64>,

View file

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