rulex 0.4.4

DEPRECATED: Use pomsky instead. A new regular expression language
Documentation
use std::iter::Enumerate;

use nom::{InputIter, InputLength, InputTake};

use crate::{
    error::{ParseError, ParseErrorKind},
    span::Span,
};

use super::token::Token;

#[derive(Clone)]
pub(crate) struct Input<'i, 'b> {
    source: &'i str,
    tokens: &'b [(Token, Span)],
    recursion: u16,
}

impl<'i, 'b> Input<'i, 'b> {
    pub(super) fn from(
        source: &'i str,
        tokens: &'b [(Token, Span)],
        recursion: u16,
    ) -> Result<Self, ParseError> {
        let error = tokens.iter().find_map(|&(t, span)| match t {
            Token::Error => Some((span, None)),
            Token::ErrorMsg(m) => Some((span, Some(m))),
            _ => None,
        });
        if let Some((span, msg)) = error {
            return match msg {
                Some(msg) => Err(ParseErrorKind::LexErrorWithMessage(msg).at(span)),
                None => Err(ParseErrorKind::UnknownToken.at(span)),
            };
        }

        Ok(Input { source, tokens, recursion })
    }

    pub(super) fn recursion_start(&mut self) -> Result<(), ParseError> {
        self.recursion = self
            .recursion
            .checked_sub(1)
            .ok_or_else(|| ParseErrorKind::RecursionLimit.at(self.span()))?;
        Ok(())
    }

    pub(super) fn recursion_end(&mut self) {
        self.recursion += 1;
    }

    pub(super) fn is_empty(&self) -> bool {
        self.tokens.is_empty()
    }

    pub(crate) fn span(&self) -> Span {
        self.tokens
            .first()
            .map(|&(_, span)| span)
            .unwrap_or_else(|| (self.source.len()..self.source.len()).into())
    }

    pub(super) fn peek(&self) -> Option<(Token, &'i str)> {
        self.iter_elements().next()
    }
}

impl<'i, 'b> PartialEq for Input<'i, 'b> {
    fn eq(&self, other: &Self) -> bool {
        Iterator::eq(self.iter_elements(), other.iter_elements())
    }
}

#[cfg(feature = "dbg")]
impl<'i, 'b> core::fmt::Debug for Input<'i, 'b> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        struct FmtHelper<'a>(Token, &'a str);

        impl core::fmt::Debug for FmtHelper<'_> {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                write!(f, "{:?} {:?}", self.0, self.1)
            }
        }

        let v = self
            .tokens
            .iter()
            .map(|&(t, span)| FmtHelper(t, &self.source[span.range()]))
            .collect::<Vec<_>>();

        v.fmt(f)
    }
}

impl<'i, 'b> Iterator for Input<'i, 'b> {
    type Item = (Token, &'i str);

    fn next(&mut self) -> Option<Self::Item> {
        match self.tokens.split_first() {
            Some((&(token, span), rest)) => {
                self.tokens = rest;
                Some((token, &self.source[span.range()]))
            }
            None => None,
        }
    }
}

impl<'i, 'b> InputIter for Input<'i, 'b> {
    type Item = (Token, &'i str);

    type Iter = Enumerate<Self>;

    type IterElem = Self;

    fn iter_indices(&self) -> Self::Iter {
        self.iter_elements().enumerate()
    }

    fn iter_elements(&self) -> Self::IterElem {
        Input { ..*self }
    }

    fn position<P>(&self, predicate: P) -> Option<usize>
    where
        P: Fn(Self::Item) -> bool,
    {
        let mut iter = self.iter_elements();
        Iterator::position(&mut iter, predicate)
    }

    fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
        if count <= self.tokens.len() {
            Ok(count)
        } else {
            Err(nom::Needed::Size((count - self.tokens.len()).try_into().unwrap()))
        }
    }
}

impl<'i, 'b> InputLength for Input<'i, 'b> {
    fn input_len(&self) -> usize {
        self.tokens.len()
    }
}

impl<'i, 'b> InputTake for Input<'i, 'b> {
    fn take(&self, count: usize) -> Self {
        let tokens = &self.tokens[..count];

        Input { tokens, ..*self }
    }

    fn take_split(&self, count: usize) -> (Self, Self) {
        let (left, right) = self.tokens.split_at(count);

        (Input { tokens: left, ..*self }, Input { tokens: right, ..*self })
    }
}