1use golem_wasm_ast::analysis::AnalysedType;
16use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType};
17use std::cmp::Ordering;
18use std::fmt::Display;
19
20pub trait GetLiteralValue {
21 fn get_literal(&self) -> Option<LiteralValue>;
22}
23
24impl GetLiteralValue for ValueAndType {
25 fn get_literal(&self) -> Option<LiteralValue> {
26 match self {
27 ValueAndType {
28 value: Value::String(value),
29 ..
30 } => Some(LiteralValue::String(value.clone())),
31 ValueAndType {
32 value: Value::Char(code_point),
33 ..
34 } => char::from_u32(*code_point as u32)
35 .map(|c| c.to_string())
36 .map(LiteralValue::String),
37 ValueAndType {
38 value: Value::Bool(value),
39 ..
40 } => Some(LiteralValue::Bool(*value)),
41 ValueAndType {
42 value: Value::Enum(idx),
43 typ: AnalysedType::Enum(typ),
44 } => {
45 Some(LiteralValue::String(typ.cases[*idx as usize].clone()))
47 }
48 ValueAndType {
49 value:
50 Value::Variant {
51 case_idx,
52 case_value,
53 },
54 typ: AnalysedType::Variant(typ),
55 } => {
56 if case_value.is_none() {
58 Some(LiteralValue::String(
59 typ.cases[*case_idx as usize].name.clone(),
60 ))
61 } else {
62 None
63 }
64 }
65 other => internal::get_numeric_value(other).map(LiteralValue::Num),
66 }
67 }
68}
69
70#[derive(Clone, Debug, PartialEq, PartialOrd)]
71pub enum LiteralValue {
72 Num(CoercedNumericValue),
73 String(String),
74 Bool(bool),
75}
76
77impl LiteralValue {
78 pub fn get_bool(&self) -> Option<bool> {
79 match self {
80 LiteralValue::Bool(value) => Some(*value),
81 _ => None,
82 }
83 }
84
85 pub fn get_number(&self) -> Option<CoercedNumericValue> {
86 match self {
87 LiteralValue::Num(num) => Some(num.clone()),
88 _ => None,
89 }
90 }
91
92 pub fn as_string(&self) -> String {
93 match self {
94 LiteralValue::Num(number) => number.to_string(),
95 LiteralValue::String(value) => value.clone(),
96 LiteralValue::Bool(value) => value.to_string(),
97 }
98 }
99}
100
101impl From<String> for LiteralValue {
102 fn from(value: String) -> Self {
103 if let Ok(u64) = value.parse::<u64>() {
104 LiteralValue::Num(CoercedNumericValue::PosInt(u64))
105 } else if let Ok(i64_value) = value.parse::<i64>() {
106 LiteralValue::Num(CoercedNumericValue::NegInt(i64_value))
107 } else if let Ok(f64_value) = value.parse::<f64>() {
108 LiteralValue::Num(CoercedNumericValue::Float(f64_value))
109 } else if let Ok(bool) = value.parse::<bool>() {
110 LiteralValue::Bool(bool)
111 } else {
112 LiteralValue::String(value.to_string())
113 }
114 }
115}
116
117#[derive(Clone, Debug)]
119pub enum CoercedNumericValue {
120 PosInt(u64),
121 NegInt(i64),
122 Float(f64),
123}
124
125impl CoercedNumericValue {
126 pub fn is_zero(&self) -> bool {
127 match self {
128 CoercedNumericValue::PosInt(val) => *val == 0,
129 CoercedNumericValue::NegInt(val) => *val == 0,
130 CoercedNumericValue::Float(val) => *val == 0.0,
131 }
132 }
133
134 pub fn cast_to(&self, analysed_type: &AnalysedType) -> Option<ValueAndType> {
135 match self {
136 CoercedNumericValue::PosInt(number) => {
137 let num = *number;
138
139 match analysed_type {
140 AnalysedType::U8(_) if num <= u8::MAX as u64 => {
141 Some((num as u8).into_value_and_type())
142 }
143 AnalysedType::U16(_) if num <= u16::MAX as u64 => {
144 Some((num as u16).into_value_and_type())
145 }
146 AnalysedType::U32(_) if num <= u32::MAX as u64 => {
147 Some((num as u32).into_value_and_type())
148 }
149 AnalysedType::U64(_) => Some(num.into_value_and_type()),
150
151 AnalysedType::S8(_) if num <= i8::MAX as u64 => {
152 Some((num as i8).into_value_and_type())
153 }
154 AnalysedType::S16(_) if num <= i16::MAX as u64 => {
155 Some((num as i16).into_value_and_type())
156 }
157 AnalysedType::S32(_) if num <= i32::MAX as u64 => {
158 Some((num as i32).into_value_and_type())
159 }
160 AnalysedType::S64(_) if num <= i64::MAX as u64 => {
161 Some((num as i64).into_value_and_type())
162 }
163
164 AnalysedType::F32(_) if num <= f32::MAX as u64 => {
165 Some((num as f32).into_value_and_type())
166 }
167 AnalysedType::F64(_) if num <= f64::MAX as u64 => {
168 Some((num as f64).into_value_and_type())
169 }
170
171 _ => None,
172 }
173 }
174
175 CoercedNumericValue::NegInt(number) => {
176 let num = *number;
177
178 match analysed_type {
179 AnalysedType::S8(_) if num >= i8::MIN as i64 && num <= i8::MAX as i64 => {
180 Some((num as i8).into_value_and_type())
181 }
182 AnalysedType::S16(_) if num >= i16::MIN as i64 && num <= i16::MAX as i64 => {
183 Some((num as i16).into_value_and_type())
184 }
185 AnalysedType::S32(_) if num >= i32::MIN as i64 && num <= i32::MAX as i64 => {
186 Some((num as i32).into_value_and_type())
187 }
188 AnalysedType::S64(_) => Some(num.into_value_and_type()),
189
190 AnalysedType::U8(_) if num >= 0 && num <= u8::MAX as i64 => {
192 Some((num as u8).into_value_and_type())
193 }
194 AnalysedType::U16(_) if num >= 0 && num <= u16::MAX as i64 => {
195 Some((num as u16).into_value_and_type())
196 }
197 AnalysedType::U32(_) if num >= 0 && num <= u32::MAX as i64 => {
198 Some((num as u32).into_value_and_type())
199 }
200 AnalysedType::U64(_) if num >= 0 => Some((num as u64).into_value_and_type()),
201
202 AnalysedType::F32(_) if num >= f32::MIN as i64 && num <= f32::MAX as i64 => {
203 Some((num as f32).into_value_and_type())
204 }
205 AnalysedType::F64(_) if num >= f64::MIN as i64 && num <= f64::MAX as i64 => {
206 Some((num as f64).into_value_and_type())
207 }
208
209 _ => None,
210 }
211 }
212
213 CoercedNumericValue::Float(number) => {
214 let num = *number;
215
216 match analysed_type {
217 AnalysedType::F64(_) => Some(num.into_value_and_type()),
218
219 AnalysedType::F32(_)
220 if num.is_finite() && num >= f32::MIN as f64 && num <= f32::MAX as f64 =>
221 {
222 Some((num as f32).into_value_and_type())
223 }
224
225 AnalysedType::U64(_)
226 if num.is_finite()
227 && num >= 0.0
228 && num <= u64::MAX as f64
229 && num.fract() == 0.0 =>
230 {
231 Some((num as u64).into_value_and_type())
232 }
233
234 AnalysedType::S64(_)
235 if num.is_finite()
236 && num >= i64::MIN as f64
237 && num <= i64::MAX as f64
238 && num.fract() == 0.0 =>
239 {
240 Some((num as i64).into_value_and_type())
241 }
242
243 _ => None,
244 }
245 }
246 }
247 }
248}
249
250macro_rules! impl_ops {
251 ($trait:ident, $method:ident, $checked_method:ident) => {
252 impl std::ops::$trait for CoercedNumericValue {
253 type Output = Result<Self, String>;
254
255 fn $method(self, rhs: Self) -> Self::Output {
256 use CoercedNumericValue::*;
257 Ok(match (self, rhs) {
258 (Float(a), Float(b)) => Float(a.$method(b)),
259 (Float(a), PosInt(b)) => Float(a.$method(b as f64)),
260 (Float(a), NegInt(b)) => Float(a.$method(b as f64)),
261 (PosInt(a), Float(b)) => Float((a as f64).$method(b)),
262 (NegInt(a), Float(b)) => Float((a as f64).$method(b)),
263 (PosInt(a), PosInt(b)) => a.$checked_method(b).map(PosInt).ok_or(format!(
264 "overflow in unsigned operation between {} and {}",
265 a, b
266 ))?,
267 (NegInt(a), NegInt(b)) => a.$checked_method(b).map(NegInt).ok_or(format!(
268 "overflow in signed operation between {} and {}",
269 a, b
270 ))?,
271 (PosInt(a), NegInt(b)) => (a as i64).$checked_method(b).map(NegInt).ok_or(
272 format!("overflow in signed operation between {} and {}", a, b),
273 )?,
274 (NegInt(a), PosInt(b)) => a.$checked_method(b as i64).map(NegInt).ok_or(
275 format!("overflow in signed operation between {} and {}", a, b),
276 )?,
277 })
278 }
279 }
280 };
281}
282
283impl_ops!(Add, add, checked_add);
284impl_ops!(Sub, sub, checked_sub);
285impl_ops!(Mul, mul, checked_mul);
286impl_ops!(Div, div, checked_div);
287
288impl PartialOrd for CoercedNumericValue {
291 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
292 use CoercedNumericValue::*;
293 match (self, other) {
294 (PosInt(a), PosInt(b)) => a.partial_cmp(b),
295 (NegInt(a), NegInt(b)) => a.partial_cmp(b),
296 (Float(a), Float(b)) => a.partial_cmp(b),
297
298 (PosInt(a), NegInt(b)) => {
299 if let Ok(b_as_u64) = u64::try_from(*b) {
300 a.partial_cmp(&b_as_u64)
301 } else {
302 Some(Ordering::Greater) }
304 }
305
306 (NegInt(a), PosInt(b)) => {
307 if let Ok(a_as_u64) = u64::try_from(*a) {
308 a_as_u64.partial_cmp(b)
309 } else {
310 Some(Ordering::Less) }
312 }
313
314 (PosInt(a), Float(b)) => (*a as f64).partial_cmp(b),
315
316 (Float(a), PosInt(b)) => a.partial_cmp(&(*b as f64)),
317
318 (NegInt(a), Float(b)) => (*a as f64).partial_cmp(b),
319
320 (Float(a), NegInt(b)) => a.partial_cmp(&(*b as f64)),
321 }
322 }
323}
324
325impl PartialEq for CoercedNumericValue {
329 fn eq(&self, other: &Self) -> bool {
330 use CoercedNumericValue::*;
331 match (self, other) {
332 (PosInt(a), PosInt(b)) => a == b,
333 (NegInt(a), NegInt(b)) => a == b,
334 (Float(a), Float(b)) => a == b,
335
336 (PosInt(a), NegInt(b)) => {
338 if let Ok(b_as_u64) = u64::try_from(*b) {
339 a == &b_as_u64
340 } else {
341 false
342 }
343 }
344
345 (NegInt(a), PosInt(b)) => {
347 if let Ok(a_as_u64) = u64::try_from(*a) {
348 &a_as_u64 == b
349 } else {
350 false
351 }
352 }
353
354 (PosInt(a), Float(b)) => (*a as f64) == *b,
356
357 (Float(a), PosInt(b)) => *a == (*b as f64),
359
360 (NegInt(a), Float(b)) => (*a as f64) == *b,
362
363 (Float(a), NegInt(b)) => *a == (*b as f64),
365 }
366 }
367}
368
369impl Display for CoercedNumericValue {
370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371 match self {
372 CoercedNumericValue::PosInt(value) => write!(f, "{value}"),
373 CoercedNumericValue::NegInt(value) => write!(f, "{value}"),
374 CoercedNumericValue::Float(value) => write!(f, "{value}"),
375 }
376 }
377}
378
379impl Display for LiteralValue {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381 match self {
382 LiteralValue::Num(number) => write!(f, "{number}"),
383 LiteralValue::String(value) => write!(f, "{value}"),
384 LiteralValue::Bool(value) => write!(f, "{value}"),
385 }
386 }
387}
388
389mod internal {
390 use crate::interpreter::literal::CoercedNumericValue;
391 use golem_wasm_rpc::{Value, ValueAndType};
392
393 pub(crate) fn get_numeric_value(value_and_type: &ValueAndType) -> Option<CoercedNumericValue> {
394 match &value_and_type.value {
395 Value::S8(value) => Some(CoercedNumericValue::NegInt(*value as i64)),
396 Value::S16(value) => Some(CoercedNumericValue::NegInt(*value as i64)),
397 Value::S32(value) => Some(CoercedNumericValue::NegInt(*value as i64)),
398 Value::S64(value) => Some(CoercedNumericValue::NegInt(*value)),
399 Value::U8(value) => Some(CoercedNumericValue::PosInt(*value as u64)),
400 Value::U16(value) => Some(CoercedNumericValue::PosInt(*value as u64)),
401 Value::U32(value) => Some(CoercedNumericValue::PosInt(*value as u64)),
402 Value::U64(value) => Some(CoercedNumericValue::PosInt(*value)),
403 Value::F32(value) => Some(CoercedNumericValue::Float(*value as f64)),
404 Value::F64(value) => Some(CoercedNumericValue::Float(*value)),
405 _ => None,
406 }
407 }
408}