From 73fb1d52b5f60161f8a59833876f12bbe5ca2041 Mon Sep 17 00:00:00 2001 From: brevalferrari Date: Wed, 28 May 2025 12:54:01 +0200 Subject: [PATCH] turn slopes map into a vec to have multiple slopes for same variable, struct Compiler --- src/compiler.rs | 84 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 4fdcb8a..3f20111 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -7,7 +7,7 @@ use std::{ use derive_new::new; use derive_wrapper::{AsRef, From}; -use fasteval::{Compiler, EvalNamespace, Evaler, Instruction, Slab}; +use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab}; use lazy_static::lazy_static; use thiserror::Error; @@ -204,13 +204,13 @@ impl Type for Slope<'_> { impl Token for Slope<'_> { fn apply(&self, mut context: Context) -> Result { - context.slopes.insert(self.0.0, self.0.1.clone()); + context.slopes.push((self.0.0, self.0.1.clone())); context = self .1 .0 .iter() .try_fold(context, |context, t| t.apply(context))?; - context.slopes.remove(&self.0.0); + context.slopes.pop(); Ok(context) } } @@ -231,7 +231,6 @@ impl Clone for Expression { } } -#[cfg(test)] impl PartialEq for Expression { fn eq(&self, other: &Self) -> bool { format!("{self:?}") == format!("{other:?}") @@ -254,13 +253,16 @@ impl FromStr for Expression { } } -#[derive(Clone)] +#[derive(Clone, new)] #[cfg_attr(test, derive(Debug, PartialEq))] pub struct Context { + #[new(default)] pub result: Vec, + #[new(into_iter = "(char, f64)")] pub variables: HashMap, pub instrument: Expression, - pub slopes: HashMap, + #[new(into_iter = "(char, Expression)")] + pub slopes: Vec<(char, Expression)>, } #[derive(Debug, Error)] @@ -282,9 +284,19 @@ pub enum CompilerError { } impl Context { - pub fn current_length(&self) -> Result { - self.eval(self.get_slope('l').map_err(CompilerError::from)?) - .map_err(Into::into) + pub fn current_length(&mut self) -> Result { + *self = self + .get_slopes_for('L') + .map_err(CompilerError::from)? + .iter() + .try_fold( + self.clone(), + |mut acc, slope| -> Result { + *acc.get_mut('L')? = self.eval(slope).map_err(Into::::into)?; + Ok(acc) + }, + )?; + Ok(*self.get('L')?) } pub fn get(&self, name: char) -> Result<&f64, VariableNotFoundError> { @@ -297,8 +309,17 @@ impl Context { .ok_or(VariableNotFoundError(name)) } - pub fn get_slope(&self, name: char) -> Result<&Expression, SlopeNotFoundError> { - self.slopes.get(&name).ok_or(SlopeNotFoundError(name)) + pub fn get_slopes_for(&self, var: char) -> Result, SlopeNotFoundError> { + let result: Vec<&Expression> = self + .slopes + .iter() + .filter_map(|(c, e)| (c == &var).then_some(e)) + .collect(); + if result.is_empty() { + return Err(SlopeNotFoundError(var)); + } else { + Ok(result) + } } fn tick(&mut self) -> Result<(), CompilerError> { @@ -383,15 +404,56 @@ impl Context { Ok(vec![0.0; (*self.get('t')? - curr_t) as usize]) } } + + pub fn finalize(self) -> Vec { + self.result + } +} + +#[derive(From)] +struct Compiler(Context); + +impl Compiler { + fn step(self, token: impl Token) -> Result { + token.apply(self.0).map(Into::into) + } + fn compile_all<'a>( + self, + tokens: impl IntoIterator, + ) -> Result, CompilerError> { + tokens + .into_iter() + .try_fold(self, |acc, token| acc.step(token)) + .map(|c| c.0) + .map(Context::finalize) + } } #[cfg(test)] mod tests { use crate::compiler::Expression; + use super::Context; + #[test] fn expression_is_clone() { let expr: Expression = "1 + 5 / x".parse().unwrap(); assert_eq!(expr, expr.clone()); } + + fn context_generator() -> Context { + Context::new( + [ + ('a', 5.0), + ('t', 0.0), + ('n', 0.0), + ('N', 12.0), + ('L', 0.0), + ('l', 4.0), + ('T', 60.0), + ], + "sin(2*PI*(442+442*((n+1)/N))*t)".parse().unwrap(), + [('L', "2^(2-log_2(l))*(60/T)")].map(|(c, e)| (c, e.parse().unwrap())), + ) + } }