loop, clippy :D

This commit is contained in:
Breval Ferrari 2025-05-20 18:58:39 +02:00
parent 6cb3633cd1
commit cfdcc50973
2 changed files with 85 additions and 59 deletions

View file

@ -35,7 +35,18 @@ pub struct VariableChange(pub char, pub Expression);
impl Token for VariableChange {}
#[cfg_attr(debug_assertions, derive(Default))]
pub struct Loop(pub usize, pub TokenVec);
pub struct Loop(pub LoopCount, pub TokenVec);
pub enum LoopCount {
Litteral(usize),
Variable(char),
}
impl Default for LoopCount {
fn default() -> Self {
LoopCount::Litteral(1)
}
}
impl Token for Loop {}

View file

@ -6,66 +6,67 @@ use std::{
use derive_builder::Builder;
use fasteval::Evaler;
use nom::{
AsBytes, AsChar, Compare, FindToken, Finish, IResult, Input, Offset, Parser as NomParser,
Finish, IResult, Input, Parser as NomParser,
branch::alt,
bytes::complete::{tag, take, take_till},
character::{
complete::{char, space1},
complete::{char, space1, usize},
streaming::one_of,
},
combinator::value,
combinator::{opt, value},
error::{Error, ErrorKind},
multi::many0,
sequence::{delimited, preceded},
};
use nom_locate::LocatedSpan;
use crate::compiler::{Expression, Marker, Note, Silence, Token, VariableChange};
pub struct ParserParametters<'n, 's, 'v, I: Input + Clone + Compare<I>, C: Into<char>> {
pub notes: &'n [I],
pub slopes: &'s HashMap<I, VariableChange>,
pub variables: &'v [C],
}
use crate::compiler::{Expression, Loop, LoopCount, Marker, Note, Silence, Token, VariableChange};
#[derive(Builder)]
pub struct Parser<'i, 'n, 's, 'v, C: Into<char>> {
pub struct Parser<'i, 'n, 's, 'v> {
input: &'i str,
notes: &'n [String],
slopes: &'s HashMap<String, VariableChange>,
variables: &'v [C],
variables: &'v [char],
}
impl<'i, 'n, 's, 'v, C> Parser<'i, 'n, 's, 'v, C>
where
C: Into<char> + Clone + Ord + Display,
&'v [C]: FindToken<char>,
{
impl<'i, 'n, 's, 'v> Parser<'i, 'n, 's, 'v> {
pub fn parse_all(
&self,
) -> Result<Vec<Box<dyn Token>>, Error<nom_locate::LocatedSpan<&'i str>>> {
let space_or_comment = || {
value(
(),
many0(value((), char('#').and(take_till(|c| c == '\n'))).or(value((), space1))),
)
};
many0(delimited(
space_or_comment(),
alt((
Silence::parser().map(into_box),
Marker::parser().map(into_box),
Note::parser(self.notes).map(into_box),
VariableChange::parser::<LocatedSpan<&'i str>, C>(self.variables).map(into_box),
)),
space_or_comment(),
))
.parse_complete(LocatedSpan::new(self.input))
.finish()
.map(|(_, o)| o)
token_parser(self)
.parse_complete(LocatedSpan::new(self.input))
.finish()
.map(|(_, o)| o)
}
}
fn token_parser<'a, 'i, 'n, 's, 'v>(
parser: &Parser,
) -> impl NomParser<
LocatedSpan<&'a str>,
Output = Vec<Box<dyn Token>>,
Error = nom::error::Error<LocatedSpan<&'a str>>,
> {
let space_or_comment = || {
value(
(),
many0(value((), char('#').and(take_till(|c| c == '\n'))).or(value((), space1))),
)
};
many0(delimited(
space_or_comment(),
alt((
Silence::parser().map(into_box),
Marker::parser().map(into_box),
Note::parser(parser.notes).map(into_box),
VariableChange::parser(parser.variables).map(into_box),
Loop::parser(parser).map(into_box),
)),
space_or_comment(),
))
}
fn into_box(token: impl Token + 'static) -> Box<dyn Token> {
Box::new(token)
}
@ -107,7 +108,7 @@ impl Note {
.enumerate()
.map(|(i, t)| {
Box::new(move |input: LocatedSpan<&'a str>| {
value(Note(i.clone() as u8), tag(t.clone().as_str())).parse(input)
value(Note(i as u8), tag(t.clone().as_str())).parse(input)
})
as Box<dyn Fn(LocatedSpan<&'a str>) -> TokenResult<'a, Self>>
})
@ -118,13 +119,9 @@ impl Note {
}
impl VariableChange {
fn parser<'c, I: Input + AsBytes + Offset, C: Into<char> + Clone + Ord + Display>(
variables: &'c [C],
) -> impl for<'a> Fn(LocatedSpan<&'a str>) -> TokenResult<'a, Self>
where
<I as Input>::Item: AsChar,
&'c [C]: FindToken<char>,
{
fn parser(
variables: &[char],
) -> impl for<'a> Fn(LocatedSpan<&'a str>) -> TokenResult<'a, Self> {
move |i: LocatedSpan<&str>| {
preceded(char('$'), one_of(variables))
.and(expression_parser(variables))
@ -134,15 +131,35 @@ impl VariableChange {
}
}
impl Loop {
fn parser<'a, 'i, 'n, 's, 'v>(
parser: &Parser<'i, 'n, 's, 'v>,
) -> impl Fn(LocatedSpan<&str>) -> TokenResult<Loop> {
|input| {
delimited(
char('('),
opt(alt((
usize.map(LoopCount::Litteral),
one_of(parser.variables).map(LoopCount::Variable),
)))
.and(token_parser(parser)),
char(')'),
)
.map(|(c, v)| Self(c.unwrap_or_default(), v))
.parse(input)
}
}
}
/// Will return the longest valid fasteval expression
fn expression_parser<'c, C: Into<char> + Ord + Display>(
variables: &'c [C],
fn expression_parser<C: Into<char> + Ord + Display>(
variables: &[C],
) -> impl Fn(LocatedSpan<&str>) -> TokenResult<Expression> {
move |input: LocatedSpan<&str>| {
let mut end_index = 0;
let mut current_expression = None;
while input.input_len() > end_index {
if let Some(e) = (&input[..end_index + 1])
if let Some(e) = input[..end_index + 1]
.parse::<Expression>()
.ok()
.and_then(|e| {
@ -150,7 +167,7 @@ fn expression_parser<'c, C: Into<char> + Ord + Display>(
.eval(
&e.slab,
&mut BTreeMap::from_iter(
variables.into_iter().map(|v| (v.to_string(), 0.0)),
variables.iter().map(|v| (v.to_string(), 0.0)),
),
)
.ok()
@ -160,15 +177,13 @@ fn expression_parser<'c, C: Into<char> + Ord + Display>(
{
current_expression = Some(e);
end_index += 1;
} else if let Some(e) = current_expression {
return take(end_index).parse(input).map(move |(r, _)| (r, e));
} else {
if let Some(e) = current_expression {
return take(end_index).parse(input).map(move |(r, _)| (r, e));
} else {
return Err(nom::Err::Failure(nom::error::Error::new(
input,
ErrorKind::Satisfy,
)));
}
return Err(nom::Err::Failure(nom::error::Error::new(
input,
ErrorKind::Satisfy,
)));
}
}
if let Some(e) = current_expression {
@ -208,12 +223,12 @@ mod tests {
for test in working_test_cases.drain(..) {
let output = parser(LocatedSpan::new(test));
assert!(matches!(output, Ok(_)), "result was not Ok: {output:?}");
assert!(output.is_ok(), "result was not Ok: {output:?}");
}
for test in not_working_test_cases.drain(..) {
let output = parser(LocatedSpan::new(test));
assert!(matches!(output, Err(_)), "result was not Err: {output:?}");
assert!(output.is_err(), "result was not Err: {output:?}");
}
}
}