From 900b8b198e51f6e7126bec1ecf86c6c38005312c Mon Sep 17 00:00:00 2001 From: p6nj Date: Sat, 9 Nov 2024 18:39:28 -0500 Subject: [PATCH 1/2] move things around, add curry --- Cargo.toml | 1 + src/bng/score.rs | 1 - src/bng/score/de.rs | 33 +++++++++++---------------------- src/bng/score/lex/lexer.rs | 26 +++++++++++++++++++++++--- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5c9009e..7aceef6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ bng_macros = { path = "bng_macros" } const_format = "0.2.33" thiserror = "1.0.64" derive-new = "0.7.0" +naan = "0.1.32" [features] default = ["play", "save"] diff --git a/src/bng/score.rs b/src/bng/score.rs index df2b65b..6a4a68e 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -8,7 +8,6 @@ use anyhow::Context; use bng_macros::{ModifierParser, QuickModifierParser, SlopeModifierParser}; use derive_new::new; use derived_deref::Deref; -use lex::lexer::atom; use nom::{ branch::alt, character::{complete::char, streaming::one_of}, diff --git a/src/bng/score/de.rs b/src/bng/score/de.rs index 11526fd..9756e9b 100644 --- a/src/bng/score/de.rs +++ b/src/bng/score/de.rs @@ -1,9 +1,11 @@ use std::{ fmt::{Debug, Display}, num::TryFromIntError, + ops::Deref, }; use derive_new::new; +use naan::fun::{F1Once, F2Once}; use nom::{ character::complete::one_of, combinator::all_consuming, @@ -18,7 +20,7 @@ use serde::{ }; use thiserror::Error; -use crate::bng::score::lex::lexer::atom; +use crate::bng::score::lex::lexer::root; use super::{ utils::{inflate, InflateError}, @@ -54,11 +56,7 @@ impl<'de> Deserialize<'de> for Atoms { Ok(Default::default()) } else { root(&sheet, ¬es) - .map_err(|e: nom::Err>| 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(|e| pretty_verbose_err.curry().call1(sheet.as_str()).call1(e)) .map_err(AtomsSerializeError::Parsing) .map_err(de::Error::custom) .and_then(|(_, v)| { @@ -71,22 +69,13 @@ impl<'de> Deserialize<'de> for Atoms { } } -fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec, E> +fn pretty_verbose_err(input: I, e: nom::Err>) -> String where - E: nom::error::ParseError<&'a str> + ContextError<&'a str>, + I: Deref, { - context("yml white space", many0(one_of(" \t\r\n"))) -} - -fn root<'a, E>(i: &'a str, notes: &'a str) -> IResult<&'a str, Vec, E> -where - E: ParseError<&'a str> - + ContextError<&'a str> - + FromExternalError<&'a str, TryFromIntError> - + FromExternalError<&'a str, E>, -{ - all_consuming(terminated( - many1(preceded(maybe_yml_str_space(), atom(notes))), - maybe_yml_str_space(), - ))(i) + 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(input, e), + } } diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index aa98244..ab0a316 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -9,9 +9,9 @@ use nom::{ branch::alt, bytes::complete::{take_till, take_till1}, character::complete::{anychar, char, one_of, space1, u16, u8}, - combinator::{map_opt, map_res, opt, value, verify}, + combinator::{all_consuming, map_opt, map_res, opt, value, verify}, error::{context, ContextError, ErrorKind, FromExternalError, ParseError}, - multi::many0, + multi::{many0, many1}, sequence::{delimited, pair, preceded, separated_pair, terminated}, Err, IResult, Parser, }; @@ -25,7 +25,27 @@ use super::{ #[cfg(test)] mod tests; -pub fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> +fn maybe_yml_str_space<'a, E>() -> impl Parser<&'a str, Vec, E> +where + E: nom::error::ParseError<&'a str> + ContextError<&'a str>, +{ + context("yml white space", many0(one_of(" \t\r\n"))) +} + +pub fn root<'a, E>(i: &'a str, notes: &'a str) -> IResult<&'a str, Vec, E> +where + E: ParseError<&'a str> + + ContextError<&'a str> + + FromExternalError<&'a str, TryFromIntError> + + FromExternalError<&'a str, E>, +{ + all_consuming(terminated( + many1(preceded(maybe_yml_str_space(), atom(notes))), + maybe_yml_str_space(), + ))(i) +} + +fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> where E: ParseError<&'a str> + ContextError<&'a str> From 9c910b80764e9450c026de14455a0fc926d8c7b4 Mon Sep 17 00:00:00 2001 From: p6nj Date: Sat, 9 Nov 2024 18:58:28 -0500 Subject: [PATCH 2/2] divide atom parser into sub-parsers with context --- src/bng/score/lex/lexer.rs | 205 +++++++++++++++++++++++++++++-------- 1 file changed, 160 insertions(+), 45 deletions(-) diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index ab0a316..45bf7ad 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -16,8 +16,6 @@ use nom::{ Err, IResult, Parser, }; -use crate::bng::score::{modifier, quick_modifier, slope_modifier}; - use super::{ super::super::Expression as Instruction, Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier, }; @@ -45,6 +43,154 @@ where ))(i) } +fn note<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str> + FromExternalError<&'a str, TryFromIntError>, +{ + context( + "note", + map_res(map_opt(one_of(notes), |c| notes.find(c)), u8::try_from).map(FlatAtom::Note), + ) +} + +fn rest<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context("rest", value(FlatAtom::Rest, char(Atom::REST)))(i) +} + +fn start_here<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "start_here", + value(FlatAtom::StartHere, char(Atom::START_HERE)), + )(i) +} + +fn modifier<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + use super::super::modifier; + context( + "modifier", + preceded(char(Atom::MODIFIER), modifier).map(FlatAtom::Modifier), + )(i) +} + +fn quick_modifier<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + use super::super::quick_modifier; + context( + "quick_modifier", + quick_modifier.map(FlatAtom::QuickModifier), + )(i) +} + +fn loop_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "loop_starts", + preceded( + char(Atom::LOOP.0), + map_opt(opt(u8), |n| { + if let Some(n) = n { + NonZeroU8::new(n) + } else { + unsafe { Some(NonZeroU8::new_unchecked(2)) } + } + }), + ) + .map(FlatAtom::LoopStarts), + )(i) +} + +fn loop_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context("loop_ends", value(FlatAtom::LoopEnds, char(Atom::LOOP.1)))(i) +} + +fn tuple_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "tuple_starts", + value(FlatAtom::TupleStarts, char(Atom::TUPLE.0)), + )(i) +} + +fn tuple_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "tuple_ends", + value(FlatAtom::TupleEnds, char(Atom::TUPLE.1)), + )(i) +} + +fn slope_starts<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str> + FromExternalError<&'a str, E>, +{ + use super::super::slope_modifier; + context( + "slope_starts", + terminated( + preceded( + char(Atom::SLOPE.0), + separated_pair( + slope_modifier, + char(' '), + map_res(take_till1(|c| c == ','), |s: &str| { + s.parse() + .map_err(|_| E::from_error_kind(s, ErrorKind::Verify)) + }), + ), + ), + char(','), + ) + .map(|(sm, i)| FlatAtom::SlopeStarts(sm, i)), + )(i) +} + +fn slope_ends<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "slope_ends", + value(FlatAtom::SlopeEnds, char(Atom::SLOPE.1)), + )(i) +} + +fn comment<'a, E>(i: &'a str) -> IResult<&'a str, FlatAtom, E> +where + E: ParseError<&'a str> + ContextError<&'a str>, +{ + context( + "comment", + value( + FlatAtom::Comment, + delimited( + char(Atom::COMMENT.0), + take_till(|c| c == Atom::COMMENT.1), + char(Atom::COMMENT.1), + ), + ), + )(i) +} + fn atom<'a, E>(notes: &'a str) -> impl Parser<&'a str, FlatAtom, E> where E: ParseError<&'a str> @@ -55,49 +201,18 @@ where context( "atom", alt(( - 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::StartHere, char(Atom::START_HERE)), - preceded(char(Atom::MODIFIER), modifier).map(FlatAtom::Modifier), - quick_modifier.map(FlatAtom::QuickModifier), - preceded( - char(Atom::LOOP.0), - map_opt(opt(u8), |n| { - if let Some(n) = n { - NonZeroU8::new(n) - } else { - unsafe { Some(NonZeroU8::new_unchecked(2)) } - } - }), - ) - .map(FlatAtom::LoopStarts), - value(FlatAtom::LoopEnds, char(Atom::LOOP.1)), - value(FlatAtom::TupleStarts, char(Atom::TUPLE.0)), - value(FlatAtom::TupleEnds, char(Atom::TUPLE.1)), - terminated( - preceded( - char(Atom::SLOPE.0), - separated_pair( - slope_modifier, - char(' '), - map_res(take_till1(|c| c == ','), |s: &str| { - s.parse() - .map_err(|_| E::from_error_kind(s, ErrorKind::Verify)) - }), - ), - ), - char(','), - ) - .map(|(sm, i)| FlatAtom::SlopeStarts(sm, i)), - value(FlatAtom::SlopeEnds, char(Atom::SLOPE.1)), - value( - FlatAtom::Comment, - delimited( - char(Atom::COMMENT.0), - take_till(|c| c == Atom::COMMENT.1), - char(Atom::COMMENT.1), - ), - ), + note(notes), + rest, + start_here, + modifier, + quick_modifier, + loop_starts, + loop_ends, + tuple_starts, + tuple_ends, + slope_starts, + slope_ends, + comment, )), ) }