use crate::parser::Error;
use nom::{
bytes::complete::tag,
character::complete::{alphanumeric1, digit1},
combinator::{map_res, not, recognize},
error::ParseError,
sequence::tuple,
AsChar, Compare, InputIter, InputLength, InputTake, InputTakeAtPosition,
};
use std::{cell::RefCell, ops::Range};
pub(crate) type LocatedSpan<'a> = nom_locate::LocatedSpan<&'a str, State<'a>>;
pub(crate) type IResult<'a, T> = nom::IResult<LocatedSpan<'a>, T>;
pub(crate) trait ToRange {
fn to_range(&self) -> Range<usize>;
}
impl<'a> ToRange for LocatedSpan<'a> {
fn to_range(&self) -> Range<usize> {
let start = self.location_offset();
let end = start + self.fragment().len();
start..end
}
}
#[derive(Clone, Debug)]
pub(crate) struct State<'a>(&'a RefCell<Vec<Error>>);
impl<'a> State<'a> {
pub fn new(errors: &'a RefCell<Vec<Error>>) -> State<'a> {
State(errors)
}
pub fn report_error(&self, error: Error) {
let mut errors = self.0.borrow_mut();
if !errors.contains(&error) {
errors.push(error);
}
}
pub fn report_error_if_no_overlap(&self, error: Error) {
let mut errors = self.0.borrow_mut();
let has_overlap = errors.iter().any(|err| {
err.0.start <= error.0.start && err.0.end >= error.0.start
|| err.0.start <= error.0.end && err.0.end >= error.0.start
});
if !has_overlap {
errors.push(error);
}
}
}
pub(crate) fn keyword<T, Input, Error: ParseError<Input>>(
keyword: T,
) -> impl FnMut(Input) -> nom::IResult<Input, Input, Error>
where
Input: InputTake
+ Compare<T>
+ Clone
+ InputLength
+ InputIter
+ InputTakeAtPosition
+ nom::Offset
+ nom::Slice<std::ops::RangeTo<usize>>,
T: InputLength + Clone,
<Input as InputTakeAtPosition>::Item: AsChar,
{
recognize(tuple((tag(keyword), not(alphanumeric1))))
}
pub(crate) fn int16(i: LocatedSpan) -> IResult<i16> {
map_res(digit1, |res: LocatedSpan| i16::from_str_radix(*res, 10))(i)
}
#[cfg(test)]
pub(crate) fn span(i: &str) -> LocatedSpan {
let errors = Box::new(RefCell::new(vec![]));
LocatedSpan::new_extra(i, State(Box::leak(errors)))
}
#[cfg(test)]
pub(crate) fn unwrap_span<T>(res: (LocatedSpan, T)) -> (&str, T) {
let (span, res) = res;
(*span, res)
}