use crate::item::Node;
use crate::parser::{ParseError, ParseInput, StaticState};
use qualname::{NamespacePrefix, NamespaceUri};
pub(crate) fn take_one<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, char), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| {
let c = input.chars().next();
match c {
None => Err(ParseError::Combinator(String::from("take_one: no input"))),
Some(ind) => Ok(((&input[ind.len_utf8()..], state), ind)),
}
}
}
pub(crate) fn take_until<'a, N: Node, L>(
s: &'static str,
) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| match input.find(s) {
None => Err(ParseError::Combinator(String::from("take_until: no input"))),
Some(ind) => Ok(((&input[ind..], state), input[0..ind].to_string())),
}
}
pub(crate) fn take_until_either_or<'a, N: Node, L>(
s1: &'static str,
s2: &'static str,
) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| {
let r1 = input.find(s1);
let r2 = input.find(s2);
match (r1, r2) {
(Some(i1), Some(i2)) => Ok((
(&input[i1.min(i2)..], state),
input[0..i1.min(i2)].to_string(),
)),
(Some(i1), None) => Ok(((&input[i1..], state), input[0..i1].to_string())),
(None, Some(i2)) => Ok(((&input[i2..], state), input[0..i2].to_string())),
(None, None) => Err(ParseError::Combinator(String::from(
"take_until_either_or: no input",
))),
}
}
}
pub(crate) fn take_until_either_or_min1<'a, N: Node, L>(
s1: &'static str,
s2: &'static str,
) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| {
let r1 = input.find(s1);
let r2 = input.find(s2);
match (r1, r2) {
(Some(i1), Some(i2)) => {
if i1 == 0 || i2 == 0 {
Err(ParseError::Combinator(String::from(
"take_until_either_or_min: no input",
)))
} else {
Ok((
(&input[i1.min(i2)..], state),
input[0..i1.min(i2)].to_string(),
))
}
}
(Some(i1), None) => {
if i1 == 0 {
Err(ParseError::Combinator(String::from(
"take_until_either_or_min: unable to find second term",
)))
} else {
Ok(((&input[i1..], state), input[0..i1].to_string()))
}
}
(None, Some(i2)) => {
if i2 == 0 {
Err(ParseError::Combinator(String::from(
"take_until_either_or_min: unable to find first term",
)))
} else {
Ok(((&input[i2..], state), input[0..i2].to_string()))
}
}
(None, None) => Err(ParseError::Combinator(String::from(
"take_until_either_or_min: no input",
))),
}
}
}
pub(crate) fn take_until_end<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| Ok((("", state), input.to_string()))
}
pub(crate) fn take_while<'a, F, N: Node, L>(
condition: F,
) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
F: Fn(char) -> bool,
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| match input.find(|c| !condition(c)) {
None => {
if input.is_empty() {
Err(ParseError::Combinator(String::from("take_while: no input")))
} else {
Ok((("", state), input.to_string()))
}
}
Some(0) => Err(ParseError::Combinator(String::from(
"take_while: term not found",
))),
Some(pos) => Ok(((&input[pos..], state), input[0..pos].to_string())),
}
}
#[allow(dead_code)]
pub(crate) fn take_while_m_n<'a, F, N: Node, L>(
min: usize,
max: usize,
condition: F,
) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
F: Fn(char) -> bool,
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), _ss| match input.find(|c| !condition(c)) {
None => {
if input.is_empty() {
Err(ParseError::Combinator(String::from(
"take_while_m_n: no input",
)))
} else {
Ok(((&input[max..], state), input[0..max].to_string()))
}
}
Some(pos) => {
if pos >= min {
if pos > max {
Ok(((&input[max..], state), input[0..max].to_string()))
} else {
Ok(((&input[pos..], state), input[0..pos].to_string()))
}
} else {
Err(ParseError::Combinator(String::from(
"take_while_m_n: term not found",
)))
}
}
}
}
#[cfg(test)]
mod tests {
use crate::parser::combinators::take::{
take_until, take_until_either_or, take_while, take_while_m_n,
};
use crate::parser::{ParseError, ParserState, StaticStateBuilder};
use crate::trees::nullo::Nullo;
use qualname::NamespaceUri;
#[test]
fn parser_take_until_test1() {
let testdoc = "<doc>";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until(">");
assert_eq!(
Ok(((">", ParserState::new()), "<doc".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_test2() {
let testdoc = "<document";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until(">");
assert_eq!(
Err(ParseError::Combinator(String::from("take_until: no input"))),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_test3() {
let testdoc = "<doc>";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until("oc");
assert_eq!(
Ok((("oc>", ParserState::new()), "<d".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_test4() {
let testdoc = "<doc>";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until("doc");
assert_eq!(
Ok((("doc>", ParserState::new()), "<".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_while_test1() {
let testdoc = "AAAAABCCCCC";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_while(|c| c != 'B');
assert_eq!(
Ok((("BCCCCC", ParserState::new()), "AAAAA".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_while_test2() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_while(|c| c != 'B' && c != 'C');
assert_eq!(
Ok((("BCDEFGH", ParserState::new()), "A".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_while_test3() {
let testdoc = "v1\"></doc>";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_while(|c| c != '&' && c != '"');
assert_eq!(
Ok((("\"></doc>", ParserState::new()), "v1".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_either_or1() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until_either_or("DE", "FG");
assert_eq!(
Ok((("DEFGH", ParserState::new()), "ABC".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_either_or2() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until_either_or("AA", "BB");
assert_eq!(
Err(ParseError::Combinator(String::from(
"take_until_either_or: no input"
))),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_either_or3() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until_either_or("EF", "FF");
assert_eq!(
Ok((("EFGH", ParserState::new()), "ABCD".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_either_or4() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until_either_or("ABD", "GH");
assert_eq!(
Ok((("GH", ParserState::new()), "ABCDEF".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_until_either_or5() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_until_either_or("BC", "BC");
assert_eq!(
Ok((("BCDEFGH", ParserState::new()), "A".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_while_m_n_1() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_while_m_n(2, 4, |c| c.is_uppercase());
assert_eq!(
Ok((("EFGH", ParserState::new()), "ABCD".to_string())),
parse_doc((testdoc, teststate), &mut static_state)
);
}
#[test]
fn parser_take_while_m_n_2() {
let testdoc = "ABCDEFGH";
let teststate: ParserState<Nullo> = ParserState::new();
let mut static_state = StaticStateBuilder::new()
.namespace(|_| {
NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
})
.build();
let parse_doc = take_while_m_n(2, 4, |c| c.is_lowercase());
assert_eq!(
Err(ParseError::Combinator(String::from(
"take_while_m_n: term not found"
))),
parse_doc((testdoc, teststate), &mut static_state)
);
}
}