158 lines
3.5 KiB
Rust
158 lines
3.5 KiB
Rust
mod boxed_parser;
|
|
mod named_parser;
|
|
|
|
use std::rc::Rc;
|
|
|
|
pub use boxed_parser::BoxedParser;
|
|
pub use named_parser::NamedParser;
|
|
|
|
pub type ParseResult<I, O, E> = Result<(O, I), E>;
|
|
|
|
pub trait ParserInput: std::fmt::Debug {}
|
|
|
|
impl ParserInput for &str {}
|
|
impl ParserInput for String {}
|
|
|
|
pub trait Parser<I, O, E>
|
|
where
|
|
I: ParserInput,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E>;
|
|
|
|
fn boxed<'a>(self) -> BoxedParser<'a, I, O, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
{
|
|
BoxedParser::new(self)
|
|
}
|
|
|
|
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,
|
|
{
|
|
crate::combinators::map(self, map_fn).boxed()
|
|
}
|
|
|
|
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,
|
|
{
|
|
crate::sequence::tuple2(self, next_parser).boxed()
|
|
}
|
|
|
|
fn ignore_then<'a, P, O2>(self, next_parser: P) -> BoxedParser<'a, I, O2, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
I: 'a,
|
|
O: 'a,
|
|
O2: 'a,
|
|
E: 'a,
|
|
P: Parser<I, O2, E> + 'a,
|
|
{
|
|
crate::sequence::tuple2(self, next_parser).map(|(_, next_output)| next_output)
|
|
}
|
|
|
|
fn then_ignore<'a, P, O2>(self, next_parser: P) -> BoxedParser<'a, I, O, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
I: 'a,
|
|
O: 'a,
|
|
O2: 'a,
|
|
E: 'a,
|
|
P: Parser<I, O2, E> + 'a,
|
|
{
|
|
crate::sequence::tuple2(self, next_parser).map(|(this_output, _)| this_output)
|
|
}
|
|
|
|
fn delimited<'a, P1, O1, P2, O2>(self, left: P1, right: P2) -> BoxedParser<'a, I, O, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
I: 'a,
|
|
O1: 'a,
|
|
O2: 'a,
|
|
O: 'a,
|
|
E: 'a,
|
|
P1: Parser<I, O1, E> + 'a,
|
|
P2: Parser<I, O2, E> + 'a,
|
|
{
|
|
crate::sequence::seq((left, self, right)).map(|(_, output, _)| output)
|
|
}
|
|
|
|
fn surrounded_by<'a, P, O1>(self, surrounding: P) -> BoxedParser<'a, I, O, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
I: 'a,
|
|
O1: 'a,
|
|
O: 'a,
|
|
E: 'a,
|
|
P: Parser<I, O1, E> + 'a,
|
|
{
|
|
BoxedParser::new(move |input| {
|
|
let p1 = |i| surrounding.parse(i);
|
|
let p2 = |i| surrounding.parse(i);
|
|
let main = |i| self.parse(i);
|
|
crate::sequence::seq((p1, main, p2))
|
|
.map(|(_, output, _)| output)
|
|
.parse(input)
|
|
})
|
|
}
|
|
|
|
fn optional<'a>(self) -> BoxedParser<'a, I, Option<O>, E>
|
|
where
|
|
I: Clone + 'a,
|
|
O: 'a,
|
|
E: 'a,
|
|
Self: Sized + 'a,
|
|
{
|
|
crate::combinators::optional(self).boxed()
|
|
}
|
|
|
|
fn named<'a>(self, parser_name: &str) -> NamedParser<'a, I, O, E>
|
|
where
|
|
Self: Sized + 'a,
|
|
I: 'a,
|
|
{
|
|
NamedParser::new(self.boxed(), parser_name.to_string())
|
|
}
|
|
}
|
|
|
|
impl<I: ParserInput, 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
|
|
I: ParserInput,
|
|
T: Parser<I, O, E>,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
self.as_ref().parse(input)
|
|
}
|
|
}
|