first Token.apply() impls, context methods
This commit is contained in:
parent
69c2869388
commit
7e831c40ac
1 changed files with 156 additions and 19 deletions
175
src/compiler.rs
175
src/compiler.rs
|
@ -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_new::new;
|
||||||
use derive_wrapper::{AsRef, From};
|
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)]
|
#[derive(From, AsRef)]
|
||||||
#[cfg_attr(test, derive(Debug))]
|
#[cfg_attr(test, derive(Debug))]
|
||||||
|
@ -10,16 +17,12 @@ pub struct TokenVec<'a>(pub(crate) Vec<Box<dyn Token + 'a>>);
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub trait Token {
|
pub trait Token {
|
||||||
fn apply(&self, context: Context) -> Context {
|
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub trait Token: Debug {
|
pub trait Token: Debug {
|
||||||
fn apply(&self, context: Context) -> Context {
|
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -33,24 +36,45 @@ impl PartialEq for TokenVec<'_> {
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Silence;
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Marker;
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, 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> {
|
||||||
|
let mut next = context.render(Some(self.0))?;
|
||||||
|
context.result.append(&mut next);
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct VariableChange(pub char, pub Expression);
|
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))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>);
|
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))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Tuplet<'a>(pub TokenVec<'a>);
|
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))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Slope<'a>(pub &'a VariableChange, pub TokenVec<'a>);
|
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)]
|
#[derive(new)]
|
||||||
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
|
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
|
||||||
|
@ -119,11 +155,112 @@ pub struct Context {
|
||||||
pub slopes: HashMap<char, Expression>,
|
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 {
|
impl Context {
|
||||||
pub fn current_length(&self) -> f64 {
|
pub fn current_length(&self) -> Result<f64, CompilerError> {
|
||||||
todo!()
|
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!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue