reorganize combinators

This commit is contained in:
Greg Shuflin 2022-10-21 19:34:27 -07:00
parent d14b470530
commit a049236300
5 changed files with 200 additions and 186 deletions

14
src/combinators/map.rs Normal file
View 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))
}
}

View File

@ -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>
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)),
}
}
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,
}
}
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]

View 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)),
}
}

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

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