1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use num_traits::Float; use std::hash::{Hash, Hasher}; use crate::types::{FloatType, IntType}; #[derive(Clone, PartialEq)] pub enum Const { Int(IntType), Float(FloatType), Str(String), } impl Eq for Const {} impl Hash for Const { fn hash<H: Hasher>(&self, state: &mut H) { match self { Const::Int(i) => i.hash(state), Const::Float(f) => { let (m, e, s) = Float::integer_decode(*f); m.hash(state); e.hash(state); s.hash(state); } Const::Str(s) => s.hash(state), } } } macro_rules! bin_op { ($name:ident, $int_int:expr, $int_float:expr, $float_int:expr, $float_float:expr) => { pub fn $name(self, other: Const) -> Option<Const> { match self { Const::Int(a) => match other { Const::Int(b) => $int_int(a, b), Const::Float(b) => $int_float(a, b), _ => unreachable!() }, Const::Float(a) => match other { Const::Int(b) => $float_int(a, b), Const::Float(b) => $float_float(a, b), _ => unreachable!() }, _ => unreachable!() } } }; } macro_rules! bin_op_normal { ($name:ident, $op:tt) => { bin_op! { $name, |a, b| Some(Const::Int(a $op b)), |a, b| Some(Const::Float(a as FloatType $op b)), |a, b| Some(Const::Float(a $op b as FloatType)), |a, b| Some(Const::Float(a $op b)) } }; } macro_rules! bin_op_int { ($name:ident, $op:tt) => { bin_op! { $name, |a, b| Some(Const::Int(a $op b)), |_, _| None, |_, _| None, |_, _| None } }; } impl Const { bin_op_normal! {add, +} bin_op_normal! {sub, -} bin_op_normal! {mul, *} bin_op! { div, |a, b| Some(Const::Float(a as FloatType / b as FloatType)), |a, b| Some(Const::Float(a as FloatType / b)), |a, b| Some(Const::Float(a / b as FloatType)), |a, b| Some(Const::Float(a / b as FloatType)) } bin_op! { idiv, |a, b| Some(Const::Int(a / b)), |a, b| Some(Const::Float((a / b as IntType) as FloatType)), |a, b| Some(Const::Float((a as IntType / b) as FloatType)), |a, b| Some(Const::Float((a as IntType / b as IntType) as FloatType)) } bin_op! { mod_, |a, b| Some(Const::Int(a % b)), |a, b| Some(Const::Float(a as FloatType % b)), |a, b| Some(Const::Float(a % b as FloatType)), |a, b| Some(Const::Float(a % b)) } bin_op! { pow, |a, b| Some(Const::Float((a as FloatType).powf(b as FloatType))), |a, b| Some(Const::Float((a as FloatType).powf(b))), |a:FloatType, b| Some(Const::Float(a.powf(b as FloatType))), |a:FloatType, b| Some(Const::Float(a.powf(b))) } bin_op_int! {band, &} bin_op_int! {bor, |} bin_op_int! {bxor, ^} bin_op_int! {shl, <<} bin_op_int! {shr, >>} }