interpreter: Add regression tests for operators and precedence
This commit is contained in:
		@@ -959,3 +959,6 @@ pub mod error {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										459
									
								
								libconlang/src/interpreter/tests.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								libconlang/src/interpreter/tests.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,459 @@
 | 
				
			|||||||
 | 
					#![allow(unused_imports)]
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    ast::*,
 | 
				
			||||||
 | 
					    interpreter::{env::Environment, temp_type_impl::ConValue, Interpret},
 | 
				
			||||||
 | 
					    lexer::Lexer,
 | 
				
			||||||
 | 
					    parser::Parser,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					pub use macros::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod macros {
 | 
				
			||||||
 | 
					    //! Useful macros for parsing Conlang
 | 
				
			||||||
 | 
					    //!
 | 
				
			||||||
 | 
					    //! # Parsing
 | 
				
			||||||
 | 
					    //! Macro [`parse`] stringifies, lexes, and parses everything you give to it
 | 
				
			||||||
 | 
					    //! ```rust
 | 
				
			||||||
 | 
					    //! # use conlang::interpreter::tests::*;
 | 
				
			||||||
 | 
					    //! parse!{
 | 
				
			||||||
 | 
					    //!     fn main () {
 | 
				
			||||||
 | 
					    //!         "Hello, world!"
 | 
				
			||||||
 | 
					    //!     }
 | 
				
			||||||
 | 
					    //! }
 | 
				
			||||||
 | 
					    //! ```
 | 
				
			||||||
 | 
					    //!
 | 
				
			||||||
 | 
					    //! # Evaluating
 | 
				
			||||||
 | 
					    //! Macro [`eval`] parses code in the given [`Environment`].
 | 
				
			||||||
 | 
					    //! - [`assert_eval`] does the above, but expects [`Ok`]
 | 
				
			||||||
 | 
					    //! - [`assert_noeval`] does the above, but expects [`Err`]
 | 
				
			||||||
 | 
					    //! ```rust
 | 
				
			||||||
 | 
					    //! # use conlang::interpreter::tests::*;
 | 
				
			||||||
 | 
					    //! let mut env = Default::default();
 | 
				
			||||||
 | 
					    //! eval!{env,
 | 
				
			||||||
 | 
					    //!     let x = 2;
 | 
				
			||||||
 | 
					    //! }.expect("variable binding should succeed.");
 | 
				
			||||||
 | 
					    //! ```
 | 
				
			||||||
 | 
					    //!
 | 
				
			||||||
 | 
					    //! # Extracting Results
 | 
				
			||||||
 | 
					    //! Macros [`env_eq`] and [`env_ne`] take an "Environment Member Expression" and a value which
 | 
				
			||||||
 | 
					    //! implements [`Into<ConValue>`], and asserts that they are either equal or not equal,
 | 
				
			||||||
 | 
					    //! respectively.
 | 
				
			||||||
 | 
					    //!
 | 
				
			||||||
 | 
					    //! Macro [`conv_cmp`] takes two things that can be converted to [`ConValue`], and calls the
 | 
				
			||||||
 | 
					    //! provided comparison function on them, returning a [`bool`].
 | 
				
			||||||
 | 
					    //! ```rust
 | 
				
			||||||
 | 
					    //! # use conlang::interpreter::tests::*;
 | 
				
			||||||
 | 
					    //! let mut env = Default::default();
 | 
				
			||||||
 | 
					    //! assert_eval!{env,
 | 
				
			||||||
 | 
					    //!     let x = 10;
 | 
				
			||||||
 | 
					    //! }
 | 
				
			||||||
 | 
					    //! env_eq!(env.x, 10); // like assert_eq! for Environments
 | 
				
			||||||
 | 
					    //! ```
 | 
				
			||||||
 | 
					    #![allow(unused_macros)]
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    /// Stringifies, lexes, and parses everything you give to it
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Returns a `Result<`[`Start`]`, ParseError>`
 | 
				
			||||||
 | 
					    pub macro parse($($t:tt)*) {
 | 
				
			||||||
 | 
					        Parser::from(Lexer::new(stringify!( $($t)* ))).parse()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Evaluates a block of code in the given environment
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust,ignore
 | 
				
			||||||
 | 
					    /// eval!(env,
 | 
				
			||||||
 | 
					    ///     // Conlang code goes here
 | 
				
			||||||
 | 
					    ///     fn main () {
 | 
				
			||||||
 | 
					    ///         "Hello, world!"
 | 
				
			||||||
 | 
					    ///     }
 | 
				
			||||||
 | 
					    /// )
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    pub macro eval($env: path, $($t:tt)*) {{
 | 
				
			||||||
 | 
					        parse!($($t)*)
 | 
				
			||||||
 | 
					            .expect("code passed to eval! should parse correctly")
 | 
				
			||||||
 | 
					            .interpret(&mut $env)
 | 
				
			||||||
 | 
					    }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Evaluates a block of code in the given environment, expecting the interpreter to succeed
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust,ignore
 | 
				
			||||||
 | 
					    /// assert_eval!(env,
 | 
				
			||||||
 | 
					    ///     // Conlang code goes here
 | 
				
			||||||
 | 
					    ///     fn main () {
 | 
				
			||||||
 | 
					    ///         "Hello, world!"
 | 
				
			||||||
 | 
					    ///     }
 | 
				
			||||||
 | 
					    /// )
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    pub macro assert_eval($($t:tt)*) {
 | 
				
			||||||
 | 
					        eval!($($t)*)
 | 
				
			||||||
 | 
					            .expect(stringify!($($t)* should execute correctly))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Evaluates a block of code in the given environment, expecting the interpreter to fail
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust,ignore
 | 
				
			||||||
 | 
					    /// assert_noeval!(env,
 | 
				
			||||||
 | 
					    ///     // Conlang code goes here
 | 
				
			||||||
 | 
					    ///     fn main () {
 | 
				
			||||||
 | 
					    ///         1 == "Hello world!" // type incompatibility
 | 
				
			||||||
 | 
					    ///     }
 | 
				
			||||||
 | 
					    /// )
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    pub macro assert_noeval($($t:tt)*) {
 | 
				
			||||||
 | 
					        eval!($($t)*)
 | 
				
			||||||
 | 
					            .expect_err(stringify!($($t)* should not execute correctly))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub macro conv_cmp($func: ident, $a: expr, $b: expr) {
 | 
				
			||||||
 | 
					        $a.$func(&($b).into())
 | 
				
			||||||
 | 
					            .expect(stringify!($a should be comparable to $b))
 | 
				
			||||||
 | 
					            .truthy()
 | 
				
			||||||
 | 
					            .expect(stringify!(result of comparison should be ConValue::Bool))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub macro env_ne($env:ident.$var:ident, $expr:expr) {{
 | 
				
			||||||
 | 
					        let evaluated = $env.get(stringify!($var))
 | 
				
			||||||
 | 
					            .expect(stringify!($var should be defined and initialized));
 | 
				
			||||||
 | 
					        if !conv_cmp!(neq, evaluated, $expr) {
 | 
				
			||||||
 | 
					            panic!("assertion {} ({evaluated}) != {} failed.", stringify!($var), stringify!($expr))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub macro env_eq($env:ident.$var:ident, $expr:expr) {{
 | 
				
			||||||
 | 
					        let evaluated = $env.get(stringify!($var))
 | 
				
			||||||
 | 
					            .expect(stringify!($var should be defined and initialized));
 | 
				
			||||||
 | 
					        if !conv_cmp!(eq, evaluated, $expr) {
 | 
				
			||||||
 | 
					            panic!("assertion {} ({evaluated}) == {} failed.", stringify!($var), stringify!($expr))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }}
 | 
				
			||||||
 | 
					    pub macro tuple($($expr:expr),*) {
 | 
				
			||||||
 | 
					        ConValue::from(vec![$(ConValue::from($expr)),*])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod let_declarations {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn let_binding_uninit() {
 | 
				
			||||||
 | 
					        let mut env = Environment::new();
 | 
				
			||||||
 | 
					        assert_eval!(
 | 
				
			||||||
 | 
					            env,
 | 
				
			||||||
 | 
					            let x;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn let_binding_with_init() {
 | 
				
			||||||
 | 
					        let mut env = Environment::new();
 | 
				
			||||||
 | 
					        assert_eval!( env,
 | 
				
			||||||
 | 
					            let x = 10;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env_eq!(env.x, 10)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn let_binding_from_another_variable() {
 | 
				
			||||||
 | 
					        let mut env = Environment::new();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let x = 10;
 | 
				
			||||||
 | 
					            let y = x;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env_eq!(env.x, 10);
 | 
				
			||||||
 | 
					        env_eq!(env.y, 10);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod fn_declarations {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn empty_fn() {
 | 
				
			||||||
 | 
					        let mut env = Environment::new();
 | 
				
			||||||
 | 
					        assert_eval!(env, fn empty_fn() {});
 | 
				
			||||||
 | 
					        // TODO: true equality for functions
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            "fn empty_fn",
 | 
				
			||||||
 | 
					            format!(
 | 
				
			||||||
 | 
					                "{}",
 | 
				
			||||||
 | 
					                env.get("empty_fn")
 | 
				
			||||||
 | 
					                    .expect(stringify!(empty_fn should be defined and initialized))
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn identity_fn() {
 | 
				
			||||||
 | 
					        let mut env = Environment::new();
 | 
				
			||||||
 | 
					        assert_eval!(
 | 
				
			||||||
 | 
					            env,
 | 
				
			||||||
 | 
					            fn identity(input: i32) -> i32 {
 | 
				
			||||||
 | 
					                input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let output = identity(12);
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.output, 12);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod operators {
 | 
				
			||||||
 | 
					    use crate::ast::preamble::expression::tuple;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn unary() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let neg_one = -1;
 | 
				
			||||||
 | 
					            let pos_one = -neg_one;
 | 
				
			||||||
 | 
					            let not_true = !true;
 | 
				
			||||||
 | 
					            let not_false = !false;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.neg_one, -1);
 | 
				
			||||||
 | 
					        env_eq!(env.pos_one, 1);
 | 
				
			||||||
 | 
					        env_eq!(env.not_true, false);
 | 
				
			||||||
 | 
					        env_eq!(env.not_false, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn mul_div_rem() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let one = 129 % 32;
 | 
				
			||||||
 | 
					            let twelve = 144 / 12;
 | 
				
			||||||
 | 
					            let one_forty_four = 12 * 12;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.one, 1);
 | 
				
			||||||
 | 
					        env_eq!(env.twelve, 12);
 | 
				
			||||||
 | 
					        env_eq!(env.one_forty_four, 144);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn add_sub() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let is_42 = 17 + 25;
 | 
				
			||||||
 | 
					            let also_42 = 165 - 123;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.is_42, 42);
 | 
				
			||||||
 | 
					        env_eq!(env.also_42, 42);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn shift() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let eight = 1<<3;
 | 
				
			||||||
 | 
					            let one = 8>>3;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.eight, 8);
 | 
				
			||||||
 | 
					        env_eq!(env.one, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn bitwise() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let and_b1010 = 0b1111 & 0b1010;
 | 
				
			||||||
 | 
					            let or__b1111 = 0b1111 | 0b1010;
 | 
				
			||||||
 | 
					            let xor_b0101 = 0b1111 ^ 0b1010;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.and_b1010, 0b1010);
 | 
				
			||||||
 | 
					        env_eq!(env.or__b1111, 0b1111);
 | 
				
			||||||
 | 
					        env_eq!(env.xor_b0101, 0b0101);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn logical() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let t_and_t = true && true;
 | 
				
			||||||
 | 
					            let t_and_f = true && false;
 | 
				
			||||||
 | 
					            let f_and_t = false && true;
 | 
				
			||||||
 | 
					            let f_and_f = false && false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let t_or_t = true || true;
 | 
				
			||||||
 | 
					            let t_or_f = true || false;
 | 
				
			||||||
 | 
					            let f_or_t = false || true;
 | 
				
			||||||
 | 
					            let f_or_f = false || false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let t_xor_t = true ^^ true;
 | 
				
			||||||
 | 
					            let t_xor_f = true ^^ false;
 | 
				
			||||||
 | 
					            let f_xor_t = false ^^ true;
 | 
				
			||||||
 | 
					            let f_xor_f = false ^^ false;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.t_and_t, true);
 | 
				
			||||||
 | 
					        env_eq!(env.t_and_f, false);
 | 
				
			||||||
 | 
					        env_eq!(env.f_and_t, false);
 | 
				
			||||||
 | 
					        env_eq!(env.f_and_f, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env_eq!(env.t_or_t, true);
 | 
				
			||||||
 | 
					        env_eq!(env.t_or_f, true);
 | 
				
			||||||
 | 
					        env_eq!(env.f_or_t, true);
 | 
				
			||||||
 | 
					        env_eq!(env.f_or_f, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env_eq!(env.t_xor_t, false);
 | 
				
			||||||
 | 
					        env_eq!(env.t_xor_f, true);
 | 
				
			||||||
 | 
					        env_eq!(env.f_xor_t, true);
 | 
				
			||||||
 | 
					        env_eq!(env.f_xor_f, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn logical_short_circuits() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let mut and_short_circuits = true;
 | 
				
			||||||
 | 
					            false && { and_short_circuits = false; false };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut or_short_circuits = true;
 | 
				
			||||||
 | 
					            true || { or_short_circuits = false; false };
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.and_short_circuits, true);
 | 
				
			||||||
 | 
					        env_eq!(env.or_short_circuits, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn range() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let inclusive = 0..=10;
 | 
				
			||||||
 | 
					            let exclusive = 0..10;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        // TODO: extract the ranges and actually check them
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn compare() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            // Less than
 | 
				
			||||||
 | 
					            let is_10_lt_20 = 10 <  20;
 | 
				
			||||||
 | 
					            let is_10_le_20 = 10 <= 20;
 | 
				
			||||||
 | 
					            let is_10_eq_20 = 10 == 20;
 | 
				
			||||||
 | 
					            let is_10_ne_20 = 10 != 20;
 | 
				
			||||||
 | 
					            let is_10_ge_20 = 10 >= 20;
 | 
				
			||||||
 | 
					            let is_10_gt_20 = 10 >  20;
 | 
				
			||||||
 | 
					            // Equal to
 | 
				
			||||||
 | 
					            let is_10_lt_10 = 10 <  10;
 | 
				
			||||||
 | 
					            let is_10_le_10 = 10 <= 10;
 | 
				
			||||||
 | 
					            let is_10_eq_10 = 10 == 10;
 | 
				
			||||||
 | 
					            let is_10_ne_10 = 10 != 10;
 | 
				
			||||||
 | 
					            let is_10_ge_10 = 10 >= 10;
 | 
				
			||||||
 | 
					            let is_10_gt_10 = 10 >  10;
 | 
				
			||||||
 | 
					            // Greater than
 | 
				
			||||||
 | 
					            let is_20_lt_10 = 20 <  10;
 | 
				
			||||||
 | 
					            let is_20_le_10 = 20 <= 10;
 | 
				
			||||||
 | 
					            let is_20_eq_10 = 20 == 10;
 | 
				
			||||||
 | 
					            let is_20_ne_10 = 20 != 10;
 | 
				
			||||||
 | 
					            let is_20_ge_10 = 20 >= 10;
 | 
				
			||||||
 | 
					            let is_20_gt_10 = 20 >  10;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Less than
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_lt_20, true); //  <
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_le_20, true); //  <=
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_eq_20, false); // ==
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_ne_20, true); //  !=
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_ge_20, false); // >=
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_gt_20, false); // >
 | 
				
			||||||
 | 
					                                         // Equal to
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_lt_10, false);
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_le_10, true);
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_eq_10, true);
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_ne_10, false);
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_ge_10, true);
 | 
				
			||||||
 | 
					        env_eq!(env.is_10_gt_10, false);
 | 
				
			||||||
 | 
					        // Greater than
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_lt_10, false);
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_le_10, false);
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_eq_10, false);
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_ne_10, true);
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_ge_10, true);
 | 
				
			||||||
 | 
					        env_eq!(env.is_20_gt_10, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn assign() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let base = 10;
 | 
				
			||||||
 | 
					            let mut assign = base;
 | 
				
			||||||
 | 
					            let mut add = base;
 | 
				
			||||||
 | 
					            let mut sub = base;
 | 
				
			||||||
 | 
					            let mut mul = base;
 | 
				
			||||||
 | 
					            let mut div = base;
 | 
				
			||||||
 | 
					            let mut rem = base;
 | 
				
			||||||
 | 
					            let mut and = base;
 | 
				
			||||||
 | 
					            let mut or_ = base;
 | 
				
			||||||
 | 
					            let mut xor = base;
 | 
				
			||||||
 | 
					            let mut shl = base;
 | 
				
			||||||
 | 
					            let mut shr = base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let modifier = 3;
 | 
				
			||||||
 | 
					            assign = modifier;
 | 
				
			||||||
 | 
					            add += modifier;
 | 
				
			||||||
 | 
					            sub -= modifier;
 | 
				
			||||||
 | 
					            mul *= modifier;
 | 
				
			||||||
 | 
					            div /= modifier;
 | 
				
			||||||
 | 
					            rem %= modifier;
 | 
				
			||||||
 | 
					            and &= modifier;
 | 
				
			||||||
 | 
					            or_ |= modifier;
 | 
				
			||||||
 | 
					            xor ^= modifier;
 | 
				
			||||||
 | 
					            shl <<= modifier;
 | 
				
			||||||
 | 
					            shr >>= modifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let (base, modifier) = (10, 3);
 | 
				
			||||||
 | 
					        env_eq!(env.assign, modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.add, base + modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.sub, base - modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.mul, base * modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.div, base / modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.rem, base % modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.and, base & modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.or_, base | modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.xor, base ^ modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.shl, base << modifier);
 | 
				
			||||||
 | 
					        env_eq!(env.shr, base >> modifier);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn assignment_is_left_assoc_and_returns_empty() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let x; // uninitialized (no type)
 | 
				
			||||||
 | 
					            let y = 0xdeadbeef;
 | 
				
			||||||
 | 
					            let z = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            x = y = z;
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.x, ());
 | 
				
			||||||
 | 
					        env_eq!(env.y, 10);
 | 
				
			||||||
 | 
					        env_eq!(env.z, 10);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    #[should_panic]
 | 
				
			||||||
 | 
					    fn assignment_accounts_for_type() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            let x = "a string";
 | 
				
			||||||
 | 
					            let y = 0xdeadbeef;
 | 
				
			||||||
 | 
					            y = x; // should crash: type error
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn precedence() {
 | 
				
			||||||
 | 
					        let mut env = Default::default();
 | 
				
			||||||
 | 
					        assert_eval!(env,
 | 
				
			||||||
 | 
					            // mul/div/rem > add/sub
 | 
				
			||||||
 | 
					            let a = 2 * 3 + 4 * 5 / 6; // = 9
 | 
				
			||||||
 | 
					            // add/sub > shift
 | 
				
			||||||
 | 
					            let b = 1 << 3 + 1 << 2; // 1 << 6 = 64
 | 
				
			||||||
 | 
					            // shift > bitwise
 | 
				
			||||||
 | 
					            let c = 4 | 4 << 4; // 4 | 64 = 68
 | 
				
			||||||
 | 
					            // all together now!
 | 
				
			||||||
 | 
					            let d = 1 << 2 + 3 * 4; // 2 << 14 = 16384
 | 
				
			||||||
 | 
					            let e = 4 * 3 + 2 << 1; // 14 << 1 = 28
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        env_eq!(env.a, 9);
 | 
				
			||||||
 | 
					        env_eq!(env.b, 64);
 | 
				
			||||||
 | 
					        env_eq!(env.c, 68);
 | 
				
			||||||
 | 
					        env_eq!(env.d, 16384);
 | 
				
			||||||
 | 
					        env_eq!(env.e, 28);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					fn test_template() {
 | 
				
			||||||
 | 
					    let mut env = Default::default();
 | 
				
			||||||
 | 
					    assert_eval!(env,);
 | 
				
			||||||
 | 
					    //env_eq!(, );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user