1use core::str::FromStr;
2use core::fmt::{self, Write};
3use crate::language::{IntType, FloatType};
4use crate::runtime::Variant;
5use crate::runtime::strings::{StringValue, StrBuffer};
6use crate::runtime::types::{MetaObject, Type};
7use crate::runtime::errors::{ExecResult, RuntimeError};
8
9macro_rules! checked_int_math {
10 ( $method:tt, $lhs:expr, $rhs:expr ) => {
11 match $lhs.$method($rhs) {
12 Some(value) => Ok(Variant::Integer(value)),
13 None => Err(RuntimeError::overflow_error()),
14 }
15 };
16}
17
18pub fn int_from_str(s: &str, radix: IntType) -> ExecResult<IntType> {
19 if !(2..=36).contains(&radix) {
20 return Err(RuntimeError::invalid_value("invalid radix"));
21 }
22
23 let value = IntType::from_str_radix(s, radix.try_into().unwrap())
24 .map_err(|_| RuntimeError::invalid_value(format!(
25 "could not parse \"{}\" as int with radix {}", s, radix)
26 ))?;
27 Ok(value)
28}
29
30impl MetaObject for IntType {
31 fn type_tag(&self) -> Type { Type::Integer }
32
33 fn as_bits(&self) -> Option<ExecResult<IntType>> { Some(Ok(*self)) }
34 fn as_int(&self) -> Option<ExecResult<IntType>> { Some(Ok(*self)) }
35 fn as_float(&self) -> Option<ExecResult<FloatType>> { Some(Ok(*self as FloatType)) }
36
37 fn op_neg(&self) -> Option<ExecResult<Variant>> { Some(Ok(Variant::from(-(*self)))) }
38 fn op_pos(&self) -> Option<ExecResult<Variant>> { Some(Ok(Variant::from(*self))) }
39 fn op_inv(&self) -> Option<ExecResult<Variant>> { Some(Ok(Variant::from(!(*self)))) }
40
41 fn op_mul(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
42 match rhs {
43 Variant::Integer(rhs) => Some(checked_int_math!(checked_mul, *self, *rhs)),
44 _ => rhs.as_meta().as_int()
45 .map(|rhs| checked_int_math!(checked_mul, *self, rhs?))
46 }
47 }
48
49 fn op_rmul(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
50 self.op_mul(lhs)
51 }
52
53 fn op_div(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
54 rhs.as_meta().as_int().map(|rhs| {
55 let rhs = rhs?;
56 if rhs == 0 {
57 Err(RuntimeError::divide_by_zero())
58 } else {
59 checked_int_math!(checked_div, *self, rhs)
60 }
61 })
62 }
63
64 fn op_rdiv(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
65 lhs.as_meta().as_int().map(|lhs| {
66 if *self == 0 {
67 Err(RuntimeError::divide_by_zero())
68 } else {
69 checked_int_math!(checked_div, lhs?, *self)
70 }
71 })
72 }
73
74 fn op_mod(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
75 rhs.as_meta().as_int().map(|rhs| Ok(Variant::from(*self % rhs?)))
76 }
77
78 fn op_rmod(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
79 lhs.as_meta().as_int().map(|lhs| Ok(Variant::from(lhs? % *self)))
80 }
81
82 fn op_add(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
83 match rhs {
84 Variant::Integer(rhs) => Some(checked_int_math!(checked_add, *self, *rhs)),
85 _ => rhs.as_meta().as_int()
86 .map(|rhs| checked_int_math!(checked_add, *self, rhs?))
87 }
88 }
89
90 fn op_radd(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
91 self.op_add(lhs)
92 }
93
94 fn op_sub(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
95 match rhs {
96 Variant::Integer(rhs) => Some(checked_int_math!(checked_sub, *self, *rhs)),
97 _ => rhs.as_meta().as_int()
98 .map(|rhs| checked_int_math!(checked_sub, *self, rhs?))
99 }
100 }
101
102 fn op_rsub(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
103 match lhs {
104 Variant::Integer(lhs) => Some(checked_int_math!(checked_sub, *lhs, *self)),
105 _ => lhs.as_meta().as_int()
106 .map(|lhs| checked_int_math!(checked_sub, lhs?, *self))
107 }
108 }
109
110 fn op_and(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
111 let lhs = self.as_bits().unwrap().unwrap();
112 match rhs {
113 Variant::BoolFalse => Some(Ok(Variant::from(lhs & false.as_bits().unwrap().unwrap()))),
114 Variant::BoolTrue => Some(Ok(Variant::from(lhs & true.as_bits().unwrap().unwrap()))),
115 Variant::Integer(rhs) => Some(Ok(Variant::from(lhs & rhs.as_bits().unwrap().unwrap()))),
116 _ => rhs.as_meta().as_bits()
117 .map(|rhs| Ok(Variant::from(lhs & rhs?)))
118 }
119 }
120
121 fn op_rand(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
122 self.op_and(lhs)
123 }
124
125 fn op_xor(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
126 let lhs = self.as_bits().unwrap().unwrap();
127 match rhs {
128 Variant::BoolFalse => Some(Ok(Variant::from(lhs ^ false.as_bits().unwrap().unwrap()))),
129 Variant::BoolTrue => Some(Ok(Variant::from(lhs ^ true.as_bits().unwrap().unwrap()))),
130 Variant::Integer(rhs) => Some(Ok(Variant::from(lhs ^ rhs.as_bits().unwrap().unwrap()))),
131 _ => rhs.as_meta().as_bits()
132 .map(|rhs| Ok(Variant::from(lhs ^ rhs?)))
133 }
134 }
135
136 fn op_rxor(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
137 self.op_xor(lhs)
138 }
139
140 fn op_or(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
141 let lhs = self.as_bits().unwrap().unwrap();
142 match rhs {
143 Variant::BoolFalse => Some(Ok(Variant::from(lhs | false.as_bits().unwrap().unwrap()))),
144 Variant::BoolTrue => Some(Ok(Variant::from(lhs | true.as_bits().unwrap().unwrap()))),
145 Variant::Integer(rhs) => Some(Ok(Variant::from(lhs | rhs.as_bits().unwrap().unwrap()))),
146 _ => rhs.as_meta().as_bits()
147 .map(|rhs| Ok(Variant::from(lhs | rhs?)))
148 }
149 }
150
151 fn op_ror(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
152 self.op_or(lhs)
153 }
154
155 fn op_shl(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
156 let rhs = match rhs {
157 Variant::BoolFalse => Some(0),
158 Variant::BoolTrue => Some(1),
159 Variant::Integer(rhs) => Some(*rhs),
160 _ => match rhs.as_meta().as_int() {
161 Some(Ok(rhs)) => Some(rhs),
162 Some(Err(error)) => return Some(Err(error)),
163 None => None,
164 },
165 };
166
167 rhs.map(|rhs| {
168 if rhs < 0 {
169 return Err(RuntimeError::negative_shift_count());
170 }
171 return checked_int_math!(checked_shl, *self, rhs.try_into().unwrap());
172 })
173 }
174
175 fn op_rshl(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
176 lhs.as_meta().as_bits().map(|lhs| {
177 let lhs = lhs?;
178 if *self < 0 {
179 return Err(RuntimeError::negative_shift_count());
180 }
181 return checked_int_math!(checked_shl, lhs, (*self).try_into().unwrap());
182 })
183 }
184
185 fn op_shr(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
186 let rhs = match rhs {
187 Variant::BoolFalse => Some(0),
188 Variant::BoolTrue => Some(1),
189 Variant::Integer(rhs) => Some(*rhs),
190 _ => match rhs.as_meta().as_int() {
191 Some(Ok(rhs)) => Some(rhs),
192 Some(Err(error)) => return Some(Err(error)),
193 None => None,
194 },
195 };
196
197 rhs.map(|rhs| {
198 if rhs < 0 {
199 return Err(RuntimeError::negative_shift_count());
200 }
201 return checked_int_math!(checked_shr, *self, rhs.try_into().unwrap());
202 })
203 }
204
205 fn op_rshr(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
206 lhs.as_meta().as_bits().map(|lhs| {
207 let lhs = lhs?;
208 if *self < 0 {
209 return Err(RuntimeError::negative_shift_count());
210 }
211 return checked_int_math!(checked_shr, lhs, (*self).try_into().unwrap());
212 })
213 }
214
215 fn cmp_eq(&self, other: &Variant) -> Option<ExecResult<bool>> {
216 match other {
217 Variant::Integer(other) => Some(Ok(*self == *other)),
218 _ => other.as_meta().as_int()
219 .map(|other| Ok(*self == other?))
220 }
221 }
222
223 fn cmp_lt(&self, other: &Variant) -> Option<ExecResult<bool>> {
224 match other {
225 Variant::Integer(other) => Some(Ok(*self < *other)),
226 _ => other.as_meta().as_int()
227 .map(|other| Ok(*self < other?))
228 }
229 }
230
231 fn cmp_le(&self, other: &Variant) -> Option<ExecResult<bool>> {
232 match other {
233 Variant::Integer(other) => Some(Ok(*self <= *other)),
234 _ => other.as_meta().as_int()
235 .map(|other| Ok(*self <= other?))
236 }
237 }
238
239 fn fmt_repr(&self) -> ExecResult<StringValue> {
240 let mut buf = StrBuffer::<32>::new();
241 if write!(buf, "{}", *self).is_ok() {
242 Ok(StringValue::new_maybe_interned(buf))
243 } else {
244 Ok(StringValue::new_maybe_interned(format!("{}", *self)))
246 }
247 }
248}
249
250
251pub fn float_from_str(s: &str) -> ExecResult<FloatType> {
252 let value = FloatType::from_str(s)
253 .map_err(|_| RuntimeError::invalid_value(format!(
254 "could not parse \"{}\" as float", s
255 )))?;
256 Ok(value)
257}
258
259impl MetaObject for FloatType {
260 fn type_tag(&self) -> Type { Type::Float }
261
262 fn as_float(&self) -> Option<ExecResult<FloatType>> { Some(Ok(*self)) }
263
264 fn op_neg(&self) -> Option<ExecResult<Variant>> { Some(Ok(Variant::from(-(*self)))) }
265 fn op_pos(&self) -> Option<ExecResult<Variant>> { Some(Ok(Variant::from(*self))) }
266
267 fn op_mul(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
268 rhs.as_meta().as_float().map(|rhs| Ok(Variant::from(*self * rhs?)))
269 }
270
271 fn op_rmul(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
272 self.op_mul(lhs)
273 }
274
275 fn op_div(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
276 rhs.as_meta().as_float().map(|rhs| Ok(Variant::from(*self / rhs?)))
277 }
278
279 fn op_rdiv(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
280 lhs.as_meta().as_float().map(|lhs| Ok(Variant::from(lhs? / *self)))
281 }
282
283 fn op_mod(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
284 rhs.as_meta().as_float().map(|rhs| Ok(Variant::from(*self % rhs?)))
285 }
286
287 fn op_rmod(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
288 lhs.as_meta().as_float().map(|lhs| Ok(Variant::from(lhs? % *self)))
289 }
290
291 fn op_add(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
292 rhs.as_meta().as_float().map(|rhs| Ok(Variant::from(*self + rhs?)))
293 }
294
295 fn op_radd(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
296 self.op_add(lhs)
297 }
298
299 fn op_sub(&self, rhs: &Variant) -> Option<ExecResult<Variant>> {
300 rhs.as_meta().as_float().map(|rhs| Ok(Variant::from(*self - rhs?)))
301 }
302
303 fn op_rsub(&self, lhs: &Variant) -> Option<ExecResult<Variant>> {
304 lhs.as_meta().as_float().map(|lhs| Ok(Variant::from(lhs? - *self)))
305 }
306
307 fn cmp_eq(&self, other: &Variant) -> Option<ExecResult<bool>> {
308 other.as_meta().as_float().map(|other| Ok(*self == other?))
309 }
310
311 fn cmp_lt(&self, other: &Variant) -> Option<ExecResult<bool>> {
312 other.as_meta().as_float().map(|other| Ok(*self < other?))
313 }
314
315 fn cmp_le(&self, other: &Variant) -> Option<ExecResult<bool>> {
316 other.as_meta().as_float().map(|other| Ok(*self <= other?))
317 }
318
319 fn fmt_repr(&self) -> ExecResult<StringValue> {
320 fn write_float(value: FloatType, fmt: &mut impl fmt::Write) -> fmt::Result {
321 if !value.is_finite() || value.trunc() != value {
322 write!(fmt, "{}", value)
323 } else {
324 write!(fmt, "{}.0", value)
325 }
326 }
327
328 let mut buf = StrBuffer::<32>::new();
329 if write_float(*self, &mut buf).is_ok() {
330 Ok(StringValue::new_maybe_interned(buf))
331 } else {
332 let mut buf = String::new();
333 write_float(*self, &mut buf)
334 .map_err(|error| RuntimeError::other(error.to_string()))?;
335 Ok(StringValue::new_maybe_interned(buf))
336 }
337 }
338}
339