diff options
Diffstat (limited to 'melib/src/parsec.rs')
-rw-r--r-- | melib/src/parsec.rs | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/melib/src/parsec.rs b/melib/src/parsec.rs index 8eebf608..c4205b19 100644 --- a/melib/src/parsec.rs +++ b/melib/src/parsec.rs @@ -267,6 +267,76 @@ where } } +pub fn pairmutation<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2)> +where + P1: Parser<'a, R1>, + P2: Parser<'a, R2>, +{ + move |input| { + if let ok @ Ok(_) = parser1.parse(input).and_then(|(next_input, result1)| { + parser2 + .parse(next_input) + .map(|(last_input, result2)| (last_input, (result1, result2))) + }) { + return ok; + } + parser2.parse(input).and_then(|(next_input, result1)| { + parser1 + .parse(next_input) + .map(|(last_input, result2)| (last_input, (result2, result1))) + }) + } +} + +#[macro_export] +macro_rules! permutation { + ($input:expr, $($field:tt, $t:ty, $parser:expr),*) => {{ + 'perm: { + struct PermStruct { + $($field: Option<$t>),* + } + let mut results = PermStruct { + $($field: None),* + }; + let mut input = $input; + let mut left = 0; + $(_ = &$parser; left += 1;)* + let mut count = 1; + let mut finished = 0; + loop { + let mut any_success = false; + $(if results.$field.is_none() { + if let Ok((rest, res)) = $parser.parse(input) { + if !matches!(res, None) || count > left { + results.$field = Some(res); + finished += 1; + count = 1; + input = rest; + } + any_success = true; + } + })* + count += 1; + + if !any_success { + break 'perm Err(input); + } + if finished == left || count >= 2*left { + break; + } + + } + if finished != left { + break 'perm Err(input); + } + let PermStruct { + $($field),* + } = results; + Ok((input, ($($field.unwrap()),*))) + } + }} +} + pub fn prefix<'a, PN, P, R, RN>(pre: PN, parser: P) -> impl Parser<'a, R> where PN: Parser<'a, RN>, @@ -293,9 +363,14 @@ where } } -pub fn delimited<'a, PN, RN, P, R>(lparser: PN, mid: P, rparser: PN) -> impl Parser<'a, R> +pub fn delimited<'a, PNL, PNR, LN, RN, P, R>( + lparser: PNL, + mid: P, + rparser: PNR, +) -> impl Parser<'a, R> where - PN: Parser<'a, RN>, + PNL: Parser<'a, LN>, + PNR: Parser<'a, RN>, P: Parser<'a, R>, { move |input| { |