token-parser 0.1.0

Utilities for parsing texts into data structures
Documentation
pub use token_parser_derive::*;

#[derive(Debug)]
pub enum Error {
    NotEnoughElements(usize),
    TooManyElements(usize),
    ListNotAllowed,
    SymbolNotAllowed,
    StringParsing,
    InvalidElement,
}

pub type Result<T> = std::result::Result<T, Error>;

pub enum Unit<I: Iterator>
where
    I::Item: Into<Unit<I>>,
{
    Symbol(String),
    Parser(Parser<I>),
}

impl<I: Iterator> Unit<I>
where
    I::Item: Into<Unit<I>>,
{
    pub fn symbol(self) -> Result<String> {
        use Unit::*;
        match self {
            Symbol(name) => Ok(name),
            Parser(_) => Err(Error::ListNotAllowed),
        }
    }

    pub fn parser(self) -> Result<Parser<I>> {
        use Unit::*;
        match self {
            Symbol(_) => Err(Error::SymbolNotAllowed),
            Parser(parser) => Ok(parser),
        }
    }
}

pub trait Parsable<C>: Sized {
    fn parse_symbol(_name: String, _context: &C) -> Result<Self> {
        Err(Error::SymbolNotAllowed)
    }

    fn parse_list<I: Iterator>(_parser: &mut Parser<I>, _context: &C) -> Result<Self>
    where
        I::Item: Into<Unit<I>>,
    {
        Err(Error::ListNotAllowed)
    }
}

fn parse<C, P: Parsable<C>, I: Iterator>(unit: Unit<I>, context: &C) -> Result<P>
where
    I::Item: Into<Unit<I>>,
{
    use Unit::*;
    match unit {
        Symbol(name) => Parsable::parse_symbol(name, context),
        Parser(mut parser) => parser.parse_rest(context),
    }
}

impl<C, T: Parsable<C>> Parsable<C> for Box<T> {
    fn parse_symbol(name: String, context: &C) -> Result<Self> {
        Ok(Box::new(Parsable::parse_symbol(name, context)?))
    }

    fn parse_list<I: Iterator>(parser: &mut Parser<I>, context: &C) -> Result<Self>
    where
        I::Item: Into<Unit<I>>,
    {
        Ok(Box::new(parser.parse_list(context)?))
    }
}

impl<C, T: Parsable<C>> Parsable<C> for Vec<T> {
    fn parse_list<I: Iterator>(parser: &mut Parser<I>, context: &C) -> Result<Self>
    where
        I::Item: Into<Unit<I>>,
    {
        let Parser { form, count } = parser;
        let result = form
            .map(|token| {
                *count += 1;
                parse(token.into(), context)
            })
            .collect();
        result
    }
}

impl<C> Parsable<C> for String {
    fn parse_symbol(name: String, _context: &C) -> Result<Self> {
        Ok(name)
    }
}

#[macro_export]
macro_rules! derive_symbol_parsable {
    ($t:ty) => {
        impl<C> Parsable<C> for $t {
            fn parse_symbol(name: String, _context: &C) -> Result<Self> {
                if let Some(value) = name.parse().ok() {
                    Ok(value)
                } else {
                    Err(Error::StringParsing)
                }
            }
        }
    };
    ($t:ty, $($rest:ty),+) => {
        derive_symbol_parsable!($t);
        derive_symbol_parsable!($($rest),+);
    };
}

derive_symbol_parsable!(i8, i16, i32, i64, i128);
derive_symbol_parsable!(u8, u16, u32, u64, u128);
derive_symbol_parsable!(f32, f64);
derive_symbol_parsable!(usize);
derive_symbol_parsable!(bool);

pub struct Parser<I: Iterator> {
    form: I,
    count: usize,
}

impl<I: Iterator> Parser<I>
where
    I::Item: Into<Unit<I>>,
{
    pub fn new(form: I) -> Self {
        Self { form, count: 0 }
    }

    pub fn parse_next<C, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
        self.count += 1;
        if let Some(token) = self.form.next() {
            parse(token.into(), context)
        } else {
            Result::Err(Error::NotEnoughElements(self.count))
        }
    }

    pub fn parse_rest<C, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
        let result = self.parse_list(context);
        if let Some(_) = self.form.next() {
            let mut count = 1;
            while let Some(_) = self.form.next() {
                count += 1;
            }
            Err(Error::TooManyElements(count))
        } else {
            result
        }
    }

    pub fn parse_list<C, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
        Parsable::parse_list(self, context)
    }
}

impl<I: Iterator> Iterator for Parser<I>
where
    I::Item: Into<Unit<I>>,
{
    type Item = Result<Parser<I>>;

    fn next(&mut self) -> Option<Result<Parser<I>>> {
        self.count += 1;
        let unit: Unit<I> = self.form.next()?.into();
        Some(unit.parser())
    }
}