use crate::core::*;
pub const NUM: i64 = 0;
pub const BOOL: i64 = 1;
pub const CHAR: i64 = 2;
pub const PAIR: i64 = 3;
pub const NIL: i64 = 4;
pub const STR: i64 = 5;
pub const SYM: i64 = 6;
pub const VEC: i64 = 7;
pub const SHIFT: i64 = 3;
pub const MASK: i64 = 0b0000_0111;
pub const FALSE: i64 = (0 << SHIFT) | BOOL;
pub const TRUE: i64 = (1 << SHIFT) | BOOL;
pub fn to(prog: &Expr) -> Option<i64> {
match prog {
Expr::Number(i) => Some((i << SHIFT) | NUM),
Expr::Boolean(true) => Some(TRUE),
Expr::Boolean(false) => Some(FALSE),
Expr::Char(c) => {
Some((i64::from(*c) << SHIFT) | CHAR)
}
Expr::Nil => Some(NIL),
_ => None,
}
}
pub fn n(i: i64) -> i64 {
(i << SHIFT) | NUM
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
pub fn from(val: i64) -> Expr {
if (val & MASK) == NUM {
Expr::Number(val >> SHIFT)
} else if (val & MASK) == CHAR {
Expr::Char((val >> SHIFT) as u8)
} else if val == TRUE {
true.into()
} else if val == FALSE {
false.into()
} else if val == NIL {
Expr::Nil
} else {
panic!("Oops")
}
}
#[test]
fn numbers() {
assert_eq!(to(&0.into()), Some(0));
assert_eq!(to(&1.into()), Some(8));
assert_eq!(from(0), 0.into());
assert_eq!(from(8), 1.into());
}
#[test]
fn chars() {
assert_eq!(to(&('A').into()), Some((65 << SHIFT) + CHAR));
}
}