reorganize combinators
This commit is contained in:
parent
d14b470530
commit
a049236300
14
src/combinators/map.rs
Normal file
14
src/combinators/map.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::parser::{Parser, ParserInput};
|
||||||
|
|
||||||
|
pub fn map<P, F, I, O1, O2, E>(parser: P, map_fn: F) -> impl Parser<I, O2, E>
|
||||||
|
where
|
||||||
|
I: ParserInput,
|
||||||
|
P: Parser<I, O1, E>,
|
||||||
|
F: Fn(O1) -> O2,
|
||||||
|
{
|
||||||
|
move |input| {
|
||||||
|
parser
|
||||||
|
.parse(input)
|
||||||
|
.map(|(result, rest)| (map_fn(result), rest))
|
||||||
|
}
|
||||||
|
}
|
@ -1,194 +1,16 @@
|
|||||||
use crate::parser::{BoxedParser, ParseResult, Parser, ParserInput};
|
mod map;
|
||||||
|
mod optional;
|
||||||
|
mod repeated;
|
||||||
|
mod separated_by;
|
||||||
|
|
||||||
pub fn optional<P, I, O, E>(parser: P) -> impl Parser<I, Option<O>, E>
|
pub use map::map;
|
||||||
where
|
pub use optional::optional;
|
||||||
P: Parser<I, O, E>,
|
pub use repeated::repeated;
|
||||||
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<P, F, I, O1, O2, E>(parser: P, map_fn: F) -> impl Parser<I, O2, E>
|
|
||||||
where
|
|
||||||
I: ParserInput,
|
|
||||||
P: Parser<I, O1, E>,
|
|
||||||
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<u16>,
|
|
||||||
at_most: Option<u16>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<D, O2>(self, delimiter: D, allow_trailing: bool) -> SeparatedBy<'a, I, O>
|
|
||||||
where
|
|
||||||
D: Parser<I, O2, I> + 'a,
|
|
||||||
O2: 'a,
|
|
||||||
I: 'a,
|
|
||||||
{
|
|
||||||
SeparatedBy {
|
|
||||||
inner_repeated: self,
|
|
||||||
delimiter: BoxedParser::new(delimiter.to(())),
|
|
||||||
allow_trailing,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I, O> Parser<I, Vec<O>, I> for Repeated<'a, I, O>
|
|
||||||
where
|
|
||||||
I: ParserInput + Clone + 'a,
|
|
||||||
{
|
|
||||||
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, 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, Vec<O>, I> for SeparatedBy<'a, I, O>
|
|
||||||
where
|
|
||||||
I: ParserInput + Clone + 'a,
|
|
||||||
{
|
|
||||||
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, 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<I, O, I> + 'static,
|
|
||||||
I: ParserInput + Clone + 'static,
|
|
||||||
{
|
|
||||||
Repeated {
|
|
||||||
inner_parser: BoxedParser::new(parser),
|
|
||||||
at_least: None,
|
|
||||||
at_most: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::parser::Parser;
|
||||||
use crate::primitives::literal;
|
use crate::primitives::literal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
12
src/combinators/optional.rs
Normal file
12
src/combinators/optional.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::parser::{Parser, ParserInput};
|
||||||
|
|
||||||
|
pub fn optional<P, I, O, E>(parser: P) -> impl Parser<I, Option<O>, E>
|
||||||
|
where
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
I: ParserInput + Clone,
|
||||||
|
{
|
||||||
|
move |input: I| match parser.parse(input.clone()) {
|
||||||
|
Ok((output, rest)) => Ok((Some(output), rest)),
|
||||||
|
Err(_e) => Ok((None, input)),
|
||||||
|
}
|
||||||
|
}
|
86
src/combinators/repeated.rs
Normal file
86
src/combinators/repeated.rs
Normal file
@ -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<I, O, I> + '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<u16>,
|
||||||
|
pub(super) at_most: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<D, O2>(self, delimiter: D, allow_trailing: bool) -> SeparatedBy<'a, I, O>
|
||||||
|
where
|
||||||
|
D: Parser<I, O2, I> + 'a,
|
||||||
|
O2: 'a,
|
||||||
|
I: 'a,
|
||||||
|
{
|
||||||
|
SeparatedBy {
|
||||||
|
inner_repeated: self,
|
||||||
|
delimiter: BoxedParser::new(delimiter.to(())),
|
||||||
|
allow_trailing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, O> Parser<I, Vec<O>, I> for Repeated<'a, I, O>
|
||||||
|
where
|
||||||
|
I: ParserInput + Clone + 'a,
|
||||||
|
{
|
||||||
|
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, 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))
|
||||||
|
}
|
||||||
|
}
|
80
src/combinators/separated_by.rs
Normal file
80
src/combinators/separated_by.rs
Normal file
@ -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, Vec<O>, I> for SeparatedBy<'a, I, O>
|
||||||
|
where
|
||||||
|
I: ParserInput + Clone + 'a,
|
||||||
|
{
|
||||||
|
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, 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))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user