sphinx/runtime/types/
ops.rs1use 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 #[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 #[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 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 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 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}