add: modified parsers.

This commit is contained in:
jackfiled 2024-11-16 17:21:37 +08:00
parent ffe288ab61
commit 0e9684c32e
4 changed files with 261 additions and 7 deletions

View File

@ -1,4 +1,2 @@
extern crate core;
mod parser; mod parser;
mod text; mod text;

View File

@ -1,7 +1,10 @@
mod modified_parsers; mod modified_parsers;
mod primitive_parsers; mod primitive_parsers;
use crate::parser::modified_parsers::{BindParser, ConvertParser, MapParser, NextParser}; use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalParser, LookAheadParser, MapParser, NextParser,
ReverseParser,
};
use crate::parser::primitive_parsers::{ use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser, AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
TakeParser, TakeParser,
@ -121,6 +124,38 @@ where
phantom_data: PhantomData, 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<TToken, T, TContext, F> Parser<TToken, T, TContext> for F impl<TToken, T, TContext, F> Parser<TToken, T, TContext> for F
@ -226,4 +261,3 @@ pub fn failed_parser_test_helper<T, P>(
assert!(result.is_err()); assert!(result.is_err());
} }

View File

@ -1,4 +1,4 @@
use crate::parser::{Parser, ParserContext, ParserResult}; use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -97,10 +97,102 @@ where
} }
} }
pub struct LitervalParser<P, T> {
pub(crate) parser: P,
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, Vec<TToken>, TContext> for LitervalParser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
{
fn parse<'a>(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<TToken>> {
let origin_input = input;
let (input, _) = self.parser.parse(context, input)?;
if origin_input.is_empty() {
return Err((
input,
FailedParserResult::new(
"Empty input, the 'literal' parser cann't get length of elememtn.".to_owned(),
),
));
}
let length = (&origin_input[1..]).as_ptr() as usize - origin_input.as_ptr() as usize;
let index = (input.as_ptr() as usize - origin_input.as_ptr() as usize) / length;
Ok((
input,
(&origin_input[..index])
.into_iter()
.map(|x| x.clone())
.collect(),
))
}
}
pub struct LookAheadParser<P, T> {
pub(crate) parser: P,
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, T, TContext> for LookAheadParser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
{
fn parse<'a>(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
let original_input = input;
let (_, r) = self.parser.parse(context, input)?;
Ok((original_input, r))
}
}
pub struct ReverseParser<P, T, TResult> {
pub(crate) parser: P,
pub(crate) result: TResult,
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TResult, TContext, P> Parser<TToken, TResult, TContext>
for ReverseParser<P, T, TResult>
where
TToken: Debug + Clone,
TResult: Debug + Clone,
P: Parser<TToken, T, TContext>,
{
fn parse<'a>(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, TResult> {
match self.parser.parse(context, input) {
Ok((input, _)) => Err((
input,
FailedParserResult::new("Reverse failed succeeded.".to_owned()),
)),
Err((input, _)) => Ok((input, self.result.clone())),
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::parser::{parser_test_helper, take}; use crate::parser::{
failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
};
use crate::text::char_parser; use crate::text::char_parser;
#[test] #[test]
@ -128,4 +220,121 @@ mod test {
.bind(|_| char_parser('c')), .bind(|_| char_parser('c')),
); );
} }
struct Number(i32);
impl From<Number> for String {
fn from(value: Number) -> Self {
format!("{}", value.0)
}
}
#[test]
fn convert_test() {
fn single_numer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, Number> {
let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
match result.to_digit(10) {
None => Err((input, FailedParserResult::new("What?".to_string()))),
Some(r) => Ok((input, Number(r as i32))),
}
}
parser_test_helper(
ParserContext::new_with_str("9", ()),
&"9".to_owned(),
single_numer_parser.convert(),
);
parser_test_helper(
ParserContext::new_with_str("1", ()),
&"1".to_owned(),
single_numer_parser.convert(),
);
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
single_numer_parser.convert::<String>(),
);
}
#[test]
fn next_test() {
let parser = || {
satisfy(|c: &char| c.is_numeric()).next(|r| match r {
Ok((input, result)) => match result.to_digit(10) {
None => Err((input, FailedParserResult::new("What?".to_string()))),
Some(r) => Ok((input, Number(r as i32))),
},
Err(r) => Err(r),
})
};
parser_test_helper(
ParserContext::new_with_str("9", ()),
&"9".to_owned(),
parser().convert(),
);
parser_test_helper(
ParserContext::new_with_str("1", ()),
&"1".to_owned(),
parser().convert(),
);
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
parser().convert::<String>(),
);
}
#[test]
fn literal_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a'],
char_parser('a').literal(),
);
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b'],
char_parser('a').bind(|_| char_parser('b')).literal(),
);
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b', 'c'],
char_parser('a')
.bind(|_| char_parser('b'))
.bind(|_| char_parser('c'))
.literal(),
);
}
#[test]
fn look_ahead_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'a',
char_parser('a').look_ahead().bind(|_| char_parser('a')),
);
}
#[test]
fn reverse_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&(),
char_parser('b').reverse(()),
);
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
char_parser('a').reverse(()),
);
}
} }

View File

@ -24,10 +24,23 @@ pub fn string_parser<TContext>(str: String) -> impl Parser<char, String, TContex
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::parser::{parser_test_helper, ParserContext, ParserResult}; use crate::parser::{
failed_parser_test_helper, parser_test_helper, ParserContext, ParserResult,
};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[test]
fn char_parser_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'a',
char_parser('a'),
);
failed_parser_test_helper(ParserContext::new_with_str("bc", ()), char_parser('a'));
}
#[test] #[test]
fn string_parser_test() { fn string_parser_test() {
parser_test_helper( parser_test_helper(