Compare commits
7 Commits
814ab29cb6
...
master
Author | SHA1 | Date | |
---|---|---|---|
307af5679b | |||
dbc56a477b | |||
0e87775943 | |||
88d1eb937f | |||
9da7290da5 | |||
3e6c2c9bde | |||
f69406bc02 |
@@ -9,7 +9,9 @@ use crate::combinators::left_right_parsers::{LeftParser, RightParser};
|
||||
use crate::combinators::many_parsers::{
|
||||
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::parser::{any, Parser};
|
||||
use std::fmt::Debug;
|
||||
@@ -190,7 +192,13 @@ where
|
||||
PLeft: Parser<'a, TToken, TLeft, 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>(
|
||||
|
@@ -17,7 +17,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
match self.first.parse(context.clone(), input) {
|
||||
@@ -38,7 +38,7 @@ mod test {
|
||||
#[test]
|
||||
fn alternate_test() {
|
||||
fn parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, char> {
|
||||
char_parser('a')
|
||||
@@ -47,35 +47,35 @@ mod test {
|
||||
.parse(context, input)
|
||||
}
|
||||
|
||||
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', parser);
|
||||
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser);
|
||||
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser);
|
||||
parser_test_helper("a", &'a', parser);
|
||||
parser_test_helper("b", &'b', parser);
|
||||
parser_test_helper("c", &'c', parser);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alternate_macro_test() {
|
||||
fn parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, char> {
|
||||
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(ParserContext::new_with_str("b", ()), &'b', parser);
|
||||
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser);
|
||||
parser_test_helper("a", &'a', parser);
|
||||
parser_test_helper("b", &'b', parser);
|
||||
parser_test_helper("c", &'c', parser);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alternate_function_test() {
|
||||
fn parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, char> {
|
||||
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('d'));
|
||||
parser.parse(c, i)
|
||||
@@ -85,27 +85,23 @@ mod test {
|
||||
#[test]
|
||||
fn alternate_pure_function_test() {
|
||||
fn parser1(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, &[char]> {
|
||||
alternate!(char_parser('a').literal(), char_parser('b').literal()).parse(context, input)
|
||||
}
|
||||
|
||||
fn parser2(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, &[char]> {
|
||||
alternate!(char_parser('c').literal(), char_parser('d').literal()).parse(context, input)
|
||||
}
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("a", ()),
|
||||
&"a".to_owned(),
|
||||
|c, i| {
|
||||
alternate!(parser1, parser2)
|
||||
.map(|x| x.iter().map(|x| x.clone()).collect())
|
||||
.parse(c, i)
|
||||
},
|
||||
);
|
||||
parser_test_helper("a", &"a".to_owned(), |c, i| {
|
||||
alternate!(parser1, parser2)
|
||||
.map(|x| x.iter().map(|x| x.clone()).collect())
|
||||
.parse(c, i)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
let (input, r) = self.left_parser.parse(context.clone(), input)?;
|
||||
@@ -46,7 +46,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, TRight> {
|
||||
let (input, _) = self.left_parser.parse(context.clone(), input)?;
|
||||
@@ -58,19 +58,19 @@ where
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::combinators::ParserExt;
|
||||
use crate::parser::{parser_test_helper, Parser, ParserContext};
|
||||
use crate::parser::{parser_test_helper, Parser};
|
||||
use crate::text::char_parser;
|
||||
|
||||
#[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)
|
||||
});
|
||||
}
|
||||
|
||||
#[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)
|
||||
})
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let mut result = vec![];
|
||||
@@ -41,7 +41,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let (mut input, first_result) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -68,7 +68,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, ()> {
|
||||
let mut input = input;
|
||||
@@ -93,7 +93,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, ()> {
|
||||
let (mut input, _) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -121,7 +121,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let mut input = input;
|
||||
@@ -159,7 +159,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let (mut input, r) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -192,130 +192,112 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn many_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("aaa", &vec!['a', 'a', 'a'], |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)
|
||||
});
|
||||
|
||||
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]
|
||||
fn many1_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("aaa", &vec!['a', 'a', 'a'], |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)
|
||||
});
|
||||
|
||||
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]
|
||||
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)
|
||||
});
|
||||
|
||||
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)
|
||||
});
|
||||
}
|
||||
|
||||
#[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)
|
||||
});
|
||||
|
||||
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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_till_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("aaab", &vec!['a', 'a', 'a'], |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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many1_till_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("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("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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_till_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("aaab", ()),
|
||||
&(vec!['a', 'a', 'a'], 'b'),
|
||||
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
|
||||
);
|
||||
parser_test_helper("aaab", &(vec!['a', 'a', 'a'], 'b'), |c, i| {
|
||||
tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("b", ()),
|
||||
&(vec![], 'b'),
|
||||
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
|
||||
);
|
||||
parser_test_helper("b", &(vec![], 'b'), |c, i| {
|
||||
tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take1_till_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("aaab", ()),
|
||||
&(vec!['a', 'a', 'a'], 'b'),
|
||||
|c, i| tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i),
|
||||
);
|
||||
parser_test_helper("aaab", &(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)
|
||||
});
|
||||
}
|
||||
|
@@ -1,9 +1,60 @@
|
||||
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
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(crate) parser: P,
|
||||
pub(crate) separator: PSeparator,
|
||||
@@ -19,7 +70,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let (mut input, first) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -54,7 +105,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||
let (mut input, first) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -82,6 +133,7 @@ mod test {
|
||||
use super::*;
|
||||
use crate::combinators::{
|
||||
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::text::char_parser;
|
||||
@@ -89,7 +141,7 @@ mod test {
|
||||
#[test]
|
||||
fn quote_test() {
|
||||
fn parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, Vec<char>> {
|
||||
quote(
|
||||
@@ -100,140 +152,112 @@ mod test {
|
||||
.parse(context, input)
|
||||
}
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("'abc'", ()),
|
||||
&vec!['a', 'b', 'c'],
|
||||
parser,
|
||||
);
|
||||
parser_test_helper(ParserContext::new_with_str("''", ()), &vec![], parser);
|
||||
failed_parser_test_helper(ParserContext::new_with_str("asd", ()), parser)
|
||||
parser_test_helper("'abc'", &vec!['a', 'b', 'c'], parser);
|
||||
parser_test_helper("''", &vec![], parser);
|
||||
failed_parser_test_helper("asd", parser);
|
||||
|
||||
parser_test_helper("'a'b", &vec!['a'], |c, i| {
|
||||
quote(char_parser('\''), char_parser('a'), char_parser('\''))
|
||||
.left(char_parser('b'))
|
||||
.parse(c, i)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_by1_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("a,b,c", ()),
|
||||
&vec!['a', 'b', 'c'],
|
||||
|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("a,b,c", &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("bbc", &vec!['b'], |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]
|
||||
fn separate_by_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("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("", ()), &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)
|
||||
});
|
||||
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]
|
||||
fn end_by1_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("aab", &vec!['a', 'a'], |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)
|
||||
});
|
||||
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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn end_by_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("aab", &vec!['a', 'a'], |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)
|
||||
});
|
||||
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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_or_end_by1_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
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(
|
||||
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| {
|
||||
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(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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_or_end_by_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
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(
|
||||
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| {
|
||||
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(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)
|
||||
});
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T>;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
self.parser.parse(context, input)
|
||||
@@ -41,7 +41,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, (T1, T2)> {
|
||||
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||
@@ -61,7 +61,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, (T1, T2, T3)> {
|
||||
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||
@@ -83,7 +83,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, (T1, T2, T3, T4)> {
|
||||
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||
@@ -107,7 +107,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5)> {
|
||||
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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -129,30 +269,22 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn tuple_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("ab", ()),
|
||||
&('a', 'b'),
|
||||
|c, i| tuple((char_parser('a'), char_parser('b'))).parse(c, i),
|
||||
);
|
||||
parser_test_helper("ab", &('a', 'b'), |c, i| {
|
||||
tuple((char_parser('a'), char_parser('b'))).parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("abc", ()),
|
||||
&('a', 'b', 'c'),
|
||||
|c, i| tuple((char_parser('a'), char_parser('b'), char_parser('c'))).parse(c, i),
|
||||
);
|
||||
parser_test_helper("abc", &('a', 'b', 'c'), |c, i| {
|
||||
tuple((char_parser('a'), char_parser('b'), char_parser('c'))).parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("abcd", ()),
|
||||
&('a', 'b', 'c', 'd'),
|
||||
|c, i| {
|
||||
tuple((
|
||||
char_parser('a'),
|
||||
char_parser('b'),
|
||||
char_parser('c'),
|
||||
char_parser('d'),
|
||||
))
|
||||
.parse(c, i)
|
||||
},
|
||||
);
|
||||
parser_test_helper("abcd", &('a', 'b', 'c', 'd'), |c, i| {
|
||||
tuple((
|
||||
char_parser('a'),
|
||||
char_parser('b'),
|
||||
char_parser('c'),
|
||||
char_parser('d'),
|
||||
))
|
||||
.parse(c, i)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
112
src/parser.rs
112
src/parser.rs
@@ -2,8 +2,8 @@ mod modified_parsers;
|
||||
mod primitive_parsers;
|
||||
|
||||
use crate::parser::modified_parsers::{
|
||||
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
|
||||
NextParser, ReverseParser, TryParser,
|
||||
AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser,
|
||||
MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser,
|
||||
};
|
||||
use crate::parser::primitive_parsers::{
|
||||
AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
|
||||
@@ -33,6 +33,13 @@ impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_error(input: &'a [TToken], err: anyhow::Error) -> Self {
|
||||
Self {
|
||||
input,
|
||||
message: format!("{}", err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn message(&self) -> &str {
|
||||
self.message.as_str()
|
||||
}
|
||||
@@ -56,36 +63,13 @@ impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> {
|
||||
|
||||
pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>;
|
||||
|
||||
pub struct ParserContext<TToken, TContext>
|
||||
where
|
||||
TToken: Debug + Clone,
|
||||
{
|
||||
pub struct ParserContext<TContext> {
|
||||
pub context: TContext,
|
||||
input_array: Vec<TToken>,
|
||||
}
|
||||
|
||||
impl<TToken, TContext> ParserContext<TToken, TContext>
|
||||
where
|
||||
TToken: Debug + Clone,
|
||||
{
|
||||
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,
|
||||
}))
|
||||
impl<TContext> ParserContext<TContext> {
|
||||
pub fn new(context: TContext) -> Rc<RefCell<Self>> {
|
||||
Rc::new(RefCell::new(Self { context }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +80,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T>;
|
||||
|
||||
@@ -200,19 +184,46 @@ where
|
||||
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
|
||||
where
|
||||
TToken: Debug + Clone + 'a,
|
||||
F: Fn(
|
||||
Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
&'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T>,
|
||||
F: Fn(Rc<RefCell<ParserContext<TContext>>>, &'a [TToken]) -> ParserResult<'a, TToken, T>,
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
(*self)(context, input)
|
||||
@@ -226,7 +237,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
(**self).parse(context, input)
|
||||
@@ -302,32 +313,27 @@ where
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn parser_test_helper<T, P>(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
excepted_node: &T,
|
||||
test_parser: P,
|
||||
) where
|
||||
pub fn parser_test_helper<T, P>(input: &str, excepted_node: &T, test_parser: P)
|
||||
where
|
||||
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 input = borrowed_context.input_slice();
|
||||
let (_, actual_result) = test_parser.parse(context.clone(), input).unwrap();
|
||||
let word: Vec<char> = input.chars().collect();
|
||||
let (_, actual_result) = test_parser
|
||||
.parse(ParserContext::new(()), word.as_slice())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(excepted_node, &actual_result);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn failed_parser_test_helper<T, P>(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
test_parser: P,
|
||||
) where
|
||||
pub fn failed_parser_test_helper<T, P>(input: &str, test_parser: P)
|
||||
where
|
||||
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 input = borrowed_context.input_slice();
|
||||
let result = test_parser.parse(context.clone(), input);
|
||||
let word: Vec<char> = input.chars().collect();
|
||||
let result = test_parser.parse(ParserContext::new(()), word.as_slice());
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T2> {
|
||||
self.parser
|
||||
@@ -44,7 +44,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T2> {
|
||||
let (input, middle) = self.parser.parse(context.clone(), input)?;
|
||||
@@ -68,7 +68,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T2> {
|
||||
self.parser
|
||||
@@ -92,7 +92,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, TResult> {
|
||||
let result = self.parser.parse(context, input);
|
||||
@@ -114,7 +114,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, &'a [TToken]> {
|
||||
let origin_input = input;
|
||||
@@ -147,7 +147,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, usize> {
|
||||
let origin_input = input;
|
||||
@@ -179,7 +179,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
let original_input = input;
|
||||
@@ -202,7 +202,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
match self.parser.parse(context, input) {
|
||||
@@ -227,7 +227,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
context: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, TResult> {
|
||||
match self.parser.parse(context, input) {
|
||||
@@ -240,30 +240,102 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::parser::{
|
||||
failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
|
||||
};
|
||||
use crate::text::char_parser;
|
||||
use crate::text::{char_parser, char_satisfy};
|
||||
|
||||
#[test]
|
||||
fn map_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("hello, world!", ()),
|
||||
&(),
|
||||
|c, i| take(5).map(|_| ()).parse(c, i),
|
||||
)
|
||||
parser_test_helper("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| {
|
||||
parser_test_helper("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| {
|
||||
parser_test_helper("abc", &'c', |c, i| {
|
||||
char_parser('a')
|
||||
.bind(|_| char_parser('b'))
|
||||
.bind(|_| char_parser('c'))
|
||||
@@ -282,7 +354,7 @@ mod test {
|
||||
#[test]
|
||||
fn convert_test() {
|
||||
fn single_numer_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, Number> {
|
||||
let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
|
||||
@@ -293,19 +365,15 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("9", ()),
|
||||
&"9".to_owned(),
|
||||
|c, i| single_numer_parser.convert().parse(c, i),
|
||||
);
|
||||
parser_test_helper("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),
|
||||
);
|
||||
parser_test_helper("1", &"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)
|
||||
});
|
||||
}
|
||||
@@ -313,7 +381,7 @@ mod test {
|
||||
#[test]
|
||||
fn next_test() {
|
||||
fn parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, Number> {
|
||||
satisfy(|c: &char| c.is_numeric())
|
||||
@@ -327,65 +395,43 @@ mod test {
|
||||
.parse(context, input)
|
||||
}
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("9", ()),
|
||||
&"9".to_owned(),
|
||||
|c, i| parser.convert().parse(c, i),
|
||||
);
|
||||
parser_test_helper("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),
|
||||
);
|
||||
parser_test_helper("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)
|
||||
});
|
||||
failed_parser_test_helper("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("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("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)
|
||||
},
|
||||
);
|
||||
parser_test_helper("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| {
|
||||
parser_test_helper("abc", &'a', |c, i| {
|
||||
char_parser('a')
|
||||
.look_ahead()
|
||||
.bind(|_| char_parser('a'))
|
||||
@@ -395,23 +441,46 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn try_parse_test() {
|
||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
||||
parser_test_helper("abc", &'a', |c, i| {
|
||||
char_parser('a').try_parse('a').parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(ParserContext::new_with_str("bc", ()), &'a', |c, i| {
|
||||
parser_test_helper("bc", &'a', |c, i| {
|
||||
char_parser('a').try_parse('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)
|
||||
});
|
||||
parser_test_helper("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)
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
Ok((input, self.value.clone()))
|
||||
@@ -32,7 +32,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
Err(FailedParserResult::new_with_str(
|
||||
@@ -53,7 +53,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
Err(FailedParserResult::new(input, self.message.clone()))
|
||||
@@ -71,7 +71,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, TToken> {
|
||||
if input.is_empty() {
|
||||
@@ -97,7 +97,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, T> {
|
||||
if input.is_empty() {
|
||||
@@ -120,7 +120,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, TToken> {
|
||||
if input.is_empty() {
|
||||
@@ -141,7 +141,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, Vec<TToken>> {
|
||||
if input.len() < self.count {
|
||||
@@ -171,7 +171,7 @@ where
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [TToken],
|
||||
) -> ParserResult<'a, TToken, ()> {
|
||||
if input.len() < self.count {
|
||||
@@ -198,85 +198,63 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn succeed_test() {
|
||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| {
|
||||
succeed(()).parse(c, i)
|
||||
});
|
||||
parser_test_helper("abc", &(), |c, i| succeed(()).parse(c, i));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_test() {
|
||||
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
|
||||
fail::<char, (), ()>().parse(c, i)
|
||||
});
|
||||
failed_parser_test_helper("abc", |c, i| fail::<char, (), ()>().parse(c, i));
|
||||
}
|
||||
|
||||
#[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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn satisfy_test() {
|
||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
||||
satisfy(|x| x == &'a').parse(c, i)
|
||||
});
|
||||
parser_test_helper("abc", &'a', |c, i| satisfy(|x| x == &'a').parse(c, i));
|
||||
|
||||
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
|
||||
satisfy(|x| x == &'b').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(ParserContext::new_with_str("123", ()), &1, |c, i| {
|
||||
parser_test_helper("123", &1, |c, i| {
|
||||
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(ParserContext::new_with_str("23", ()), &2, |c, i| {
|
||||
parser_test_helper("23", &2, |c, i| {
|
||||
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
|
||||
});
|
||||
|
||||
parser_test_helper(ParserContext::new_with_str("3", ()), &3, |c, i| {
|
||||
parser_test_helper("3", &3, |c, i| {
|
||||
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn any_test() {
|
||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
||||
any().parse(c, i)
|
||||
});
|
||||
parser_test_helper("abc", &'a', |c, i| any().parse(c, i));
|
||||
|
||||
parser_test_helper(ParserContext::new_with_str("cde", ()), &'c', |c, i| {
|
||||
any().parse(c, i)
|
||||
});
|
||||
parser_test_helper("cde", &'c', |c, i| any().parse(c, i));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_test() {
|
||||
parser_test_helper(
|
||||
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| {
|
||||
parser_test_helper("hello, world!", &("hello".chars().collect()), |c, i| {
|
||||
take(5).parse(c, i)
|
||||
});
|
||||
|
||||
failed_parser_test_helper("abcd", |c, i| take(5).parse(c, i));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("hello, world!", ()),
|
||||
&(),
|
||||
|c, i| skip(5).parse(c, i),
|
||||
);
|
||||
parser_test_helper("hello, world!", &(), |c, i| skip(5).parse(c, i));
|
||||
|
||||
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), |c, i| {
|
||||
skip(5).parse(c, i)
|
||||
});
|
||||
failed_parser_test_helper("abcd", |c, i| skip(5).parse(c, i));
|
||||
}
|
||||
}
|
||||
|
44
src/text.rs
44
src/text.rs
@@ -36,31 +36,25 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn char_parser_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("abc", ()),
|
||||
&'a',
|
||||
|context, input| char_parser('a').parse(context, input),
|
||||
);
|
||||
parser_test_helper("abc", &'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)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_parser_test() {
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("Hello, world!", ()),
|
||||
&"Hello".to_owned(),
|
||||
|context, input| {
|
||||
string_parser("Hello")
|
||||
.map(|x| x.iter().collect())
|
||||
.parse(context, input)
|
||||
},
|
||||
);
|
||||
parser_test_helper("Hello, world!", &"Hello".to_owned(), |context, input| {
|
||||
string_parser("Hello")
|
||||
.map(|x| x.iter().collect())
|
||||
.parse(context, input)
|
||||
});
|
||||
|
||||
fn test_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, String> {
|
||||
let (input, first) = string_parser("hello, ").parse(context.clone(), input)?;
|
||||
@@ -72,22 +66,14 @@ mod test {
|
||||
))
|
||||
}
|
||||
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("hello, world!", ()),
|
||||
&"hello, world!".to_owned(),
|
||||
test_parser,
|
||||
);
|
||||
parser_test_helper(
|
||||
ParserContext::new_with_str("hello, world!", ()),
|
||||
&(),
|
||||
|context, input| test_parser.map(|_| ()).parse(context, input),
|
||||
)
|
||||
parser_test_helper("hello, world!", &"hello, world!".to_owned(), test_parser);
|
||||
parser_test_helper("hello, world!", &(), |context, input| {
|
||||
test_parser.map(|_| ()).parse(context, input)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_satsify_test() {
|
||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
||||
char_satisfy(char::is_ascii).parse(c, i)
|
||||
});
|
||||
parser_test_helper("abc", &'a', |c, i| char_satisfy(char::is_ascii).parse(c, i));
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ pub struct StringParser {
|
||||
impl<'a, TContext> Parser<'a, char, &'a [char], TContext> for StringParser {
|
||||
fn parse(
|
||||
&self,
|
||||
_: Rc<RefCell<ParserContext<char, TContext>>>,
|
||||
_: Rc<RefCell<ParserContext<TContext>>>,
|
||||
input: &'a [char],
|
||||
) -> ParserResult<'a, char, &'a [char]> {
|
||||
let length = self.str.chars().count();
|
||||
|
@@ -75,9 +75,9 @@ fn file_lexical_parser_test() -> anyhow::Result<()> {
|
||||
let (_, nom_tokens) =
|
||||
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 borrowed_context = context.borrow();
|
||||
let (_, zero_tokens) = zero_lexical_parser(context.clone(), borrowed_context.input_slice())
|
||||
let context = ParserContext::new(());
|
||||
let word: Vec<char> = source_file.content.chars().collect();
|
||||
let (_, zero_tokens) = zero_lexical_parser(context.clone(), word.as_slice())
|
||||
.or_else(|e| Err(anyhow!("{}", e)))?;
|
||||
|
||||
assert_eq!(nom_tokens.len(), zero_tokens.len());
|
||||
|
@@ -5,11 +5,10 @@ use zero_parser::parser::ParserContext;
|
||||
mod tokenizer;
|
||||
|
||||
fn validate_tokens(input: &'static str, tokens: Vec<LexicalTokenType>) {
|
||||
let context = ParserContext::new_with_str(input, ());
|
||||
let borrowed_context = context.borrow();
|
||||
let context = ParserContext::new(());
|
||||
let word: Vec<char> = input.chars().collect();
|
||||
|
||||
let (_, actual_tokens) =
|
||||
zero_lexical_parser(context.clone(), borrowed_context.input_slice()).unwrap();
|
||||
let (_, actual_tokens) = zero_lexical_parser(context.clone(), word.as_slice()).unwrap();
|
||||
|
||||
dbg!(&tokens, &actual_tokens);
|
||||
assert_eq!(tokens.len(), actual_tokens.len());
|
||||
|
@@ -109,7 +109,7 @@ pub fn nom_lexical_parser(mut input: &str) -> IResult<&str, Vec<LexicalToken>> {
|
||||
}
|
||||
|
||||
pub fn zero_lexical_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
mut input: &[char],
|
||||
) -> ParserResult<char, Vec<NewLexicalToken>> {
|
||||
let mut array = vec![];
|
||||
|
@@ -9,7 +9,7 @@ use zero_parser::text::{char_parser, one_of, string_parser};
|
||||
use zero_parser::{alternate, parser::satisfy};
|
||||
|
||||
pub fn keyword_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -38,7 +38,7 @@ pub fn keyword_parser(
|
||||
}
|
||||
|
||||
pub fn delimiter_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
alternate!(
|
||||
@@ -60,7 +60,7 @@ pub fn delimiter_parser(
|
||||
}
|
||||
|
||||
pub fn operator_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
alternate!(
|
||||
@@ -89,7 +89,7 @@ pub fn operator_parser(
|
||||
}
|
||||
|
||||
pub fn identifier_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -105,7 +105,7 @@ pub fn identifier_parser(
|
||||
}
|
||||
|
||||
pub fn decimal_integer_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -126,7 +126,7 @@ pub fn decimal_integer_parser(
|
||||
}
|
||||
|
||||
pub fn octal_integer_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -147,7 +147,7 @@ pub fn octal_integer_parser(
|
||||
}
|
||||
|
||||
pub fn hexadecimal_integer_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -168,7 +168,7 @@ pub fn hexadecimal_integer_parser(
|
||||
}
|
||||
|
||||
pub fn integer_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
alternate!(
|
||||
@@ -180,7 +180,7 @@ pub fn integer_parser(
|
||||
}
|
||||
|
||||
pub fn float_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
tuple((
|
||||
@@ -202,7 +202,7 @@ pub fn float_parser(
|
||||
}
|
||||
|
||||
pub fn literal_string_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
quote(char_parser('"'), any(), char_parser('"'))
|
||||
@@ -211,14 +211,14 @@ pub fn literal_string_parser(
|
||||
let length = x.len();
|
||||
NewLexicalToken {
|
||||
token_type: LexicalTokenType::LiteralString,
|
||||
literal_value: &x[1..length],
|
||||
literal_value: &x[1..length - 1],
|
||||
}
|
||||
})
|
||||
.parse(context, input)
|
||||
}
|
||||
|
||||
pub fn comments_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, ()> {
|
||||
alternate!(
|
||||
@@ -239,7 +239,7 @@ pub fn comments_parser(
|
||||
}
|
||||
|
||||
pub fn junk_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, ()> {
|
||||
alternate!(
|
||||
@@ -250,7 +250,7 @@ pub fn junk_parser(
|
||||
}
|
||||
|
||||
pub fn combine_parser(
|
||||
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||
context: Rc<RefCell<ParserContext<()>>>,
|
||||
input: &[char],
|
||||
) -> ParserResult<char, NewLexicalToken> {
|
||||
alternate!(
|
||||
|
@@ -1,3 +1,5 @@
|
||||
extern crate core;
|
||||
|
||||
use crate::tokenizer::zero_parsers::{
|
||||
combine_parser, comments_parser, decimal_integer_parser, delimiter_parser, float_parser,
|
||||
hexadecimal_integer_parser, identifier_parser, integer_parser, keyword_parser,
|
||||
@@ -13,16 +15,12 @@ mod tokenizer;
|
||||
|
||||
fn assert_lexical_parser(
|
||||
except: LexicalToken,
|
||||
parser: fn(
|
||||
Rc<RefCell<ParserContext<char, ()>>>,
|
||||
&[char],
|
||||
) -> ParserResult<char, NewLexicalToken>,
|
||||
parser: fn(Rc<RefCell<ParserContext<()>>>, &[char]) -> ParserResult<char, NewLexicalToken>,
|
||||
input: &str,
|
||||
) {
|
||||
let context = ParserContext::new_with_str(input, ());
|
||||
let borrowed_context = context.borrow();
|
||||
let input = borrowed_context.input_slice();
|
||||
let (_, token) = parser(context.clone(), input).unwrap();
|
||||
let context = ParserContext::new(());
|
||||
let word: Vec<char> = input.chars().collect();
|
||||
let (_, token) = parser(context.clone(), word.as_slice()).unwrap();
|
||||
|
||||
assert_eq!(except, token);
|
||||
}
|
||||
@@ -30,11 +28,11 @@ fn assert_lexical_parser(
|
||||
fn assert_parser<T, F>(except: T, parser: F, input: &str)
|
||||
where
|
||||
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 borrowed_context = context.borrow();
|
||||
let (_, token) = parser(context.clone(), borrowed_context.input_slice()).unwrap();
|
||||
let context = ParserContext::new(());
|
||||
let word: Vec<char> = input.chars().collect();
|
||||
let (_, token) = parser(context.clone(), word.as_slice()).unwrap();
|
||||
|
||||
assert_eq!(except, token);
|
||||
}
|
||||
|
Reference in New Issue
Block a user