From 56042dbbe26e3a8f6b5e91648212ef43fbb96371 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 28 Jan 2024 02:53:13 -0800 Subject: [PATCH] Use trait in choice --- src/choice.rs | 56 +++++++++++++++++++++++++++++++++++++------------ src/test/mod.rs | 8 ++----- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/choice.rs b/src/choice.rs index 9577e77..069136f 100644 --- a/src/choice.rs +++ b/src/choice.rs @@ -1,19 +1,49 @@ -use crate::Parser; +use crate::{ParseResult, Parser}; -pub fn choice<'a, I, O, E>(parsers: &'a [&'a dyn Parser]) -> impl Parser + 'a { - move |mut input: I| { - //TODO need a more principled way to return an error when no choices work - let mut err = None; +pub trait Choice { + fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)>; +} - for parser in parsers.iter() { - match parser.parse(input) { - Ok(res) => return Ok(res), - Err((e, rest)) => { - err = Some(e); - input = rest; - } +pub fn choice, I, O, E>(choices: C) -> impl Parser { + move |input| choices.parse_choice(input) +} + +fn choice_loop<'a, I, O, E>( + mut input: I, + parsers: &'a [&'a dyn Parser], +) -> ParseResult { + //TODO need a more principled way to return an error when no choices work + let mut err = None; + + for parser in parsers.iter() { + match parser.parse(input) { + Ok(res) => return Ok(res), + Err((e, rest)) => { + err = Some(e); + input = rest; } } - Err((err.unwrap(), input)) + } + Err((err.unwrap(), input)) +} + +impl Choice for (P1, P2) +where + P1: Parser, + P2: Parser, +{ + fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> { + choice_loop(input, &[&self.0, &self.1]) + } +} + +impl Choice for (P1, P2, P3) +where + P1: Parser, + P2: Parser, + P3: Parser, +{ + fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> { + choice_loop(input, &[&self.0, &self.1, &self.2]) } } diff --git a/src/test/mod.rs b/src/test/mod.rs index 0538e03..a4211b5 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -18,11 +18,7 @@ fn test_sequence() { #[test] fn test_choice() { - let a = literal("bongo"); - let b = literal("sucy"); - let c = literal("ara"); - let inputs = [&a as &dyn Parser<&str, &str, ()>, &b, &c]; - let parser = choice(&inputs); + let parser = choice((literal("bongo"), literal("sucy"), literal("ara"))); let output = parser.parse("ara hajimete").unwrap(); assert_eq!(("ara", " hajimete"), output); @@ -53,7 +49,7 @@ fn test_optional() { let parser = seq2( optional(literal("alpha")), seq2(repeated(literal(" ")), literal("beta")), - ); + ); let output1 = parser.parse(" beta").unwrap(); assert_eq!(output1.0 .0, None);