mod tag;
use crate::{
span::{Spanned, Symbol},
LocatedSegment,
Span,
};
use nom::{
combinator::{opt, recognize},
error::{ErrorKind, ParseError},
FindToken,
Parser,
};
use std::ops::{RangeFrom, RangeTo};
pub use tag::Tag;
pub fn symbol<T, E, P, A>(
mut parser: P,
) -> impl FnMut(T) -> nom::IResult<T, Symbol<A>, E>
where
T: Spanned,
E: ParseError<T>,
P: Parser<T, A, E>,
{
move |input| {
let start = input.span().start();
let (new_input, data) = parser.parse(input)?;
let end = new_input.span().end();
let span = Span::from_range(start, end);
Ok((new_input, Symbol { span, data }))
}
}
pub fn alpha0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_alphabetic())
}
pub fn alpha1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_alphabetic(),
ErrorKind::Alpha,
)
}
pub fn char_alpha0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| {
!item.is_alphabetic() || !item.is_single_char()
})
}
pub fn char_alpha1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_alphabetic() || !item.is_single_char(),
ErrorKind::Alpha,
)
}
pub fn ascii_alpha0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_ascii_alphabetic())
}
pub fn ascii_alpha1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_ascii_alphabetic(),
ErrorKind::Alpha,
)
}
pub fn alphanumeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_alphanumeric())
}
pub fn alphanumeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_alphanumeric(),
ErrorKind::AlphaNumeric,
)
}
pub fn char_alphanumeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| {
!item.is_alphanumeric() || !item.is_single_char()
})
}
pub fn char_alphanumeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_alphanumeric() || !item.is_single_char(),
ErrorKind::AlphaNumeric,
)
}
pub fn ascii_alphanumeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_ascii_alphanumeric())
}
pub fn ascii_alphanumeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_ascii_alphanumeric(),
ErrorKind::AlphaNumeric,
)
}
pub fn numeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_numeric())
}
pub fn numeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_numeric(),
ErrorKind::Digit,
)
}
pub fn char_numeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| {
!item.is_numeric() || !item.is_single_char()
})
}
pub fn char_numeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_numeric() || !item.is_single_char(),
ErrorKind::Digit,
)
}
pub fn ascii_numeric0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_ascii_numeric())
}
pub fn ascii_numeric1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_ascii_numeric(),
ErrorKind::Digit,
)
}
pub fn digit0<T, E>(base: u32) -> impl FnMut(T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
move |input| input.split_at_position_complete(|item| item.is_digit(base))
}
pub fn digit1<T, E>(base: u32) -> impl FnMut(T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
move |input| {
input.split_at_position1_complete(
|item| item.is_digit(base),
match base {
8 => ErrorKind::OctDigit,
16 => ErrorKind::HexDigit,
_ => ErrorKind::Digit,
},
)
}
}
pub fn whitespace0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_whitespace())
}
pub fn whitespace1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(
|item| !item.is_whitespace(),
ErrorKind::Space,
)
}
pub fn space0<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position_complete(|item| !item.is_space())
}
pub fn space1<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
E: ParseError<T>,
{
input.split_at_position1_complete(|item| !item.is_space(), ErrorKind::Space)
}
pub fn tab<T, E>(input: T) -> nom::IResult<T, T::Item, E>
where
T: nom::InputIter + nom::InputLength + nom::InputTake,
for<'tok> T::Item: PartialEq<&'tok str>,
E: ParseError<T>,
{
segment("\t")(input)
}
pub fn newline<T, E>(input: T) -> nom::IResult<T, T::Item, E>
where
T: nom::InputIter + nom::InputLength + nom::InputTake,
for<'tok> T::Item: PartialEq<&'tok str>,
E: ParseError<T>,
{
segment("\n")(input)
}
pub fn crlf<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTake,
for<'slice, 'seg> T: nom::Compare<Tag<'slice, 'seg>>,
E: ParseError<T>,
{
match Tag(&["\r", "\n"]).into_fn::<_, nom::error::Error<T>>()(input) {
Ok(data) => Ok(data),
Err(nom_err) => Err(nom_err
.map(|error| E::from_error_kind(error.input, ErrorKind::CrLf))),
}
}
pub fn line_ending<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTake,
for<'slice, 'seg> T: nom::Compare<Tag<'slice, 'seg>>,
E: ParseError<T>,
{
match input.compare(Tag(&["\n"])) {
nom::CompareResult::Ok => Ok(input.take_split(1)),
nom::CompareResult::Error => crlf(input),
nom::CompareResult::Incomplete => {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::CrLf)))
},
}
}
pub fn not_line_ending<T, E>(input: T) -> nom::IResult<T, T, E>
where
T: nom::InputTake + nom::InputIter,
for<'tok> T::Item: PartialEq<&'tok str>,
E: ParseError<T>,
{
let mut previous_car = false;
for (i, segment) in input.iter_indices() {
if segment == "\n" {
let split_index = i - 1 - usize::from(previous_car);
return Ok(input.take_split(split_index));
}
previous_car = segment == "\r";
}
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Tag)))
}
pub fn segment<T, A, E>(
expected: A,
) -> impl FnMut(T) -> nom::IResult<T, T::Item, E>
where
T: nom::InputIter + nom::InputLength + nom::InputTake,
T::Item: PartialEq<A>,
E: ParseError<T>,
{
move |input| {
let mut iterator = input.iter_indices();
match iterator.next() {
Some((_, segment)) => {
if segment == expected {
match iterator.next() {
Some((index, _)) => Ok((input.take(index), segment)),
None => Ok((input.take(input.input_len()), segment)),
}
} else {
Err(nom::Err::Error(E::from_error_kind(
input,
ErrorKind::IsA,
)))
}
},
None => {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof)))
},
}
}
}
pub fn any_segment<T, E>(input: T) -> nom::IResult<T, LocatedSegment, E>
where
T: nom::InputIter<Item = LocatedSegment>
+ nom::InputLength
+ nom::InputTake,
E: ParseError<T>,
{
let mut iterator = input.iter_indices();
match iterator.next() {
Some((_, segment)) => match iterator.next() {
Some((index, _)) => Ok((input.take(index), segment)),
None => Ok((input.take(input.input_len()), segment)),
},
None => Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
}
}
pub fn one_of<T, L, E>(list: L) -> impl FnMut(T) -> nom::IResult<T, T::Item, E>
where
T: nom::InputIter + nom::InputLength + nom::InputTake,
for<'tok> L: FindToken<&'tok T::Item>,
E: ParseError<T>,
{
move |input| {
let mut iterator = input.iter_indices();
match iterator.next() {
Some((_, segment)) => {
if list.find_token(&segment) {
match iterator.next() {
Some((index, _)) => Ok((input.take(index), segment)),
None => Ok((input.take(input.input_len()), segment)),
}
} else {
Err(nom::Err::Error(E::from_error_kind(
input,
ErrorKind::IsNot,
)))
}
},
None => {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof)))
},
}
}
}
pub fn none_of<T, L, E>(list: L) -> impl FnMut(T) -> nom::IResult<T, T::Item, E>
where
T: nom::InputIter + nom::InputLength + nom::InputTake,
for<'tok> L: FindToken<&'tok T::Item>,
E: ParseError<T>,
{
move |input| {
let mut iterator = input.iter_indices();
match iterator.next() {
Some((_, segment)) => {
if !list.find_token(&segment) {
match iterator.next() {
Some((index, _)) => Ok((input.take(index), segment)),
None => Ok((input.take(input.input_len()), segment)),
}
} else {
Err(nom::Err::Error(E::from_error_kind(
input,
ErrorKind::IsNot,
)))
}
},
None => {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof)))
},
}
}
}
pub fn satisfy<F, T, E>(
mut condition: F,
) -> impl FnMut(T) -> nom::IResult<T, T::Item, E>
where
for<'item> F: FnMut(&'item T::Item) -> bool,
T: nom::InputTake + nom::InputIter,
E: ParseError<T>,
{
move |input| match input.iter_elements().next() {
Some(elem) if condition(&elem) => Ok((input.take(1), elem)),
_ => {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Satisfy)))
},
}
}
macro_rules! parse_unsigned_int {
($fn_name:ident, $ty:ty, $($doc:tt)*) => {
$($doc)*
pub fn $fn_name<T, E>(base: u32) -> impl FnMut(T) -> nom::IResult<T, $ty, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment>,
T: AsRef<str> + Clone,
E: ParseError<T>,
{
move |input0| {
let (input1, digits) = digit1(base)(input0.clone())?;
match <$ty>::from_str_radix(digits.as_ref(), base) {
Ok(num) => Ok((input1, num)),
Err(_) => Err(nom::Err::Error(E::from_error_kind(
input0,
ErrorKind::TooLarge
))),
}
}
}
};
}
parse_unsigned_int! {
digits_u8,
u8,
}
parse_unsigned_int! {
digits_u16,
u16,
}
parse_unsigned_int! {
digits_u32,
u32,
}
parse_unsigned_int! {
digits_u64,
u64,
}
parse_unsigned_int! {
digits_u128,
u128,
}
macro_rules! parse_signed_int {
($fn_name:ident, $ty:ty, $($doc:tt)*) => {
$($doc)*
pub fn $fn_name<T, E>(base: u32) -> impl FnMut(T) -> nom::IResult<T, $ty, E>
where
T: nom::InputTakeAtPosition<Item = LocatedSegment> + nom::InputTake,
T: nom::InputLength + nom::InputIter<Item = LocatedSegment>,
T: AsRef<str> + Clone + nom::Offset,
T: nom::Slice<RangeFrom<usize>> + nom::Slice<RangeTo<usize>>,
E: ParseError<T>,
{
move |input0| {
let (input1, digits) = recognize(
nom::Parser::and(
opt(one_of(Tag(&["+", "-"]))),
digit1(base)
)
)(input0.clone())?;
match <$ty>::from_str_radix(digits.as_ref(), base) {
Ok(num) => Ok((input1, num)),
Err(_) => Err(nom::Err::Error(E::from_error_kind(
input0,
ErrorKind::TooLarge
))),
}
}
}
};
}
parse_signed_int! {
digits_i8,
i8,
}
parse_signed_int! {
digits_i16,
i16,
}
parse_signed_int! {
digits_i32,
i32,
}
parse_signed_int! {
digits_i64,
i64,
}
parse_signed_int! {
digits_i128,
i128,
}