From 25f4eb1b13aaf270e2a1d8d069efa270688a29db Mon Sep 17 00:00:00 2001 From: brevalferrari Date: Mon, 2 Jun 2025 23:27:51 +0200 Subject: [PATCH] generalize default variables --- src/cli/main.rs | 15 ++++++++++++--- src/compiler.rs | 13 +++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/cli/main.rs b/src/cli/main.rs index a793424..a7c187f 100644 --- a/src/cli/main.rs +++ b/src/cli/main.rs @@ -1,5 +1,5 @@ mod cli; -use std::io::read_to_string; +use std::{collections::HashMap, io::read_to_string}; use anyhow::{Context as _, anyhow}; use bliplib::{ @@ -20,12 +20,17 @@ fn main() -> anyhow::Result<()> { .context("Failed to find (or use) default audio device")?; let sink = Sink::try_new(&stream_handle).context("Epic audio playback failure")?; + let default_variables = HashMap::from([('l', 4f64), ('L', 0.0), ('t', 0.0)]); + let parser = Parser::new( opts.notes(), opts.slopes() .map(|(s, (v, e))| (s, VariableChange(*v, e.clone()))) .collect::>(), - opts.variables().map(|(v, _)| *v).collect::>(), + opts.variables() + .chain(default_variables.iter()) + .map(|(v, _)| *v) + .collect::>(), ); let input = read_to_string(opts.input().get()).context("Failed to read input")?; let tokens = parser @@ -34,7 +39,11 @@ fn main() -> anyhow::Result<()> { .context("Failed to parse input")?; let compiler = Compiler::from(Context::new( - opts.variables().map(|(a, b)| (*a, *b)), + 'n', + 'L', + opts.variables() + .map(|(a, b)| (*a, *b)) + .chain(default_variables.into_iter()), opts.instrument().clone(), opts.slopes().map(|(_, (a, b))| (*a, b.clone())), )); diff --git a/src/compiler.rs b/src/compiler.rs index 782f7a4..aea8e60 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -266,6 +266,8 @@ impl FromStr for Expression { #[derive(Clone, new)] #[cfg_attr(test, derive(Debug, PartialEq))] pub struct Context { + note_length_variable: char, + note_index_variable: char, #[new(default)] pub result: Vec, #[new(into_iter = "(char, f64)")] @@ -298,18 +300,19 @@ pub enum CompilerError { impl Context { pub fn current_length(&self) -> Result { - self.get_slopes_for('L') + self.get_slopes_for(self.note_length_variable) .map_err(CompilerError::from)? .iter() .try_fold( self.clone(), |mut acc, slope| -> Result { // just in case next slopes use L too - *acc.get_mut('L')? = self.eval(slope).map_err(Into::::into)?; + *acc.get_mut(self.note_length_variable)? = + self.eval(slope).map_err(Into::::into)?; Ok(acc) }, )? - .get('L') + .get(self.note_length_variable) .map_err(Into::into) .cloned() } @@ -377,7 +380,7 @@ impl Context { if let Some(note) = n { let mut result = Vec::new(); let mut map = self.namespace_generator().collect::>(); - map.insert('n'.to_string(), note as f64); + map.insert(self.note_index_variable.to_string(), note as f64); while self.current_length()? > *self.get('t')? - curr_t + (1f64 / SAMPLE_RATE as f64) { result.push(self.eval_with(&self.instrument, &mut map)? * f64::MAX); self.tick()?; @@ -442,6 +445,8 @@ mod tests { fn context_generator() -> Context { Context::new( + 'n', + 'L', [ ('a', 5.0), ('t', 0.0),