log
This commit is contained in:
parent
20c7db953e
commit
0ccc81551a
4 changed files with 85 additions and 42 deletions
|
@ -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"]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue