use crate::ast::{Block, Inline};
use nom::{
branch::alt,
character::complete::{line_ending, space0},
combinator::{eof, fail},
multi::many0,
sequence::{preceded, terminated},
IResult, Parser,
};
pub(crate) fn char_m_n(min: usize, max: usize, c: char) -> impl Fn(&str) -> IResult<&str, &str> {
debug_assert!(c.is_ascii());
move |input: &str| {
let bytes = input.as_bytes();
let limit = bytes.len().min(max);
let mut n = 0;
while n < limit && bytes[n] == c as u8 {
n += 1;
}
if n < min {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::ManyMN,
)));
}
Ok((&input[n..], &input[..n]))
}
}
pub(crate) fn eof_or_eol(input: &str) -> IResult<&str, &str> {
alt((line_ending, eof)).parse(input)
}
pub(crate) fn many_empty_lines0(input: &str) -> IResult<&str, Vec<&str>> {
many0(preceded(space0, eof_or_eol)).parse(input)
}
pub(crate) fn not_eof_or_eol1(input: &str) -> IResult<&str, &str> {
let bytes = input.as_bytes();
let mut end = bytes
.iter()
.position(|&b| b == b'\n')
.unwrap_or(bytes.len());
if end < bytes.len() && end > 0 && bytes[end - 1] == b'\r' {
end -= 1;
}
if end == 0 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many1,
)));
}
Ok((&input[end..], &input[..end]))
}
pub(crate) fn not_eof_or_eol0(input: &str) -> IResult<&str, &str> {
let bytes = input.as_bytes();
let end = bytes
.iter()
.position(|&b| b == b'\n' || b == b'\r')
.unwrap_or(bytes.len());
if end < bytes.len() && bytes[end] == b'\r' && bytes.get(end + 1) != Some(&b'\n') {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)));
}
Ok((&input[end..], &input[..end]))
}
pub(crate) fn line_terminated<'a, O, P>(
inner: P,
) -> impl Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>,
{
terminated(inner, eof_or_eol)
}
#[derive(Clone, Debug)]
pub(crate) enum Pieces<T> {
One(T),
Many(Vec<T>),
}
impl<T> Pieces<T> {
pub(crate) fn extend_into(self, out: &mut Vec<T>) {
match self {
Pieces::One(item) => out.push(item),
Pieces::Many(items) => out.extend(items),
}
}
}
pub(crate) fn conditional<'a, O, P>(
behavior: crate::parser::config::ElementBehavior<O>,
default: impl Fn() -> O,
mut inner: P,
) -> impl Parser<&'a str, Output = Pieces<O>, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>,
{
move |input: &'a str| {
let mut inner1 = |s: &'a str| inner.parse(s);
match &behavior {
crate::parser::config::ElementBehavior::Ignore => fail().parse(input),
crate::parser::config::ElementBehavior::Parse => inner1.map(Pieces::One).parse(input),
crate::parser::config::ElementBehavior::Skip => {
let (i, _) = inner1(input)?;
Ok((i, Pieces::One(default())))
}
crate::parser::config::ElementBehavior::Map(f) => {
let (i, o) = inner.parse(input)?;
let mut f1 = (**f).borrow_mut();
let mapped = (f1.as_mut())(o);
Ok((i, Pieces::One(mapped)))
}
crate::parser::config::ElementBehavior::FlatMap(f) => {
let (i, o) = inner.parse(input)?;
let mut f1 = (**f).borrow_mut();
let mapped = (f1.as_mut())(o);
Ok((i, Pieces::Many(mapped)))
}
}
}
}
pub(crate) fn conditional_block_unit<'a, P>(
behavior: crate::parser::config::ElementBehavior<Block>,
mut inner: P,
) -> impl Parser<&'a str, Output = Pieces<()>, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = (), Error = nom::error::Error<&'a str>>,
{
let behavior: crate::parser::config::ElementBehavior<()> = match behavior {
super::config::ElementBehavior::Parse => super::config::ElementBehavior::Parse,
super::config::ElementBehavior::Ignore => super::config::ElementBehavior::Ignore,
super::config::ElementBehavior::Skip => super::config::ElementBehavior::Skip,
super::config::ElementBehavior::Map(_) => super::config::ElementBehavior::Parse,
super::config::ElementBehavior::FlatMap(_) => super::config::ElementBehavior::Parse,
};
move |input: &'a str| {
let inner1 = |s: &'a str| inner.parse(s);
conditional(behavior.clone(), || (), inner1).parse(input)
}
}
pub(crate) fn conditional_block<'a, P>(
behavior: crate::parser::config::ElementBehavior<Block>,
mut inner: P,
) -> impl Parser<&'a str, Output = Pieces<Block>, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = Block, Error = nom::error::Error<&'a str>>,
{
move |input: &'a str| {
let inner1 = |s: &'a str| inner.parse(s);
conditional(behavior.clone(), || Block::Empty, inner1).parse(input)
}
}
pub(crate) fn conditional_inline<'a, P>(
behavior: crate::parser::config::ElementBehavior<Inline>,
mut inner: P,
) -> impl Parser<&'a str, Output = Pieces<Inline>, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = Inline, Error = nom::error::Error<&'a str>>,
{
move |input: &'a str| {
let inner1 = |s: &'a str| inner.parse(s);
conditional(behavior.clone(), || Inline::Empty, inner1).parse(input)
}
}
pub(crate) fn conditional_block_vec<'a, P>(
behavior: crate::parser::config::ElementBehavior<Block>,
mut inner: P,
) -> impl Parser<&'a str, Output = Pieces<Block>, Error = nom::error::Error<&'a str>>
where
P: Parser<&'a str, Output = Vec<Block>, Error = nom::error::Error<&'a str>>,
{
move |input: &'a str| {
let mut inner1 = |s: &'a str| inner.parse(s);
match &behavior {
crate::parser::config::ElementBehavior::Ignore => fail().parse(input),
crate::parser::config::ElementBehavior::Skip => {
let (remaining, _) = inner1(input)?;
Ok((remaining, Pieces::One(Block::Empty)))
}
crate::parser::config::ElementBehavior::Parse
| crate::parser::config::ElementBehavior::Map(_)
| crate::parser::config::ElementBehavior::FlatMap(_) => {
let (remaining, blocks) = inner1(input)?;
Ok((remaining, Pieces::Many(blocks)))
}
}
}
}