zero-parser/src/parser.rs

295 lines
6.9 KiB
Rust

mod modified_parsers;
mod primitive_parsers;
use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
NextParser, ReverseParser,
};
use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
TakeParser,
};
use std::cell::RefCell;
use std::fmt::{Debug, Display, Formatter};
use std::marker::PhantomData;
use std::rc::Rc;
#[derive(Debug)]
pub struct FailedParserResult {
message: String,
}
impl FailedParserResult {
pub fn new(message: String) -> Self {
Self { message }
}
pub fn message(&self) -> &str {
self.message.as_str()
}
}
impl Display for FailedParserResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Parse failed: {}.", self.message)
}
}
pub type ParserResult<'a, TToken, T> =
Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>;
pub struct ParserContext<TToken, TContext>
where
TToken: Debug + Clone,
{
pub context: TContext,
input_array: Vec<TToken>,
}
impl<TToken, TContext> ParserContext<TToken, TContext>
where
TToken: Debug + Clone,
{
pub fn new(input: &[TToken], context: TContext) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
input_array: input.iter().map(|x| x.clone()).collect(),
context,
}))
}
pub fn input_slice(&self) -> &[TToken] {
self.input_array.as_slice()
}
}
impl<TContext> ParserContext<char, TContext> {
pub fn new_with_str(input: &str, context: TContext) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
input_array: input.chars().collect(),
context,
}))
}
}
pub trait Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
T: 'a,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, 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 reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
where
Self: Sized,
TResult: Debug + Clone,
{
ReverseParser {
parser: self,
result,
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<TToken, TContext>>>,
&'a [TToken],
) -> ParserResult<'a, TToken, T>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, 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<TToken, 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 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>(
context: Rc<RefCell<ParserContext<char, ()>>>,
excepted_node: &T,
test_parser: P,
) where
T: PartialEq + Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let borrowed_context = context.borrow();
let input = borrowed_context.input_slice();
let (_, actual_result) = test_parser.parse(context.clone(), input).unwrap();
assert_eq!(excepted_node, &actual_result);
}
#[cfg(test)]
pub fn failed_parser_test_helper<T, P>(
context: Rc<RefCell<ParserContext<char, ()>>>,
test_parser: P,
) where
T: Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let borrowed_context = context.borrow();
let input = borrowed_context.input_slice();
let result = test_parser.parse(context.clone(), input);
assert!(result.is_err());
}