zero-parser/src/parser.rs

340 lines
7.9 KiB
Rust

mod modified_parsers;
mod primitive_parsers;
use crate::parser::modified_parsers::{
AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser,
MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser,
};
use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
SucceedParser, TakeParser,
};
use std::cell::RefCell;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::marker::PhantomData;
use std::rc::Rc;
#[derive(Debug)]
pub struct FailedParserResult<'a, TToken: Debug> {
input: &'a [TToken],
message: String,
}
impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
pub fn new(input: &'a [TToken], message: String) -> Self {
Self { input, message }
}
pub fn new_with_str(input: &'a [TToken], message: &'static str) -> Self {
Self {
input,
message: message.to_owned(),
}
}
pub fn new_with_error(input: &'a [TToken], err: anyhow::Error) -> Self {
Self {
input,
message: format!("{}", err),
}
}
pub fn message(&self) -> &str {
self.message.as_str()
}
pub fn input(&self) -> &'a [TToken] {
self.input
}
}
impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {}
impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Parse failed: {}, the input is '{:?}'.",
self.message, self.input
)
}
}
pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>;
pub struct ParserContext<TContext> {
pub context: TContext,
}
impl<TContext> ParserContext<TContext> {
pub fn new(context: TContext) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self { context }))
}
}
pub trait Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
T: 'a,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T>;
fn map<TResult, F>(self, f: F) -> MapParser<Self, F, T>
where
Self: Sized,
F: Fn(T) -> TResult,
{
MapParser {
parser: self,
mapper: f,
phantom: PhantomData,
}
}
fn bind<TResult: 'a, F, P>(self, f: F) -> BindParser<Self, F, T>
where
Self: Sized,
F: Fn(T) -> P,
P: Parser<'a, TToken, TResult, TContext>,
{
BindParser {
parser: self,
binder: f,
phantom_data: PhantomData,
}
}
fn convert<TResult>(self) -> ConvertParser<Self, T, TResult>
where
Self: Sized,
{
ConvertParser {
parser: self,
phantom_data1: PhantomData,
phantom_data2: PhantomData,
}
}
fn next<TResult, H>(self, handler: H) -> NextParser<Self, H, T>
where
Self: Sized,
H: for<'f> Fn(ParserResult<'f, TToken, T>) -> ParserResult<'f, TToken, TResult>,
{
NextParser {
parser: self,
handler,
phantom_data: PhantomData,
}
}
fn literal_count(self) -> LitervalCountParser<Self, T>
where
Self: Sized,
{
LitervalCountParser {
parser: self,
phantom_data: PhantomData,
}
}
fn literal(self) -> LitervalParser<Self, T>
where
Self: Sized,
{
LitervalParser {
parser: self,
phantom_data: PhantomData,
}
}
fn look_ahead(self) -> LookAheadParser<Self, T>
where
Self: Sized,
{
LookAheadParser {
parser: self,
phantom_data: PhantomData,
}
}
fn try_parse(self, result: T) -> TryParser<Self, T>
where
Self: Sized,
T: Clone,
{
TryParser {
parser: self,
result,
}
}
fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
where
Self: Sized,
TResult: Debug + Clone,
{
ReverseParser {
parser: self,
result,
phantom_data: PhantomData,
}
}
fn optional(self) -> OptionalParser<Self>
where
Self: Sized,
{
OptionalParser { parser: self }
}
fn run<F>(self, action: F) -> RunParser<Self, F>
where
Self: Sized,
F: Fn(&T) -> (),
{
RunParser {
parser: self,
action,
}
}
fn and_then<TResult, F>(self, mapper: F) -> AndThenParser<Self, F, T>
where
Self: Sized,
F: Fn(T) -> anyhow::Result<TResult>,
{
AndThenParser {
parser: self,
mapper,
phantom_data: PhantomData,
}
}
}
impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F
where
TToken: Debug + Clone + 'a,
F: Fn(Rc<RefCell<ParserContext<TContext>>>, &'a [TToken]) -> ParserResult<'a, TToken, T>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
(*self)(context, input)
}
}
impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext>
for Box<dyn Parser<'a, TToken, T, TContext>>
where
TToken: Debug + Clone,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
(**self).parse(context, input)
}
}
pub fn succeed<'a, TToken, T, TContext>(value: T) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
T: Debug + Clone + 'a,
{
SucceedParser { value }
}
pub fn fail<'a, TToken, T: 'a, TContext>() -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
FailParser {
phantom_data: PhantomData,
}
}
pub fn fail_with_message<'a, TToken, T: 'a, TContext>(
message: &str,
) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
FailWithMessageParser {
message: message.to_owned(),
phantom_data: PhantomData,
}
}
pub fn satisfy<'a, TToken, TContext, TP>(predicate: TP) -> impl Parser<'a, TToken, TToken, TContext>
where
TToken: Debug + Clone + 'a,
TP: Fn(&TToken) -> bool,
{
SatisfyParser { predicate }
}
pub fn satified_map<'a, TToken, TContext, T: 'a, F>(
mapper: F,
) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
F: Fn(&TToken) -> Option<T>,
{
SatifiedMapParser { mapper }
}
pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext>
where
TToken: Debug + Clone + 'a,
{
AnyParser {}
}
pub fn take<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone + 'a,
{
TakeParser { count }
}
pub fn skip<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, (), TContext>
where
TToken: Debug + Clone,
{
SkipParser { count }
}
#[cfg(test)]
pub fn parser_test_helper<T, P>(input: &str, excepted_node: &T, test_parser: P)
where
T: PartialEq + Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let word: Vec<char> = input.chars().collect();
let (_, actual_result) = test_parser
.parse(ParserContext::new(()), word.as_slice())
.unwrap();
assert_eq!(excepted_node, &actual_result);
}
#[cfg(test)]
pub fn failed_parser_test_helper<T, P>(input: &str, test_parser: P)
where
T: Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let word: Vec<char> = input.chars().collect();
let result = test_parser.parse(ParserContext::new(()), word.as_slice());
assert!(result.is_err());
}