384 lines
11 KiB
Rust
384 lines
11 KiB
Rust
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
|
|
use std::cell::RefCell;
|
|
use std::fmt::Debug;
|
|
use std::marker::PhantomData;
|
|
use std::rc::Rc;
|
|
|
|
pub struct MapParser<P, F, T1> {
|
|
pub(crate) parser: P,
|
|
pub(crate) mapper: F,
|
|
pub(crate) phantom: PhantomData<T1>,
|
|
}
|
|
|
|
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, F> Parser<'a, TToken, T2, TContext>
|
|
for MapParser<P, F, T1>
|
|
where
|
|
TToken: Debug + Clone,
|
|
P: Parser<'a, TToken, T1, TContext>,
|
|
F: Fn(T1) -> T2,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, T2> {
|
|
self.parser
|
|
.parse(context, input)
|
|
.map(|(remainder, result)| (remainder, (self.mapper)(result)))
|
|
}
|
|
}
|
|
|
|
pub struct BindParser<P, F, T1> {
|
|
pub(crate) parser: P,
|
|
pub(crate) binder: F,
|
|
pub(crate) phantom_data: PhantomData<T1>,
|
|
}
|
|
|
|
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, P2, F> Parser<'a, TToken, T2, TContext>
|
|
for BindParser<P, F, T1>
|
|
where
|
|
TToken: Debug + Clone,
|
|
P: Parser<'a, TToken, T1, TContext>,
|
|
F: Fn(T1) -> P2,
|
|
P2: Parser<'a, TToken, T2, TContext>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, T2> {
|
|
let (input, middle) = self.parser.parse(context.clone(), input)?;
|
|
|
|
(self.binder)(middle).parse(context, input)
|
|
}
|
|
}
|
|
|
|
pub struct ConvertParser<P, T1, T2> {
|
|
pub(crate) parser: P,
|
|
pub(crate) phantom_data1: PhantomData<T1>,
|
|
pub(crate) phantom_data2: PhantomData<T2>,
|
|
}
|
|
|
|
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P> Parser<'a, TToken, T2, TContext>
|
|
for ConvertParser<P, T1, T2>
|
|
where
|
|
TToken: Debug + Clone,
|
|
T2: From<T1>,
|
|
P: Parser<'a, TToken, T1, TContext>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, T2> {
|
|
self.parser
|
|
.parse(context, input)
|
|
.map(|(input, result)| (input, result.into()))
|
|
}
|
|
}
|
|
|
|
pub struct NextParser<P, H, T> {
|
|
pub(crate) parser: P,
|
|
pub(crate) handler: H,
|
|
pub(crate) phantom_data: PhantomData<T>,
|
|
}
|
|
|
|
impl<'a, TToken, T: 'a, TResult: 'a, TContext, P, H> Parser<'a, TToken, TResult, TContext>
|
|
for NextParser<P, H, T>
|
|
where
|
|
TToken: Debug + Clone,
|
|
P: Parser<'a, TToken, T, TContext>,
|
|
H: for<'f> Fn(ParserResult<'f, TToken, T>) -> ParserResult<'f, TToken, TResult>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, TResult> {
|
|
let result = self.parser.parse(context, input);
|
|
|
|
(self.handler)(result)
|
|
}
|
|
}
|
|
|
|
pub struct LitervalParser<P, T> {
|
|
pub(crate) parser: P,
|
|
pub(crate) phantom_data: PhantomData<T>,
|
|
}
|
|
|
|
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, &'a [TToken], TContext>
|
|
for LitervalParser<P, T>
|
|
where
|
|
TToken: Debug + Clone + 'a,
|
|
P: Parser<'a, TToken, T, TContext>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, &'a [TToken]> {
|
|
let origin_input = input;
|
|
let (input, _) = self.parser.parse(context, input)?;
|
|
|
|
if origin_input.is_empty() {
|
|
return Err(FailedParserResult::new_with_str(
|
|
input,
|
|
"Empty input, the 'literal' parser cann't get length of elememt.",
|
|
));
|
|
}
|
|
|
|
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]))
|
|
}
|
|
}
|
|
|
|
pub struct LitervalCountParser<P, T> {
|
|
pub(crate) parser: P,
|
|
pub(crate) phantom_data: PhantomData<T>,
|
|
}
|
|
|
|
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, usize, TContext>
|
|
for LitervalCountParser<P, T>
|
|
where
|
|
TToken: Debug + Clone,
|
|
P: Parser<'a, TToken, T, TContext>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, usize> {
|
|
let origin_input = input;
|
|
let (input, _) = self.parser.parse(context, input)?;
|
|
|
|
if origin_input.is_empty() {
|
|
return Err(FailedParserResult::new_with_str(
|
|
input,
|
|
"Empty input, the 'literal' parser cann't get length of elememt.",
|
|
));
|
|
}
|
|
|
|
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, index))
|
|
}
|
|
}
|
|
|
|
pub struct LookAheadParser<P, T> {
|
|
pub(crate) parser: P,
|
|
pub(crate) phantom_data: PhantomData<T>,
|
|
}
|
|
|
|
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, T, TContext> for LookAheadParser<P, T>
|
|
where
|
|
TToken: Debug + Clone,
|
|
P: Parser<'a, TToken, T, TContext>,
|
|
{
|
|
fn parse(
|
|
&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<'a, TToken, T: 'a, TResult: 'a, TContext, P> Parser<'a, TToken, TResult, TContext>
|
|
for ReverseParser<P, T, TResult>
|
|
where
|
|
TToken: Debug + Clone,
|
|
TResult: Debug + Clone,
|
|
P: Parser<'a, TToken, T, TContext>,
|
|
{
|
|
fn parse(
|
|
&self,
|
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
|
input: &'a [TToken],
|
|
) -> ParserResult<'a, TToken, TResult> {
|
|
match self.parser.parse(context, input) {
|
|
Ok(_) => Err(FailedParserResult::new_with_str(
|
|
input,
|
|
"Reverse successful parser.",
|
|
)),
|
|
Err(_) => Ok((input, self.result.clone())),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use crate::parser::{
|
|
failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
|
|
};
|
|
use crate::text::char_parser;
|
|
|
|
#[test]
|
|
fn map_test() {
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("hello, world!", ()),
|
|
&(),
|
|
|c, i| take(5).map(|_| ()).parse(c, i),
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn bind_test() {
|
|
parser_test_helper(ParserContext::new_with_str("abc", ()), &'b', |c, i| {
|
|
char_parser('a').bind(|_| char_parser('b')).parse(c, i)
|
|
});
|
|
|
|
parser_test_helper(ParserContext::new_with_str("abc", ()), &'c', |c, i| {
|
|
char_parser('a')
|
|
.bind(|_| char_parser('b'))
|
|
.bind(|_| char_parser('c'))
|
|
.parse(c, i)
|
|
});
|
|
}
|
|
|
|
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(FailedParserResult::new_with_str(input, "What?")),
|
|
Some(r) => Ok((input, Number(r as i32))),
|
|
}
|
|
}
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("9", ()),
|
|
&"9".to_owned(),
|
|
|c, i| single_numer_parser.convert().parse(c, i),
|
|
);
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("1", ()),
|
|
&"1".to_owned(),
|
|
|c, i| single_numer_parser.convert().parse(c, i),
|
|
);
|
|
|
|
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
|
|
single_numer_parser.convert::<String>().parse(c, i)
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn next_test() {
|
|
fn parser(
|
|
context: Rc<RefCell<ParserContext<char, ()>>>,
|
|
input: &[char],
|
|
) -> ParserResult<char, Number> {
|
|
satisfy(|c: &char| c.is_numeric())
|
|
.next(|r| match r {
|
|
Ok((input, result)) => match result.to_digit(10) {
|
|
None => Err(FailedParserResult::new_with_str(input, "What?")),
|
|
Some(r) => Ok((input, Number(r as i32))),
|
|
},
|
|
Err(r) => Err(r),
|
|
})
|
|
.parse(context, input)
|
|
}
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("9", ()),
|
|
&"9".to_owned(),
|
|
|c, i| parser.convert().parse(c, i),
|
|
);
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("1", ()),
|
|
&"1".to_owned(),
|
|
|c, i| parser.convert().parse(c, i),
|
|
);
|
|
|
|
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
|
|
parser.convert::<String>().parse(c, i)
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn literal_test() {
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("abc", ()),
|
|
&vec!['a'],
|
|
|c, i| {
|
|
char_parser('a')
|
|
.literal()
|
|
.map(|x| x.iter().map(|x| x.clone()).collect())
|
|
.parse(c, i)
|
|
},
|
|
);
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("abc", ()),
|
|
&vec!['a', 'b'],
|
|
|c, i| {
|
|
char_parser('a')
|
|
.bind(|_| char_parser('b'))
|
|
.literal()
|
|
.map(|x| x.iter().map(|x| x.clone()).collect())
|
|
.parse(c, i)
|
|
},
|
|
);
|
|
|
|
parser_test_helper(
|
|
ParserContext::new_with_str("abc", ()),
|
|
&vec!['a', 'b', 'c'],
|
|
|c, i| {
|
|
char_parser('a')
|
|
.bind(|_| char_parser('b'))
|
|
.bind(|_| char_parser('c'))
|
|
.literal()
|
|
.map(|x| x.iter().map(|x| x.clone()).collect())
|
|
.parse(c, i)
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn look_ahead_test() {
|
|
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
|
char_parser('a')
|
|
.look_ahead()
|
|
.bind(|_| char_parser('a'))
|
|
.parse(c, i)
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reverse_test() {
|
|
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| {
|
|
char_parser('b').reverse(()).parse(c, i)
|
|
});
|
|
|
|
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
|
|
char_parser('a').reverse(()).parse(c, i)
|
|
});
|
|
}
|
|
}
|