From a04923630020c8c445baa6c45e36ce15eca245cc Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Fri, 21 Oct 2022 19:34:27 -0700 Subject: [PATCH] reorganize combinators --- src/combinators/map.rs | 14 +++ src/combinators/mod.rs | 194 ++------------------------------ src/combinators/optional.rs | 12 ++ src/combinators/repeated.rs | 86 ++++++++++++++ src/combinators/separated_by.rs | 80 +++++++++++++ 5 files changed, 200 insertions(+), 186 deletions(-) create mode 100644 src/combinators/map.rs create mode 100644 src/combinators/optional.rs create mode 100644 src/combinators/repeated.rs create mode 100644 src/combinators/separated_by.rs diff --git a/src/combinators/map.rs b/src/combinators/map.rs new file mode 100644 index 0000000..0d72d5a --- /dev/null +++ b/src/combinators/map.rs @@ -0,0 +1,14 @@ +use crate::parser::{Parser, ParserInput}; + +pub fn map(parser: P, map_fn: F) -> impl Parser +where + I: ParserInput, + P: Parser, + F: Fn(O1) -> O2, +{ + move |input| { + parser + .parse(input) + .map(|(result, rest)| (map_fn(result), rest)) + } +} diff --git a/src/combinators/mod.rs b/src/combinators/mod.rs index 6ea5292..364df44 100644 --- a/src/combinators/mod.rs +++ b/src/combinators/mod.rs @@ -1,194 +1,16 @@ -use crate::parser::{BoxedParser, ParseResult, Parser, ParserInput}; +mod map; +mod optional; +mod repeated; +mod separated_by; -pub fn optional(parser: P) -> impl Parser, E> -where - P: Parser, - I: ParserInput + Clone, -{ - move |input: I| match parser.parse(input.clone()) { - Ok((output, rest)) => Ok((Some(output), rest)), - Err(_e) => Ok((None, input)), - } -} - -pub fn map(parser: P, map_fn: F) -> impl Parser -where - I: ParserInput, - P: Parser, - F: Fn(O1) -> O2, -{ - move |input| { - parser - .parse(input) - .map(|(result, rest)| (map_fn(result), rest)) - } -} - -pub struct Repeated<'a, I, O> -where - I: ParserInput + Clone, -{ - inner_parser: BoxedParser<'a, I, O, I>, - at_least: Option, - at_most: Option, -} - -impl<'a, I, O> Repeated<'a, I, O> -where - I: ParserInput + Clone, -{ - pub fn at_least(self, n: u16) -> Self { - Self { - at_least: Some(n), - ..self - } - } - pub fn at_most(self, n: u16) -> Self { - Self { - at_most: Some(n), - ..self - } - } - - pub fn separated_by(self, delimiter: D, allow_trailing: bool) -> SeparatedBy<'a, I, O> - where - D: Parser + 'a, - O2: 'a, - I: 'a, - { - SeparatedBy { - inner_repeated: self, - delimiter: BoxedParser::new(delimiter.to(())), - allow_trailing, - } - } -} - -impl<'a, I, O> Parser, I> for Repeated<'a, I, O> -where - I: ParserInput + Clone + 'a, -{ - fn parse(&self, input: I) -> ParseResult, I> { - let at_least = self.at_least.unwrap_or(0); - let at_most = self.at_most.unwrap_or(u16::MAX); - - if at_most == 0 { - return Ok((vec![], input)); - } - - let mut results = Vec::new(); - let mut count: u16 = 0; - let mut further_input = input.clone(); - - while let Ok((item, rest)) = self.inner_parser.parse(further_input.clone()) { - results.push(item); - further_input = rest; - count += 1; - if count >= at_most { - break; - } - } - if count < at_least { - return Err(input); - } - - Ok((results, further_input)) - } -} - -pub struct SeparatedBy<'a, I, O> -where - I: ParserInput + Clone, -{ - inner_repeated: Repeated<'a, I, O>, - delimiter: BoxedParser<'a, I, (), I>, - allow_trailing: bool, -} - -impl<'a, I, O> Parser, I> for SeparatedBy<'a, I, O> -where - I: ParserInput + Clone + 'a, -{ - fn parse(&self, input: I) -> ParseResult, I> { - let at_least = self.inner_repeated.at_least.unwrap_or(0); - let at_most = self.inner_repeated.at_most.unwrap_or(u16::MAX); - let parser = &self.inner_repeated.inner_parser; - let delimiter = &self.delimiter; - - if at_most == 0 { - return Ok((vec![], input)); - } - - let mut results = Vec::new(); - let mut count: u16 = 0; - let mut further_input; - - match parser.parse(input.clone()) { - Ok((item, rest)) => { - results.push(item); - further_input = rest; - } - Err(_e) => { - if at_least > 0 { - return Err(input); - } else { - return Ok((vec![], input)); - } - } - } - - loop { - match delimiter.parse(further_input.clone()) { - Ok(((), rest)) => { - further_input = rest; - } - Err(_e) => { - break; - } - } - - match parser.parse(further_input.clone()) { - Ok((item, rest)) => { - results.push(item); - further_input = rest; - count += 1; - } - Err(_e) if self.allow_trailing => { - break; - } - Err(e) => { - return Err(e); - } - } - - if count >= at_most { - break; - } - } - - if count < at_least { - return Err(input); - } - - Ok((results, further_input)) - } -} - -pub fn repeated<'a, P, I, O>(parser: P) -> Repeated<'a, I, O> -where - P: Parser + 'static, - I: ParserInput + Clone + 'static, -{ - Repeated { - inner_parser: BoxedParser::new(parser), - at_least: None, - at_most: None, - } -} +pub use map::map; +pub use optional::optional; +pub use repeated::repeated; #[cfg(test)] mod tests { use super::*; + use crate::parser::Parser; use crate::primitives::literal; #[test] diff --git a/src/combinators/optional.rs b/src/combinators/optional.rs new file mode 100644 index 0000000..c630268 --- /dev/null +++ b/src/combinators/optional.rs @@ -0,0 +1,12 @@ +use crate::parser::{Parser, ParserInput}; + +pub fn optional(parser: P) -> impl Parser, E> +where + P: Parser, + I: ParserInput + Clone, +{ + move |input: I| match parser.parse(input.clone()) { + Ok((output, rest)) => Ok((Some(output), rest)), + Err(_e) => Ok((None, input)), + } +} diff --git a/src/combinators/repeated.rs b/src/combinators/repeated.rs new file mode 100644 index 0000000..2b1c35c --- /dev/null +++ b/src/combinators/repeated.rs @@ -0,0 +1,86 @@ +use crate::combinators::separated_by::SeparatedBy; +use crate::parser::{BoxedParser, ParseResult, Parser, ParserInput}; + +pub fn repeated<'a, P, I, O>(parser: P) -> Repeated<'a, I, O> +where + P: Parser + 'static, + I: ParserInput + Clone + 'static, +{ + Repeated { + inner_parser: BoxedParser::new(parser), + at_least: None, + at_most: None, + } +} + +pub struct Repeated<'a, I, O> +where + I: ParserInput + Clone, +{ + pub(super) inner_parser: BoxedParser<'a, I, O, I>, + pub(super) at_least: Option, + pub(super) at_most: Option, +} + +impl<'a, I, O> Repeated<'a, I, O> +where + I: ParserInput + Clone, +{ + pub fn at_least(self, n: u16) -> Self { + Self { + at_least: Some(n), + ..self + } + } + pub fn at_most(self, n: u16) -> Self { + Self { + at_most: Some(n), + ..self + } + } + + pub fn separated_by(self, delimiter: D, allow_trailing: bool) -> SeparatedBy<'a, I, O> + where + D: Parser + 'a, + O2: 'a, + I: 'a, + { + SeparatedBy { + inner_repeated: self, + delimiter: BoxedParser::new(delimiter.to(())), + allow_trailing, + } + } +} + +impl<'a, I, O> Parser, I> for Repeated<'a, I, O> +where + I: ParserInput + Clone + 'a, +{ + fn parse(&self, input: I) -> ParseResult, I> { + let at_least = self.at_least.unwrap_or(0); + let at_most = self.at_most.unwrap_or(u16::MAX); + + if at_most == 0 { + return Ok((vec![], input)); + } + + let mut results = Vec::new(); + let mut count: u16 = 0; + let mut further_input = input.clone(); + + while let Ok((item, rest)) = self.inner_parser.parse(further_input.clone()) { + results.push(item); + further_input = rest; + count += 1; + if count >= at_most { + break; + } + } + if count < at_least { + return Err(input); + } + + Ok((results, further_input)) + } +} diff --git a/src/combinators/separated_by.rs b/src/combinators/separated_by.rs new file mode 100644 index 0000000..3c2350b --- /dev/null +++ b/src/combinators/separated_by.rs @@ -0,0 +1,80 @@ +use crate::combinators::repeated::Repeated; +use crate::parser::{BoxedParser, ParseResult, Parser, ParserInput}; + +pub struct SeparatedBy<'a, I, O> +where + I: ParserInput + Clone, +{ + pub(super) inner_repeated: Repeated<'a, I, O>, + pub(super) delimiter: BoxedParser<'a, I, (), I>, + pub(super) allow_trailing: bool, +} + +impl<'a, I, O> Parser, I> for SeparatedBy<'a, I, O> +where + I: ParserInput + Clone + 'a, +{ + fn parse(&self, input: I) -> ParseResult, I> { + let at_least = self.inner_repeated.at_least.unwrap_or(0); + let at_most = self.inner_repeated.at_most.unwrap_or(u16::MAX); + let parser = &self.inner_repeated.inner_parser; + let delimiter = &self.delimiter; + + if at_most == 0 { + return Ok((vec![], input)); + } + + let mut results = Vec::new(); + let mut count: u16 = 0; + let mut further_input; + + match parser.parse(input.clone()) { + Ok((item, rest)) => { + results.push(item); + further_input = rest; + } + Err(_e) => { + if at_least > 0 { + return Err(input); + } else { + return Ok((vec![], input)); + } + } + } + + loop { + match delimiter.parse(further_input.clone()) { + Ok(((), rest)) => { + further_input = rest; + } + Err(_e) => { + break; + } + } + + match parser.parse(further_input.clone()) { + Ok((item, rest)) => { + results.push(item); + further_input = rest; + count += 1; + } + Err(_e) if self.allow_trailing => { + break; + } + Err(e) => { + return Err(e); + } + } + + if count >= at_most { + break; + } + } + + if count < at_least { + return Err(input); + } + + Ok((results, further_input)) + } +}