Documentation
//! # math
//!
//! Example for parsing simple math expressions with integers, + = * / and ()
//! it doesn't include unary operators, and doesn't allow implicit multiplication
//! like (1-2)(3+4) or 2(3+4)
//!

use teleparse::prelude::*;

// note that this example is not the only way to define the parser

/// Token types for the lexer
#[derive_lexicon]
#[teleparse(
    ignore(r#"\s"#), // ignore whitespaces, separate multiple with comma
)]
pub enum TokenType {
    /// Numbers in the expression
    #[teleparse(regex(r#"\d+"#), terminal(Integer, Zero = "0"))]
    Integer,
    /// The 4 basic operators
    #[teleparse(terminal(OpAdd = "+", OpSub = "-", OpMul = "*", OpDiv = "/",))]
    Operator,
    /// Parentheses
    #[teleparse(terminal(ParamOpen = "(", ParamClose = ")"))]
    Param,
}

#[test]
fn empty() {
    let mut lexer = TokenType::lexer("").unwrap();
    assert_eq!(lexer.next(), (None, None));

    let mut lexer = TokenType::lexer("   ").unwrap();
    assert_eq!(lexer.next(), (None, None));
}

#[test]
fn single() {
    let mut lexer = TokenType::lexer("3").unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Integer)))
    );

    let mut lexer = TokenType::lexer("(").unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Param)))
    );

    let mut lexer = TokenType::lexer("*").unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Operator)))
    );
}

#[test]
fn basic() {
    let source = "3+4*(5-6)/7";
    let mut lexer = TokenType::lexer(source).unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((1, 2), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((2, 3), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((3, 4), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((4, 5), TokenType::Param)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((5, 6), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((6, 7), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((7, 8), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((8, 9), TokenType::Param)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((9, 10), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((10, 11), TokenType::Integer)))
    );
    assert_eq!(lexer.next(), (None, None));
}

#[test]
fn with_ignore() {
    // -----------0123456789101214
    let source = "3 + 4  *( 5 -6";
    let mut lexer = TokenType::lexer(source).unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((2, 3), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((4, 5), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((7, 8), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((8, 9), TokenType::Param)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((10, 11), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((12, 13), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((13, 14), TokenType::Integer)))
    );
    assert_eq!(lexer.next(), (None, None));
}

#[test]
fn invalid() {
    // -----------01234567891012141618202224262830
    let source = "3+ 4 what is (this 5)   invalid";
    let mut lexer = TokenType::lexer(source).unwrap();
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((0, 1), TokenType::Integer)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((1, 2), TokenType::Operator)))
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((3, 4), TokenType::Integer)))
    );
    // the invalid part is "what is", then starting from the space,
    // it was able to ignore the space and find the valid "("
    assert_eq!(
        lexer.next(),
        (
            Some((5, 12).into()),
            Some(Token::new((13, 14), TokenType::Param))
        )
    );
    assert_eq!(
        lexer.next(),
        (
            Some((14, 18).into()),
            Some(Token::new((19, 20), TokenType::Integer))
        )
    );
    assert_eq!(
        lexer.next(),
        (None, Some(Token::new((20, 21), TokenType::Param)))
    );
    assert_eq!(lexer.next(), (Some((24, 31).into()), None));
}