verbose error support
This commit is contained in:
parent
a2566f1be3
commit
bdb42ac846
4 changed files with 120 additions and 125 deletions
46
poc/poc.yml
46
poc/poc.yml
|
@ -15,7 +15,7 @@ channels:
|
||||||
instr: sine
|
instr: sine
|
||||||
score:
|
score:
|
||||||
notes: cCdDefFgGaAb
|
notes: cCdDefFgGaAb
|
||||||
sheet:
|
sheet: |
|
||||||
aabc.
|
aabc.
|
||||||
'ab°A
|
'ab°A
|
||||||
+d+d+d---
|
+d+d+d---
|
||||||
|
@ -28,24 +28,26 @@ channels:
|
||||||
[ffe]
|
[ffe]
|
||||||
{l 1-cos((PI*x)/2),acced}
|
{l 1-cos((PI*x)/2),acced}
|
||||||
abbc!o5cc!v15feed!l4fedd!t60Gdd
|
abbc!o5cc!v15feed!l4fedd!t60Gdd
|
||||||
# rest: .
|
|
||||||
# pizz.: '°
|
; syntax :
|
||||||
# volume: +-
|
rest: .
|
||||||
# length: /\
|
pizz.: '°
|
||||||
# octave: ><
|
volume: +-
|
||||||
# comment?: ;,
|
length: /\
|
||||||
# start here: ':'
|
octave: ><
|
||||||
# slope: {MODIFIER EXPR, score}
|
comment?: ;,
|
||||||
# note modifier prefix: n
|
start here: ':'
|
||||||
# volume modifier prefix: v
|
slope: {MODIFIER EXPR, score}
|
||||||
# octave modifier prefix: o
|
note modifier prefix: n
|
||||||
# length modifier prefix: l
|
volume modifier prefix: v
|
||||||
# tempo modifier prefix: t
|
octave modifier prefix: o
|
||||||
# loop: ()
|
length modifier prefix: l
|
||||||
# loop with count: (COUNT, score)
|
tempo modifier prefix: t
|
||||||
# tuple: []
|
loop: ()
|
||||||
# modifier: !
|
loop with count: (COUNT, score)
|
||||||
# volume modifier prefix: v
|
tuple: []
|
||||||
# octave modifier prefix: o
|
modifier: !
|
||||||
# length modifier prefix: l
|
volume modifier prefix: v
|
||||||
# tempo modifier prefix: t
|
octave modifier prefix: o
|
||||||
|
length modifier prefix: l
|
||||||
|
tempo modifier prefix: t,
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use nom::{
|
use nom::{
|
||||||
character::complete::one_of,
|
character::complete::one_of,
|
||||||
combinator::all_consuming,
|
combinator::all_consuming,
|
||||||
|
error::{context, convert_error, ContextError, ParseError, VerboseError},
|
||||||
multi::{many0, many1},
|
multi::{many0, many1},
|
||||||
sequence::{preceded, terminated},
|
sequence::{preceded, terminated},
|
||||||
Parser,
|
Needed, Parser,
|
||||||
};
|
};
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{self, Deserializer, Visitor},
|
de::{self, Deserializer, Visitor},
|
||||||
|
@ -21,29 +24,12 @@ use super::{
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
enum AtomsSerializeError {
|
enum AtomsSerializeError {
|
||||||
#[error("sheet parsing error: {0}")]
|
#[error("sheet parsing error:\n{0}")]
|
||||||
Parsing(String),
|
Parsing(String),
|
||||||
#[error("sheet semantics: {0}")]
|
#[error("sheet semantics: {0}")]
|
||||||
Inflation(#[from] InflateError),
|
Inflation(#[from] InflateError),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nom_err_message(e: nom::Err<nom::error::Error<&str>>) -> String {
|
|
||||||
match e {
|
|
||||||
nom::Err::Incomplete(needed) => format!(
|
|
||||||
"input is incomplete, needed {} byte(s) more",
|
|
||||||
match needed {
|
|
||||||
nom::Needed::Unknown => "?".to_string(),
|
|
||||||
nom::Needed::Size(s) => s.to_string(),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
nom::Err::Error(e) | nom::Err::Failure(e) => format!(
|
|
||||||
"got error code {code:#?} at \"{input}\"",
|
|
||||||
code = e.code,
|
|
||||||
input = e.input
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Atoms {
|
impl<'de> Deserialize<'de> for Atoms {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -64,31 +50,15 @@ impl<'de> Deserialize<'de> for Atoms {
|
||||||
if sheet.is_empty() {
|
if sheet.is_empty() {
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
} else {
|
} else {
|
||||||
atom_mapper::<D, _>(&sheet, atom(¬es))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec<char>, E>
|
|
||||||
where
|
|
||||||
E: nom::error::ParseError<&'a str>,
|
|
||||||
{
|
|
||||||
many0(one_of(" \t\r"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn atom_mapper<'a, 'de, D, P>(
|
|
||||||
input: &'a str,
|
|
||||||
parser: P,
|
|
||||||
) -> Result<Atoms, <D as Deserializer<'de>>::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
P: Parser<&'a str, FlatAtom, nom::error::Error<&'a str>>,
|
|
||||||
{
|
|
||||||
all_consuming(terminated(
|
all_consuming(terminated(
|
||||||
many1(preceded(maybe_yml_str_space(), parser)),
|
many1(preceded(maybe_yml_str_space(), atom(¬es))),
|
||||||
maybe_yml_str_space(),
|
maybe_yml_str_space(),
|
||||||
))(input)
|
))(&sheet)
|
||||||
.map_err(nom_err_message)
|
.map_err(|e: nom::Err<VerboseError<&str>>| match e {
|
||||||
|
nom::Err::Incomplete(Needed::Unknown) => "needed some more bytes".to_string(),
|
||||||
|
nom::Err::Incomplete(Needed::Size(n)) => format!("needed {} more bytes", n),
|
||||||
|
nom::Err::Error(e) | nom::Err::Failure(e) => convert_error(sheet.as_str(), e),
|
||||||
|
})
|
||||||
.map_err(AtomsSerializeError::Parsing)
|
.map_err(AtomsSerializeError::Parsing)
|
||||||
.map_err(de::Error::custom)
|
.map_err(de::Error::custom)
|
||||||
.and_then(|(_, v)| {
|
.and_then(|(_, v)| {
|
||||||
|
@ -98,3 +68,12 @@ where
|
||||||
})
|
})
|
||||||
.map(Atoms)
|
.map(Atoms)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec<char>, E>
|
||||||
|
where
|
||||||
|
E: nom::error::ParseError<&'a str> + ContextError<&'a str>,
|
||||||
|
{
|
||||||
|
context("yml white space", many0(one_of(" \t\r\n")))
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
num::{NonZeroU16, NonZeroU8},
|
num::{NonZeroU16, NonZeroU8, TryFromIntError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::builder::TypedValueParser;
|
use clap::builder::TypedValueParser;
|
||||||
|
@ -10,7 +10,7 @@ use nom::{
|
||||||
bytes::complete::{take_till, take_till1},
|
bytes::complete::{take_till, take_till1},
|
||||||
character::complete::{anychar, char, one_of, space1, u16, u8},
|
character::complete::{anychar, char, one_of, space1, u16, u8},
|
||||||
combinator::{map_opt, map_res, opt, value, verify},
|
combinator::{map_opt, map_res, opt, value, verify},
|
||||||
error::{context, ContextError, ParseError},
|
error::{context, ContextError, ErrorKind, FromExternalError, ParseError},
|
||||||
multi::many0,
|
multi::many0,
|
||||||
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
||||||
Err, IResult, Parser,
|
Err, IResult, Parser,
|
||||||
|
@ -25,7 +25,15 @@ use super::{
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub fn atom(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>> {
|
pub fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E>
|
||||||
|
where
|
||||||
|
E: ParseError<&'a str>
|
||||||
|
+ ContextError<&'a str>
|
||||||
|
+ FromExternalError<&'a str, TryFromIntError>
|
||||||
|
+ FromExternalError<&'a str, E>,
|
||||||
|
{
|
||||||
|
context(
|
||||||
|
"atom",
|
||||||
alt((
|
alt((
|
||||||
map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).map(FlatAtom::Note),
|
map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).map(FlatAtom::Note),
|
||||||
value(FlatAtom::Rest, char(Atom::REST)),
|
value(FlatAtom::Rest, char(Atom::REST)),
|
||||||
|
@ -54,7 +62,7 @@ pub fn atom(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>>
|
||||||
char(' '),
|
char(' '),
|
||||||
map_res(take_till1(|c| c == ','), |s: &str| {
|
map_res(take_till1(|c| c == ','), |s: &str| {
|
||||||
s.parse()
|
s.parse()
|
||||||
.map_err(|_| nom::error::Error::new(s, nom::error::ErrorKind::Verify))
|
.map_err(|_| E::from_error_kind(s, ErrorKind::Verify))
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -70,5 +78,6 @@ pub fn atom(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Error<&str>>
|
||||||
char(Atom::COMMENT.1),
|
char(Atom::COMMENT.1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
))
|
)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ mod flat_atom {
|
||||||
fn note() {
|
fn note() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::Note(2))),
|
Ok((SAMPLE_STR, FlatAtom::Note(2))),
|
||||||
atom("abcdefg").parse(concatcp!('c', SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!('c', SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ mod flat_atom {
|
||||||
fn rest() {
|
fn rest() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::Rest)),
|
Ok((SAMPLE_STR, FlatAtom::Rest)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::REST, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ mod flat_atom {
|
||||||
fn start_here() {
|
fn start_here() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::StartHere)),
|
Ok((SAMPLE_STR, FlatAtom::StartHere)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::START_HERE, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,12 @@ mod flat_atom {
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) }))
|
FlatAtom::Modifier(Modifier::Length(unsafe { NonZeroU8::new_unchecked(2) }))
|
||||||
)),
|
)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::MODIFIER, Modifier::LENGTH, 2u8, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(
|
||||||
|
Atom::MODIFIER,
|
||||||
|
Modifier::LENGTH,
|
||||||
|
2u8,
|
||||||
|
SAMPLE_STR
|
||||||
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +78,7 @@ mod flat_atom {
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
FlatAtom::QuickModifier(QuickModifier::Length(UP))
|
FlatAtom::QuickModifier(QuickModifier::Length(UP))
|
||||||
)),
|
)),
|
||||||
atom("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(QuickModifier::LENGTH.0, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,14 +89,14 @@ mod flat_atom {
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) })
|
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(3) })
|
||||||
)),
|
)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, 3u8, SAMPLE_STR))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((
|
Ok((
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) })
|
FlatAtom::LoopStarts(unsafe { NonZeroU8::new_unchecked(2) })
|
||||||
)),
|
)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.0, SAMPLE_STR))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(nom::Err::Error(Error::new(
|
Err(nom::Err::Error(Error::new(
|
||||||
|
@ -106,7 +111,7 @@ mod flat_atom {
|
||||||
fn loop_ends() {
|
fn loop_ends() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::LoopEnds)),
|
Ok((SAMPLE_STR, FlatAtom::LoopEnds)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::LOOP.1, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +119,7 @@ mod flat_atom {
|
||||||
fn tuple_starts() {
|
fn tuple_starts() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::TupleStarts)),
|
Ok((SAMPLE_STR, FlatAtom::TupleStarts)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.0, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +127,7 @@ mod flat_atom {
|
||||||
fn tuple_ends() {
|
fn tuple_ends() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::TupleEnds)),
|
Ok((SAMPLE_STR, FlatAtom::TupleEnds)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::TUPLE.1, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +138,7 @@ mod flat_atom {
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap())
|
FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap())
|
||||||
)),
|
)),
|
||||||
atom("abcdefg").parse(concatcp!(
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(
|
||||||
Atom::SLOPE.0,
|
Atom::SLOPE.0,
|
||||||
SlopeModifier::NOTE,
|
SlopeModifier::NOTE,
|
||||||
' ',
|
' ',
|
||||||
|
@ -148,7 +153,7 @@ mod flat_atom {
|
||||||
fn slope_ends() {
|
fn slope_ends() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::SlopeEnds)),
|
Ok((SAMPLE_STR, FlatAtom::SlopeEnds)),
|
||||||
atom("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR))
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(Atom::SLOPE.1, SAMPLE_STR))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +161,7 @@ mod flat_atom {
|
||||||
fn comment() {
|
fn comment() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((SAMPLE_STR, FlatAtom::Comment)),
|
Ok((SAMPLE_STR, FlatAtom::Comment)),
|
||||||
atom("abcdefg").parse(concatcp!(
|
atom::<Error<&str>>("abcdefg").parse(concatcp!(
|
||||||
Atom::COMMENT.0,
|
Atom::COMMENT.0,
|
||||||
"hi I'm a little pony",
|
"hi I'm a little pony",
|
||||||
SAMPLE_STR,
|
SAMPLE_STR,
|
||||||
|
|
Loading…
Reference in a new issue