first Token.apply() impls, context methods

This commit is contained in:
Breval Ferrari 2025-05-23 15:12:12 +02:00
parent 69c2869388
commit 7e831c40ac

View file

@ -1,8 +1,15 @@
use std::{collections::HashMap, fmt::Debug, str::FromStr};
use std::{
collections::{BTreeMap, HashMap},
fmt::Debug,
str::FromStr,
};
use derive_new::new;
use derive_wrapper::{AsRef, From};
use fasteval::{Compiler, Instruction, Slab};
use fasteval::{Compiler, Evaler, Instruction, Slab};
use thiserror::Error;
const SAMPLE_RATE: u16 = 48000;
#[derive(From, AsRef)]
#[cfg_attr(test, derive(Debug))]
@ -10,16 +17,12 @@ pub struct TokenVec<'a>(pub(crate) Vec<Box<dyn Token + 'a>>);
#[cfg(not(test))]
pub trait Token {
fn apply(&self, context: Context) -> Context {
todo!()
}
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
}
#[cfg(test)]
pub trait Token: Debug {
fn apply(&self, context: Context) -> Context {
todo!()
}
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
}
#[cfg(test)]
@ -33,24 +36,45 @@ impl PartialEq for TokenVec<'_> {
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Silence;
impl Token for Silence {}
impl Token for Silence {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
context.render(None)?;
Ok(context)
}
}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Marker;
impl Token for Marker {}
impl Token for Marker {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
context.result.clear();
Ok(context)
}
}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Note(pub u8);
impl Token for Note {}
impl Token for Note {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
let mut next = context.render(Some(self.0))?;
context.result.append(&mut next);
Ok(context)
}
}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct VariableChange(pub char, pub Expression);
impl Token for VariableChange {}
impl Token for VariableChange {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
*context.get_mut(self.0)? = context.eval(&self.1)?;
Ok(context)
}
}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>);
@ -67,17 +91,29 @@ impl Default for LoopCount {
}
}
impl Token for Loop<'_> {}
impl Token for Loop<'_> {
fn apply(&self, context: Context) -> Result<Context, CompilerError> {
todo!()
}
}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Tuplet<'a>(pub TokenVec<'a>);
impl Token for Tuplet<'_> {}
impl Token for Tuplet<'_> {
fn apply(&self, context: Context) -> Result<Context, CompilerError> {
todo!()
}
}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>);
impl Token for Slope<'_> {}
impl Token for Slope<'_> {
fn apply(&self, context: Context) -> Result<Context, CompilerError> {
todo!()
}
}
#[derive(new)]
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
@ -119,11 +155,112 @@ pub struct Context {
pub slopes: HashMap<char, Expression>,
}
#[derive(Debug, Error)]
#[error("variable not found: {0}")]
pub struct VariableNotFoundError(char);
#[derive(Debug, Error)]
#[error("expression not found: {0}")]
pub struct SlopeNotFoundError(char);
#[derive(Debug, Error)]
pub enum CompilerError {
#[error("expression evaluation: {0:?}")]
FastEval(#[from] fasteval::Error),
#[error("{0}")]
VariableNotFound(#[from] VariableNotFoundError),
#[error("{0}")]
SlopeNotFound(#[from] SlopeNotFoundError),
}
impl Context {
pub fn current_length(&self) -> f64 {
todo!()
pub fn current_length(&self) -> Result<f64, CompilerError> {
self.eval(self.get_slope('l').map_err(CompilerError::from)?)
.map_err(Into::into)
}
pub fn get(&self, name: char) -> Result<&f64, VariableNotFoundError> {
self.variables.get(&name).ok_or(VariableNotFoundError(name))
}
pub fn get_mut(&mut self, name: char) -> Result<&mut f64, VariableNotFoundError> {
self.variables
.get_mut(&name)
.ok_or(VariableNotFoundError(name))
}
pub fn get_slope(&self, name: char) -> Result<&Expression, SlopeNotFoundError> {
self.slopes.get(&name).ok_or(SlopeNotFoundError(name))
}
fn tick(&mut self) -> Result<(), CompilerError> {
*self.get_mut('t')? += 1f64 / SAMPLE_RATE as f64;
{
let changes = self
.slopes
.iter()
.map(
|(v, Expression { instruction, slab })| -> Result<(char, f64), fasteval::Error> {
Ok((
*v,
instruction.eval(
slab,
&mut self
.variables
.iter()
.map(|(c, f)| (c.to_string(), *f))
.collect::<BTreeMap<String, f64>>(),
)?,
))
},
)
.collect::<Result<Vec<(char, f64)>, fasteval::Error>>()?;
for (variable, new_value) in changes {
*self.get_mut(variable)? = new_value;
}
}
Ok(())
}
fn namespace_generator(&self) -> BTreeMap<String, f64> {
self.variables
.iter()
.map(|(c, f)| (c.to_string(), *f))
.collect()
}
pub fn eval(
&self,
Expression { instruction, slab }: &Expression,
) -> Result<f64, fasteval::Error> {
instruction.eval(&slab, &mut self.namespace_generator())
}
pub fn render(&mut self, n: Option<u8>) -> Result<Vec<f64>, CompilerError> {
let curr_t = *self.get('t')?;
if let Some(note) = n {
let mut result = Vec::new();
while (self.current_length()? * SAMPLE_RATE as f64) > *self.get('t')? - curr_t {
{
let Expression { instruction, slab } = &self.instrument;
result.push(instruction.eval(&slab, &mut {
let mut map = self
.variables
.iter()
.map(|(c, f)| (format!("{c}"), *f))
.collect::<BTreeMap<String, f64>>();
map.insert('n'.to_string(), note as f64);
map
})?);
}
self.tick()?;
}
Ok(result)
} else {
while (self.current_length()? * SAMPLE_RATE as f64) > *self.get('t')? - curr_t {
self.tick()?;
}
Ok(vec![0.0; (*self.get('t')? - curr_t) as usize])
}
pub fn render(&self, n: Option<u8>) -> Vec<f64> {
todo!()
}
}