This commit is contained in:
brevalferrari 2025-06-04 12:10:13 +02:00
parent 20c7db953e
commit 0ccc81551a
4 changed files with 85 additions and 42 deletions

View file

@ -31,10 +31,12 @@ strum = { version = "0.27", features = ["derive"] }
thiserror = "2.0" thiserror = "2.0"
rodio = { version = "0.20", default-features = false, optional = true } rodio = { version = "0.20", default-features = false, optional = true }
dasp_sample = { version = "0", optional = true } dasp_sample = { version = "0", optional = true }
log = "0"
env_logger = { version = "0", optional = true }
[features] [features]
default = ["bin", "all-formats"] default = ["bin", "all-formats"]
bin = ["anyhow", "clap", "rodio", "dasp_sample"] bin = ["anyhow", "clap", "rodio", "dasp_sample", "env_logger"]
all-formats = ["mp3", "wav", "flac", "raw"] all-formats = ["mp3", "wav", "flac", "raw"]
mp3 = ["mp3lame-encoder"] mp3 = ["mp3lame-encoder"]
wav = ["hound"] wav = ["hound"]

View file

@ -12,6 +12,7 @@ use dasp_sample::Sample;
use rodio::{OutputStream, Sink, buffer::SamplesBuffer}; use rodio::{OutputStream, Sink, buffer::SamplesBuffer};
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
env_logger::init();
let cli = Cli::parse(); let cli = Cli::parse();
use Cli::*; use Cli::*;
match cli { match cli {

View file

@ -1,5 +1,5 @@
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId, type_name},
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
f64, f64,
fmt::Debug, fmt::Debug,
@ -10,6 +10,7 @@ use cfg_if::cfg_if;
use derive_new::new; use derive_new::new;
use derive_wrapper::{AsRef, From}; use derive_wrapper::{AsRef, From};
use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab}; use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab};
use log::trace;
use thiserror::Error; use thiserror::Error;
cfg_if! { cfg_if! {
@ -20,8 +21,7 @@ cfg_if! {
} }
} }
#[derive(From, AsRef, Default)] #[derive(Debug, From, AsRef, Default)]
#[cfg_attr(test, derive(Debug))]
pub struct TokenVec(pub(crate) Vec<Box<dyn Token>>); pub struct TokenVec(pub(crate) Vec<Box<dyn Token>>);
impl IntoIterator for TokenVec { impl IntoIterator for TokenVec {
@ -57,12 +57,6 @@ where
} }
} }
#[cfg(not(test))]
pub trait Token: Type {
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
}
#[cfg(test)]
pub trait Token: Debug + Type { pub trait Token: Debug + Type {
fn apply(&self, context: Context) -> Result<Context, CompilerError>; fn apply(&self, context: Context) -> Result<Context, CompilerError>;
} }
@ -74,43 +68,46 @@ impl PartialEq for TokenVec {
} }
} }
#[derive(Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Silence; pub struct Silence;
impl Token for Silence { impl Token for Silence {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
let mut next = context.render(None)?; let mut next = context.render(None)?;
context.result.append(&mut next); context.result.append(&mut next);
Ok(context) Ok(context)
} }
} }
#[derive(Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Marker; pub struct Marker;
impl Token for Marker { impl Token for Marker {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
context.result.clear(); context.result.clear();
Ok(context) Ok(context)
} }
} }
#[derive(Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Note(pub u8); pub struct Note(pub u8);
impl Token for Note { impl Token for Note {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
let mut next = context.render(Some(self.0))?; let mut next = context.render(Some(self.0))?;
context.result.append(&mut next); context.result.append(&mut next);
Ok(context) Ok(context)
} }
} }
#[derive(Clone, Default)] #[derive(Debug, Clone, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct VariableChange(pub char, pub Expression); pub struct VariableChange(pub char, pub Expression);
impl AsRef<VariableChange> for VariableChange { impl AsRef<VariableChange> for VariableChange {
@ -121,16 +118,18 @@ impl AsRef<VariableChange> for VariableChange {
impl Token for VariableChange { impl Token for VariableChange {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
*context.get_mut(self.0)? = context.eval(self.1.as_ref())?; *context.get_mut(self.0)? = context.eval(self.1.as_ref())?;
Ok(context) Ok(context)
} }
} }
#[derive(Default)] #[derive(Debug, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Loop(pub LoopCount, pub TokenVec); pub struct Loop(pub LoopCount, pub TokenVec);
#[cfg_attr(test, derive(Debug, PartialEq))] #[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub enum LoopCount { pub enum LoopCount {
Litteral(usize), Litteral(usize),
Variable(char), Variable(char),
@ -144,6 +143,7 @@ impl Default for LoopCount {
impl Token for Loop { impl Token for Loop {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
let mut old_result = context.result.clone(); let mut old_result = context.result.clone();
let count = match self.0 { let count = match self.0 {
LoopCount::Litteral(n) => n, LoopCount::Litteral(n) => n,
@ -163,12 +163,13 @@ impl Token for Loop {
} }
} }
#[derive(Default)] #[derive(Debug, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Tuplet(pub TokenVec); pub struct Tuplet(pub TokenVec);
impl Token for Tuplet { impl Token for Tuplet {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
let mut old_result = context.result.clone(); let mut old_result = context.result.clone();
context.result.clear(); context.result.clear();
let mut new_context = self let mut new_context = self
@ -200,12 +201,13 @@ impl Token for Tuplet {
} }
} }
#[derive(new, Default)] #[derive(Debug, new, Default)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Slope(pub VariableChange, pub TokenVec); pub struct Slope(pub VariableChange, pub TokenVec);
impl Token for Slope { impl Token for Slope {
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> { fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
trace!("⚡ {}", type_name::<Self>());
context context
.slopes .slopes
.push((self.0.as_ref().0, self.0.as_ref().1.as_ref().clone())); .push((self.0.as_ref().0, self.0.as_ref().1.as_ref().clone()));
@ -219,8 +221,7 @@ impl Token for Slope {
} }
} }
#[derive(new, Default)] #[derive(Debug, new, Default)]
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
pub struct Expression { pub struct Expression {
from: String, from: String,
pub(crate) instruction: Instruction, pub(crate) instruction: Instruction,
@ -263,8 +264,8 @@ impl FromStr for Expression {
} }
} }
#[derive(Clone, new)] #[derive(Debug, Clone, new)]
#[cfg_attr(test, derive(Debug, PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub struct Context { pub struct Context {
note_length_variable: char, note_length_variable: char,
note_index_variable: char, note_index_variable: char,

View file

@ -1,7 +1,8 @@
use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData}; use std::{any::type_name, borrow::Borrow, collections::BTreeMap, marker::PhantomData};
use derive_new::new; use derive_new::new;
use fasteval::Evaler; use fasteval::Evaler;
use log::{debug, error};
use nom::{ use nom::{
AsChar, Compare, Finish, IResult, Input, Parser as NomParser, AsChar, Compare, Finish, IResult, Input, Parser as NomParser,
branch::alt, branch::alt,
@ -51,6 +52,7 @@ where
&self, &self,
input: &'a str, input: &'a str,
) -> Result<TokenVec, Error<nom_locate::LocatedSpan<&'a str>>> { ) -> Result<TokenVec, Error<nom_locate::LocatedSpan<&'a str>>> {
debug!("parsing input \"{input}\"");
token_parser(self) token_parser(self)
.parse_complete(LocatedSpan::new(input)) .parse_complete(LocatedSpan::new(input))
.finish() .finish()
@ -72,6 +74,7 @@ where
SV: Borrow<VariableChange>, SV: Borrow<VariableChange>,
V: AsRef<[char]>, V: AsRef<[char]>,
{ {
debug!("making the TOKEN parser");
let space_or_comment = || { let space_or_comment = || {
value( value(
(), (),
@ -104,6 +107,7 @@ impl Silence {
I: Input, I: Input,
<I as Input>::Item: AsChar, <I as Input>::Item: AsChar,
{ {
debug!("making the {} parser", type_name::<Self>());
value(Self, char('.')) value(Self, char('.'))
} }
} }
@ -114,6 +118,7 @@ impl Marker {
I: Input, I: Input,
<I as Input>::Item: AsChar, <I as Input>::Item: AsChar,
{ {
debug!("making the {} parser", type_name::<Self>());
value(Marker, char('%')) value(Marker, char('%'))
} }
} }
@ -127,20 +132,23 @@ impl Note {
NS: AsRef<str>, NS: AsRef<str>,
I: Input + for<'z> Compare<&'z str>, I: Input + for<'z> Compare<&'z str>,
{ {
debug!("making the {} parser", type_name::<Self>());
let notes = { let notes = {
let mut sorted = notes let mut sorted = notes
.into_iter() .into_iter()
.map(|s| s.as_ref().to_string()) .map(|s| s.as_ref().to_string())
.enumerate() .enumerate()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
debug!("got notes {sorted:?}");
sorted.sort_by_key(|(_, n)| n.len()); sorted.sort_by_key(|(_, n)| n.len());
sorted.reverse();
debug!("sorted to {sorted:?}");
sorted sorted
}; };
move |input: I| { move |input: I| {
let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = notes let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = notes
.clone() .clone()
.drain(..) .drain(..)
.rev()
.map(|(i, t)| { .map(|(i, t)| {
Box::new(move |input: I| { Box::new(move |input: I| {
value(Note(i as u8), tag(t.clone().as_ref())).parse(input) value(Note(i as u8), tag(t.clone().as_ref())).parse(input)
@ -159,6 +167,7 @@ impl VariableChange {
<I as Input>::Item: AsChar, <I as Input>::Item: AsChar,
V: AsRef<[char]>, V: AsRef<[char]>,
{ {
debug!("making the {} parser", type_name::<Self>());
move |i: I| { move |i: I| {
preceded( preceded(
char('$'), char('$'),
@ -186,6 +195,7 @@ impl Loop {
SV: Borrow<VariableChange>, SV: Borrow<VariableChange>,
V: AsRef<[char]>, V: AsRef<[char]>,
{ {
debug!("making the {} parser", type_name::<Self>());
move |input| { move |input| {
delimited( delimited(
char('('), char('('),
@ -225,6 +235,7 @@ impl Tuplet {
SV: Borrow<VariableChange>, SV: Borrow<VariableChange>,
V: AsRef<[char]>, V: AsRef<[char]>,
{ {
debug!("making the {} parser", type_name::<Self>());
|input| { |input| {
delimited(char('['), token_parser(parser), char(']')) delimited(char('['), token_parser(parser), char(']'))
.map(Self) .map(Self)
@ -248,6 +259,7 @@ impl Slope {
SV: Borrow<VariableChange>, SV: Borrow<VariableChange>,
V: AsRef<[char]>, V: AsRef<[char]>,
{ {
debug!("making the {} parser", type_name::<Self>());
move |input| { move |input| {
let slopes = { let slopes = {
let mut vec = parser let mut vec = parser
@ -256,11 +268,13 @@ impl Slope {
.into_iter() .into_iter()
.map(|(s1, s2)| (s1.as_ref().to_string(), s2.borrow().clone())) .map(|(s1, s2)| (s1.as_ref().to_string(), s2.borrow().clone()))
.collect::<Vec<(String, VariableChange)>>(); .collect::<Vec<(String, VariableChange)>>();
debug!("got slopes {vec:?}");
vec.sort_by_key(|(name, _)| name.len()); vec.sort_by_key(|(name, _)| name.len());
vec.reverse();
debug!("sorted to {vec:?}");
vec vec
}; };
let iter: std::iter::Rev<std::vec::IntoIter<(String, VariableChange)>> = let iter: std::vec::IntoIter<(String, VariableChange)> = slopes.into_iter();
slopes.into_iter().rev();
delimited( delimited(
char('{'), char('{'),
alt(iter alt(iter
@ -286,22 +300,41 @@ where
V: IntoIterator<Item = C>, V: IntoIterator<Item = C>,
C: Borrow<char>, C: Borrow<char>,
{ {
debug!("making the Expression parser");
let variables: Vec<(String, f64)> = variables let variables: Vec<(String, f64)> = variables
.into_iter() .into_iter()
.map(|v| (v.borrow().to_string(), 0.0)) .map(|v| (v.borrow().to_string(), 0.0))
.collect(); .collect();
debug!("got variables {variables:?}");
move |input: I| { move |input: I| {
take_while_map(|i: I| { take_while_map(|i: I| {
i.as_ref().parse::<Expression>().ok().and_then(|e| { i.as_ref()
e.instruction .parse::<Expression>()
.eval( .inspect_err(|e| {
&e.slab, error!(
&mut BTreeMap::from_iter(variables.clone().drain(..)), "failed parsing expression {expr} with {err}",
expr = i.as_ref(),
err = e
) )
.ok() })
.is_some() .ok()
.then_some(e) .and_then(|e| {
}) e.instruction
.eval(
&e.slab,
&mut BTreeMap::from_iter(variables.clone().drain(..)),
)
.inspect_err(|e| {
error!(
"failed expression evaluation {expr:?} with {err}",
expr = e,
err = e
)
})
.ok()
.is_some()
.then_some(e)
})
}) })
.parse(input) .parse(input)
} }
@ -314,16 +347,22 @@ where
I: Input + Copy, I: Input + Copy,
F: Fn(I) -> Option<O>, F: Fn(I) -> Option<O>,
{ {
debug!("making take_while_map parser");
move |input: I| { move |input: I| {
let mut len = input.input_len(); let mut len = input.input_len();
debug!(
"take_while_map will now match biggest munch from the rest of the input ({len} elements)"
);
while len > 0 { while len > 0 {
let result = take(len).map_opt(&cond).parse(input); let result = take(len).map_opt(&cond).parse(input);
if result.is_ok() { if result.is_ok() {
debug!("found a match using {len} elements");
return result; return result;
} else { } else {
len -= 1; len -= 1;
} }
} }
error!("take_while_map found no match");
Err(nom::Err::Incomplete(nom::Needed::Unknown)) Err(nom::Err::Incomplete(nom::Needed::Unknown))
} }
} }