Put Parser in separate module

This commit is contained in:
Greg Shuflin 2022-10-16 18:57:10 -07:00
parent a9f2d4d771
commit 364ddeac00
2 changed files with 87 additions and 85 deletions

View File

@ -1,93 +1,10 @@
#![feature(assert_matches)]
#![allow(dead_code)] //TODO eventually turn this off
mod bnf;
mod parser;
mod sequence;
use bnf::Bnf;
use std::rc::Rc;
pub type ParseResult<I, O, E> = Result<(O, I), E>;
pub trait Parser<I, O, E> {
fn parse(&self, input: I) -> ParseResult<I, O, E>;
fn bnf(&self) -> Option<Bnf> {
None
}
fn map<'a, F, O2>(self, map_fn: F) -> BoxedParser<'a, I, O2, E>
where
Self: Sized + 'a,
I: 'a,
E: 'a,
O: 'a,
O2: 'a,
F: Fn(O) -> O2 + 'a,
{
BoxedParser::new(map(self, map_fn))
}
fn to<'a, O2>(self, item: O2) -> BoxedParser<'a, I, O2, E>
where
Self: Sized + 'a,
I: 'a,
O: 'a,
O2: Clone + 'a,
E: 'a,
{
self.map(move |_| item.clone())
}
fn then<'a, P, O2>(self, next_parser: P) -> BoxedParser<'a, I, (O, O2), E>
where
Self: Sized + 'a,
I: 'a,
O: 'a,
O2: 'a,
E: 'a,
P: Parser<I, O2, E> + 'a,
{
BoxedParser::new(sequence::tuple2(self, next_parser))
}
}
pub struct BoxedParser<'a, I, O, E> {
inner: Box<dyn Parser<I, O, E> + 'a>,
}
impl<'a, I, O, E> BoxedParser<'a, I, O, E> {
fn new<P>(inner: P) -> Self
where
P: Parser<I, O, E> + 'a,
{
BoxedParser {
inner: Box::new(inner),
}
}
}
impl<'a, I, O, E> Parser<I, O, E> for BoxedParser<'a, I, O, E> {
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self.inner.parse(input)
}
}
impl<I, O, E, F> Parser<I, O, E> for F
where
F: Fn(I) -> ParseResult<I, O, E>,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self(input)
}
}
impl<I, O, E, T> Parser<I, O, E> for Rc<T>
where
T: Parser<I, O, E>,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self.as_ref().parse(input)
}
}
use parser::{ParseResult, Parser};
fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> {
move |input| match input.get(0..expected.len()) {

85
src/parser.rs Normal file
View File

@ -0,0 +1,85 @@
use crate::bnf::Bnf;
use std::rc::Rc;
pub type ParseResult<I, O, E> = Result<(O, I), E>;
pub trait Parser<I, O, E> {
fn parse(&self, input: I) -> ParseResult<I, O, E>;
fn bnf(&self) -> Option<Bnf> {
None
}
fn map<'a, F, O2>(self, map_fn: F) -> BoxedParser<'a, I, O2, E>
where
Self: Sized + 'a,
I: 'a,
E: 'a,
O: 'a,
O2: 'a,
F: Fn(O) -> O2 + 'a,
{
BoxedParser::new(crate::map(self, map_fn))
}
fn to<'a, O2>(self, item: O2) -> BoxedParser<'a, I, O2, E>
where
Self: Sized + 'a,
I: 'a,
O: 'a,
O2: Clone + 'a,
E: 'a,
{
self.map(move |_| item.clone())
}
fn then<'a, P, O2>(self, next_parser: P) -> BoxedParser<'a, I, (O, O2), E>
where
Self: Sized + 'a,
I: 'a,
O: 'a,
O2: 'a,
E: 'a,
P: Parser<I, O2, E> + 'a,
{
BoxedParser::new(crate::sequence::tuple2(self, next_parser))
}
}
pub struct BoxedParser<'a, I, O, E> {
inner: Box<dyn Parser<I, O, E> + 'a>,
}
impl<'a, I, O, E> BoxedParser<'a, I, O, E> {
fn new<P>(inner: P) -> Self
where
P: Parser<I, O, E> + 'a,
{
BoxedParser {
inner: Box::new(inner),
}
}
}
impl<'a, I, O, E> Parser<I, O, E> for BoxedParser<'a, I, O, E> {
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self.inner.parse(input)
}
}
impl<I, O, E, F> Parser<I, O, E> for F
where
F: Fn(I) -> ParseResult<I, O, E>,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self(input)
}
}
impl<I, O, E, T> Parser<I, O, E> for Rc<T>
where
T: Parser<I, O, E>,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self.as_ref().parse(input)
}
}