rust-parser-combinator/src/combinators.rs

235 lines
5.9 KiB
Rust

use std::marker::PhantomData;
use crate::{
representation::{Representation, EBNF},
ParseResult, Parser,
};
pub fn repeated<P, I, O, E>(parser: P) -> Repeated<P, I, O, E>
where
P: Parser<I, O, E>,
{
Repeated::new(parser)
}
pub struct Repeated<P, I, O, E>
where
P: Parser<I, O, E>,
{
inner_parser: P,
phantom: PhantomData<(I, O, E)>,
at_least: Option<u32>,
at_most: Option<u32>,
}
impl<P, I, O, E> Repeated<P, I, O, E>
where
P: Parser<I, O, E>,
{
fn new(inner_parser: P) -> Self {
Self {
inner_parser,
phantom: PhantomData,
at_least: None,
at_most: None,
}
}
pub fn at_least(self, at_least: u32) -> Self {
Self {
at_least: Some(at_least),
..self
}
}
pub fn at_most(self, at_most: u32) -> Self {
Self {
at_most: Some(at_most),
..self
}
}
pub fn separated_by<D>(self, delimiter: D) -> SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
E: Default,
{
SeparatedBy {
inner_repeated: self,
delimiter,
allow_trailing: false,
}
}
}
impl<P, I, O, E> Parser<I, Vec<O>, E> for Repeated<P, I, O, E>
where
P: Parser<I, O, E>,
E: Default,
{
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
let at_least = self.at_least.unwrap_or(0);
let at_most = self.at_most.unwrap_or(u32::MAX);
let mut results = vec![];
let mut count = 0;
if at_most == 0 {
return Ok((vec![], input));
}
loop {
match self.inner_parser.parse(input) {
Ok((item, rest)) => {
results.push(item);
input = rest;
count += 1;
if count >= at_most {
break;
}
}
Err((_err, rest)) => {
input = rest;
break;
}
}
}
if count < at_least {
return Err((Default::default(), input));
}
Ok((results, input))
}
fn name(&self) -> Option<String> {
self.inner_parser.name()
}
fn representation(&self) -> Representation {
let at_least = self.at_least.unwrap_or(0);
//TODO flesh this out better
let _at_most = self.at_most.unwrap_or(u32::MAX);
let production = EBNF::Repeated {
inner: Box::new(self.inner_parser.representation().production()),
more_than_once: at_least >= 1,
};
Representation::new().with_production(production)
}
}
pub struct SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
P: Parser<I, O, E>,
E: Default,
{
inner_repeated: Repeated<P, I, O, E>,
delimiter: D,
allow_trailing: bool,
}
impl<D, P, I, O, E> SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
P: Parser<I, O, E>,
E: Default,
{
pub fn allow_trailing(self, allow_trailing: bool) -> Self {
Self {
allow_trailing,
..self
}
}
}
impl<D, P, I, O, E> Parser<I, Vec<O>, E> for SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
P: Parser<I, O, E>,
E: Default,
{
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
let at_least = self.inner_repeated.at_least.unwrap_or(0);
let at_most = self.inner_repeated.at_most.unwrap_or(u32::MAX);
let inner = &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: u32 = 0;
match inner.parse(input) {
Ok((item, rest)) => {
results.push(item);
input = rest;
}
Err((err, rest)) => {
if at_least > 0 {
return Err((err, rest));
} else {
return Ok((vec![], rest));
}
}
}
loop {
match delimiter.parse(input) {
Ok(((), rest)) => {
input = rest;
count += 1;
}
Err((_err, rest)) => {
input = rest;
break;
}
}
match inner.parse(input) {
Ok((item, rest)) => {
input = rest;
results.push(item);
}
Err((err, rest)) => {
if self.allow_trailing {
input = rest;
break;
} else {
return Err((err, rest));
}
}
}
if count >= at_most {
break;
}
}
if count < at_least {
//return Err(??, rest) <- need to handle errors better
unimplemented!();
}
Ok((results, input))
}
fn representation(&self) -> Representation {
let inner = &self.inner_repeated.inner_parser;
let at_least = self.inner_repeated.at_least.unwrap_or(0);
let inner_production = inner.representation().production();
let delimiter_production = self.delimiter.representation().production();
let production = EBNF::Repeated {
inner: Box::new(EBNF::Sequence(vec![inner_production, delimiter_production])),
more_than_once: at_least >= 1,
};
Representation::new().with_production(production)
}
}
pub fn optional<I, O, E>(parser: impl Parser<I, O, E>) -> impl Parser<I, Option<O>, E>
where
I: Clone,
{
move |input: I| match parser.parse(input.clone()) {
Ok((output, rest)) => Ok((Some(output), rest)),
Err(_e) => Ok((None, input)),
}
}