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