roan_engine/value/
mod.rs

1use crate::{
2    entries,
3    module::StoredStruct,
4    value::methods::{
5        char::{
6            __char_escape_default, __char_escape_unicode, __char_from_digit, __char_is_alphabetic,
7            __char_is_alphanumeric, __char_is_ascii, __char_is_ascii_alphabetic,
8            __char_is_ascii_alphanumeric, __char_is_ascii_control, __char_is_ascii_digit,
9            __char_is_ascii_graphic, __char_is_ascii_lowercase, __char_is_ascii_punctuation,
10            __char_is_ascii_uppercase, __char_is_ascii_whitespace, __char_is_control,
11            __char_is_digit, __char_is_digit_in_base, __char_is_lowercase, __char_is_numeric,
12            __char_is_uppercase, __char_is_whitespace, __char_len_utf8, __char_to_ascii_lowercase,
13            __char_to_ascii_uppercase, __char_to_int, __char_to_lowercase, __char_to_string,
14            __char_to_uppercase,
15        },
16        string::{
17            __string_char_at, __string_char_code_at, __string_chars, __string_contains,
18            __string_ends_with, __string_index_of, __string_last_index_of, __string_len,
19            __string_replace, __string_reverse, __string_slice, __string_split,
20            __string_starts_with, __string_to_lowercase, __string_to_uppercase, __string_trim,
21            __string_trim_end, __string_trim_start,
22        },
23        vec::{__vec_len, __vec_next},
24    },
25    vm::native_fn::NativeFunction,
26};
27use anyhow::Result;
28use indexmap::IndexMap;
29use roan_ast::{Literal, LiteralType};
30use roan_error::{error::RoanError::TypeMismatch, TextSpan};
31use std::{
32    collections::HashMap,
33    fmt::{Debug, Display},
34    ops,
35};
36
37pub mod methods {
38    pub mod char;
39    pub mod string;
40    pub mod vec;
41}
42
43#[derive(Clone)]
44pub enum Value {
45    Int(i64),
46    Float(f64),
47    Bool(bool),
48    Char(char),
49    String(String),
50    Vec(Vec<Value>),
51    Struct(StoredStruct, HashMap<String, Value>),
52    Object(IndexMap<String, Value>),
53    Null,
54    Void,
55}
56
57impl Value {
58    pub fn builtin_methods(&self) -> HashMap<String, NativeFunction> {
59        match self {
60            Value::Vec(_) => {
61                entries!(
62                    "len" => __vec_len(),
63                    "next" => __vec_next()
64                )
65            }
66            Value::String(_) => {
67                entries!(
68                    "len" => __string_len(),
69                    "split" => __string_split(),
70                    "chars" => __string_chars(),
71                    "contains" => __string_contains(),
72                    "starts_with" => __string_starts_with(),
73                    "ends_with" => __string_ends_with(),
74                    "replace" => __string_replace(),
75                    "trim" => __string_trim(),
76                    "trim_start" => __string_trim_start(),
77                    "trim_end" => __string_trim_end(),
78                    "to_uppercase" => __string_to_uppercase(),
79                    "to_lowercase" => __string_to_lowercase(),
80                    "reverse" => __string_reverse(),
81                    "char_at" => __string_char_at(),
82                    "char_code_at" => __string_char_code_at(),
83                    "slice" => __string_slice(),
84                    "index_of" => __string_index_of(),
85                    "last_index_of" => __string_last_index_of()
86                )
87            }
88            Value::Char(_) => {
89                entries!(
90                    "is_alphabetic" => __char_is_alphabetic(),
91                    "is_alphanumeric" => __char_is_alphanumeric(),
92                    "is_ascii" => __char_is_ascii(),
93                    "is_ascii_alphabetic" => __char_is_ascii_alphabetic(),
94                    "is_ascii_alphanumeric" => __char_is_ascii_alphanumeric(),
95                    "is_ascii_control" => __char_is_ascii_control(),
96                    "is_ascii_digit" => __char_is_ascii_digit(),
97                    "is_ascii_graphic" => __char_is_ascii_graphic(),
98                    "is_ascii_lowercase" => __char_is_ascii_lowercase(),
99                    "is_ascii_punctuation" => __char_is_ascii_punctuation(),
100                    "is_ascii_uppercase" => __char_is_ascii_uppercase(),
101                    "is_ascii_whitespace" => __char_is_ascii_whitespace(),
102                    "is_control" => __char_is_control(),
103                    "is_digit" => __char_is_digit(),
104                    "is_lowercase" => __char_is_lowercase(),
105                    "is_numeric" => __char_is_numeric(),
106                    "is_uppercase" => __char_is_uppercase(),
107                    "is_whitespace" => __char_is_whitespace(),
108                    "to_ascii_lowercase" => __char_to_ascii_lowercase(),
109                    "to_ascii_uppercase" => __char_to_ascii_uppercase(),
110                    "to_lowercase" => __char_to_lowercase(),
111                    "to_uppercase" => __char_to_uppercase(),
112                    "is_digit_in_base" => __char_is_digit_in_base(),
113                    "escape_default" => __char_escape_default(),
114                    "escape_unicode" => __char_escape_unicode(),
115                    "from_digit" => __char_from_digit(),
116                    "len_utf8" => __char_len_utf8(),
117                    "to_string" => __char_to_string(),
118                    "to_int" => __char_to_int()
119                )
120            }
121            _ => HashMap::new(),
122        }
123    }
124}
125
126impl Value {
127    pub fn from_literal(literal: Literal) -> Self {
128        match literal.value {
129            LiteralType::Int(i) => Value::Int(i),
130            LiteralType::Float(f) => Value::Float(f),
131            LiteralType::Bool(b) => Value::Bool(b),
132            LiteralType::String(s) => Value::String(s.clone()),
133            LiteralType::Null => Value::Null,
134            LiteralType::Char(c) => Value::Char(c),
135        }
136    }
137}
138
139impl ops::Add for Value {
140    type Output = Self;
141
142    fn add(self, other: Self) -> Self {
143        match (self.clone(), other.clone()) {
144            (Value::Int(a), Value::Int(b)) => Value::Int(a + b),
145            (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
146            (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 + b),
147            (Value::Float(a), Value::Int(b)) => Value::Float(a + b as f64),
148            (Value::String(a), Value::String(b)) => Value::String(a + &b),
149            (Value::Char(a), Value::Char(b)) => Value::String(format!("{}{}", a, b)),
150            (Value::Char(a), Value::String(b)) => Value::String(format!("{}{}", a, b)),
151            (Value::String(a), Value::Char(b)) => Value::String(format!("{}{}", a, b)),
152            _ => panic!(
153                "Cannot add values of different types: {:?} and {:?}",
154                self, other
155            ),
156        }
157    }
158}
159
160impl Debug for Value {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        match self {
163            Value::Int(i) => write!(f, "Int({})", i),
164            Value::Float(fl) => write!(f, "Float({})", fl),
165            Value::Bool(b) => write!(f, "Bool({})", b),
166            Value::String(s) => write!(f, "String({})", s),
167            Value::Vec(v) => write!(f, "Vec({:?})", v),
168            Value::Null => write!(f, "Null"),
169            Value::Void => write!(f, "Void"),
170            Value::Struct(struct_def, fields) => {
171                write!(f, "Struct({} with fields: ", struct_def.name.literal())?;
172                for (name, val) in fields {
173                    write!(f, "{}: {:?}, ", name, val)?;
174                }
175                write!(f, ")")
176            }
177            Value::Char(c) => write!(f, "Char({})", c),
178            Value::Object(fields) => {
179                write!(f, "{:#?}", fields)
180            }
181        }
182    }
183}
184
185impl Display for Value {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        match self {
188            Value::Int(i) => write!(f, "{}", i),
189            Value::Float(fl) => write!(f, "{}", fl),
190            Value::Bool(b) => write!(f, "{}", b),
191            Value::String(s) => write!(f, "{}", s),
192            Value::Vec(v) => {
193                write!(f, "[")?;
194                for (i, val) in v.iter().enumerate() {
195                    write!(f, "{}", val)?;
196                    if i < v.len() - 1 {
197                        write!(f, ", ")?;
198                    }
199                }
200                write!(f, "]")
201            }
202            Value::Null => write!(f, "null"),
203            Value::Void => write!(f, "void"),
204            Value::Struct(st, fields) => {
205                let def = st.clone();
206
207                write!(f, "{} {{", def.name.literal())?;
208                for (i, (name, val)) in fields.iter().enumerate() {
209                    write!(f, "{}: {}", name, val)?;
210                    if i < fields.len() - 1 {
211                        write!(f, ", ")?;
212                    }
213                }
214                write!(f, "}}")
215            }
216            Value::Char(c) => write!(f, "{}", c),
217            Value::Object(fields) => {
218                write!(f, "{{")?;
219                for (i, (name, val)) in fields.iter().enumerate() {
220                    write!(f, "{}: {}", name, val)?;
221                    if i < fields.len() - 1 {
222                        write!(f, ", ")?;
223                    }
224                }
225                write!(f, "}}")
226            }
227        }
228    }
229}
230
231impl ops::Sub for Value {
232    type Output = Self;
233
234    fn sub(self, other: Self) -> Self {
235        match (self, other) {
236            (Value::Int(a), Value::Int(b)) => Value::Int(a - b),
237            (Value::Float(a), Value::Float(b)) => Value::Float(a - b),
238            (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 - b),
239            (Value::Float(a), Value::Int(b)) => Value::Float(a - b as f64),
240            _ => panic!("Cannot subtract values of different types"),
241        }
242    }
243}
244
245impl ops::Mul for Value {
246    type Output = Self;
247
248    fn mul(self, other: Self) -> Self {
249        match (self, other) {
250            (Value::Int(a), Value::Int(b)) => Value::Int(a * b),
251            (Value::Float(a), Value::Float(b)) => Value::Float(a * b),
252            (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 * b),
253            (Value::Float(a), Value::Int(b)) => Value::Float(a * b as f64),
254            _ => panic!("Cannot multiply values of different types"),
255        }
256    }
257}
258
259impl ops::Div for Value {
260    type Output = Self;
261
262    fn div(self, other: Self) -> Self {
263        match (self, other) {
264            (Value::Int(a), Value::Int(b)) => Value::Int(a / b),
265            (Value::Float(a), Value::Float(b)) => Value::Float(a / b),
266            (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 / b),
267            (Value::Float(a), Value::Int(b)) => Value::Float(a / b as f64),
268            _ => panic!("Cannot divide values of different types"),
269        }
270    }
271}
272
273impl ops::Rem for Value {
274    type Output = Self;
275
276    fn rem(self, other: Self) -> Self {
277        match (self, other) {
278            (Value::Int(a), Value::Int(b)) => Value::Int(a % b),
279            (Value::Float(a), Value::Float(b)) => Value::Float(a % b),
280            (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 % b),
281            (Value::Float(a), Value::Int(b)) => Value::Float(a % b as f64),
282            _ => panic!("Cannot modulo values of different types"),
283        }
284    }
285}
286
287impl PartialEq for Value {
288    fn eq(&self, other: &Self) -> bool {
289        match (self, other) {
290            (Value::Int(a), Value::Int(b)) => a == b,
291            (Value::Float(a), Value::Float(b)) => a == b,
292            (Value::Bool(a), Value::Bool(b)) => a == b,
293            (Value::String(a), Value::String(b)) => a == b,
294            (Value::Vec(a), Value::Vec(b)) => {
295                if a.len() != b.len() {
296                    return false;
297                }
298                for (a, b) in a.iter().zip(b.iter()) {
299                    if a != b {
300                        return false;
301                    }
302                }
303                true
304            }
305            (Value::Null, Value::Null) => true,
306            (Value::Void, Value::Void) => true,
307            (Value::Char(a), Value::Char(b)) => a == b,
308            (Value::Char(a), Value::String(b)) => a.to_string() == *b,
309            (Value::String(a), Value::Char(b)) => a == &b.to_string(),
310            _ => false,
311        }
312    }
313}
314
315impl Eq for Value {}
316
317impl PartialOrd for Value {
318    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
319        match (self, other) {
320            (Value::Int(a), Value::Int(b)) => a.partial_cmp(b),
321            (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
322            (Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
323            (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
324            _ => None,
325        }
326    }
327}
328
329impl Value {
330    pub fn pow(self, other: Self) -> Self {
331        match (self, other) {
332            (Value::Int(a), Value::Int(b)) => Value::Int(a.pow(b as u32)),
333            (Value::Float(a), Value::Float(b)) => Value::Float(a.powf(b)),
334            (Value::Int(a), Value::Float(b)) => Value::Float((a as f64).powf(b)),
335            (Value::Float(a), Value::Int(b)) => Value::Float(a.powf(b as f64)),
336            _ => panic!("Cannot apply power operator on values of different or unsupported types"),
337        }
338    }
339}
340
341impl Value {
342    pub fn access_index(&self, index: Self) -> Self {
343        match self {
344            Value::Vec(v) => match index {
345                Value::Int(i) => v.get(i as usize).cloned().unwrap_or(Value::Null),
346                _ => Value::Null,
347            },
348            Value::String(s) => match index {
349                Value::Int(i) => {
350                    if i < 0 {
351                        Value::Null
352                    } else {
353                        s.chars()
354                            .nth(i as usize)
355                            .map(Value::Char)
356                            .unwrap_or(Value::Null)
357                    }
358                }
359                _ => Value::Null,
360            },
361            Value::Object(fields) => match index {
362                Value::String(key) => fields.get(&key).cloned().unwrap_or(Value::Null),
363                _ => Value::Null,
364            },
365            // TODO: proper error handling
366            _ => panic!("Cannot access index of non-indexable value"),
367        }
368    }
369}
370
371impl Value {
372    pub fn is_array(&self) -> bool {
373        matches!(self, Value::Vec(_))
374    }
375
376    pub fn is_bool(&self) -> bool {
377        matches!(self, Value::Bool(_))
378    }
379
380    pub fn is_float(&self) -> bool {
381        matches!(self, Value::Float(_))
382    }
383
384    pub fn is_int(&self) -> bool {
385        matches!(self, Value::Int(_))
386    }
387
388    pub fn is_null(&self) -> bool {
389        matches!(self, Value::Null)
390    }
391
392    pub fn is_string(&self) -> bool {
393        matches!(self, Value::String(_))
394    }
395
396    pub fn is_struct(&self) -> bool {
397        matches!(self, Value::Struct(_, _))
398    }
399
400    pub fn is_void(&self) -> bool {
401        matches!(self, Value::Void)
402    }
403}
404
405impl Value {
406    pub fn check_type(&self, expected_type: &str, span: TextSpan) -> Result<()> {
407        if self.is_type(expected_type) {
408            Ok(())
409        } else {
410            Err(TypeMismatch(
411                format!(
412                    "Expected type {} but got {}",
413                    expected_type,
414                    self.type_name()
415                ),
416                span,
417            )
418            .into())
419        }
420    }
421
422    pub fn is_type(&self, type_name: &str) -> bool {
423        match type_name {
424            "int" => self.is_int(),
425            "float" => self.is_float(),
426            "bool" => self.is_bool(),
427            "string" => self.is_string(),
428            "null" => self.is_null(),
429            "void" => self.is_void(),
430            _ => false,
431        }
432    }
433
434    pub fn type_name(&self) -> String {
435        match self {
436            Value::Int(_) => "int".to_string(),
437            Value::Float(_) => "float".to_string(),
438            Value::Bool(_) => "bool".to_string(),
439            Value::String(_) => "string".to_string(),
440            // Type of vector is based on the type of its first element
441            Value::Vec(vals) => {
442                if vals.is_empty() {
443                    "void[]".to_string()
444                } else {
445                    format!("{}[]", vals[0].type_name())
446                }
447            }
448            Value::Struct(struct_def, _) => struct_def.name.literal(),
449            Value::Null => "null".to_string(),
450            Value::Void => "void".to_string(),
451            Value::Char(_) => "char".to_string(),
452            Value::Object(_) => "object".to_string(),
453        }
454    }
455}
456
457impl Value {
458    pub fn is_truthy(&self) -> bool {
459        match self {
460            Value::Int(i) => *i != 0,
461            Value::Float(f) => *f != 0.0,
462            Value::Bool(b) => *b,
463            Value::String(s) => !s.is_empty(),
464            Value::Vec(v) => !v.is_empty(),
465            Value::Null => false,
466            Value::Void => false,
467            Value::Struct(_, _) => true,
468            Value::Char(_) => true,
469            Value::Object(_) => true,
470        }
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use super::*;
477
478    #[test]
479    fn test_value_add() {
480        assert_eq!(Value::Int(1) + Value::Int(2), Value::Int(3));
481        assert_eq!(Value::Float(1.0) + Value::Float(2.0), Value::Float(3.0));
482        assert_eq!(Value::Int(1) + Value::Float(2.0), Value::Float(3.0));
483        assert_eq!(Value::Float(1.0) + Value::Int(2), Value::Float(3.0));
484        assert_eq!(
485            Value::String("Hello".to_string()) + Value::String("World".to_string()),
486            Value::String("HelloWorld".to_string())
487        );
488    }
489
490    #[test]
491    fn test_value_sub() {
492        assert_eq!(Value::Int(1) - Value::Int(2), Value::Int(-1));
493        assert_eq!(Value::Float(1.0) - Value::Float(2.0), Value::Float(-1.0));
494        assert_eq!(Value::Int(1) - Value::Float(2.0), Value::Float(-1.0));
495        assert_eq!(Value::Float(1.0) - Value::Int(2), Value::Float(-1.0));
496    }
497
498    #[test]
499    fn test_value_mul() {
500        assert_eq!(Value::Int(1) * Value::Int(2), Value::Int(2));
501        assert_eq!(Value::Float(1.0) * Value::Float(2.0), Value::Float(2.0));
502        assert_eq!(Value::Int(1) * Value::Float(2.0), Value::Float(2.0));
503        assert_eq!(Value::Float(1.0) * Value::Int(2), Value::Float(2.0));
504    }
505
506    #[test]
507    fn test_value_div() {
508        assert_eq!(Value::Int(1) / Value::Int(2), Value::Int(0));
509        assert_eq!(Value::Float(1.0) / Value::Float(2.0), Value::Float(0.5));
510        assert_eq!(Value::Int(1) / Value::Float(2.0), Value::Float(0.5));
511        assert_eq!(Value::Float(5.5) / Value::Int(2), Value::Float(2.75));
512    }
513
514    #[test]
515    fn test_value_rem() {
516        assert_eq!(Value::Int(1) % Value::Int(2), Value::Int(1));
517        assert_eq!(Value::Float(1.0) % Value::Float(2.0), Value::Float(1.0));
518        assert_eq!(Value::Int(1) % Value::Float(2.0), Value::Float(1.0));
519        assert_eq!(Value::Float(5.5) % Value::Int(2), Value::Float(1.5));
520    }
521
522    #[test]
523    fn test_value_pow() {
524        assert_eq!(Value::Int(2).pow(Value::Int(3)), Value::Int(8));
525        assert_eq!(Value::Float(2.0).pow(Value::Float(3.0)), Value::Float(8.0));
526        assert_eq!(Value::Int(2).pow(Value::Float(3.0)), Value::Float(8.0));
527        assert_eq!(Value::Float(2.0).pow(Value::Int(3)), Value::Float(8.0));
528    }
529
530    #[test]
531    fn test_value_access_index() {
532        assert_eq!(
533            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
534                .access_index(Value::Int(1)),
535            Value::Int(2)
536        );
537        assert_eq!(
538            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
539                .access_index(Value::Int(3)),
540            Value::Null
541        );
542        assert_eq!(
543            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
544                .access_index(Value::Float(1.0)),
545            Value::Null
546        );
547    }
548
549    #[test]
550    fn test_value_eq() {
551        assert_eq!(Value::Int(1), Value::Int(1));
552        assert_eq!(Value::Float(1.0), Value::Float(1.0));
553        assert_eq!(Value::Bool(true), Value::Bool(true));
554        assert_eq!(
555            Value::String("Hello".to_string()),
556            Value::String("Hello".to_string())
557        );
558        assert_eq!(
559            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)]),
560            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
561        );
562        assert_eq!(Value::Null, Value::Null);
563        assert_eq!(Value::Void, Value::Void);
564    }
565
566    #[test]
567    fn test_value_partial_cmp() {
568        assert_eq!(
569            Value::Int(1).partial_cmp(&Value::Int(2)),
570            Some(std::cmp::Ordering::Less)
571        );
572        assert_eq!(
573            Value::Float(1.0).partial_cmp(&Value::Float(2.0)),
574            Some(std::cmp::Ordering::Less)
575        );
576        assert_eq!(
577            Value::Int(1).partial_cmp(&Value::Float(2.0)),
578            Some(std::cmp::Ordering::Less)
579        );
580        assert_eq!(
581            Value::Float(1.0).partial_cmp(&Value::Int(2)),
582            Some(std::cmp::Ordering::Less)
583        );
584    }
585
586    #[test]
587    fn test_value_display() {
588        assert_eq!(format!("{}", Value::Int(1)), "1");
589        assert_eq!(format!("{}", Value::Float(1.0)), "1");
590        assert_eq!(format!("{}", Value::Bool(true)), "true");
591        assert_eq!(format!("{}", Value::String("Hello".to_string())), "Hello");
592        assert_eq!(
593            format!(
594                "{}",
595                Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
596            ),
597            "[1, 2, 3]"
598        );
599        assert_eq!(format!("{}", Value::Null), "null");
600        assert_eq!(format!("{}", Value::Void), "void");
601    }
602
603    #[test]
604    fn test_value_type_name() {
605        assert_eq!(Value::Int(1).type_name(), "int");
606        assert_eq!(Value::Float(1.0).type_name(), "float");
607        assert_eq!(Value::Bool(true).type_name(), "bool");
608        assert_eq!(Value::String("Hello".to_string()).type_name(), "string");
609        assert_eq!(
610            Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)]).type_name(),
611            "int[]"
612        );
613        assert_eq!(Value::Null.type_name(), "null");
614        assert_eq!(Value::Void.type_name(), "void");
615    }
616
617    #[test]
618    fn test_value_is_type() {
619        assert!(Value::Int(1).is_type("int"));
620        assert!(Value::Float(1.0).is_type("float"));
621        assert!(Value::Bool(true).is_type("bool"));
622        assert!(Value::String("Hello".to_string()).is_type("string"));
623        // We check it outside the is_type method
624        // assert!(
625        //     Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)]).is_type("int[]")
626        // );
627        assert!(Value::Null.is_type("null"));
628        assert!(Value::Void.is_type("void"));
629    }
630
631    #[test]
632    fn test_value_is_array() {
633        assert!(Value::Vec(vec![Value::Int(1), Value::Int(2), Value::Int(3)]).is_array());
634        assert!(!Value::Int(1).is_array());
635    }
636
637    #[test]
638    fn test_value_is_bool() {
639        assert!(Value::Bool(true).is_bool());
640        assert!(!Value::Int(1).is_bool());
641    }
642
643    #[test]
644    fn test_value_is_float() {
645        assert!(Value::Float(1.0).is_float());
646        assert!(!Value::Int(1).is_float());
647    }
648
649    #[test]
650    fn test_value_is_int() {
651        assert!(Value::Int(1).is_int());
652        assert!(!Value::Float(1.0).is_int());
653    }
654
655    #[test]
656    fn test_value_is_null() {
657        assert!(Value::Null.is_null());
658        assert!(!Value::Int(1).is_null());
659    }
660
661    #[test]
662    fn test_value_is_string() {
663        assert!(Value::String("Hello".to_string()).is_string());
664        assert!(!Value::Int(1).is_string());
665    }
666}