stackr-rs 0.1.14

A stack-based interpreter to be embedded in your application. Heavily inspired by Forth.
Documentation
use super::*;

pub fn register_builtins<State>(interpreter: &mut Interpreter<State>) {
    interpreter.register_builtin(
        "&&",
        "n n -- 0|1",
        "Checks if both numbers are true. Puts 1 on the stack if they are, 0 otherwise.",
        "1 1 &&",
        |interpreter| {
            let a = interpreter.pop_bool()?;
            let b = interpreter.pop_bool()?;
            if a && b {
                interpreter.push_number(1.0);
            } else {
                interpreter.push_number(0.0);
            }
            Ok(())
        },
    );

    interpreter.register_builtin(
        "||",
        "n n -- 0|1",
        "Checks if one of the numbers is true. Puts 1 on the stack if they are, 0 otherwise.",
        "0 1 ||",
        |interpreter| {
            let a = interpreter.pop_bool()?;
            let b = interpreter.pop_bool()?;
            if a || b {
                interpreter.push_number(1.0);
            } else {
                interpreter.push_number(0.0);
            }
            Ok(())
        },
    );

    interpreter.register_builtin(
        "!",
        "n -- 0|1",
        "Inverts the boolean value on the stack. Puts 1 on the stack if the value is 0, 0 otherwise.",
        "0 !",
        |interpreter| {
            let a = interpreter.pop_bool()?;
            if !a {
                interpreter.push_number(1.0);
            } else {
                interpreter.push_number(0.0);
            }
            Ok(())
        },
    );
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn not_returns_true() {
        let mut interpreter = Interpreter::new(());
        let code = "0 !";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(1.0, interpreter.pop_number().unwrap());
    }

    #[test]
    fn not_returns_false() {
        let mut interpreter = Interpreter::new(());
        let code = "1 !";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(0.0, interpreter.pop_number().unwrap());
    }

    #[test]
    fn or_returns_true() {
        let mut interpreter = Interpreter::new(());
        let code = "0 1 ||";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(1.0, interpreter.pop_number().unwrap());
    }

    #[test]
    fn or_returns_false() {
        let mut interpreter = Interpreter::new(());
        let code = "0 0 ||";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(0.0, interpreter.pop_number().unwrap());
    }

    #[test]
    fn and_returns_true() {
        let mut interpreter = Interpreter::new(());
        let code = "1 1 &&";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(1.0, interpreter.pop_number().unwrap());
    }

    #[test]
    fn and_returns_false() {
        let mut interpreter = Interpreter::new(());
        let code = "0 1 &&";
        let result = interpreter.evaluate(code, None);
        assert_eq!(result, Ok(()));
        assert_eq!(0.0, interpreter.pop_number().unwrap());
    }
}