simple-ll 0.1.0

A small parsing library.
Documentation
#![forbid(missing_docs, missing_debug_implementations)]

//! A simple parser library for Rust.

type Stack<'a, T> = &'a mut Vec<T>;
type Parser<N, T> = fn(Stack<T>) -> Option<N>;

/// Parser for consuming and testing a single token.
/// Takes a function and the stack as input.
/// The input function should convert the token into the parse node.
pub fn enum_parse<N, T>(f: fn(&T) -> Option<N>, stack: Stack<T>) -> Option<N> {
    match stack.pop() {
        Some(t) => match f(&t) {
            Some(n) => Some(n),
            None => {
                stack.push(t);
                None
            }
        },
        None => None,
    }
}

// Please don't clone
/// Trys different parsers from a list until one works.
/// The first argument is the list of parsers, and the second is the stack.
pub fn options_parse<N, T: Clone>(l: &[Parser<N, T>], stack: Stack<T>) -> Option<N> {
    for p in l.iter() {
        if let Some(n) = p(stack) {
            return Some(n);
        }
    }
    None
}

/// Uses a parser as many times as possible, then returns a vec of nodes
pub fn repeated_parse<N, T>(p: Parser<N, T>, stack: Stack<T>) -> Vec<N> {
    let mut res: Vec<N> = Vec::new();
    loop {
        match p(stack) {
            Some(s) => res.push(s),
            None => return res,
        };
    }
}

#[cfg(test)]
mod tests {
    use crate::{enum_parse, options_parse, repeated_parse, Stack};

    #[derive(Debug, PartialEq)]
    enum Enum1 {
        Even,
        Odd,
        Zero,
    }

    fn enum_parse_1(stack: Stack<i32>) -> Option<Enum1> {
        enum_parse(
            |&n| {
                if n < 0 {
                    None
                } else if n == 0 {
                    Some(Enum1::Zero)
                } else if n % 2 == 0 {
                    Some(Enum1::Even)
                } else {
                    Some(Enum1::Odd)
                }
            },
            stack,
        )
    }

    #[test]
    fn enum_parse_1_ok() {
        assert_eq!(enum_parse_1(&mut vec![-32, 25, 0]), Some(Enum1::Zero));
        assert_eq!(enum_parse_1(&mut vec![-32, 25, 23]), Some(Enum1::Odd));
        assert_eq!(enum_parse_1(&mut vec![-32, 25, 2]), Some(Enum1::Even));
    }

    #[test]
    fn enum_parse_1_err() {
        assert_eq!(enum_parse_1(&mut vec![-32, 25, -2]), None);
        assert_eq!(enum_parse_1(&mut vec![]), None);
    }

    #[derive(Debug, PartialEq)]
    enum Enum2 {
        Small,
        Tiny,
    }

    fn enum_parse_2(stack: Stack<i32>) -> Option<Enum2> {
        enum_parse(
            |&n| {
                if n > -10 && n < 0 {
                    Some(Enum2::Small)
                } else if n <= -10 {
                    Some(Enum2::Tiny)
                } else {
                    None
                }
            },
            stack,
        )
    }

    #[test]
    fn enum_parse_2_ok() {
        assert_eq!(enum_parse_2(&mut vec![-32, 25, -5]), Some(Enum2::Small));
        assert_eq!(enum_parse_2(&mut vec![-32, 25, -20]), Some(Enum2::Tiny));
    }

    #[test]
    fn enum_parse_2_err() {
        assert_eq!(enum_parse_2(&mut vec![-32, 25, 2]), None);
        assert_eq!(enum_parse_2(&mut vec![]), None);
    }

    #[derive(Debug, PartialEq)]
    enum Enum1And2 {
        Is1(Enum1),
        Is2(Enum2),
    }

    fn options_parse_1(stack: Stack<i32>) -> Option<Enum1And2> {
        options_parse(
            &[
                |s| enum_parse_1(s).map(Enum1And2::Is1),
                |s| enum_parse_2(s).map(Enum1And2::Is2),
            ],
            stack,
        )
    }

    #[test]
    fn options_parse_1_ok() {
        assert_eq!(
            options_parse_1(&mut vec![5]),
            Some(Enum1And2::Is1(Enum1::Odd))
        );
        assert_eq!(
            options_parse_1(&mut vec![0]),
            Some(Enum1And2::Is1(Enum1::Zero))
        );
        assert_eq!(
            options_parse_1(&mut vec![-1]),
            Some(Enum1And2::Is2(Enum2::Small))
        );
        assert_eq!(
            options_parse_1(&mut vec![-20]),
            Some(Enum1And2::Is2(Enum2::Tiny))
        );
    }

    fn repeated_parse_1(stack: Stack<i32>) -> Vec<Enum1> {
        repeated_parse(enum_parse_1, stack)
    }

    #[test]
    fn repeated_parse_1_ok() {
        assert_eq!(
            repeated_parse_1(&mut vec![-1, 3, 2, 1]),
            vec![Enum1::Odd, Enum1::Even, Enum1::Odd]
        );
        assert_eq!(repeated_parse_1(&mut vec![]), vec![]);
        assert_eq!(repeated_parse_1(&mut vec![-1]), vec![]);
    }

    fn repeated_parse_2(stack: Stack<i32>) -> Vec<Enum1And2> {
        repeated_parse(options_parse_1, stack)
    }

    #[test]
    fn repeated_parse_2_ok() {
        assert_eq!(
            repeated_parse_2(&mut vec![-1, 3, 2, 1]),
            vec![
                Enum1And2::Is1(Enum1::Odd),
                Enum1And2::Is1(Enum1::Even),
                Enum1And2::Is1(Enum1::Odd),
                Enum1And2::Is2(Enum2::Small)
            ]
        );
    }
}