sphinx/runtime/types/
ops.rs

1use crate::runtime::Variant;
2use crate::runtime::types::MetaObject;
3use crate::runtime::errors::{ExecResult, RuntimeError};
4
5
6macro_rules! meta_eval_unary {
7    ( $operand:expr, $unary_method:tt ) => {
8        $operand.as_meta().$unary_method()
9            .unwrap_or_else(|| Err(RuntimeError::invalid_unary_operand($operand)))
10    };
11}
12
13macro_rules! meta_eval_binary {
14    ( $lhs:expr, $rhs:expr, $binary_method:tt, $reflected_method:tt) => {
15        {
16            if let Some(result) = $lhs.as_meta().$binary_method($rhs) {
17                return result;
18            }
19            
20            if $lhs.type_tag() != $rhs.type_tag() {
21                if let Some(result) = $rhs.as_meta().$reflected_method($lhs) {
22                    return result;
23                }
24            }
25            
26            Err(RuntimeError::invalid_binary_operands($lhs, $rhs))
27        }
28    };
29}
30
31macro_rules! meta_eval_inequality {
32    ( $lhs:expr, $rhs:expr, $compare_method:tt, $reflected_method:tt) => {
33        {
34            if let Some(result) = $lhs.as_meta().$compare_method($rhs) {
35                return result;
36            }
37            
38            if $lhs.type_tag() != $rhs.type_tag() {
39                if let Some(result) = $rhs.as_meta().$reflected_method($lhs) {
40                    return result.map(|cmp| !cmp);
41                }
42            }
43            
44            Err(RuntimeError::invalid_binary_operands($lhs, $rhs))
45        }
46    };
47}
48
49impl Variant {
50    
51    // Unary
52    
53    #[inline(always)]
54    pub fn apply_neg(&self) -> ExecResult<Variant> {
55        meta_eval_unary!(self, op_neg)
56    }
57    
58    #[inline(always)]
59    pub fn apply_pos(&self) -> ExecResult<Variant> {
60        meta_eval_unary!(self, op_pos)
61    }
62    
63    #[inline(always)]
64    pub fn apply_inv(&self) -> ExecResult<Variant> {
65        meta_eval_unary!(self, op_inv)
66    }
67    
68    #[inline(always)]
69    pub fn apply_not(&self) -> ExecResult<Variant> {
70        Ok(Variant::from(!self.as_bool()?))
71    }
72    
73    // Arithmetic
74    
75    #[inline(always)]
76    pub fn apply_mul(&self, rhs: &Variant) -> ExecResult<Variant> {
77        meta_eval_binary!(self, rhs, op_mul, op_rmul)
78    }
79    
80    #[inline(always)]
81    pub fn apply_div(&self, rhs: &Variant) -> ExecResult<Variant> {
82        meta_eval_binary!(self, rhs, op_div, op_rdiv)
83    }
84    
85    #[inline(always)]
86    pub fn apply_mod(&self, rhs: &Variant) -> ExecResult<Variant> {
87        meta_eval_binary!(self, rhs, op_mod, op_rmod)
88    }
89    
90    #[inline(always)]
91    pub fn apply_add(&self, rhs: &Variant) -> ExecResult<Variant> {
92        meta_eval_binary!(self, rhs, op_add, op_radd)
93    }
94    
95    #[inline(always)]
96    pub fn apply_sub(&self, rhs: &Variant) -> ExecResult<Variant> {
97        meta_eval_binary!(self, rhs, op_sub, op_rsub)
98    }
99    
100    // Bitwise
101    
102    pub fn apply_and(&self, rhs: &Variant) -> ExecResult<Variant> {
103        meta_eval_binary!(self, rhs, op_and, op_rand)
104    }
105    
106    pub fn apply_xor(&self, rhs: &Variant) -> ExecResult<Variant> {
107        meta_eval_binary!(self, rhs, op_xor, op_rxor)
108    }
109    
110    pub fn apply_or(&self, rhs: &Variant) -> ExecResult<Variant> {
111        meta_eval_binary!(self, rhs, op_or, op_ror)
112    }
113    
114    // Shifts
115    
116    pub fn apply_shl(&self, rhs: &Variant) -> ExecResult<Variant> {
117        meta_eval_binary!(self, rhs, op_shl, op_rshl)
118    }
119    
120    pub fn apply_shr(&self, rhs: &Variant) -> ExecResult<Variant> {
121        meta_eval_binary!(self, rhs, op_shr, op_rshr)
122    }
123
124    // Comparison
125    
126    pub fn cmp_eq(&self, other: &Variant) -> ExecResult<bool> {
127        if let Some(result) = self.as_meta().cmp_eq(other) {
128            return result;
129        }
130        
131        if self.type_tag() != other.type_tag() {
132            if let Some(result) = other.as_meta().cmp_eq(self) {
133                return result;
134            }
135        }
136        
137        Ok(false)
138    }
139    
140    pub fn cmp_ne(&self, other: &Variant) -> ExecResult<bool> {
141        self.cmp_eq(other).map(|cmp| !cmp)
142    }
143    
144    pub fn cmp_lt(&self, other: &Variant) -> ExecResult<bool> {
145        meta_eval_inequality!(self, other, cmp_lt, cmp_le)
146    }
147    
148    pub fn cmp_le(&self, other: &Variant) -> ExecResult<bool> {
149        meta_eval_inequality!(self, other, cmp_le, cmp_lt)
150    }
151    
152    pub fn cmp_gt(&self, other: &Variant) -> ExecResult<bool> {
153        self.cmp_le(other).map(|cmp| !cmp)
154    }
155
156    pub fn cmp_ge(&self, other: &Variant) -> ExecResult<bool> {
157        self.cmp_lt(other).map(|cmp| !cmp)
158    }
159}