turn slopes map into a vec to have multiple slopes for same variable, struct Compiler
This commit is contained in:
parent
7852f2d5c5
commit
73fb1d52b5
1 changed files with 73 additions and 11 deletions
|
@ -7,7 +7,7 @@ use std::{
|
||||||
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use derive_wrapper::{AsRef, From};
|
use derive_wrapper::{AsRef, From};
|
||||||
use fasteval::{Compiler, EvalNamespace, Evaler, Instruction, Slab};
|
use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -204,13 +204,13 @@ impl Type for Slope<'_> {
|
||||||
|
|
||||||
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> {
|
||||||
context.slopes.insert(self.0.0, self.0.1.clone());
|
context.slopes.push((self.0.0, self.0.1.clone()));
|
||||||
context = self
|
context = self
|
||||||
.1
|
.1
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.try_fold(context, |context, t| t.apply(context))?;
|
.try_fold(context, |context, t| t.apply(context))?;
|
||||||
context.slopes.remove(&self.0.0);
|
context.slopes.pop();
|
||||||
Ok(context)
|
Ok(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,6 @@ impl Clone for Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl PartialEq for Expression {
|
impl PartialEq for Expression {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
format!("{self:?}") == format!("{other:?}")
|
format!("{self:?}") == format!("{other:?}")
|
||||||
|
@ -254,13 +253,16 @@ impl FromStr for Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, new)]
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
#[new(default)]
|
||||||
pub result: Vec<f64>,
|
pub result: Vec<f64>,
|
||||||
|
#[new(into_iter = "(char, f64)")]
|
||||||
pub variables: HashMap<char, f64>,
|
pub variables: HashMap<char, f64>,
|
||||||
pub instrument: Expression,
|
pub instrument: Expression,
|
||||||
pub slopes: HashMap<char, Expression>,
|
#[new(into_iter = "(char, Expression)")]
|
||||||
|
pub slopes: Vec<(char, Expression)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -282,9 +284,19 @@ pub enum CompilerError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn current_length(&self) -> Result<f64, CompilerError> {
|
pub fn current_length(&mut self) -> Result<f64, CompilerError> {
|
||||||
self.eval(self.get_slope('l').map_err(CompilerError::from)?)
|
*self = self
|
||||||
.map_err(Into::into)
|
.get_slopes_for('L')
|
||||||
|
.map_err(CompilerError::from)?
|
||||||
|
.iter()
|
||||||
|
.try_fold(
|
||||||
|
self.clone(),
|
||||||
|
|mut acc, slope| -> Result<Context, CompilerError> {
|
||||||
|
*acc.get_mut('L')? = self.eval(slope).map_err(Into::<CompilerError>::into)?;
|
||||||
|
Ok(acc)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Ok(*self.get('L')?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: char) -> Result<&f64, VariableNotFoundError> {
|
pub fn get(&self, name: char) -> Result<&f64, VariableNotFoundError> {
|
||||||
|
@ -297,8 +309,17 @@ impl Context {
|
||||||
.ok_or(VariableNotFoundError(name))
|
.ok_or(VariableNotFoundError(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_slope(&self, name: char) -> Result<&Expression, SlopeNotFoundError> {
|
pub fn get_slopes_for(&self, var: char) -> Result<Vec<&Expression>, SlopeNotFoundError> {
|
||||||
self.slopes.get(&name).ok_or(SlopeNotFoundError(name))
|
let result: Vec<&Expression> = self
|
||||||
|
.slopes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(c, e)| (c == &var).then_some(e))
|
||||||
|
.collect();
|
||||||
|
if result.is_empty() {
|
||||||
|
return Err(SlopeNotFoundError(var));
|
||||||
|
} else {
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) -> Result<(), CompilerError> {
|
fn tick(&mut self) -> Result<(), CompilerError> {
|
||||||
|
@ -383,15 +404,56 @@ impl Context {
|
||||||
Ok(vec![0.0; (*self.get('t')? - curr_t) as usize])
|
Ok(vec![0.0; (*self.get('t')? - curr_t) as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn finalize(self) -> Vec<f64> {
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(From)]
|
||||||
|
struct Compiler(Context);
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
fn step(self, token: impl Token) -> Result<Self, CompilerError> {
|
||||||
|
token.apply(self.0).map(Into::into)
|
||||||
|
}
|
||||||
|
fn compile_all<'a>(
|
||||||
|
self,
|
||||||
|
tokens: impl IntoIterator<Item = impl Token>,
|
||||||
|
) -> Result<Vec<f64>, CompilerError> {
|
||||||
|
tokens
|
||||||
|
.into_iter()
|
||||||
|
.try_fold(self, |acc, token| acc.step(token))
|
||||||
|
.map(|c| c.0)
|
||||||
|
.map(Context::finalize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::compiler::Expression;
|
use crate::compiler::Expression;
|
||||||
|
|
||||||
|
use super::Context;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_is_clone() {
|
fn expression_is_clone() {
|
||||||
let expr: Expression = "1 + 5 / x".parse().unwrap();
|
let expr: Expression = "1 + 5 / x".parse().unwrap();
|
||||||
assert_eq!(expr, expr.clone());
|
assert_eq!(expr, expr.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn context_generator() -> Context {
|
||||||
|
Context::new(
|
||||||
|
[
|
||||||
|
('a', 5.0),
|
||||||
|
('t', 0.0),
|
||||||
|
('n', 0.0),
|
||||||
|
('N', 12.0),
|
||||||
|
('L', 0.0),
|
||||||
|
('l', 4.0),
|
||||||
|
('T', 60.0),
|
||||||
|
],
|
||||||
|
"sin(2*PI*(442+442*((n+1)/N))*t)".parse().unwrap(),
|
||||||
|
[('L', "2^(2-log_2(l))*(60/T)")].map(|(c, e)| (c, e.parse().unwrap())),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue