use std::borrow::Borrow;
use std::cell::Cell;
use nom::branch::alt;
use nom::bytes::complete::{tag, take, take_while};
use nom::character::complete::{char, digit1};
use nom::combinator::{opt, recognize};
use nom::error::{ErrorKind, ParseError};
use nom::lib::std::ops::{RangeFrom, RangeTo};
use nom::multi::count;
use nom::sequence::{delimited, pair};
use nom::{AsChar, IResult};
use nom::{InputIter, InputTakeAtPosition, Offset, Slice};
#[allow(dead_code)]
pub fn anything<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: nom::InputLength + nom::InputIter + nom::InputTake,
{
take(i.input_len())(i)
}
pub fn eof<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: Clone + nom::InputLength,
{
if i.input_len() == 0 {
Ok((i.clone(), i))
} else {
Err(nom::Err::Error(ParseError::from_error_kind(
i,
ErrorKind::Eof,
)))
}
}
pub fn br<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: Clone + nom::InputTake + nom::Compare<&'static str>,
{
alt((tag("\n"), tag("\r\n")))(i)
}
pub fn sp<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: Clone + nom::InputTake + nom::Compare<&'static str>,
{
alt((tag(" "), tag("\t"), tag("\n"), tag("\r\n")))(i)
}
pub fn take_sp<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: nom::InputTakeAtPosition,
<I as nom::InputTakeAtPosition>::Item: AsChar,
{
take_while(|c: <I as nom::InputTakeAtPosition>::Item| " \t\r\n".contains(c.as_char()))(i)
}
pub fn ws<I, O, E: ParseError<I>, F>(parser: F) -> impl Fn(I) -> IResult<I, O, E>
where
F: Fn(I) -> IResult<I, O, E>,
I: nom::InputTakeAtPosition,
<I as nom::InputTakeAtPosition>::Item: nom::AsChar,
{
let delim = delimited(take_sp, parser, take_sp);
move |input: I| delim(input)
}
pub fn recognize_integer<I, E: ParseError<I>>(i: I) -> IResult<I, I, E>
where
I: Clone
+ Offset
+ Slice<RangeTo<usize>>
+ Slice<RangeFrom<usize>>
+ InputIter
+ InputTakeAtPosition,
<I as InputIter>::Item: AsChar,
<I as InputTakeAtPosition>::Item: AsChar,
{
recognize(pair(opt(char('-')), digit1))(i)
}
#[allow(dead_code)]
pub fn take_till_parses<I, O, E: ParseError<I>, F>(parser: F) -> impl Fn(I) -> IResult<I, I, E>
where
I: Clone + nom::InputIter + nom::InputTake,
F: Fn(I) -> IResult<I, O, E>,
{
move |mut input: I| {
let mut bytes_taken: usize = 0;
let org_input = input.clone();
loop {
if parser(input.clone()).is_ok() {
return take(bytes_taken as usize)(org_input);
}
bytes_taken += 1;
match take(bytes_taken)(org_input.clone()) {
Ok((i, _)) => {
input = i;
}
e @ Err(_) => return e,
};
}
}
}
pub fn take_after_parses<I, O, E: ParseError<I>, F>(
parser: F,
) -> impl Fn(I) -> IResult<I, (I, O), E>
where
I: Clone + nom::InputIter + nom::InputTake,
F: Fn(I) -> IResult<I, O, E>,
{
move |mut input: I| {
let mut bytes_taken: usize = 0;
let org_input = input.clone();
loop {
if let Ok((i, t)) = parser(input.clone()) {
let (_, c) = take(bytes_taken as usize)(org_input)?;
return Ok((i, (c, t)));
}
bytes_taken += 1;
match take(bytes_taken)(org_input.clone()) {
Ok((i, _)) => {
input = i;
}
Err(e) => return Err(e),
};
}
}
}
pub fn delimited_block<I, O, E: ParseError<I>, F, G>(
start: F,
end: G,
) -> impl Fn(I) -> IResult<I, I, E>
where
I: Clone + nom::InputIter + nom::InputTake,
F: Fn(I) -> IResult<I, O, E>,
G: Fn(I) -> IResult<I, O, E>,
{
let taker = take_after_parses(end);
move |input: I| {
let (input, _) = start(input)?;
let (input, (content, _)) = taker(input)?;
Ok((input, content))
}
}
pub fn parse_delimited_block<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
start: F,
end: G,
parser: H,
) -> impl Fn(I) -> IResult<I, O3, E>
where
I: Clone + nom::InputIter + nom::InputTake,
F: Fn(I) -> IResult<I, O1, E>,
G: Fn(I) -> IResult<I, O2, E>,
H: Fn(I) -> IResult<I, O3, E>,
{
let taker = take_after_parses(end);
move |input: I| {
let (input, _) = start(input)?;
let (input, (content, _)) = taker(input)?;
let (_, out) = parser(content)?;
Ok((input, out))
}
}
pub fn verify_or<I, O1, O2, E: ParseError<I>, F, G, H>(
parser: F,
validator: G,
alt: H,
) -> impl Fn(I) -> IResult<I, O1, E>
where
I: Clone,
O1: Borrow<O2>,
O2: ?Sized,
F: Fn(I) -> IResult<I, O1, E>,
G: Fn(&O2) -> bool,
H: Fn(I) -> IResult<I, O1, E>,
{
move |input: I| {
let i = input.clone();
let (input, out) = parser(input)?;
if !validator(out.borrow()) {
return alt(i);
}
Ok((input, out))
}
}
pub fn count_indexed<I, O, E, F>(parser: F, counts: usize) -> impl Fn(I) -> IResult<I, Vec<O>, E>
where
I: Clone + PartialEq,
F: Fn(usize, I) -> IResult<I, O, E>,
E: ParseError<I>,
{
let counter = Cell::new(0);
move |input: I| {
count(
|input| {
let res = parser(counter.get(), input);
counter.set(counter.get() + 1);
res
},
counts,
)(input)
}
}