move input to parsing time, loop parser test
This commit is contained in:
parent
1044ad9b1d
commit
28bd727090
2 changed files with 83 additions and 19 deletions
|
@ -6,7 +6,7 @@ use fasteval::{Compiler, Instruction, Slab};
|
||||||
|
|
||||||
#[derive(From, AsRef)]
|
#[derive(From, AsRef)]
|
||||||
#[cfg_attr(test, derive(Debug))]
|
#[cfg_attr(test, derive(Debug))]
|
||||||
pub struct TokenVec<'a>(Vec<Box<dyn Token + 'a>>);
|
pub struct TokenVec<'a>(pub(crate) Vec<Box<dyn Token + 'a>>);
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub trait Token {
|
pub trait Token {
|
||||||
|
@ -63,7 +63,7 @@ pub enum LoopCount {
|
||||||
|
|
||||||
impl Default for LoopCount {
|
impl Default for LoopCount {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LoopCount::Litteral(1)
|
LoopCount::Litteral(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,24 +26,26 @@ use crate::compiler::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Builder)]
|
#[derive(Builder)]
|
||||||
pub struct Parser<'i, 'n, 's, 'v, N: AsRef<str> + Clone> {
|
pub struct Parser<'n, 's, 'v, N: AsRef<str> + Clone> {
|
||||||
input: &'i str,
|
|
||||||
notes: &'n [N],
|
notes: &'n [N],
|
||||||
slopes: &'s HashMap<String, VariableChange>,
|
slopes: &'s HashMap<String, VariableChange>,
|
||||||
variables: &'v [char],
|
variables: &'v [char],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i, 's, N: AsRef<str> + Clone> Parser<'i, '_, 's, '_, N> {
|
impl<'a, 's, N: AsRef<str> + Clone> Parser<'_, 's, '_, N> {
|
||||||
pub fn parse_all(&self) -> Result<TokenVec<'s>, Error<nom_locate::LocatedSpan<&'i str>>> {
|
pub fn parse_all(
|
||||||
|
&self,
|
||||||
|
input: &'a str,
|
||||||
|
) -> Result<TokenVec<'s>, Error<nom_locate::LocatedSpan<&'a str>>> {
|
||||||
token_parser(self)
|
token_parser(self)
|
||||||
.parse_complete(LocatedSpan::new(self.input))
|
.parse_complete(LocatedSpan::new(input))
|
||||||
.finish()
|
.finish()
|
||||||
.map(|(_, o)| o)
|
.map(|(_, o)| o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_parser<'a, 's, I, N>(
|
fn token_parser<'a, 's, I, N>(
|
||||||
parser: &Parser<'_, '_, 's, '_, N>,
|
parser: &Parser<'_, 's, '_, N>,
|
||||||
) -> impl NomParser<I, Output = TokenVec<'s>, Error = nom::error::Error<I>>
|
) -> impl NomParser<I, Output = TokenVec<'s>, 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,
|
||||||
|
@ -139,9 +141,7 @@ impl VariableChange {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Loop<'s> {
|
impl<'s> Loop<'s> {
|
||||||
fn parser<'i, 'n, 'v, I, N>(
|
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
||||||
parser: &Parser<'i, 'n, 's, 'v, N>,
|
|
||||||
) -> 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,
|
||||||
|
@ -165,9 +165,7 @@ impl<'s> Loop<'s> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Tuplet<'s> {
|
impl<'s> Tuplet<'s> {
|
||||||
fn parser<'i, 'n, 'v, I, N>(
|
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
||||||
parser: &Parser<'i, 'n, 's, 'v, N>,
|
|
||||||
) -> 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,
|
||||||
|
@ -183,9 +181,7 @@ impl<'s> Tuplet<'s> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Slope<'s> {
|
impl<'s> Slope<'s> {
|
||||||
fn parser<'i, 'n, 'v, I, N>(
|
fn parser<'n, 'v, I, N>(parser: &Parser<'n, 's, 'v, N>) -> impl Fn(I) -> IResult<I, Self>
|
||||||
parser: &Parser<'i, 'n, 's, 'v, N>,
|
|
||||||
) -> 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,
|
||||||
|
@ -257,13 +253,19 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use nom::Parser;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use nom::{IResult, Parser};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compiler::{Marker, Note, Silence, VariableChange},
|
compiler::{
|
||||||
|
Loop, LoopCount, Marker, Note, Silence, Slope, Token, TokenVec, VariableChange,
|
||||||
|
},
|
||||||
parser::expression_parser,
|
parser::expression_parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::ParserBuilder;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_parser_test() {
|
fn expression_parser_test() {
|
||||||
let parser = expression_parser(&['x']);
|
let parser = expression_parser(&['x']);
|
||||||
|
@ -419,4 +421,66 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn r#loop() {
|
||||||
|
let slopes = Default::default();
|
||||||
|
fn parser_builder<'s>(
|
||||||
|
slopes: &'s HashMap<String, VariableChange>,
|
||||||
|
) -> impl Fn(&str) -> IResult<&str, Loop<'s>> {
|
||||||
|
move |input: &str| {
|
||||||
|
Loop::parser(
|
||||||
|
&ParserBuilder::create_empty()
|
||||||
|
.notes(&["do", "ré", "mi"])
|
||||||
|
.slopes(slopes)
|
||||||
|
.variables(&['n'])
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.parse(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let parser = parser_builder(&slopes);
|
||||||
|
let mut working_cases = vec![
|
||||||
|
(
|
||||||
|
"(.%)",
|
||||||
|
(
|
||||||
|
"",
|
||||||
|
Loop(
|
||||||
|
LoopCount::Litteral(2),
|
||||||
|
TokenVec(vec![Box::new(Silence), Box::new(Marker)]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("()", ("", Loop(LoopCount::Litteral(2), TokenVec(vec![])))),
|
||||||
|
("(4)", ("", Loop(LoopCount::Litteral(4), TokenVec(vec![])))),
|
||||||
|
(
|
||||||
|
"(n)",
|
||||||
|
("", Loop(LoopCount::Variable('n'), TokenVec(vec![]))),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"(ndo)",
|
||||||
|
(
|
||||||
|
"",
|
||||||
|
Loop(LoopCount::Variable('n'), TokenVec(vec![Box::new(Note(0))])),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
let mut not_working_cases = vec!["", "(", ")", "(2", "(p)"];
|
||||||
|
for (test, expected) in working_cases.drain(..) {
|
||||||
|
let output = parser(test);
|
||||||
|
if let Ok(result) = output {
|
||||||
|
assert_eq!(expected, result, "case \"{test}\"");
|
||||||
|
} else {
|
||||||
|
panic!("result of \"{test}\" was not Ok: {output:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for test in not_working_cases.drain(..) {
|
||||||
|
let output = parser(test);
|
||||||
|
assert!(
|
||||||
|
output.is_err(),
|
||||||
|
"result of \"{test}\" was not Err: {output:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue