Compare commits

..

10 Commits

16 changed files with 842 additions and 506 deletions

View File

@@ -9,7 +9,9 @@ use crate::combinators::left_right_parsers::{LeftParser, RightParser};
use crate::combinators::many_parsers::{ use crate::combinators::many_parsers::{
Many1Parser, Many1TillParser, ManyParser, ManyTillParser, Skip1Parser, SkipParser, Many1Parser, Many1TillParser, ManyParser, ManyTillParser, Skip1Parser, SkipParser,
}; };
use crate::combinators::separated_parsers::{SeparateBy1Parser, SeparateOrEndBy1Parser}; use crate::combinators::separated_parsers::{
QuoteParser, SeparateBy1Parser, SeparateOrEndBy1Parser,
};
use crate::combinators::tuple_parser::{ParserTuple, TupleParser}; use crate::combinators::tuple_parser::{ParserTuple, TupleParser};
use crate::parser::{any, Parser}; use crate::parser::{any, Parser};
use std::fmt::Debug; use std::fmt::Debug;
@@ -190,7 +192,13 @@ where
PLeft: Parser<'a, TToken, TLeft, TContext>, PLeft: Parser<'a, TToken, TLeft, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>, PRight: Parser<'a, TToken, TRight, TContext>,
{ {
left.right(parser.many_till(right)) QuoteParser {
left,
parser,
right,
left_data: PhantomData,
right_data: PhantomData,
}
} }
pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
@@ -219,7 +227,7 @@ where
PSeparator: Parser<'a, TToken, TSeparator, TContext>, PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{ {
separate_by1(parser, separator).next(|r| match r { separate_by1(parser, separator).next(|r| match r {
Err((input, _)) => Ok((input, vec![])), Err(r) => Ok((r.input(), vec![])),
r => r, r => r,
}) })
} }
@@ -274,7 +282,7 @@ where
PSeparator: Parser<'a, TToken, TSeparator, TContext>, PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{ {
separate_or_end_by1(parser, separator).next(|r| match r { separate_or_end_by1(parser, separator).next(|r| match r {
Err((i, _)) => Ok((i, vec![])), Err(r) => Ok((r.input(), vec![])),
r => r, r => r,
}) })
} }

View File

@@ -17,7 +17,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
match self.first.parse(context.clone(), input) { match self.first.parse(context.clone(), input) {
@@ -38,7 +38,7 @@ mod test {
#[test] #[test]
fn alternate_test() { fn alternate_test() {
fn parser( fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, char> { ) -> ParserResult<char, char> {
char_parser('a') char_parser('a')
@@ -47,35 +47,35 @@ mod test {
.parse(context, input) .parse(context, input)
} }
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', parser); parser_test_helper("a", &'a', parser);
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser); parser_test_helper("b", &'b', parser);
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser); parser_test_helper("c", &'c', parser);
} }
#[test] #[test]
fn alternate_macro_test() { fn alternate_macro_test() {
fn parser( fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, char> { ) -> ParserResult<char, char> {
alternate!(char_parser('a'), char_parser('b'), char_parser('c')).parse(context, input) alternate!(char_parser('a'), char_parser('b'), char_parser('c')).parse(context, input)
} }
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', parser); parser_test_helper("a", &'a', parser);
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser); parser_test_helper("b", &'b', parser);
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser); parser_test_helper("c", &'c', parser);
} }
#[test] #[test]
fn alternate_function_test() { fn alternate_function_test() {
fn parser( fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, char> { ) -> ParserResult<char, char> {
alternate!(char_parser('a'), char_parser('b')).parse(context, input) alternate!(char_parser('a'), char_parser('b')).parse(context, input)
} }
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', |c, i| { parser_test_helper("a", &'a', |c, i| {
let parser = alternate!(parser, char_parser('c')); let parser = alternate!(parser, char_parser('c'));
let parser = alternate!(parser, char_parser('d')); let parser = alternate!(parser, char_parser('d'));
parser.parse(c, i) parser.parse(c, i)
@@ -85,27 +85,23 @@ mod test {
#[test] #[test]
fn alternate_pure_function_test() { fn alternate_pure_function_test() {
fn parser1( fn parser1(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, &[char]> { ) -> ParserResult<char, &[char]> {
alternate!(char_parser('a').literal(), char_parser('b').literal()).parse(context, input) alternate!(char_parser('a').literal(), char_parser('b').literal()).parse(context, input)
} }
fn parser2( fn parser2(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, &[char]> { ) -> ParserResult<char, &[char]> {
alternate!(char_parser('c').literal(), char_parser('d').literal()).parse(context, input) alternate!(char_parser('c').literal(), char_parser('d').literal()).parse(context, input)
} }
parser_test_helper( parser_test_helper("a", &"a".to_owned(), |c, i| {
ParserContext::new_with_str("a", ()),
&"a".to_owned(),
|c, i| {
alternate!(parser1, parser2) alternate!(parser1, parser2)
.map(|x| x.iter().map(|x| x.clone()).collect()) .map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i) .parse(c, i)
}, });
);
} }
} }

View File

@@ -19,7 +19,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
let (input, r) = self.left_parser.parse(context.clone(), input)?; let (input, r) = self.left_parser.parse(context.clone(), input)?;
@@ -46,7 +46,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, TRight> { ) -> ParserResult<'a, TToken, TRight> {
let (input, _) = self.left_parser.parse(context.clone(), input)?; let (input, _) = self.left_parser.parse(context.clone(), input)?;
@@ -58,19 +58,19 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::combinators::ParserExt; use crate::combinators::ParserExt;
use crate::parser::{parser_test_helper, Parser, ParserContext}; use crate::parser::{parser_test_helper, Parser};
use crate::text::char_parser; use crate::text::char_parser;
#[test] #[test]
fn left_test() { fn left_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| { parser_test_helper("abc", &'a', |c, i| {
char_parser('a').left(char_parser('b')).parse(c, i) char_parser('a').left(char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn right_test() { fn right_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'b', |c, i| { parser_test_helper("abc", &'b', |c, i| {
char_parser('a').right(char_parser('b')).parse(c, i) char_parser('a').right(char_parser('b')).parse(c, i)
}) })
} }

View File

@@ -15,7 +15,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let mut result = vec![]; let mut result = vec![];
@@ -41,7 +41,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, first_result) = self.parser.parse(context.clone(), input)?; let (mut input, first_result) = self.parser.parse(context.clone(), input)?;
@@ -68,7 +68,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, ()> { ) -> ParserResult<'a, TToken, ()> {
let mut input = input; let mut input = input;
@@ -93,7 +93,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, ()> { ) -> ParserResult<'a, TToken, ()> {
let (mut input, _) = self.parser.parse(context.clone(), input)?; let (mut input, _) = self.parser.parse(context.clone(), input)?;
@@ -121,7 +121,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let mut input = input; let mut input = input;
@@ -136,9 +136,9 @@ where
input = i; input = i;
result.push(r); result.push(r);
} else { } else {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("End with other elements.".to_owned()), "End with other elements.",
)); ));
} }
} }
@@ -159,7 +159,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, r) = self.parser.parse(context.clone(), input)?; let (mut input, r) = self.parser.parse(context.clone(), input)?;
@@ -174,9 +174,9 @@ where
result.push(r); result.push(r);
input = i; input = i;
} else { } else {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("End with other elements.".to_owned()), "End with other elements.",
)); ));
} }
} }
@@ -192,130 +192,112 @@ mod test {
#[test] #[test]
fn many_test() { fn many_test() {
parser_test_helper( parser_test_helper("aaa", &vec!['a', 'a', 'a'], |c, i| {
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("bbaa", ()), &vec![], |c, i| {
char_parser('a').many().parse(c, i) char_parser('a').many().parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("", ()), &vec![], |c, i| { parser_test_helper("aaabbaa", &vec!['a', 'a', 'a'], |c, i| {
char_parser('a').many().parse(c, i) char_parser('a').many().parse(c, i)
}); });
parser_test_helper("bbaa", &vec![], |c, i| char_parser('a').many().parse(c, i));
parser_test_helper("", &vec![], |c, i| char_parser('a').many().parse(c, i));
} }
#[test] #[test]
fn many1_test() { fn many1_test() {
parser_test_helper( parser_test_helper("aaa", &vec!['a', 'a', 'a'], |c, i| {
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1().parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("bbaa", ()), |c, i| {
char_parser('a').many1().parse(c, i) char_parser('a').many1().parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("", ()), |c, i| { parser_test_helper("aaabbaa", &vec!['a', 'a', 'a'], |c, i| {
char_parser('a').many1().parse(c, i) char_parser('a').many1().parse(c, i)
}); });
failed_parser_test_helper("bbaa", |c, i| char_parser('a').many1().parse(c, i));
failed_parser_test_helper("baa", |c, i| char_parser('a').many1().parse(c, i));
} }
#[test] #[test]
fn skip_test() { fn skip_test() {
parser_test_helper(ParserContext::new_with_str("aaab", ()), &'b', |c, i| { parser_test_helper("aaab", &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i) char_parser('a').skip().right(char_parser('b')).parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', |c, i| { parser_test_helper("b", &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i) char_parser('a').skip().right(char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn skip1_test() { fn skip1_test() {
parser_test_helper(ParserContext::new_with_str("aaab", ()), &'b', |c, i| { parser_test_helper("aaab", &'b', |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i) char_parser('a').skip1().right(char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| { failed_parser_test_helper("b", |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i) char_parser('a').skip1().right(char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn many_till_test() { fn many_till_test() {
parser_test_helper( parser_test_helper("aaab", &vec!['a', 'a', 'a'], |c, i| {
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many_till(char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("b", ()), &vec![], |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i) char_parser('a').many_till(char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| { parser_test_helper("b", &vec![], |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i)
});
parser_test_helper("aaabc", &vec!['a', 'a', 'a'], |c, i| {
char_parser('a')
.many_till(char_parser('b'))
.left(char_parser('b'))
.left(char_parser('c'))
.parse(c, i)
});
failed_parser_test_helper("aaacb", |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i) char_parser('a').many_till(char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn many1_till_test() { fn many1_till_test() {
parser_test_helper( parser_test_helper("aaab", &vec!['a', 'a', 'a'], |c, i| {
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1_till(char_parser('b')).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i) char_parser('a').many1_till(char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| { failed_parser_test_helper("b", |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i)
});
failed_parser_test_helper("aaacb", |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i) char_parser('a').many1_till(char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn take_till_test() { fn take_till_test() {
parser_test_helper( parser_test_helper("aaab", &(vec!['a', 'a', 'a'], 'b'), |c, i| {
ParserContext::new_with_str("aaab", ()), tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i)
&(vec!['a', 'a', 'a'], 'b'), });
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
parser_test_helper( parser_test_helper("b", &(vec![], 'b'), |c, i| {
ParserContext::new_with_str("b", ()), tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i)
&(vec![], 'b'), });
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
} }
#[test] #[test]
fn take1_till_test() { fn take1_till_test() {
parser_test_helper( parser_test_helper("aaab", &(vec!['a', 'a', 'a'], 'b'), |c, i| {
ParserContext::new_with_str("aaab", ()), tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i)
&(vec!['a', 'a', 'a'], 'b'), });
|c, i| tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| { failed_parser_test_helper("b", |c, i| {
tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i) tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i)
}); });
} }

View File

@@ -1,9 +1,60 @@
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;
use std::rc::Rc; use std::rc::Rc;
pub struct QuoteParser<P, PLeft, PRight, TLeft, TRight> {
pub(crate) parser: P,
pub(crate) left: PLeft,
pub(crate) right: PRight,
pub(crate) left_data: PhantomData<TLeft>,
pub(crate) right_data: PhantomData<TRight>,
}
impl<'a, TToken, T: 'a, TLeft: 'a, TRight: 'a, TContext, P, PLeft, PRight>
Parser<'a, TToken, Vec<T>, TContext> for QuoteParser<P, PLeft, PRight, TLeft, TRight>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
PLeft: Parser<'a, TToken, TLeft, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, _) = match self.left.parse(context.clone(), input) {
Err(r) => Err(FailedParserResult::new(
r.input(),
format!("Failed to parse left quote: {}", r.message()),
)),
r => r,
}?;
let mut result = vec![];
loop {
if let Ok((i, _)) = self.right.parse(context.clone(), input) {
input = i;
break;
}
if let Ok((i, r)) = self.parser.parse(context.clone(), input) {
input = i;
result.push(r);
} else {
return Err(FailedParserResult::new_with_str(
input,
"Quote without the right quote.",
));
}
}
Ok((input, result))
}
}
pub struct SeparateBy1Parser<P, PSeparator, TSeparator> { pub struct SeparateBy1Parser<P, PSeparator, TSeparator> {
pub(crate) parser: P, pub(crate) parser: P,
pub(crate) separator: PSeparator, pub(crate) separator: PSeparator,
@@ -19,7 +70,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, first) = self.parser.parse(context.clone(), input)?; let (mut input, first) = self.parser.parse(context.clone(), input)?;
@@ -54,7 +105,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> { ) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, first) = self.parser.parse(context.clone(), input)?; let (mut input, first) = self.parser.parse(context.clone(), input)?;
@@ -82,6 +133,7 @@ mod test {
use super::*; use super::*;
use crate::combinators::{ use crate::combinators::{
end_by, end_by1, quote, separate_by, separate_by1, separate_or_end_by, separate_or_end_by1, end_by, end_by1, quote, separate_by, separate_by1, separate_or_end_by, separate_or_end_by1,
ParserExt,
}; };
use crate::parser::{failed_parser_test_helper, parser_test_helper, satisfy}; use crate::parser::{failed_parser_test_helper, parser_test_helper, satisfy};
use crate::text::char_parser; use crate::text::char_parser;
@@ -89,7 +141,7 @@ mod test {
#[test] #[test]
fn quote_test() { fn quote_test() {
fn parser( fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, Vec<char>> { ) -> ParserResult<char, Vec<char>> {
quote( quote(
@@ -100,140 +152,112 @@ mod test {
.parse(context, input) .parse(context, input)
} }
parser_test_helper( parser_test_helper("'abc'", &vec!['a', 'b', 'c'], parser);
ParserContext::new_with_str("'abc'", ()), parser_test_helper("''", &vec![], parser);
&vec!['a', 'b', 'c'], failed_parser_test_helper("asd", parser);
parser,
); parser_test_helper("'a'b", &vec!['a'], |c, i| {
parser_test_helper(ParserContext::new_with_str("''", ()), &vec![], parser); quote(char_parser('\''), char_parser('a'), char_parser('\''))
failed_parser_test_helper(ParserContext::new_with_str("asd", ()), parser) .left(char_parser('b'))
.parse(c, i)
})
} }
#[test] #[test]
fn separate_by1_test() { fn separate_by1_test() {
parser_test_helper( parser_test_helper("a,b,c", &vec!['a', 'b', 'c'], |c, i| {
ParserContext::new_with_str("a,b,c", ()), separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
&vec!['a', 'b', 'c'], });
|c, i| separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i), parser_test_helper("a", &vec!['a'], |c, i| {
); separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
parser_test_helper(ParserContext::new_with_str("a", ()), &vec!['a'], |c, i| { });
parser_test_helper("bbc", &vec!['b'], |c, i| {
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i) separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
}); });
parser_test_helper(
ParserContext::new_with_str("bbc", ()),
&vec!['b'],
|c, i| separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
} }
#[test] #[test]
fn separate_by_test() { fn separate_by_test() {
parser_test_helper( parser_test_helper("1,2,3", &vec!['1', '2', '3'], |c, i| {
ParserContext::new_with_str("1,2,3", ()),
&vec!['1', '2', '3'],
|c, i| separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i) separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("", ()), &vec![], |c, i| { parser_test_helper("1", &vec!['1'], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
});
parser_test_helper("", &vec![], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
});
parser_test_helper("abc", &vec!['a'], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i) separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
}); });
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a'],
|c, i| separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
} }
#[test] #[test]
fn end_by1_test() { fn end_by1_test() {
parser_test_helper( parser_test_helper("aab", &vec!['a', 'a'], |c, i| {
ParserContext::new_with_str("aab", ()),
&vec!['a', 'a'],
|c, i| end_by1(char_parser('a'), char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("ab", ()), &vec!['a'], |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i) end_by1(char_parser('a'), char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| { parser_test_helper("ab", &vec!['a'], |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i) end_by1(char_parser('a'), char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("cd", ()), |c, i| { failed_parser_test_helper("b", |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i)
});
failed_parser_test_helper("cd", |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i) end_by1(char_parser('a'), char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn end_by_test() { fn end_by_test() {
parser_test_helper( parser_test_helper("aab", &vec!['a', 'a'], |c, i| {
ParserContext::new_with_str("aab", ()),
&vec!['a', 'a'],
|c, i| end_by(char_parser('a'), char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("ab", ()), &vec!['a'], |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i) end_by(char_parser('a'), char_parser('b')).parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("b", ()), &vec![], |c, i| { parser_test_helper("ab", &vec!['a'], |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i) end_by(char_parser('a'), char_parser('b')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("cd", ()), |c, i| { parser_test_helper("b", &vec![], |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i)
});
failed_parser_test_helper("cd", |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i) end_by(char_parser('a'), char_parser('b')).parse(c, i)
}); });
} }
#[test] #[test]
fn separate_or_end_by1_test() { fn separate_or_end_by1_test() {
parser_test_helper( parser_test_helper("1,2,3,", &vec!['1', '2', '3'], |c, i| {
ParserContext::new_with_str("1,2,3,", ()),
&vec!['1', '2', '3'],
|c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(','))
.parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1,", ()), &vec!['1'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
parser_test_helper( parser_test_helper("1,", &vec!['1'], |c, i| {
ParserContext::new_with_str("1,2,3", ()),
&vec!['1', '2', '3'],
|c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(','))
.parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { parser_test_helper("1,2,3", &vec!['1', '2', '3'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
parser_test_helper("1", &vec!['1'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
failed_parser_test_helper("abc", |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
} }
#[test] #[test]
fn separate_or_end_by_test() { fn separate_or_end_by_test() {
parser_test_helper( parser_test_helper("1,2,3,", &vec!['1', '2', '3'], |c, i| {
ParserContext::new_with_str("1,2,3,", ()),
&vec!['1', '2', '3'],
|c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1,", ()), &vec!['1'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
parser_test_helper( parser_test_helper("1", &vec!['1'], |c, i| {
ParserContext::new_with_str("1,2,3", ()),
&vec!['1', '2', '3'],
|c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("abc", ()), &vec![], |c, i| { parser_test_helper("1,2,3", &vec!['1', '2', '3'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
parser_test_helper("1,", &vec!['1'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
parser_test_helper("abc", &vec![], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i) separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
}); });
} }

View File

@@ -9,7 +9,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T>; ) -> ParserResult<'a, TToken, T>;
} }
@@ -25,7 +25,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
self.parser.parse(context, input) self.parser.parse(context, input)
@@ -41,7 +41,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2)> { ) -> ParserResult<'a, TToken, (T1, T2)> {
let (input, r1) = self.0.parse(context.clone(), input)?; let (input, r1) = self.0.parse(context.clone(), input)?;
@@ -61,7 +61,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3)> { ) -> ParserResult<'a, TToken, (T1, T2, T3)> {
let (input, r1) = self.0.parse(context.clone(), input)?; let (input, r1) = self.0.parse(context.clone(), input)?;
@@ -83,7 +83,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3, T4)> { ) -> ParserResult<'a, TToken, (T1, T2, T3, T4)> {
let (input, r1) = self.0.parse(context.clone(), input)?; let (input, r1) = self.0.parse(context.clone(), input)?;
@@ -107,7 +107,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5)> { ) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5)> {
let (input, r1) = self.0.parse(context.clone(), input)?; let (input, r1) = self.0.parse(context.clone(), input)?;
@@ -120,6 +120,146 @@ where
} }
} }
impl<
'a,
TToken,
T1: 'a,
T2: 'a,
T3: 'a,
T4: 'a,
T5: 'a,
T6: 'a,
TContext,
P1,
P2,
P3,
P4,
P5,
P6,
> ParserTuple<'a, TToken, (T1, T2, T3, T4, T5, T6), TContext> for (P1, P2, P3, P4, P5, P6)
where
TToken: Debug + Clone,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
P4: Parser<'a, TToken, T4, TContext>,
P5: Parser<'a, TToken, T5, TContext>,
P6: Parser<'a, TToken, T6, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5, T6)> {
let (input, r1) = self.0.parse(context.clone(), input)?;
let (input, r2) = self.1.parse(context.clone(), input)?;
let (input, r3) = self.2.parse(context.clone(), input)?;
let (input, r4) = self.3.parse(context.clone(), input)?;
let (input, r5) = self.4.parse(context.clone(), input)?;
let (input, r6) = self.5.parse(context.clone(), input)?;
Ok((input, (r1, r2, r3, r4, r5, r6)))
}
}
impl<
'a,
TToken,
T1: 'a,
T2: 'a,
T3: 'a,
T4: 'a,
T5: 'a,
T6: 'a,
T7: 'a,
TContext,
P1,
P2,
P3,
P4,
P5,
P6,
P7,
> ParserTuple<'a, TToken, (T1, T2, T3, T4, T5, T6, T7), TContext>
for (P1, P2, P3, P4, P5, P6, P7)
where
TToken: Debug + Clone,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
P4: Parser<'a, TToken, T4, TContext>,
P5: Parser<'a, TToken, T5, TContext>,
P6: Parser<'a, TToken, T6, TContext>,
P7: Parser<'a, TToken, T7, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5, T6, T7)> {
let (input, r1) = self.0.parse(context.clone(), input)?;
let (input, r2) = self.1.parse(context.clone(), input)?;
let (input, r3) = self.2.parse(context.clone(), input)?;
let (input, r4) = self.3.parse(context.clone(), input)?;
let (input, r5) = self.4.parse(context.clone(), input)?;
let (input, r6) = self.5.parse(context.clone(), input)?;
let (input, r7) = self.6.parse(context.clone(), input)?;
Ok((input, (r1, r2, r3, r4, r5, r6, r7)))
}
}
impl<
'a,
TToken,
T1: 'a,
T2: 'a,
T3: 'a,
T4: 'a,
T5: 'a,
T6: 'a,
T7: 'a,
T8: 'a,
TContext,
P1,
P2,
P3,
P4,
P5,
P6,
P7,
P8,
> ParserTuple<'a, TToken, (T1, T2, T3, T4, T5, T6, T7, T8), TContext>
for (P1, P2, P3, P4, P5, P6, P7, P8)
where
TToken: Debug + Clone,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
P4: Parser<'a, TToken, T4, TContext>,
P5: Parser<'a, TToken, T5, TContext>,
P6: Parser<'a, TToken, T6, TContext>,
P7: Parser<'a, TToken, T7, TContext>,
P8: Parser<'a, TToken, T8, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5, T6, T7, T8)> {
let (input, r1) = self.0.parse(context.clone(), input)?;
let (input, r2) = self.1.parse(context.clone(), input)?;
let (input, r3) = self.2.parse(context.clone(), input)?;
let (input, r4) = self.3.parse(context.clone(), input)?;
let (input, r5) = self.4.parse(context.clone(), input)?;
let (input, r6) = self.5.parse(context.clone(), input)?;
let (input, r7) = self.6.parse(context.clone(), input)?;
let (input, r8) = self.7.parse(context.clone(), input)?;
Ok((input, (r1, r2, r3, r4, r5, r6, r7, r8)))
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@@ -129,22 +269,15 @@ mod test {
#[test] #[test]
fn tuple_test() { fn tuple_test() {
parser_test_helper( parser_test_helper("ab", &('a', 'b'), |c, i| {
ParserContext::new_with_str("ab", ()), tuple((char_parser('a'), char_parser('b'))).parse(c, i)
&('a', 'b'), });
|c, i| tuple((char_parser('a'), char_parser('b'))).parse(c, i),
);
parser_test_helper( parser_test_helper("abc", &('a', 'b', 'c'), |c, i| {
ParserContext::new_with_str("abc", ()), tuple((char_parser('a'), char_parser('b'), char_parser('c'))).parse(c, i)
&('a', 'b', 'c'), });
|c, i| tuple((char_parser('a'), char_parser('b'), char_parser('c'))).parse(c, i),
);
parser_test_helper( parser_test_helper("abcd", &('a', 'b', 'c', 'd'), |c, i| {
ParserContext::new_with_str("abcd", ()),
&('a', 'b', 'c', 'd'),
|c, i| {
tuple(( tuple((
char_parser('a'), char_parser('a'),
char_parser('b'), char_parser('b'),
@@ -152,7 +285,6 @@ mod test {
char_parser('d'), char_parser('d'),
)) ))
.parse(c, i) .parse(c, i)
}, });
);
} }
} }

View File

@@ -2,72 +2,74 @@ mod modified_parsers;
mod primitive_parsers; mod primitive_parsers;
use crate::parser::modified_parsers::{ use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser, AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser,
NextParser, ReverseParser, MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser,
}; };
use crate::parser::primitive_parsers::{ use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser, AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
TakeParser, SucceedParser, TakeParser,
}; };
use std::cell::RefCell; use std::cell::RefCell;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct FailedParserResult { pub struct FailedParserResult<'a, TToken: Debug> {
input: &'a [TToken],
message: String, message: String,
} }
impl FailedParserResult { impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
pub fn new(message: String) -> Self { pub fn new(input: &'a [TToken], message: String) -> Self {
Self { message } Self { input, message }
}
pub fn new_with_str(input: &'a [TToken], message: &'static str) -> Self {
Self {
input,
message: message.to_owned(),
}
}
pub fn new_with_error(input: &'a [TToken], err: anyhow::Error) -> Self {
Self {
input,
message: format!("{}", err),
}
} }
pub fn message(&self) -> &str { pub fn message(&self) -> &str {
self.message.as_str() self.message.as_str()
} }
pub fn input(&self) -> &'a [TToken] {
self.input
}
} }
impl Display for FailedParserResult { impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {}
impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Parse failed: {}.", self.message) write!(
f,
"Parse failed: {}, the input is '{:?}'.",
self.message, self.input
)
} }
} }
pub type ParserResult<'a, TToken, T> = pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>;
Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>;
pub struct ParserContext<TToken, TContext> pub struct ParserContext<TContext> {
where
TToken: Debug + Clone,
{
pub context: TContext, pub context: TContext,
input_array: Vec<TToken>,
} }
impl<TToken, TContext> ParserContext<TToken, TContext> impl<TContext> ParserContext<TContext> {
where pub fn new(context: TContext) -> Rc<RefCell<Self>> {
TToken: Debug + Clone, Rc::new(RefCell::new(Self { context }))
{
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,
}))
} }
} }
@@ -78,7 +80,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T>; ) -> ParserResult<'a, TToken, T>;
@@ -160,6 +162,17 @@ where
} }
} }
fn try_parse(self, result: T) -> TryParser<Self, T>
where
Self: Sized,
T: Clone,
{
TryParser {
parser: self,
result,
}
}
fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult> fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
where where
Self: Sized, Self: Sized,
@@ -171,19 +184,46 @@ where
phantom_data: PhantomData, phantom_data: PhantomData,
} }
} }
fn optional(self) -> OptionalParser<Self>
where
Self: Sized,
{
OptionalParser { parser: self }
}
fn run<F>(self, action: F) -> RunParser<Self, F>
where
Self: Sized,
F: Fn(&T) -> (),
{
RunParser {
parser: self,
action,
}
}
fn and_then<TResult, F>(self, mapper: F) -> AndThenParser<Self, F, T>
where
Self: Sized,
F: Fn(T) -> anyhow::Result<TResult>,
{
AndThenParser {
parser: self,
mapper,
phantom_data: PhantomData,
}
}
} }
impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F
where where
TToken: Debug + Clone + 'a, TToken: Debug + Clone + 'a,
F: Fn( F: Fn(Rc<RefCell<ParserContext<TContext>>>, &'a [TToken]) -> ParserResult<'a, TToken, T>,
Rc<RefCell<ParserContext<TToken, TContext>>>,
&'a [TToken],
) -> ParserResult<'a, TToken, T>,
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
(*self)(context, input) (*self)(context, input)
@@ -197,7 +237,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
(**self).parse(context, input) (**self).parse(context, input)
@@ -241,6 +281,16 @@ where
SatisfyParser { predicate } SatisfyParser { predicate }
} }
pub fn satified_map<'a, TToken, TContext, T: 'a, F>(
mapper: F,
) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
F: Fn(&TToken) -> Option<T>,
{
SatifiedMapParser { mapper }
}
pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext> pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext>
where where
TToken: Debug + Clone + 'a, TToken: Debug + Clone + 'a,
@@ -263,32 +313,27 @@ where
} }
#[cfg(test)] #[cfg(test)]
pub fn parser_test_helper<T, P>( pub fn parser_test_helper<T, P>(input: &str, excepted_node: &T, test_parser: P)
context: Rc<RefCell<ParserContext<char, ()>>>, where
excepted_node: &T,
test_parser: P,
) where
T: PartialEq + Debug, T: PartialEq + Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>, P: for<'a> Fn(Rc<RefCell<ParserContext<()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{ {
let borrowed_context = context.borrow(); let word: Vec<char> = input.chars().collect();
let input = borrowed_context.input_slice(); let (_, actual_result) = test_parser
let (_, actual_result) = test_parser.parse(context.clone(), input).unwrap(); .parse(ParserContext::new(()), word.as_slice())
.unwrap();
assert_eq!(excepted_node, &actual_result); assert_eq!(excepted_node, &actual_result);
} }
#[cfg(test)] #[cfg(test)]
pub fn failed_parser_test_helper<T, P>( pub fn failed_parser_test_helper<T, P>(input: &str, test_parser: P)
context: Rc<RefCell<ParserContext<char, ()>>>, where
test_parser: P,
) where
T: Debug, T: Debug,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>, P: for<'a> Fn(Rc<RefCell<ParserContext<()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{ {
let borrowed_context = context.borrow(); let word: Vec<char> = input.chars().collect();
let input = borrowed_context.input_slice(); let result = test_parser.parse(ParserContext::new(()), word.as_slice());
let result = test_parser.parse(context.clone(), input);
assert!(result.is_err()); assert!(result.is_err());
} }

View File

@@ -19,7 +19,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T2> { ) -> ParserResult<'a, TToken, T2> {
self.parser self.parser
@@ -44,7 +44,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T2> { ) -> ParserResult<'a, TToken, T2> {
let (input, middle) = self.parser.parse(context.clone(), input)?; let (input, middle) = self.parser.parse(context.clone(), input)?;
@@ -68,7 +68,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T2> { ) -> ParserResult<'a, TToken, T2> {
self.parser self.parser
@@ -92,7 +92,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, TResult> { ) -> ParserResult<'a, TToken, TResult> {
let result = self.parser.parse(context, input); let result = self.parser.parse(context, input);
@@ -114,18 +114,16 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, &'a [TToken]> { ) -> ParserResult<'a, TToken, &'a [TToken]> {
let origin_input = input; let origin_input = input;
let (input, _) = self.parser.parse(context, input)?; let (input, _) = self.parser.parse(context, input)?;
if origin_input.is_empty() { if origin_input.is_empty() {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new( "Empty input, the 'literal' parser cann't get length of elememt.",
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
)); ));
} }
@@ -149,18 +147,16 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, usize> { ) -> ParserResult<'a, TToken, usize> {
let origin_input = input; let origin_input = input;
let (input, _) = self.parser.parse(context, input)?; let (input, _) = self.parser.parse(context, input)?;
if origin_input.is_empty() { if origin_input.is_empty() {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new( "Empty input, the 'literal' parser cann't get length of elememt.",
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
)); ));
} }
@@ -183,7 +179,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
let original_input = input; let original_input = input;
@@ -193,6 +189,29 @@ where
} }
} }
pub struct TryParser<P, T> {
pub(crate) parser: P,
pub(crate) result: T,
}
impl<'a, TToken, T, TContext, P> Parser<'a, TToken, T, TContext> for TryParser<P, T>
where
TToken: Debug + Clone,
T: Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
match self.parser.parse(context, input) {
Err(r) => Ok((r.input, self.result.clone())),
r => r,
}
}
}
pub struct ReverseParser<P, T, TResult> { pub struct ReverseParser<P, T, TResult> {
pub(crate) parser: P, pub(crate) parser: P,
pub(crate) result: TResult, pub(crate) result: TResult,
@@ -208,15 +227,91 @@ where
{ {
fn parse( fn parse(
&self, &self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>, context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, TResult> { ) -> ParserResult<'a, TToken, TResult> {
match self.parser.parse(context, input) { match self.parser.parse(context, input) {
Ok((input, _)) => Err(( Ok(_) => Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("Reverse failed succeeded.".to_owned()), "Reverse successful parser.",
)), )),
Err((input, _)) => Ok((input, self.result.clone())), Err(_) => Ok((input, self.result.clone())),
}
}
}
pub struct OptionalParser<P> {
pub(crate) parser: P,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Option<T>, TContext> for OptionalParser<P>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Option<T>> {
match self.parser.parse(context, input) {
Ok(r) => Ok((r.0, Some(r.1))),
Err(r) => Ok((r.input, None)),
}
}
}
pub struct RunParser<P, F> {
pub(crate) parser: P,
pub(crate) action: F,
}
impl<'a, TToken, T: 'a, TContext, P, F> Parser<'a, TToken, T, TContext> for RunParser<P, F>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
F: Fn(&T) -> (),
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
match self.parser.parse(context, input) {
Ok(r) => {
(self.action)(&r.1);
Ok(r)
}
r => r,
}
}
}
pub struct AndThenParser<P, F, T> {
pub(crate) parser: P,
pub(crate) mapper: F,
pub(crate) phantom_data: PhantomData<T>,
}
impl<'a, TToken, T: 'a, TResult: 'a, TContext, P, F> Parser<'a, TToken, TResult, TContext>
for AndThenParser<P, F, T>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
F: Fn(T) -> anyhow::Result<TResult>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, TResult> {
match self.parser.parse(context, input) {
Ok((i, r)) => match (self.mapper)(r) {
Ok(result) => Ok((i, result)),
Err(err) => Err(FailedParserResult::new_with_error(i, err)),
},
Err(r) => Err(r),
} }
} }
} }
@@ -227,24 +322,20 @@ mod test {
use crate::parser::{ use crate::parser::{
failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult, failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
}; };
use crate::text::char_parser; use crate::text::{char_parser, char_satisfy};
#[test] #[test]
fn map_test() { fn map_test() {
parser_test_helper( parser_test_helper("hello, world!", &(), |c, i| take(5).map(|_| ()).parse(c, i))
ParserContext::new_with_str("hello, world!", ()),
&(),
|c, i| take(5).map(|_| ()).parse(c, i),
)
} }
#[test] #[test]
fn bind_test() { fn bind_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'b', |c, i| { parser_test_helper("abc", &'b', |c, i| {
char_parser('a').bind(|_| char_parser('b')).parse(c, i) char_parser('a').bind(|_| char_parser('b')).parse(c, i)
}); });
parser_test_helper(ParserContext::new_with_str("abc", ()), &'c', |c, i| { parser_test_helper("abc", &'c', |c, i| {
char_parser('a') char_parser('a')
.bind(|_| char_parser('b')) .bind(|_| char_parser('b'))
.bind(|_| char_parser('c')) .bind(|_| char_parser('c'))
@@ -263,30 +354,26 @@ mod test {
#[test] #[test]
fn convert_test() { fn convert_test() {
fn single_numer_parser( fn single_numer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, Number> { ) -> ParserResult<char, Number> {
let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?; let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
match result.to_digit(10) { match result.to_digit(10) {
None => Err((input, FailedParserResult::new("What?".to_string()))), None => Err(FailedParserResult::new_with_str(input, "What?")),
Some(r) => Ok((input, Number(r as i32))), Some(r) => Ok((input, Number(r as i32))),
} }
} }
parser_test_helper( parser_test_helper("9", &"9".to_owned(), |c, i| {
ParserContext::new_with_str("9", ()), single_numer_parser.convert().parse(c, i)
&"9".to_owned(), });
|c, i| single_numer_parser.convert().parse(c, i),
);
parser_test_helper( parser_test_helper("1", &"1".to_owned(), |c, i| {
ParserContext::new_with_str("1", ()), single_numer_parser.convert().parse(c, i)
&"1".to_owned(), });
|c, i| single_numer_parser.convert().parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { failed_parser_test_helper("abc", |c, i| {
single_numer_parser.convert::<String>().parse(c, i) single_numer_parser.convert::<String>().parse(c, i)
}); });
} }
@@ -294,13 +381,13 @@ mod test {
#[test] #[test]
fn next_test() { fn next_test() {
fn parser( fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, Number> { ) -> ParserResult<char, Number> {
satisfy(|c: &char| c.is_numeric()) satisfy(|c: &char| c.is_numeric())
.next(|r| match r { .next(|r| match r {
Ok((input, result)) => match result.to_digit(10) { Ok((input, result)) => match result.to_digit(10) {
None => Err((input, FailedParserResult::new("What?".to_string()))), None => Err(FailedParserResult::new_with_str(input, "What?")),
Some(r) => Ok((input, Number(r as i32))), Some(r) => Ok((input, Number(r as i32))),
}, },
Err(r) => Err(r), Err(r) => Err(r),
@@ -308,65 +395,43 @@ mod test {
.parse(context, input) .parse(context, input)
} }
parser_test_helper( parser_test_helper("9", &"9".to_owned(), |c, i| parser.convert().parse(c, i));
ParserContext::new_with_str("9", ()),
&"9".to_owned(),
|c, i| parser.convert().parse(c, i),
);
parser_test_helper( parser_test_helper("1", &"1".to_owned(), |c, i| parser.convert().parse(c, i));
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| { failed_parser_test_helper("abc", |c, i| parser.convert::<String>().parse(c, i));
parser.convert::<String>().parse(c, i)
});
} }
#[test] #[test]
fn literal_test() { fn literal_test() {
parser_test_helper( parser_test_helper("abc", &vec!['a'], |c, i| {
ParserContext::new_with_str("abc", ()),
&vec!['a'],
|c, i| {
char_parser('a') char_parser('a')
.literal() .literal()
.map(|x| x.iter().map(|x| x.clone()).collect()) .map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i) .parse(c, i)
}, });
);
parser_test_helper( parser_test_helper("abc", &vec!['a', 'b'], |c, i| {
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b'],
|c, i| {
char_parser('a') char_parser('a')
.bind(|_| char_parser('b')) .bind(|_| char_parser('b'))
.literal() .literal()
.map(|x| x.iter().map(|x| x.clone()).collect()) .map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i) .parse(c, i)
}, });
);
parser_test_helper( parser_test_helper("abc", &vec!['a', 'b', 'c'], |c, i| {
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b', 'c'],
|c, i| {
char_parser('a') char_parser('a')
.bind(|_| char_parser('b')) .bind(|_| char_parser('b'))
.bind(|_| char_parser('c')) .bind(|_| char_parser('c'))
.literal() .literal()
.map(|x| x.iter().map(|x| x.clone()).collect()) .map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i) .parse(c, i)
}, });
);
} }
#[test] #[test]
fn look_ahead_test() { fn look_ahead_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| { parser_test_helper("abc", &'a', |c, i| {
char_parser('a') char_parser('a')
.look_ahead() .look_ahead()
.bind(|_| char_parser('a')) .bind(|_| char_parser('a'))
@@ -375,13 +440,47 @@ mod test {
} }
#[test] #[test]
fn reverse_test() { fn try_parse_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| { parser_test_helper("abc", &'a', |c, i| {
char_parser('b').reverse(()).parse(c, i) char_parser('a').try_parse('a').parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { parser_test_helper("bc", &'a', |c, i| {
char_parser('a').reverse(()).parse(c, i) char_parser('a').try_parse('a').parse(c, i)
});
}
#[test]
fn reverse_test() {
parser_test_helper("abc", &(), |c, i| char_parser('b').reverse(()).parse(c, i));
failed_parser_test_helper("abc", |c, i| char_parser('a').reverse(()).parse(c, i));
}
#[test]
fn optional_test() {
parser_test_helper("abc", &Some('a'), |c, i| {
char_parser('a').optional().parse(c, i)
});
parser_test_helper("bc", &None, |c, i| char_parser('a').optional().parse(c, i));
}
#[test]
fn run_test() {
parser_test_helper("abc", &'a', |c, i| {
char_parser('a').run(|c| assert_eq!(c, &'a')).parse(c, i)
})
}
#[test]
fn and_then_test() {
parser_test_helper("123", &1, |c, i| {
char_satisfy(char::is_ascii_digit)
.and_then(|c| {
let word = c.to_string();
Ok(i32::from_str_radix(word.as_str(), 10)?)
})
.parse(c, i)
}); });
} }
} }

View File

@@ -15,7 +15,7 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
Ok((input, self.value.clone())) Ok((input, self.value.clone()))
@@ -32,12 +32,12 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
Err(( Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("Default failed parser.".to_owned()), "Default failed parser.",
)) ))
} }
} }
@@ -53,10 +53,10 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, T> { ) -> ParserResult<'a, TToken, T> {
Err((input, FailedParserResult::new(self.message.clone()))) Err(FailedParserResult::new(input, self.message.clone()))
} }
} }
@@ -71,20 +71,43 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, TToken> { ) -> ParserResult<'a, TToken, TToken> {
if input.is_empty() { if input.is_empty() {
return Err((input, FailedParserResult::new("Input is empty.".to_owned()))); return Err(FailedParserResult::new_with_str(input, "Input is empty"));
} }
if (self.predicate)(&input[0]) { if (self.predicate)(&input[0]) {
Ok((&input[1..], input[0].clone())) Ok((&input[1..], input[0].clone()))
} else { } else {
Err(( Err(FailedParserResult::new_with_str(input, "Predicate failed."))
input, }
FailedParserResult::new("Predicate failed.".to_owned()), }
)) }
pub struct SatifiedMapParser<F> {
pub(crate) mapper: F,
}
impl<'a, TToken, TContext, T: 'a, F> Parser<'a, TToken, T, TContext> for SatifiedMapParser<F>
where
TToken: Debug + Clone,
F: Fn(&TToken) -> Option<T>,
{
fn parse(
&self,
_: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
if input.is_empty() {
return Err(FailedParserResult::new_with_str(input, "Input is empty"));
}
if let Some(result) = (self.mapper)(&input[0]) {
Ok((&input[1..], result))
} else {
Err(FailedParserResult::new_with_str(input, "Predicate failed."))
} }
} }
} }
@@ -97,11 +120,11 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, TToken> { ) -> ParserResult<'a, TToken, TToken> {
if input.is_empty() { if input.is_empty() {
Err((input, FailedParserResult::new("Input is empty.".to_owned()))) Err(FailedParserResult::new_with_str(input, "Input is empty"))
} else { } else {
Ok((&input[1..], input[0].clone())) Ok((&input[1..], input[0].clone()))
} }
@@ -118,16 +141,16 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<TToken>> { ) -> ParserResult<'a, TToken, Vec<TToken>> {
if input.len() < self.count { if input.len() < self.count {
Err(( Err(FailedParserResult::new(
input, input,
FailedParserResult::new(format!( format!(
"The input doesn't contain enough {} elemements.", "The input doesn't contain enough {} elemements.",
self.count self.count
)), ),
)) ))
} else { } else {
Ok(( Ok((
@@ -148,16 +171,16 @@ where
{ {
fn parse( fn parse(
&self, &self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>, _: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [TToken], input: &'a [TToken],
) -> ParserResult<'a, TToken, ()> { ) -> ParserResult<'a, TToken, ()> {
if input.len() < self.count { if input.len() < self.count {
Err(( Err(FailedParserResult::new(
input, input,
FailedParserResult::new(format!( format!(
"The input doesn't contain enough {} elemements.", "The input doesn't contain enough {} elemements.",
self.count self.count
)), ),
)) ))
} else { } else {
Ok((&input[self.count..], ())) Ok((&input[self.count..], ()))
@@ -169,76 +192,69 @@ where
mod test { mod test {
use super::*; use super::*;
use crate::parser::{ use crate::parser::{
any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satisfy, skip, any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satified_map,
succeed, take, satisfy, skip, succeed, take,
}; };
#[test] #[test]
fn succeed_test() { fn succeed_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| { parser_test_helper("abc", &(), |c, i| succeed(()).parse(c, i));
succeed(()).parse(c, i)
});
} }
#[test] #[test]
fn fail_test() { fn fail_test() {
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { failed_parser_test_helper("abc", |c, i| fail::<char, (), ()>().parse(c, i));
fail::<char, (), ()>().parse(c, i)
});
} }
#[test] #[test]
fn fail_with_message_test() { fn fail_with_message_test() {
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { failed_parser_test_helper("abc", |c, i| {
fail_with_message::<char, (), ()>("Failed!").parse(c, i) fail_with_message::<char, (), ()>("Failed!").parse(c, i)
}); });
} }
#[test] #[test]
fn satisfy_test() { fn satisfy_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| { parser_test_helper("abc", &'a', |c, i| satisfy(|x| x == &'a').parse(c, i));
satisfy(|x| x == &'a').parse(c, i)
failed_parser_test_helper("abc", |c, i| satisfy(|x| x == &'b').parse(c, i));
}
#[test]
fn satified_map_test() {
parser_test_helper("123", &1, |c, i| {
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
}); });
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { parser_test_helper("23", &2, |c, i| {
satisfy(|x| x == &'b').parse(c, i) satified_map(|x: &char| x.to_digit(10)).parse(c, i)
});
parser_test_helper("3", &3, |c, i| {
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
}); });
} }
#[test] #[test]
fn any_test() { fn any_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| { parser_test_helper("abc", &'a', |c, i| any().parse(c, i));
any().parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("cde", ()), &'c', |c, i| { parser_test_helper("cde", &'c', |c, i| any().parse(c, i));
any().parse(c, i)
});
} }
#[test] #[test]
fn take_test() { fn take_test() {
parser_test_helper( parser_test_helper("hello, world!", &("hello".chars().collect()), |c, i| {
ParserContext::new_with_str("hello, world!", ()),
&("hello".chars().collect()),
|c, i| take(5).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), |c, i| {
take(5).parse(c, i) take(5).parse(c, i)
}); });
failed_parser_test_helper("abcd", |c, i| take(5).parse(c, i));
} }
#[test] #[test]
fn skip_test() { fn skip_test() {
parser_test_helper( parser_test_helper("hello, world!", &(), |c, i| skip(5).parse(c, i));
ParserContext::new_with_str("hello, world!", ()),
&(),
|c, i| skip(5).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), |c, i| { failed_parser_test_helper("abcd", |c, i| skip(5).parse(c, i));
skip(5).parse(c, i)
});
} }
} }

View File

@@ -1,23 +1,16 @@
use crate::parser::{satisfy, take, FailedParserResult, Parser}; mod string_parsers;
use crate::parser::{satisfy, Parser};
use crate::text::string_parsers::StringParser;
pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> { pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> {
satisfy(move |x| *x == c) satisfy(move |x| *x == c)
} }
pub fn string_parser<'a, TContext>(str: &'static str) -> impl Parser<'a, char, String, TContext> { pub fn string_parser<'a, TContext>(
take::<char, TContext>(str.chars().count()).next(move |result| { str: &'static str,
result.and_then(|(input, chars)| { ) -> impl Parser<'a, char, &'a [char], TContext> {
let chars: String = chars.iter().collect(); StringParser { str }
if chars == str {
Ok((input, chars))
} else {
Err((
input,
FailedParserResult::new(format!("Failed to parse '{}'.", str)),
))
}
})
})
} }
pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TContext> { pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TContext> {
@@ -25,6 +18,13 @@ pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TC
satisfy(move |c: &char| str.contains(c)) satisfy(move |c: &char| str.contains(c))
} }
pub fn char_satisfy<'a, TContext, F>(condition: F) -> impl Parser<'a, char, char, TContext>
where
F: Fn(&char) -> bool,
{
satisfy(move |x: &char| condition(x))
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@@ -36,44 +36,44 @@ mod test {
#[test] #[test]
fn char_parser_test() { fn char_parser_test() {
parser_test_helper( parser_test_helper("abc", &'a', |context, input| {
ParserContext::new_with_str("abc", ()), char_parser('a').parse(context, input)
&'a', });
|context, input| char_parser('a').parse(context, input),
);
failed_parser_test_helper(ParserContext::new_with_str("bc", ()), |context, input| { failed_parser_test_helper("bc", |context, input| {
char_parser('a').parse(context, input) char_parser('a').parse(context, input)
}); });
} }
#[test] #[test]
fn string_parser_test() { fn string_parser_test() {
parser_test_helper( parser_test_helper("Hello, world!", &"Hello".to_owned(), |context, input| {
ParserContext::new_with_str("Hello, world!", ()), string_parser("Hello")
&"Hello".to_owned(), .map(|x| x.iter().collect())
|context, input| string_parser("Hello").parse(context, input), .parse(context, input)
); });
fn test_parser( fn test_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, String> { ) -> ParserResult<char, String> {
let (input, first) = string_parser("hello, ").parse(context.clone(), input)?; let (input, first) = string_parser("hello, ").parse(context.clone(), input)?;
let (input, second) = string_parser("world!").parse(context.clone(), input)?; let (input, second) = string_parser("world!").parse(context.clone(), input)?;
Ok((input, first + second.as_str())) Ok((
input,
first.iter().collect::<String>() + second.iter().collect::<String>().as_str(),
))
} }
parser_test_helper( parser_test_helper("hello, world!", &"hello, world!".to_owned(), test_parser);
ParserContext::new_with_str("hello, world!", ()), parser_test_helper("hello, world!", &(), |context, input| {
&"hello, world!".to_owned(), test_parser.map(|_| ()).parse(context, input)
test_parser, })
); }
parser_test_helper(
ParserContext::new_with_str("hello, world!", ()), #[test]
&(), fn char_satsify_test() {
|context, input| test_parser.map(|_| ()).parse(context, input), parser_test_helper("abc", &'a', |c, i| char_satisfy(char::is_ascii).parse(c, i));
)
} }
} }

View File

@@ -0,0 +1,37 @@
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
use std::cell::RefCell;
use std::rc::Rc;
pub struct StringParser {
pub(crate) str: &'static str,
}
impl<'a, TContext> Parser<'a, char, &'a [char], TContext> for StringParser {
fn parse(
&self,
_: Rc<RefCell<ParserContext<TContext>>>,
input: &'a [char],
) -> ParserResult<'a, char, &'a [char]> {
let length = self.str.chars().count();
if input.len() < length {
return Err(FailedParserResult::new(
input,
format!("Failed to get enough elements for string '{}'.", self.str),
));
}
if (&input[..length])
.iter()
.zip(self.str.chars())
.map(|(x, y)| *x == y)
.all(|x| x)
{
Ok((&input[length..], &input[..length]))
} else {
Err(FailedParserResult::new(
input,
format!("Input is not string '{}'", self.str),
))
}
}
}

View File

@@ -75,10 +75,10 @@ fn file_lexical_parser_test() -> anyhow::Result<()> {
let (_, nom_tokens) = let (_, nom_tokens) =
nom_lexical_parser(source_file.content.as_str()).or_else(|e| Err(e.to_owned()))?; nom_lexical_parser(source_file.content.as_str()).or_else(|e| Err(e.to_owned()))?;
let context = ParserContext::new_with_str(source_file.content.as_str(), ()); let context = ParserContext::new(());
let borrowed_context = context.borrow(); let word: Vec<char> = source_file.content.chars().collect();
let (_, zero_tokens) = zero_lexical_parser(context.clone(), borrowed_context.input_slice()) let (_, zero_tokens) = zero_lexical_parser(context.clone(), word.as_slice())
.or_else(|e| Err(anyhow!("{}", e.1)))?; .or_else(|e| Err(anyhow!("{}", e)))?;
assert_eq!(nom_tokens.len(), zero_tokens.len()); assert_eq!(nom_tokens.len(), zero_tokens.len());

View File

@@ -5,11 +5,10 @@ use zero_parser::parser::ParserContext;
mod tokenizer; mod tokenizer;
fn validate_tokens(input: &'static str, tokens: Vec<LexicalTokenType>) { fn validate_tokens(input: &'static str, tokens: Vec<LexicalTokenType>) {
let context = ParserContext::new_with_str(input, ()); let context = ParserContext::new(());
let borrowed_context = context.borrow(); let word: Vec<char> = input.chars().collect();
let (_, actual_tokens) = let (_, actual_tokens) = zero_lexical_parser(context.clone(), word.as_slice()).unwrap();
zero_lexical_parser(context.clone(), borrowed_context.input_slice()).unwrap();
dbg!(&tokens, &actual_tokens); dbg!(&tokens, &actual_tokens);
assert_eq!(tokens.len(), actual_tokens.len()); assert_eq!(tokens.len(), actual_tokens.len());

View File

@@ -109,7 +109,7 @@ pub fn nom_lexical_parser(mut input: &str) -> IResult<&str, Vec<LexicalToken>> {
} }
pub fn zero_lexical_parser( pub fn zero_lexical_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
mut input: &[char], mut input: &[char],
) -> ParserResult<char, Vec<NewLexicalToken>> { ) -> ParserResult<char, Vec<NewLexicalToken>> {
let mut array = vec![]; let mut array = vec![];

View File

@@ -9,7 +9,7 @@ use zero_parser::text::{char_parser, one_of, string_parser};
use zero_parser::{alternate, parser::satisfy}; use zero_parser::{alternate, parser::satisfy};
pub fn keyword_parser( pub fn keyword_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -38,7 +38,7 @@ pub fn keyword_parser(
} }
pub fn delimiter_parser( pub fn delimiter_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
alternate!( alternate!(
@@ -60,7 +60,7 @@ pub fn delimiter_parser(
} }
pub fn operator_parser( pub fn operator_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
alternate!( alternate!(
@@ -89,7 +89,7 @@ pub fn operator_parser(
} }
pub fn identifier_parser( pub fn identifier_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -105,7 +105,7 @@ pub fn identifier_parser(
} }
pub fn decimal_integer_parser( pub fn decimal_integer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -126,7 +126,7 @@ pub fn decimal_integer_parser(
} }
pub fn octal_integer_parser( pub fn octal_integer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -147,7 +147,7 @@ pub fn octal_integer_parser(
} }
pub fn hexadecimal_integer_parser( pub fn hexadecimal_integer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -168,7 +168,7 @@ pub fn hexadecimal_integer_parser(
} }
pub fn integer_parser( pub fn integer_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
alternate!( alternate!(
@@ -180,7 +180,7 @@ pub fn integer_parser(
} }
pub fn float_parser( pub fn float_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
tuple(( tuple((
@@ -202,7 +202,7 @@ pub fn float_parser(
} }
pub fn literal_string_parser( pub fn literal_string_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
quote(char_parser('"'), any(), char_parser('"')) quote(char_parser('"'), any(), char_parser('"'))
@@ -211,14 +211,14 @@ pub fn literal_string_parser(
let length = x.len(); let length = x.len();
NewLexicalToken { NewLexicalToken {
token_type: LexicalTokenType::LiteralString, token_type: LexicalTokenType::LiteralString,
literal_value: &x[1..length], literal_value: &x[1..length - 1],
} }
}) })
.parse(context, input) .parse(context, input)
} }
pub fn comments_parser( pub fn comments_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, ()> { ) -> ParserResult<char, ()> {
alternate!( alternate!(
@@ -239,7 +239,7 @@ pub fn comments_parser(
} }
pub fn junk_parser( pub fn junk_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, ()> { ) -> ParserResult<char, ()> {
alternate!( alternate!(
@@ -250,7 +250,7 @@ pub fn junk_parser(
} }
pub fn combine_parser( pub fn combine_parser(
context: Rc<RefCell<ParserContext<char, ()>>>, context: Rc<RefCell<ParserContext<()>>>,
input: &[char], input: &[char],
) -> ParserResult<char, NewLexicalToken> { ) -> ParserResult<char, NewLexicalToken> {
alternate!( alternate!(

View File

@@ -1,3 +1,5 @@
extern crate core;
use crate::tokenizer::zero_parsers::{ use crate::tokenizer::zero_parsers::{
combine_parser, comments_parser, decimal_integer_parser, delimiter_parser, float_parser, combine_parser, comments_parser, decimal_integer_parser, delimiter_parser, float_parser,
hexadecimal_integer_parser, identifier_parser, integer_parser, keyword_parser, hexadecimal_integer_parser, identifier_parser, integer_parser, keyword_parser,
@@ -13,16 +15,12 @@ mod tokenizer;
fn assert_lexical_parser( fn assert_lexical_parser(
except: LexicalToken, except: LexicalToken,
parser: fn( parser: fn(Rc<RefCell<ParserContext<()>>>, &[char]) -> ParserResult<char, NewLexicalToken>,
Rc<RefCell<ParserContext<char, ()>>>,
&[char],
) -> ParserResult<char, NewLexicalToken>,
input: &str, input: &str,
) { ) {
let context = ParserContext::new_with_str(input, ()); let context = ParserContext::new(());
let borrowed_context = context.borrow(); let word: Vec<char> = input.chars().collect();
let input = borrowed_context.input_slice(); let (_, token) = parser(context.clone(), word.as_slice()).unwrap();
let (_, token) = parser(context.clone(), input).unwrap();
assert_eq!(except, token); assert_eq!(except, token);
} }
@@ -30,11 +28,11 @@ fn assert_lexical_parser(
fn assert_parser<T, F>(except: T, parser: F, input: &str) fn assert_parser<T, F>(except: T, parser: F, input: &str)
where where
T: PartialEq + Debug, T: PartialEq + Debug,
F: Fn(Rc<RefCell<ParserContext<char, ()>>>, &[char]) -> ParserResult<char, T>, F: Fn(Rc<RefCell<ParserContext<()>>>, &[char]) -> ParserResult<char, T>,
{ {
let context = ParserContext::new_with_str(input, ()); let context = ParserContext::new(());
let borrowed_context = context.borrow(); let word: Vec<char> = input.chars().collect();
let (_, token) = parser(context.clone(), borrowed_context.input_slice()).unwrap(); let (_, token) = parser(context.clone(), word.as_slice()).unwrap();
assert_eq!(except, token); assert_eq!(except, token);
} }