simplify bliplib API
This commit is contained in:
parent
c0e3478ae0
commit
3168370a37
2 changed files with 216 additions and 168 deletions
|
@ -1,12 +1,15 @@
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId}, collections::{BTreeMap, HashMap}, f64, fmt::Debug, str::FromStr
|
any::{Any, TypeId},
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
f64,
|
||||||
|
fmt::Debug,
|
||||||
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
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 lazy_static::lazy_static;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
|
@ -19,30 +22,19 @@ cfg_if! {
|
||||||
|
|
||||||
#[derive(From, AsRef, Default)]
|
#[derive(From, AsRef, Default)]
|
||||||
#[cfg_attr(test, derive(Debug))]
|
#[cfg_attr(test, derive(Debug))]
|
||||||
pub struct TokenVec<'a>(pub(crate) Vec<Box<dyn Token + 'a>>);
|
pub struct TokenVec(pub(crate) Vec<Box<dyn Token>>);
|
||||||
|
|
||||||
pub trait Type {
|
pub trait Type {
|
||||||
fn type_id(&self) -> TypeId;
|
fn type_id(&self) -> TypeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_type {
|
impl<T> Type for T
|
||||||
($name:ty) => {
|
where
|
||||||
impl Type for $name {
|
T: Default + 'static,
|
||||||
fn type_id(&self) -> std::any::TypeId {
|
{
|
||||||
<Self as std::any::Any>::type_id(self)
|
fn type_id(&self) -> TypeId {
|
||||||
}
|
<Self as Any>::type_id(&Default::default())
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_type_life {
|
|
||||||
($name:ty) => {
|
|
||||||
impl Type for $name {
|
|
||||||
fn type_id(&self) -> TypeId {
|
|
||||||
<$name as Any>::type_id(&Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
|
@ -56,7 +48,7 @@ pub trait Token: Debug + Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl PartialEq for TokenVec<'_> {
|
impl PartialEq for TokenVec {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
format!("{self:?}") == format!("{other:?}")
|
format!("{self:?}") == format!("{other:?}")
|
||||||
}
|
}
|
||||||
|
@ -66,8 +58,6 @@ impl PartialEq for TokenVec<'_> {
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Silence;
|
pub struct Silence;
|
||||||
|
|
||||||
impl_type!(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> {
|
||||||
let mut next = context.render(None)?;
|
let mut next = context.render(None)?;
|
||||||
|
@ -80,8 +70,6 @@ impl Token for Silence {
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Marker;
|
pub struct Marker;
|
||||||
|
|
||||||
impl_type!(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> {
|
||||||
context.result.clear();
|
context.result.clear();
|
||||||
|
@ -93,8 +81,6 @@ impl Token for Marker {
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Note(pub u8);
|
pub struct Note(pub u8);
|
||||||
|
|
||||||
impl_type!(Note);
|
|
||||||
|
|
||||||
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> {
|
||||||
let mut next = context.render(Some(self.0))?;
|
let mut next = context.render(Some(self.0))?;
|
||||||
|
@ -107,20 +93,22 @@ impl Token for Note {
|
||||||
#[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_type!(VariableChange);
|
impl AsRef<VariableChange> for VariableChange {
|
||||||
|
fn as_ref(&self) -> &VariableChange {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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> {
|
||||||
*context.get_mut(self.0)? = context.eval(&self.1)?;
|
*context.get_mut(self.0)? = context.eval(self.1.as_ref())?;
|
||||||
Ok(context)
|
Ok(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Loop<'a>(pub LoopCount, pub TokenVec<'a>);
|
pub struct Loop(pub LoopCount, pub TokenVec);
|
||||||
|
|
||||||
impl_type_life!(Loop<'_>);
|
|
||||||
|
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub enum LoopCount {
|
pub enum LoopCount {
|
||||||
|
@ -134,7 +122,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> {
|
||||||
let mut old_result = context.result.clone();
|
let mut old_result = context.result.clone();
|
||||||
let count = match self.0 {
|
let count = match self.0 {
|
||||||
|
@ -157,11 +145,9 @@ impl Token for Loop<'_> {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct Tuplet<'a>(pub TokenVec<'a>);
|
pub struct Tuplet(pub TokenVec);
|
||||||
|
|
||||||
impl_type_life!(Tuplet<'_>);
|
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> {
|
||||||
let mut old_result = context.result.clone();
|
let mut old_result = context.result.clone();
|
||||||
context.result.clear();
|
context.result.clear();
|
||||||
|
@ -194,22 +180,15 @@ impl Token for Tuplet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(new, Default)]
|
||||||
#[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(pub VariableChange, pub TokenVec);
|
||||||
|
|
||||||
lazy_static! {
|
impl Token for Slope {
|
||||||
static ref VARIABLE_CHANGE_DEFAULT: VariableChange = Default::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Type for Slope<'_> {
|
|
||||||
fn type_id(&self) -> TypeId {
|
|
||||||
<Slope as Any>::type_id(&Slope(&VARIABLE_CHANGE_DEFAULT, Default::default()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Token for Slope<'_> {
|
|
||||||
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
|
fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
|
||||||
context.slopes.push((self.0.0, self.0.1.clone()));
|
context
|
||||||
|
.slopes
|
||||||
|
.push((self.0.as_ref().0, self.0.as_ref().1.as_ref().clone()));
|
||||||
context = self
|
context = self
|
||||||
.1
|
.1
|
||||||
.0
|
.0
|
||||||
|
@ -228,6 +207,12 @@ pub struct Expression {
|
||||||
pub(crate) slab: Slab,
|
pub(crate) slab: Slab,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<Expression> for Expression {
|
||||||
|
fn as_ref(&self) -> &Expression {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for Expression {
|
impl Clone for Expression {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
self.from
|
self.from
|
||||||
|
|
297
src/parser.rs
297
src/parser.rs
|
@ -1,9 +1,6 @@
|
||||||
use std::{
|
use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData};
|
||||||
collections::{BTreeMap, HashMap},
|
|
||||||
fmt::Display,
|
|
||||||
};
|
|
||||||
|
|
||||||
use derive_builder::Builder;
|
use derive_new::new;
|
||||||
use fasteval::Evaler;
|
use fasteval::Evaler;
|
||||||
use nom::{
|
use nom::{
|
||||||
AsChar, Compare, Finish, IResult, Input, Parser as NomParser,
|
AsChar, Compare, Finish, IResult, Input, Parser as NomParser,
|
||||||
|
@ -25,18 +22,35 @@ use crate::compiler::{
|
||||||
VariableChange,
|
VariableChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Builder)]
|
#[derive(new)]
|
||||||
pub struct Parser<'n, 's, 'v, N: AsRef<str> + Clone> {
|
pub struct Parser<N, NS, S, SS, SV, V>
|
||||||
notes: &'n [N],
|
where
|
||||||
slopes: &'s HashMap<String, VariableChange>,
|
N: AsRef<[NS]>,
|
||||||
variables: &'v [char],
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)>,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
|
{
|
||||||
|
notes: N,
|
||||||
|
slopes: S,
|
||||||
|
variables: V,
|
||||||
|
phantom: PhantomData<(NS, SS)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 's, N: AsRef<str> + Clone> Parser<'_, 's, '_, N> {
|
impl<'a, N, NS, S, SS, SV, V> Parser<N, NS, S, SS, SV, V>
|
||||||
|
where
|
||||||
|
N: AsRef<[NS]>,
|
||||||
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)> + Clone,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
|
{
|
||||||
pub fn parse_all(
|
pub fn parse_all(
|
||||||
&self,
|
&self,
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
) -> Result<TokenVec<'s>, Error<nom_locate::LocatedSpan<&'a str>>> {
|
) -> Result<TokenVec, Error<nom_locate::LocatedSpan<&'a str>>> {
|
||||||
token_parser(self)
|
token_parser(self)
|
||||||
.parse_complete(LocatedSpan::new(input))
|
.parse_complete(LocatedSpan::new(input))
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -44,14 +58,19 @@ impl<'a, 's, N: AsRef<str> + Clone> Parser<'_, 's, '_, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_parser<'a, 's, I, N>(
|
fn token_parser<'a, I, N, NS, S, SS, SV, V>(
|
||||||
parser: &Parser<'_, 's, '_, N>,
|
parser: &Parser<N, NS, S, SS, SV, V>,
|
||||||
) -> impl NomParser<I, Output = TokenVec<'s>, Error = nom::error::Error<I>>
|
) -> impl NomParser<I, Output = TokenVec, Error = nom::error::Error<I>>
|
||||||
where
|
where
|
||||||
I: Input + AsRef<str> + for<'z> nom::Compare<&'z str> + Copy,
|
I: Input + AsRef<str> + for<'z> nom::Compare<&'z str> + Copy,
|
||||||
<I as Input>::Item: AsChar,
|
<I as Input>::Item: AsChar,
|
||||||
<I as Input>::Item: PartialEq<char>,
|
<I as Input>::Item: PartialEq<char>,
|
||||||
N: AsRef<str> + Clone,
|
N: AsRef<[NS]>,
|
||||||
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)> + Clone,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
{
|
{
|
||||||
let space_or_comment = || {
|
let space_or_comment = || {
|
||||||
value(
|
value(
|
||||||
|
@ -64,8 +83,8 @@ where
|
||||||
alt((
|
alt((
|
||||||
Silence::parser().map(into_box),
|
Silence::parser().map(into_box),
|
||||||
Marker::parser().map(into_box),
|
Marker::parser().map(into_box),
|
||||||
Note::parser(parser.notes).map(into_box),
|
Note::parser(parser.notes.as_ref()).map(into_box),
|
||||||
VariableChange::parser(parser.variables).map(into_box),
|
VariableChange::parser(&parser.variables).map(into_box),
|
||||||
Loop::parser(parser).map(into_box),
|
Loop::parser(parser).map(into_box),
|
||||||
Tuplet::parser(parser).map(into_box),
|
Tuplet::parser(parser).map(into_box),
|
||||||
Slope::parser(parser).map(into_box),
|
Slope::parser(parser).map(into_box),
|
||||||
|
@ -100,60 +119,87 @@ impl Marker {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Note {
|
impl Note {
|
||||||
fn parser<'n, N, I>(
|
fn parser<'a, N, NS, I>(
|
||||||
notes: &'n [N],
|
notes: N,
|
||||||
) -> impl NomParser<I, Output = Self, Error = nom::error::Error<I>>
|
) -> impl NomParser<I, Output = Self, Error = nom::error::Error<I>> + 'a
|
||||||
where
|
where
|
||||||
N: AsRef<str> + Clone,
|
N: IntoIterator<Item = NS>,
|
||||||
|
NS: AsRef<str>,
|
||||||
I: Input + for<'z> Compare<&'z str>,
|
I: Input + for<'z> Compare<&'z str>,
|
||||||
{
|
{
|
||||||
|input: I| {
|
let notes = {
|
||||||
let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = {
|
let mut sorted = notes
|
||||||
let mut sorted = notes.iter().enumerate().collect::<Vec<(usize, &N)>>();
|
.into_iter()
|
||||||
sorted.sort_by_key(|(_, n)| n.as_ref().len());
|
.map(|s| s.as_ref().to_string())
|
||||||
sorted
|
.enumerate()
|
||||||
}
|
.collect::<Vec<_>>();
|
||||||
.drain(..)
|
sorted.sort_by_key(|(_, n)| n.len());
|
||||||
.rev()
|
sorted
|
||||||
.map(|(i, t)| {
|
};
|
||||||
Box::new(move |input: I| value(Note(i as u8), tag(t.clone().as_ref())).parse(input))
|
move |input: I| {
|
||||||
as Box<dyn Fn(I) -> IResult<I, Self>>
|
let mut parsers: Vec<Box<dyn Fn(I) -> IResult<I, Self>>> = notes
|
||||||
})
|
.clone()
|
||||||
.collect();
|
.drain(..)
|
||||||
|
.rev()
|
||||||
|
.map(|(i, t)| {
|
||||||
|
Box::new(move |input: I| {
|
||||||
|
value(Note(i as u8), tag(t.clone().as_ref())).parse(input)
|
||||||
|
}) as Box<dyn Fn(I) -> IResult<I, Self>>
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
alt(parsers.as_mut_slice()).parse(input)
|
alt(parsers.as_mut_slice()).parse(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableChange {
|
impl VariableChange {
|
||||||
fn parser<I>(variables: &[char]) -> impl Fn(I) -> IResult<I, Self>
|
fn parser<I, V>(variables: V) -> impl Fn(I) -> IResult<I, Self>
|
||||||
where
|
where
|
||||||
I: Input + AsRef<str> + Copy,
|
I: Input + AsRef<str> + Copy,
|
||||||
<I as Input>::Item: AsChar,
|
<I as Input>::Item: AsChar,
|
||||||
|
V: AsRef<[char]>,
|
||||||
{
|
{
|
||||||
move |i: I| {
|
move |i: I| {
|
||||||
preceded(char('$'), one_of(variables))
|
preceded(
|
||||||
.and(expression_parser(variables))
|
char('$'),
|
||||||
.map(|(name, change)| VariableChange(name, change))
|
one_of(variables.as_ref().iter().collect::<String>().as_str()),
|
||||||
.parse(i)
|
)
|
||||||
|
.and(expression_parser(variables.as_ref()))
|
||||||
|
.map(|(name, change)| VariableChange(name, change))
|
||||||
|
.parse(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Loop<'s> {
|
impl Loop {
|
||||||
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
fn parser<I, N, NS, S, SS, SV, V>(
|
||||||
|
parser: &Parser<N, NS, S, SS, SV, V>,
|
||||||
|
) -> impl Fn(I) -> IResult<I, Self>
|
||||||
where
|
where
|
||||||
I: Input + AsRef<str> + for<'z> nom::Compare<&'z str> + Copy,
|
I: Input + AsRef<str> + for<'z> nom::Compare<&'z str> + Copy,
|
||||||
<I as Input>::Item: AsChar,
|
<I as Input>::Item: AsChar,
|
||||||
<I as Input>::Item: PartialEq<char>,
|
<I as Input>::Item: PartialEq<char>,
|
||||||
N: AsRef<str> + Clone,
|
N: AsRef<[NS]>,
|
||||||
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)> + Clone,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
{
|
{
|
||||||
|input| {
|
move |input| {
|
||||||
delimited(
|
delimited(
|
||||||
char('('),
|
char('('),
|
||||||
opt(alt((
|
opt(alt((
|
||||||
usize.map(LoopCount::Litteral),
|
usize.map(LoopCount::Litteral),
|
||||||
one_of(parser.variables).map(LoopCount::Variable),
|
one_of(
|
||||||
|
parser
|
||||||
|
.variables
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.collect::<String>()
|
||||||
|
.as_str(),
|
||||||
|
)
|
||||||
|
.map(LoopCount::Variable),
|
||||||
)))
|
)))
|
||||||
.and(token_parser(parser)),
|
.and(token_parser(parser)),
|
||||||
char(')'),
|
char(')'),
|
||||||
|
@ -164,13 +210,20 @@ impl<'s> Loop<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Tuplet<'s> {
|
impl Tuplet {
|
||||||
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
fn parser<I, N, NS, S, SS, SV, V>(
|
||||||
|
parser: &Parser<N, NS, S, SS, SV, V>,
|
||||||
|
) -> impl Fn(I) -> IResult<I, Self>
|
||||||
where
|
where
|
||||||
I: Input + for<'z> Compare<&'z str> + AsRef<str> + Copy,
|
I: Input + for<'z> Compare<&'z str> + AsRef<str> + Copy,
|
||||||
<I as Input>::Item: AsChar,
|
<I as Input>::Item: AsChar,
|
||||||
<I as Input>::Item: PartialEq<char>,
|
<I as Input>::Item: PartialEq<char>,
|
||||||
N: AsRef<str> + Clone,
|
N: AsRef<[NS]>,
|
||||||
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)> + Clone,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
{
|
{
|
||||||
|input| {
|
|input| {
|
||||||
delimited(char('['), token_parser(parser), char(']'))
|
delimited(char('['), token_parser(parser), char(']'))
|
||||||
|
@ -180,54 +233,70 @@ impl<'s> Tuplet<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Slope<'s> {
|
impl Slope {
|
||||||
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
fn parser<'p, I, N, NS, S, SS, SV, V>(
|
||||||
|
parser: &'p Parser<N, NS, S, SS, SV, V>,
|
||||||
|
) -> impl Fn(I) -> IResult<I, Self>
|
||||||
where
|
where
|
||||||
I: Input + for<'z> Compare<&'z str> + AsRef<str> + Copy,
|
I: Input + for<'z> Compare<&'z str> + AsRef<str> + Copy,
|
||||||
<I as Input>::Item: AsChar,
|
<I as Input>::Item: AsChar,
|
||||||
<I as Input>::Item: PartialEq<char>,
|
<I as Input>::Item: PartialEq<char>,
|
||||||
N: AsRef<str> + Clone,
|
N: AsRef<[NS]>,
|
||||||
|
NS: AsRef<str>,
|
||||||
|
S: IntoIterator<Item = (SS, SV)> + Clone,
|
||||||
|
SS: AsRef<str>,
|
||||||
|
SV: Borrow<VariableChange>,
|
||||||
|
V: AsRef<[char]>,
|
||||||
{
|
{
|
||||||
|input| {
|
move |input| {
|
||||||
let iter: std::iter::Rev<std::vec::IntoIter<(&'s String, &'s VariableChange)>> = {
|
let slopes = {
|
||||||
let mut vec = parser
|
let mut vec = parser
|
||||||
.slopes
|
.slopes
|
||||||
.iter()
|
.clone()
|
||||||
.collect::<Vec<(&'s String, &'s VariableChange)>>();
|
.into_iter()
|
||||||
|
.map(|(s1, s2)| (s1.as_ref().to_string(), s2.borrow().clone()))
|
||||||
|
.collect::<Vec<(String, VariableChange)>>();
|
||||||
vec.sort_by_key(|(name, _)| name.len());
|
vec.sort_by_key(|(name, _)| name.len());
|
||||||
vec
|
vec
|
||||||
}
|
};
|
||||||
.into_iter()
|
let iter: std::iter::Rev<std::vec::IntoIter<(String, VariableChange)>> =
|
||||||
.rev();
|
slopes.into_iter().rev();
|
||||||
delimited(
|
delimited(
|
||||||
char('{'),
|
char('{'),
|
||||||
alt(iter
|
alt(iter
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
Box::new(move |input: I| value(v, tag(k.as_str())).parse(input))
|
Box::new(move |input: I| value(v.clone(), tag(k.as_str())).parse(input))
|
||||||
as Box<dyn 's + Fn(I) -> IResult<I, &'s VariableChange>>
|
as Box<dyn Fn(I) -> IResult<I, VariableChange>>
|
||||||
})
|
})
|
||||||
.collect::<Vec<Box<dyn 's + Fn(I) -> IResult<I, &'s VariableChange>>>>()
|
.collect::<Vec<Box<dyn Fn(I) -> IResult<I, VariableChange>>>>()
|
||||||
.as_mut_slice())
|
.as_mut_slice())
|
||||||
.and(token_parser(parser)),
|
.and(token_parser(parser)),
|
||||||
char('}'),
|
char('}'),
|
||||||
)
|
)
|
||||||
.map(|(i, v)| Self(i, v))
|
.map(|(i, v)| Self::new(i, v))
|
||||||
.parse(input)
|
.parse(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will return the longest valid fasteval expression
|
/// Will return the longest valid fasteval expression
|
||||||
fn expression_parser<I: Input + AsRef<str> + Copy, C: Into<char> + Ord + Display>(
|
fn expression_parser<'v, I, V, C>(variables: V) -> impl 'v + Fn(I) -> IResult<I, Expression>
|
||||||
variables: &[C],
|
where
|
||||||
) -> impl Fn(I) -> IResult<I, Expression> {
|
I: Input + AsRef<str> + Copy,
|
||||||
|input: I| {
|
V: IntoIterator<Item = C>,
|
||||||
|
C: Borrow<char>,
|
||||||
|
{
|
||||||
|
let variables: Vec<(String, f64)> = variables
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| (v.borrow().to_string(), 0.0))
|
||||||
|
.collect();
|
||||||
|
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().parse::<Expression>().ok().and_then(|e| {
|
||||||
e.instruction
|
e.instruction
|
||||||
.eval(
|
.eval(
|
||||||
&e.slab,
|
&e.slab,
|
||||||
&mut BTreeMap::from_iter(variables.iter().map(|v| (v.to_string(), 0.0))),
|
&mut BTreeMap::from_iter(variables.clone().drain(..)),
|
||||||
)
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.is_some()
|
.is_some()
|
||||||
|
@ -261,9 +330,11 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::Parser;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use nom::{IResult, Parser};
|
use nom::{IResult, Parser as _};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compiler::{
|
compiler::{
|
||||||
|
@ -272,7 +343,31 @@ mod tests {
|
||||||
parser::expression_parser,
|
parser::expression_parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ParserBuilder;
|
fn very_fancy_slope() -> VariableChange {
|
||||||
|
VariableChange('n', "1+1".parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_slope() -> VariableChange {
|
||||||
|
VariableChange('n', "1".parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parser_generator() -> Parser<
|
||||||
|
[&'static str; 3],
|
||||||
|
&'static str,
|
||||||
|
HashMap<String, VariableChange>,
|
||||||
|
String,
|
||||||
|
VariableChange,
|
||||||
|
[char; 1],
|
||||||
|
> {
|
||||||
|
Parser::new(
|
||||||
|
["do", "ré", "mi"],
|
||||||
|
HashMap::from([
|
||||||
|
("nor".to_string(), very_fancy_slope()),
|
||||||
|
("normal".to_string(), normal_slope()),
|
||||||
|
]),
|
||||||
|
['n'],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_parser_test() {
|
fn expression_parser_test() {
|
||||||
|
@ -435,17 +530,9 @@ mod tests {
|
||||||
let slopes = Default::default();
|
let slopes = Default::default();
|
||||||
fn parser_builder<'s>(
|
fn parser_builder<'s>(
|
||||||
slopes: &'s HashMap<String, VariableChange>,
|
slopes: &'s HashMap<String, VariableChange>,
|
||||||
) -> impl Fn(&str) -> IResult<&str, Loop<'s>> {
|
) -> impl Fn(&str) -> IResult<&str, Loop> {
|
||||||
move |input: &str| {
|
move |input: &str| {
|
||||||
Loop::parser(
|
Loop::parser(&Parser::new(["do", "ré", "mi"], slopes, ['n'])).parse(input)
|
||||||
&ParserBuilder::create_empty()
|
|
||||||
.notes(&["do", "ré", "mi"])
|
|
||||||
.slopes(slopes)
|
|
||||||
.variables(&['n'])
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.parse(input)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let parser = parser_builder(&slopes);
|
let parser = parser_builder(&slopes);
|
||||||
|
@ -497,17 +584,9 @@ mod tests {
|
||||||
let slopes = Default::default();
|
let slopes = Default::default();
|
||||||
fn parser_builder<'s>(
|
fn parser_builder<'s>(
|
||||||
slopes: &'s HashMap<String, VariableChange>,
|
slopes: &'s HashMap<String, VariableChange>,
|
||||||
) -> impl Fn(&str) -> IResult<&str, Tuplet<'s>> {
|
) -> impl Fn(&str) -> IResult<&str, Tuplet> {
|
||||||
move |input: &str| {
|
move |input: &str| {
|
||||||
Tuplet::parser(
|
Tuplet::parser(&Parser::new(["do", "ré", "mi"], slopes, ['n'])).parse(input)
|
||||||
&ParserBuilder::create_empty()
|
|
||||||
.notes(&["do", "ré", "mi"])
|
|
||||||
.slopes(slopes)
|
|
||||||
.variables(&['n'])
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.parse(input)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let parser = parser_builder(&slopes);
|
let parser = parser_builder(&slopes);
|
||||||
|
@ -542,46 +621,30 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn slope() {
|
fn slope() {
|
||||||
let normal = || VariableChange('n', "1".parse().unwrap());
|
let p = parser_generator();
|
||||||
let very_fancy = || VariableChange('n', "1+1".parse().unwrap());
|
let parser_builder = || Slope::parser(&p);
|
||||||
let slopes = HashMap::from([
|
let parser = parser_builder();
|
||||||
("nor".to_string(), very_fancy()),
|
let normal_value = normal_slope();
|
||||||
("normal".to_string(), normal()),
|
let very_fancy_value = very_fancy_slope();
|
||||||
]);
|
|
||||||
fn parser_builder<'s>(
|
|
||||||
slopes: &'s HashMap<String, VariableChange>,
|
|
||||||
) -> impl Fn(&str) -> IResult<&str, Slope<'s>> {
|
|
||||||
move |input: &str| {
|
|
||||||
Slope::parser(
|
|
||||||
&ParserBuilder::create_empty()
|
|
||||||
.notes(&["do", "ré", "mi"])
|
|
||||||
.slopes(slopes)
|
|
||||||
.variables(&['n'])
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let parser = parser_builder(&slopes);
|
|
||||||
let normal_value = normal();
|
|
||||||
let very_fancy_value = very_fancy();
|
|
||||||
let mut working_cases = vec![
|
let mut working_cases = vec![
|
||||||
(
|
(
|
||||||
"{normal.%}",
|
"{normal.%}",
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
Slope(
|
Slope(
|
||||||
&normal_value,
|
normal_value.clone(),
|
||||||
TokenVec(vec![Box::new(Silence), Box::new(Marker)]),
|
TokenVec(vec![Box::new(Silence), Box::new(Marker)]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("{normal}", ("", Slope(&normal_value, TokenVec(vec![])))),
|
(
|
||||||
("{nor}", ("", Slope(&very_fancy_value, TokenVec(vec![])))),
|
"{normal}",
|
||||||
|
("", Slope(normal_value.clone(), TokenVec(vec![]))),
|
||||||
|
),
|
||||||
|
("{nor}", ("", Slope(very_fancy_value, TokenVec(vec![])))),
|
||||||
(
|
(
|
||||||
"{normal do}f",
|
"{normal do}f",
|
||||||
("f", Slope(&normal_value, TokenVec(vec![Box::new(Note(0))]))),
|
("f", Slope(normal_value, TokenVec(vec![Box::new(Note(0))]))),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
let mut not_working_cases = vec![
|
let mut not_working_cases = vec![
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue