add: modified parsers.
This commit is contained in:
parent
ffe288ab61
commit
0e9684c32e
|
@ -1,4 +1,2 @@
|
||||||
extern crate core;
|
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(()),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
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)]
|
#[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(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user