add: modified parsers.
This commit is contained in:
parent
ffe288ab61
commit
0e9684c32e
|
@ -1,4 +1,2 @@
|
|||
extern crate core;
|
||||
|
||||
mod parser;
|
||||
mod text;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
mod modified_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::{
|
||||
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
|
||||
TakeParser,
|
||||
|
@ -121,6 +124,38 @@ where
|
|||
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
|
||||
|
@ -226,4 +261,3 @@ pub fn failed_parser_test_helper<T, P>(
|
|||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
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)]
|
||||
mod test {
|
||||
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;
|
||||
|
||||
#[test]
|
||||
|
@ -128,4 +220,121 @@ mod test {
|
|||
.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(()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
15
src/text.rs
15
src/text.rs
|
@ -24,10 +24,23 @@ pub fn string_parser<TContext>(str: String) -> impl Parser<char, String, TContex
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
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::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]
|
||||
fn string_parser_test() {
|
||||
parser_test_helper(
|
||||
|
|
Loading…
Reference in New Issue
Block a user