xod 1.0.1

A tiny REPL for bitwise arithmetic and expression evaluation.
Documentation
use super::{
    Span,
    ast::{Compare, CompareOp},
    general::var_or_num,
    utils::space_around,
};
use nom::{IResult, Parser, branch::alt, bytes::complete::tag};

pub fn equals(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag("==").parse_complete(input)?;
    Ok((input, (Compare::Equal, op)))
}

pub fn not_equals(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag("!=").parse_complete(input)?;
    Ok((input, (Compare::NotEqual, op)))
}

pub fn greater(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag(">").parse_complete(input)?;
    Ok((input, (Compare::Greater, op)))
}

pub fn greater_equal(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag(">=").parse_complete(input)?;
    Ok((input, (Compare::GreaterEqual, op)))
}

pub fn lesser(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag("<").parse_complete(input)?;
    Ok((input, (Compare::Less, op)))
}

pub fn lesser_equal(input: Span) -> IResult<Span, (Compare, Span)> {
    let (input, op) = tag("<=").parse_complete(input)?;
    Ok((input, (Compare::LessEqual, op)))
}

pub fn operator(input: Span) -> IResult<Span, (Compare, Span)> {
    alt((
        equals,
        not_equals,
        greater_equal,
        lesser_equal,
        greater,
        lesser,
    ))
    .parse_complete(input)
}

pub fn compare(input: Span) -> IResult<Span, CompareOp> {
    let (input, left) = space_around(var_or_num).parse_complete(input)?;
    let (input, (op, op_span)) = space_around(operator).parse_complete(input)?;
    let (input, right) = var_or_num(input)?;
    Ok((input, CompareOp::new(left, op, op_span, right)))
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::parsers::ast::{Number, VarNum};

    #[test]
    fn test_equals() {
        unsafe {
            assert_eq!(
                equals(Span::new("== 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (Compare::Equal, Span::new_from_raw_offset(0, 1, "==", ()))
                ))
            );
            assert_eq!(
                operator(Span::new("== 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (Compare::Equal, Span::new_from_raw_offset(0, 1, "==", ()))
                ))
            );
        }
    }

    #[test]
    fn test_not_equals() {
        unsafe {
            assert_eq!(
                not_equals(Span::new("!= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (Compare::NotEqual, Span::new_from_raw_offset(0, 1, "!=", ()))
                ))
            );
            assert_eq!(
                operator(Span::new("!= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (Compare::NotEqual, Span::new_from_raw_offset(0, 1, "!=", ()))
                ))
            );
        }
    }

    #[test]
    fn test_greater_than() {
        unsafe {
            assert_eq!(
                greater(Span::new("> 10")),
                Ok((
                    Span::new_from_raw_offset(1, 1, " 10", ()),
                    (Compare::Greater, Span::new_from_raw_offset(0, 1, ">", ()))
                ))
            );
            assert_eq!(
                operator(Span::new("> 10")),
                Ok((
                    Span::new_from_raw_offset(1, 1, " 10", ()),
                    (Compare::Greater, Span::new_from_raw_offset(0, 1, ">", ()))
                ))
            );
        }
    }

    #[test]
    fn test_greater_than_or_equal_to() {
        unsafe {
            assert_eq!(
                greater_equal(Span::new(">= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (
                        Compare::GreaterEqual,
                        Span::new_from_raw_offset(0, 1, ">=", ())
                    )
                ))
            );
            assert_eq!(
                operator(Span::new(">= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (
                        Compare::GreaterEqual,
                        Span::new_from_raw_offset(0, 1, ">=", ())
                    )
                ))
            );
        }
    }

    #[test]
    fn test_less_than() {
        unsafe {
            assert_eq!(
                lesser(Span::new("< 10")),
                Ok((
                    Span::new_from_raw_offset(1, 1, " 10", ()),
                    (Compare::Less, Span::new_from_raw_offset(0, 1, "<", ()))
                ))
            );
            assert_eq!(
                operator(Span::new("< 10")),
                Ok((
                    Span::new_from_raw_offset(1, 1, " 10", ()),
                    (Compare::Less, Span::new_from_raw_offset(0, 1, "<", ()))
                ))
            );
        }
    }

    #[test]
    fn test_less_than_or_equal_to() {
        unsafe {
            assert_eq!(
                lesser_equal(Span::new("<= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (
                        Compare::LessEqual,
                        Span::new_from_raw_offset(0, 1, "<=", ())
                    )
                ))
            );
            assert_eq!(
                operator(Span::new("<= 10")),
                Ok((
                    Span::new_from_raw_offset(2, 1, " 10", ()),
                    (
                        Compare::LessEqual,
                        Span::new_from_raw_offset(0, 1, "<=", ())
                    )
                ))
            );
        }
    }

    #[test]
    fn test_comparison() {
        unsafe {
            assert_eq!(
                compare(Span::new("10 >= 12 ")),
                Ok((
                    Span::new_from_raw_offset(8, 1, " ", ()),
                    CompareOp::new(
                        VarNum::Num(Number::new(
                            10,
                            Span::new_from_raw_offset(0, 1, "10", ()),
                            None
                        )),
                        Compare::GreaterEqual,
                        Span::new_from_raw_offset(3, 1, ">=", ()),
                        VarNum::Num(Number::new(
                            12,
                            Span::new_from_raw_offset(6, 1, "12", ()),
                            None
                        ))
                    )
                ))
            );

            assert_eq!(
                compare(Span::new("10 >= someVar ")),
                Ok((
                    Span::new_from_raw_offset(13, 1, " ", ()),
                    CompareOp::new(
                        VarNum::Num(Number::new(
                            10,
                            Span::new_from_raw_offset(0, 1, "10", ()),
                            None
                        )),
                        Compare::GreaterEqual,
                        Span::new_from_raw_offset(3, 1, ">=", ()),
                        VarNum::Var(Span::new_from_raw_offset(6, 1, "someVar", ()))
                    )
                ))
            );
        }
    }
}