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))
+ }
+}