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_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)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
|
@ -10,16 +17,12 @@ pub struct TokenVec<'a>(pub(crate) Vec<Box<dyn Token + 'a>>);
|
|||
|
||||
#[cfg(not(test))]
|
||||
pub trait Token {
|
||||
fn apply(&self, context: Context) -> Context {
|
||||
todo!()
|
||||
}
|
||||
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub trait Token: Debug {
|
||||
fn apply(&self, context: Context) -> Context {
|
||||
todo!()
|
||||
}
|
||||
fn apply(&self, context: Context) -> Result<Context, CompilerError>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -33,24 +36,45 @@ impl PartialEq for TokenVec<'_> {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
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)]
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
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)]
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
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))]
|
||||
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))]
|
||||
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))]
|
||||
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))]
|
||||
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)]
|
||||
#[cfg_attr(any(debug_assertions, test), derive(Debug))]
|
||||
|
@ -119,11 +155,112 @@ pub struct Context {
|
|||
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 {
|
||||
pub fn current_length(&self) -> f64 {
|
||||
todo!()
|
||||
pub fn current_length(&self) -> Result<f64, CompilerError> {
|
||||
self.eval(self.get_slope('l').map_err(CompilerError::from)?)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn render(&self, n: Option<u8>) -> Vec<f64> {
|
||||
todo!()
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue