From 4456734134518e8ef1ff8f061551a31d471741f4 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 16 Oct 2022 20:07:45 -0700 Subject: [PATCH] choice function --- src/choice.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 2 +- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/choice.rs b/src/choice.rs index f0ca4cf..1658d5e 100644 --- a/src/choice.rs +++ b/src/choice.rs @@ -1,6 +1,6 @@ -use crate::parser::Parser; +use crate::parser::{ParseResult, Parser}; -pub fn choice(parser1: P1, parser2: P2) -> impl Parser +pub fn choice2(parser1: P1, parser2: P2) -> impl Parser where P1: Parser, P2: Parser, @@ -12,6 +12,43 @@ where } } +pub fn choice(choices: C) -> impl Parser +where + C: Choice, + I: Clone, +{ + move |input| choices.parse(input) +} + +pub trait Choice { + fn parse(&self, input: I) -> ParseResult; +} + +impl Choice for (P1, P2) +where + P1: Parser, + P2: Parser, + I: Clone, +{ + fn parse(&self, input: I) -> ParseResult { + let parser1 = &self.0; + let parser2 = &self.1; + + //TODO need a more principled way to return an error when no choices work + let mut err = None; + + for parser in [parser1 as &dyn Parser, parser2].iter() { + match parser.parse(input.clone()) { + Ok(result) => return Ok(result), + Err(e) => { + err = Some(e); + } + } + } + Err(err.unwrap()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -20,7 +57,7 @@ mod tests { #[test] fn test_choice() { - let p = choice(literal("gnostika").to(1), one_or_more(literal(" ")).to(2)); + let p = choice2(literal("gnostika").to(1), one_or_more(literal(" ")).to(2)); assert_eq!(p.parse("gnostika twentynine"), Ok((1, " twentynine"))); } } diff --git a/src/lib.rs b/src/lib.rs index 978d26b..941769c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod tests { let json_true = literal("true").to(JsonValue::Bool(true)); let json_false = literal("false").to(JsonValue::Bool(false)); - let json_value = choice(json_null, choice(json_true, json_false)); + let json_value = choice((json_null, choice((json_true, json_false)))); assert_eq!(json_value.parse("true"), Ok((JsonValue::Bool(true), ""))); }