add: string_parser and char_satisfy parser.
This commit is contained in:
parent
e2c4388a0c
commit
dd00a37369
48
src/text.rs
48
src/text.rs
|
@ -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::*;
|
||||||
|
@ -52,7 +52,11 @@ mod test {
|
||||||
parser_test_helper(
|
parser_test_helper(
|
||||||
ParserContext::new_with_str("Hello, world!", ()),
|
ParserContext::new_with_str("Hello, world!", ()),
|
||||||
&"Hello".to_owned(),
|
&"Hello".to_owned(),
|
||||||
|context, input| string_parser("Hello").parse(context, input),
|
|context, input| {
|
||||||
|
string_parser("Hello")
|
||||||
|
.map(|x| x.iter().collect())
|
||||||
|
.parse(context, input)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
fn test_parser(
|
fn test_parser(
|
||||||
|
@ -62,7 +66,10 @@ mod test {
|
||||||
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(
|
||||||
|
@ -76,4 +83,11 @@ mod test {
|
||||||
|context, input| test_parser.map(|_| ()).parse(context, input),
|
|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)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
37
src/text/string_parsers.rs
Normal file
37
src/text/string_parsers.rs
Normal 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<char, 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),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user