slvm/
value.rs

1use crate::vm::GVm;
2use crate::{FxHasher, Handle, Heap, Interned, VMError, VMResult, float};
3use bridge_types::BridgedType;
4use std::collections::{BTreeSet, HashMap};
5use std::fmt;
6use std::fmt::{Display, Formatter};
7use std::hash::{Hash, Hasher};
8use std::iter;
9use std::ops::Deref;
10use std::sync::Arc;
11
12pub type CallFuncSig<ENV> = fn(vm: &mut GVm<ENV>, registers: &[Value]) -> VMResult<Value>;
13#[derive(Copy, Clone)]
14pub struct CallFunc<ENV> {
15    pub func: CallFuncSig<ENV>,
16}
17
18impl<ENV> PartialEq for CallFunc<ENV> {
19    fn eq(&self, other: &CallFunc<ENV>) -> bool {
20        std::ptr::eq(
21            self.func as *const CallFuncSig<ENV>,
22            other.func as *const CallFuncSig<ENV>,
23        )
24    }
25}
26
27impl<ENV> Eq for CallFunc<ENV> {}
28
29impl<ENV> Hash for CallFunc<ENV> {
30    fn hash<H: Hasher>(&self, state: &mut H) {
31        state.write_usize(self.func as usize);
32    }
33}
34
35impl<ENV> fmt::Debug for CallFunc<ENV> {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "...")
38    }
39}
40
41pub struct PairIter<'vm, ENV> {
42    vm: &'vm GVm<ENV>,
43    current: Option<Value>,
44    dotted: bool,
45}
46
47impl<'vm, ENV> PairIter<'vm, ENV> {
48    pub fn new(vm: &'vm GVm<ENV>, exp: Value) -> Self {
49        Self {
50            vm,
51            current: Some(exp),
52            dotted: false,
53        }
54    }
55
56    pub fn is_dotted(&self) -> bool {
57        self.dotted
58    }
59}
60
61impl<ENV> Iterator for PairIter<'_, ENV> {
62    type Item = Value;
63
64    fn next(&mut self) -> Option<Self::Item> {
65        if let Some(current) = self.current {
66            match current {
67                Value::Pair(h) => {
68                    let (car, cdr) = self.vm.get_pair(h);
69                    self.current = Some(cdr);
70                    Some(car)
71                }
72                // TODO: Handle List?
73                Value::Nil => None,
74                _ => {
75                    let cur = Some(current);
76                    self.current = None;
77                    self.dotted = true;
78                    cur
79                }
80            }
81        } else {
82            None
83        }
84    }
85}
86
87pub const INT_BITS: u8 = 56;
88pub const INT_MAX: i64 = 2_i64.pow(INT_BITS as u32 - 1) - 1;
89pub const INT_MIN: i64 = -(2_i64.pow(INT_BITS as u32 - 1));
90
91#[derive(Copy, Clone)]
92pub struct I56(pub [u8; 7]);
93
94impl I56 {
95    pub fn max() -> i64 {
96        INT_MAX
97    }
98
99    pub fn max_i56() -> Self {
100        I56(Self::into_inner(Self::max()))
101    }
102
103    pub fn min() -> i64 {
104        INT_MIN
105    }
106
107    pub fn min_i56() -> Self {
108        I56(Self::into_inner(Self::min()))
109    }
110
111    /// Take the inner representation of [`Value`]::Int, and turn it into an [`i64`].
112    pub fn from_inner(arr: &[u8; 7]) -> i64 {
113        from_i56(arr)
114    }
115
116    /// Turn an [`i64`] into the inner representation of [`Value`]::Int
117    pub fn into_inner(i: i64) -> [u8; 7] {
118        to_i56_raw(i)
119    }
120
121    pub fn into_i56_fallible(f: f64) -> VMResult<i64> {
122        if !f.is_finite() {
123            Err(VMError::new_conversion(
124                "Can not represent NaN or infinity as int.",
125            ))
126        } else if f > i64::MAX as f64 || f > I56::max() as f64 {
127            Err(VMError::new_conversion(
128                "Can not represent number greater than max i56.",
129            ))
130        } else if f < i64::MIN as f64 || f < I56::min() as f64 {
131            Err(VMError::new_conversion(
132                "Can not represent number less than max i56.",
133            ))
134        } else {
135            Ok(f.round() as i64)
136        }
137    }
138
139    pub fn from_byte(byte: u8) -> Self {
140        Self(Self::into_inner(byte as i64))
141    }
142}
143
144pub fn from_i56(arr: &[u8; 7]) -> i64 {
145    let mut bytes = [0x00, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6]];
146    if (arr[0] & 0x80) > 0 {
147        bytes[0] = 0xff;
148        i64::from_be_bytes(bytes)
149    } else {
150        i64::from_be_bytes(bytes)
151    }
152}
153
154pub fn to_i56_raw(i: i64) -> [u8; 7] {
155    let bytes = i.to_be_bytes();
156    [
157        bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
158    ]
159}
160
161pub fn to_i56(i: i64) -> Value {
162    Value::Int(to_i56_raw(i))
163}
164
165#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
166pub enum Value {
167    Byte(u8),
168    /// Store a 7 byte int (i56...).
169    Int([u8; 7]),
170    /// Replace with float::F32Wrap if desired
171    Float(float::F56),
172    CodePoint(char),
173    CharCluster(u8, [u8; 6]),
174    /// Handle points to a String on the heap.
175    CharClusterLong(Handle),
176    Symbol(Interned),
177    Keyword(Interned),
178    StringConst(Interned),
179    /// Intended for symbols that are compiled.
180    Special(Interned),
181    Builtin(u32),
182    True,
183    False,
184    Nil,
185    /// Value is a placeholder only, should never appear at runtime. Can be
186    /// instantiated at times as a placeholder but should always be overwritten.
187    Undefined,
188    String(Handle),
189    Vector(Handle),
190    Map(Handle),
191    Bytes(Handle),
192    Pair(Handle),
193    List(Handle, u16),
194    Lambda(Handle),
195    Closure(Handle),
196    Continuation(Handle),
197    CallFrame(Handle),
198    Value(Handle),
199    Error(Handle),
200    Io(Handle),
201}
202
203impl Default for Value {
204    fn default() -> Self {
205        Self::new()
206    }
207}
208
209impl From<f32> for Value {
210    fn from(value: f32) -> Self {
211        Self::Float(value.into())
212    }
213}
214
215impl From<f64> for Value {
216    fn from(value: f64) -> Self {
217        Self::Float(value.into())
218    }
219}
220
221impl From<i64> for Value {
222    fn from(value: i64) -> Self {
223        to_i56(value)
224    }
225}
226
227impl From<i32> for Value {
228    fn from(value: i32) -> Self {
229        to_i56(value as i64)
230    }
231}
232
233impl From<u32> for Value {
234    fn from(value: u32) -> Self {
235        to_i56(value as i64)
236    }
237}
238
239impl BridgedType for Value {}
240impl BridgedType for &Value {}
241impl BridgedType for &mut Value {}
242
243impl Value {
244    pub fn new() -> Self {
245        Value::Undefined
246    }
247
248    #[inline(always)]
249    pub fn unref<ENV>(self, vm: &GVm<ENV>) -> Value {
250        match &self {
251            Value::Value(handle) => vm.get_value(*handle),
252            _ => self,
253        }
254    }
255
256    pub fn get_symbol(&self) -> Option<Interned> {
257        if let Value::Symbol(i) = self {
258            Some(*i)
259        } else {
260            None
261        }
262    }
263
264    pub fn is_symbol(&self, sym: Interned) -> bool {
265        if let Value::Symbol(i) = self {
266            *i == sym
267        } else {
268            false
269        }
270    }
271
272    pub fn is_indirect(&self) -> bool {
273        matches!(self, Value::Value(_))
274    }
275
276    pub fn is_nil(&self) -> bool {
277        matches!(self, Value::Nil)
278    }
279
280    pub fn is_undef(&self) -> bool {
281        matches!(self, Value::Undefined)
282    }
283
284    pub fn is_true(&self) -> bool {
285        matches!(self, Value::True)
286    }
287
288    pub fn is_truthy(&self) -> bool {
289        !matches!(self, Value::False | Value::Nil)
290    }
291
292    pub fn is_false(&self) -> bool {
293        matches!(self, Value::False)
294    }
295
296    pub fn is_falsey(&self) -> bool {
297        matches!(self, Value::False | Value::Nil)
298    }
299
300    pub fn is_int(&self) -> bool {
301        matches!(&self, Value::Byte(_) | Value::Int(_))
302    }
303
304    pub fn is_number(&self) -> bool {
305        matches!(&self, Value::Byte(_) | Value::Int(_) | Value::Float(_))
306    }
307
308    pub fn is_float(&self) -> bool {
309        matches!(self, Value::Float(_))
310    }
311
312    pub fn not(&self) -> Value {
313        match self {
314            Value::False | Value::Nil => Value::True,
315            _ => Value::False,
316        }
317    }
318
319    pub fn get_int<ENV>(&self, vm: &GVm<ENV>) -> VMResult<i64> {
320        match &self {
321            Value::Byte(b) => Ok(*b as i64),
322            Value::Int(i) => Ok(from_i56(i)),
323            _ => Err(VMError::new_value(format!(
324                "Not an integer: {}",
325                self.display_value(vm)
326            ))),
327        }
328    }
329
330    pub fn get_float<ENV>(&self, _vm: &GVm<ENV>) -> VMResult<f64> {
331        match &self {
332            Value::Byte(b) => Ok(*b as f64),
333            Value::Int(i) => Ok(from_i56(i) as f64),
334            Value::Float(f) => Ok(f64::from(*f)),
335            _ => Err(VMError::new_value(format!("Not a float: {self:?}"))),
336        }
337    }
338
339    pub fn get_string<'vm, ENV>(&self, vm: &'vm GVm<ENV>) -> VMResult<&'vm str> {
340        match &self {
341            Value::String(h) => Ok(vm.get_string(*h)),
342            Value::StringConst(i) => Ok(vm.get_interned(*i)),
343            // TODO- handle chars/codepoints...
344            _ => Err(VMError::new_value(format!("Not a string: {self:?}"))),
345        }
346    }
347
348    pub fn get_handle(&self) -> Option<Handle> {
349        match &self {
350            Value::CharClusterLong(handle) => Some(*handle),
351            Value::String(handle) => Some(*handle),
352            Value::Vector(handle) => Some(*handle),
353            Value::Map(handle) => Some(*handle),
354            Value::Bytes(handle) => Some(*handle),
355            Value::Pair(handle) => Some(*handle),
356            Value::List(handle, _) => Some(*handle),
357            Value::Lambda(handle) => Some(*handle),
358            Value::Closure(handle) => Some(*handle),
359            Value::Continuation(handle) => Some(*handle),
360            Value::CallFrame(handle) => Some(*handle),
361            Value::Value(handle) => Some(*handle),
362            Value::Error(handle) => Some(*handle),
363            Value::Io(handle) => Some(*handle),
364
365            Value::Byte(_) => None,
366            Value::Int(_) => None,
367            Value::Float(_) => None,
368            Value::CodePoint(_) => None,
369            Value::CharCluster(_, _) => None,
370            Value::Symbol(_) => None,
371            Value::Keyword(_) => None,
372            Value::Special(_) => None,
373            Value::StringConst(_) => None,
374            Value::Builtin(_) => None,
375            Value::True => None,
376            Value::False => None,
377            Value::Nil => None,
378            Value::Undefined => None,
379        }
380    }
381
382    pub fn get_pair<ENV>(&self, vm: &GVm<ENV>) -> Option<(Value, Value)> {
383        match &self {
384            Value::Pair(handle) => {
385                let (car, cdr) = vm.get_pair(*handle);
386                Some((car, cdr))
387            }
388            Value::List(handle, start_u32) => {
389                let start = *start_u32 as usize;
390                let v = vm.get_vector(*handle);
391                let car = if start < v.len() {
392                    v[start]
393                } else {
394                    Value::Nil
395                };
396                let cdr = if start + 1 < v.len() {
397                    Value::List(*handle, start_u32 + 1)
398                } else {
399                    Value::Nil
400                };
401                Some((car, cdr))
402            }
403            _ => None,
404        }
405    }
406
407    /// Returns an iterator over all values in the list, vector, pair.
408    /// If the item is not one of the above it returns an empty iterator.
409    pub fn iter<'vm, ENV>(&self, vm: &'vm GVm<ENV>) -> Box<dyn Iterator<Item = Value> + 'vm> {
410        match &self.unref(vm) {
411            Value::Pair(_) => Box::new(PairIter::new(vm, *self)),
412            Value::List(handle, start) => {
413                Box::new(vm.get_vector(*handle)[*start as usize..].iter().copied())
414            }
415            Value::Vector(handle) => Box::new(vm.get_vector(*handle).iter().copied()),
416            _ => Box::new(iter::empty()),
417        }
418    }
419
420    /// Returns an iterator over all values in the list, vector, pair.
421    /// Returns an empty iterator if the value is nil.
422    /// If the item is not one of the above it returns a once iter of the value.
423    ///
424    /// Particularly useful  if iterating over a [`Vec<Value>`] that contains a heterogeneous
425    /// mix of List(s), Vector(s), Pair(s), and potentially other values, rather than
426    /// returning an empty list for any non-iterable thing, return a once iter so
427    /// the item is not missed.
428    pub fn iter_all<'vm, ENV>(&self, vm: &'vm GVm<ENV>) -> Box<dyn Iterator<Item = Value> + 'vm> {
429        match &self.unref(vm) {
430            Value::Pair(_) => Box::new(PairIter::new(vm, *self)),
431            Value::List(handle, start) => {
432                Box::new(vm.get_vector(*handle)[*start as usize..].iter().copied())
433            }
434            Value::Vector(handle) => Box::new(vm.get_vector(*handle).iter().copied()),
435            Value::Nil => Box::new(iter::empty()),
436            v => Box::new(iter::once(*v)),
437        }
438    }
439
440    pub fn display_value<ENV>(&self, vm: &GVm<ENV>) -> String {
441        fn list_out_iter<ENV>(
442            vm: &GVm<ENV>,
443            res: &mut String,
444            itr: &mut dyn Iterator<Item = Value>,
445        ) {
446            let mut first = true;
447            for p in itr {
448                if !first {
449                    res.push(' ');
450                } else {
451                    first = false;
452                }
453                res.push_str(&p.display_value(vm));
454            }
455        }
456        fn list_out<ENV>(vm: &GVm<ENV>, res: &mut String, lst: Value) {
457            let mut first = true;
458            let mut cdr = lst;
459            loop {
460                if let Value::Nil = cdr {
461                    break;
462                }
463                if !first {
464                    res.push(' ');
465                } else {
466                    first = false;
467                }
468                match cdr {
469                    Value::Pair(handle) => {
470                        let (car, ncdr) = vm.get_pair(handle);
471                        res.push_str(&car.display_value(vm));
472                        cdr = ncdr;
473                    }
474                    _ => {
475                        res.push_str(". ");
476                        res.push_str(&cdr.display_value(vm));
477                        break;
478                    }
479                }
480            }
481        }
482        match self {
483            Value::True => "true".to_string(),
484            Value::False => "false".to_string(),
485            Value::Int(i) => format!("{}", from_i56(i)),
486            Value::Float(f) => format!("{}", f),
487            Value::Byte(b) => format!("{b}"),
488            Value::Symbol(i) => vm.get_interned(*i).to_string(),
489            Value::Keyword(i) => format!(":{}", vm.get_interned(*i)),
490            Value::StringConst(i) => format!("\"{}\"", vm.get_interned(*i)),
491            Value::Special(i) => format!("#<SpecialFn({})>", vm.get_interned(*i)),
492            Value::CodePoint(ch) => format!("\\{ch}"),
493            Value::CharCluster(l, c) => {
494                format!("\\{}", String::from_utf8_lossy(&c[0..*l as usize]))
495            }
496            Value::CharClusterLong(h) => format!("\\{}", vm.get_string(*h)),
497            Value::Builtin(_) => "#<Function>".to_string(),
498            Value::Nil => "nil".to_string(),
499            Value::Undefined => "#<Undefined>".to_string(), //panic!("Tried to get type for undefined!"),
500            Value::Lambda(_) => "#<Lambda>".to_string(),
501            Value::Closure(_) => "#<Lambda>".to_string(),
502            Value::Continuation(_) => "#<Continuation>".to_string(),
503            Value::CallFrame(_) => "#<CallFrame>".to_string(),
504            Value::Vector(handle) => {
505                let v = vm.get_vector(*handle);
506                let mut res = String::new();
507                res.push('[');
508                list_out_iter(vm, &mut res, &mut v.iter().copied());
509                res.push(']');
510                res
511            }
512            Value::Map(handle) => {
513                let mut res = String::new();
514                res.push('{');
515                for (key, val) in vm.get_map(*handle).iter() {
516                    res.push_str(&format!(
517                        "{} {}\n",
518                        key.display_value(vm),
519                        val.display_value(vm)
520                    ));
521                }
522                res.push('}');
523                res
524            }
525            Value::Pair(_) => {
526                let mut res = String::new();
527                res.push('(');
528                list_out(vm, &mut res, *self);
529                res.push(')');
530                res
531            }
532            Value::List(handle, start) => {
533                let v = vm.get_vector(*handle);
534                let mut res = String::new();
535                res.push('(');
536                list_out_iter(vm, &mut res, &mut v[*start as usize..].iter().copied());
537                res.push(')');
538                res
539            }
540            Value::String(handle) => format!("\"{}\"", vm.get_string(*handle)),
541            Value::Bytes(_) => "Bytes".to_string(), // XXX TODO
542            Value::Value(handle) => vm.get_value(*handle).display_value(vm),
543            Value::Error(handle) => {
544                let err = vm.get_error(*handle);
545                let key = vm.get_interned(err.keyword);
546                format!("error [{key}]: {}", err.data.display_value(vm))
547            }
548            Value::Io(_) => "#<IO>".to_string(),
549        }
550    }
551
552    pub fn pretty_value<ENV>(&self, vm: &GVm<ENV>) -> String {
553        match self {
554            Value::StringConst(i) => vm.get_interned(*i).to_string(),
555            Value::CodePoint(ch) => format!("{ch}"),
556            Value::CharCluster(l, c) => {
557                format!("{}", String::from_utf8_lossy(&c[0..*l as usize]))
558            }
559            Value::CharClusterLong(h) => vm.get_string(*h).to_string(),
560            Value::String(handle) => vm.get_string(*handle).to_string(),
561            _ => self.display_value(vm),
562        }
563    }
564
565    /// Map a [`Value`] to a [`ValueType`] which can be written to a debug string that refers to the
566    /// Slosh types and does not require passing in a [`GVm`] to do so.
567    pub fn value_type<ENV>(&self, vm: &GVm<ENV>) -> ValueType {
568        match self {
569            Value::Byte(_) => ValueType::Byte,
570            Value::Int(_) => ValueType::Int,
571            Value::Float(_) => ValueType::Float,
572            Value::CodePoint(_) => ValueType::CodePoint,
573            Value::CharCluster(_, _) => ValueType::CharCluster,
574            Value::CharClusterLong(_) => ValueType::CharClusterLong,
575            Value::Symbol(_) => ValueType::Symbol,
576            Value::Keyword(_) => ValueType::Keyword,
577            Value::StringConst(_) => ValueType::StringConst,
578            Value::Special(_) => ValueType::Special,
579            Value::Builtin(_) => ValueType::Builtin,
580            Value::True => ValueType::True,
581            Value::False => ValueType::False,
582            Value::Nil => ValueType::Nil,
583            Value::Undefined => ValueType::Undefined,
584            Value::String(_) => ValueType::String,
585            Value::Vector(_) => ValueType::Vector,
586            Value::Map(_) => ValueType::Map,
587            Value::Bytes(_) => ValueType::Bytes,
588            Value::Pair(_) => ValueType::Pair,
589            Value::List(_, _) => ValueType::List,
590            Value::Lambda(_) => ValueType::Lambda,
591            Value::Closure(_) => ValueType::Closure,
592            Value::Continuation(_) => ValueType::Continuation,
593            Value::CallFrame(_) => ValueType::CallFrame,
594            Value::Error(_) => ValueType::Error,
595            Value::Io(_) => ValueType::Io,
596            Value::Value(handle) => vm.get_value(*handle).value_type(vm),
597        }
598    }
599
600    pub fn display_type<ENV>(&self, vm: &GVm<ENV>) -> &'static str {
601        self.value_type(vm).into()
602    }
603
604    pub fn is_proper_list<ENV>(&self, vm: &GVm<ENV>) -> bool {
605        // does not detect empty (nil) lists on purpose.
606        if let Value::Pair(handle) = self {
607            let (_car, cdr) = vm.get_pair(*handle);
608            if cdr.is_nil() {
609                true
610            } else {
611                cdr.is_proper_list(vm)
612            }
613        } else {
614            matches!(self, Value::List(_, _))
615        }
616    }
617
618    /**
619     * Get the hash of a value making sure that strings (whether const or allocated) hash to the same
620     * value.
621     * Note: This use the FxHasher which means it is fast and stable but is not randomized to be
622     * hardened against external key attacks.
623     */
624    pub fn get_hash<ENV>(&self, vm: &GVm<ENV>) -> u64 {
625        let mut hasher = FxHasher::default();
626        match self {
627            Value::StringConst(i) => {
628                let s = vm.get_interned(*i);
629                hasher.write_u8(0xFF);
630                hasher.write(s.as_bytes());
631            }
632            Value::String(h) => {
633                let s = vm.get_string(*h);
634                hasher.write_u8(0xFF);
635                hasher.write(s.as_bytes());
636            }
637
638            Value::Byte(_)
639            | Value::Int(_)
640            | Value::Float(_)
641            | Value::CodePoint(_)
642            | Value::CharCluster(_, _)
643            | Value::CharClusterLong(_)
644            | Value::Symbol(_)
645            | Value::Keyword(_)
646            | Value::Builtin(_)
647            | Value::True
648            | Value::False
649            | Value::Nil
650            | Value::Undefined
651            | Value::Special(_)
652            | Value::Vector(_)
653            | Value::Map(_)
654            | Value::Bytes(_)
655            | Value::Pair(_)
656            | Value::List(_, _)
657            | Value::Lambda(_)
658            | Value::Closure(_)
659            | Value::Continuation(_)
660            | Value::CallFrame(_)
661            | Value::Value(_)
662            | Value::Error(_)
663            | Value::Io(_) => self.hash(&mut hasher),
664        }
665        hasher.finish()
666    }
667}
668
669#[derive(Clone, Debug)]
670pub struct Globals {
671    objects: Vec<Value>,
672    props: HashMap<u32, Arc<HashMap<Interned, Value>>>,
673}
674
675impl Default for Globals {
676    fn default() -> Self {
677        Self::new()
678    }
679}
680
681impl Globals {
682    pub fn new() -> Self {
683        Globals {
684            objects: Vec::new(),
685            props: HashMap::new(),
686        }
687    }
688
689    pub fn reserve(&mut self) -> u32 {
690        let index = self.objects.len();
691        self.objects.push(Value::Undefined);
692        index as u32
693    }
694
695    /// Sets a global to val.  The value needs have local numbers promoted to the heap before
696    /// setting it.
697    pub fn set(&mut self, idx: u32, val: Value) {
698        self.objects[idx as usize] = val;
699    }
700
701    pub fn get(&self, idx: u32) -> Value {
702        self.objects
703            .get(idx as usize)
704            .map_or_else(|| Value::Undefined, |v| *v)
705    }
706
707    pub fn mark(&self, heap: &mut Heap) {
708        self.objects.iter().for_each(|obj| {
709            heap.mark(*obj);
710        });
711        self.props.iter().for_each(|(_, map)| {
712            for val in map.values() {
713                heap.mark(*val);
714            }
715        });
716    }
717
718    pub fn get_property(&self, global: u32, prop: Interned) -> Option<Value> {
719        if let Some(map) = self.props.get(&global) {
720            if let Some(val) = map.get(&prop) {
721                return Some(*val);
722            }
723        }
724        None
725    }
726
727    pub fn set_property(&mut self, global: u32, prop: Interned, value: Value) {
728        if let Some(map) = self.props.get_mut(&global) {
729            let map = Arc::make_mut(map);
730            map.insert(prop, value);
731        } else {
732            let mut map = HashMap::new();
733            map.insert(prop, value);
734            self.props.insert(global, Arc::new(map));
735        }
736    }
737}
738
739pub const SLOSH_CHAR: &str = "Char";
740pub const SLOSH_STRING: &str = "String";
741pub const SLOSH_INT: &str = "Int";
742pub const SLOSH_FLOAT: &str = "Float";
743pub const SLOSH_BOOL_TRUE: &str = "True";
744pub const SLOSH_BOOL_FALSE: &str = "False";
745pub const SLOSH_SYMBOL: &str = "Symbol";
746pub const SLOSH_KEYWORD: &str = "Keyword";
747pub const SLOSH_SPECIAL: &str = "Special";
748pub const SLOSH_BUILTIN: &str = "Builtin";
749pub const SLOSH_BYTE: &str = "Byte";
750pub const SLOSH_BYTES: &str = "Bytes";
751pub const SLOSH_NIL: &str = "Nil";
752pub const SLOSH_UNDEFINED: &str = "Undefined";
753pub const SLOSH_LAMBDA: &str = "Lambda";
754pub const SLOSH_CLOSURE: &str = "Lambda";
755pub const SLOSH_CONTINUATION: &str = "Continuation";
756pub const SLOSH_CALLFRAME: &str = "CallFrame";
757pub const SLOSH_VECTOR: &str = "Vector";
758pub const SLOSH_MAP: &str = "Map";
759pub const SLOSH_PAIR: &str = "Pair";
760pub const SLOSH_ERROR: &str = "Error";
761pub const SLOSH_IO: &str = "Io";
762
763/// Enum representing the various types of values in Slosh.
764#[derive(Copy, Clone, PartialEq, Eq, Hash)]
765pub enum ValueType {
766    Byte,
767    Int,
768    Float,
769    CodePoint,
770    CharCluster,
771    CharClusterLong,
772    Symbol,
773    Keyword,
774    StringConst,
775    Special,
776    Builtin,
777    True,
778    False,
779    Nil,
780    Undefined,
781    String,
782    Vector,
783    Map,
784    Bytes,
785    Pair,
786    List,
787    Lambda,
788    Closure,
789    Continuation,
790    CallFrame,
791    Error,
792    Io,
793}
794
795impl Display for ValueType {
796    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
797        write!(f, "{}", <ValueType as Into<&'static str>>::into(*self))
798    }
799}
800
801impl From<ValueType> for &'static str {
802    fn from(value: ValueType) -> Self {
803        match value {
804            ValueType::True => SLOSH_BOOL_TRUE,
805            ValueType::False => SLOSH_BOOL_FALSE,
806            ValueType::Int => SLOSH_INT,
807            ValueType::Float => SLOSH_FLOAT,
808            ValueType::Symbol => SLOSH_SYMBOL,
809            ValueType::Keyword => SLOSH_KEYWORD,
810            ValueType::StringConst => SLOSH_STRING,
811            ValueType::Special => SLOSH_SPECIAL,
812            ValueType::CodePoint => SLOSH_CHAR,
813            ValueType::CharCluster => SLOSH_CHAR,
814            ValueType::CharClusterLong => SLOSH_CHAR,
815            ValueType::Builtin => SLOSH_BUILTIN,
816            ValueType::Byte => SLOSH_BYTE,
817            ValueType::Bytes => SLOSH_BYTES,
818            ValueType::Nil => SLOSH_NIL,
819            ValueType::Undefined => SLOSH_UNDEFINED,
820            ValueType::Lambda => SLOSH_LAMBDA,
821            ValueType::Closure => SLOSH_LAMBDA,
822            ValueType::Continuation => SLOSH_CONTINUATION,
823            ValueType::CallFrame => SLOSH_CALLFRAME,
824            ValueType::Vector => SLOSH_VECTOR,
825            ValueType::Map => SLOSH_MAP,
826            ValueType::Pair => SLOSH_PAIR,
827            ValueType::List => SLOSH_PAIR,
828            ValueType::String => SLOSH_STRING,
829            ValueType::Error => SLOSH_ERROR,
830            ValueType::Io => SLOSH_IO,
831        }
832    }
833}
834
835pub struct ValueTypes<const N: usize> {
836    values: [ValueType; N],
837}
838
839impl<const N: usize> From<[ValueType; N]> for ValueTypes<N> {
840    fn from(values: [ValueType; N]) -> Self {
841        Self { values }
842    }
843}
844
845impl<const N: usize> Deref for ValueTypes<N> {
846    type Target = [ValueType];
847
848    fn deref(&self) -> &Self::Target {
849        &self.values
850    }
851}
852
853impl<const N: usize> From<ValueTypes<N>> for String {
854    fn from(value: ValueTypes<N>) -> Self {
855        let mut res = String::new();
856        let set: BTreeSet<&str> = BTreeSet::from_iter(
857            value
858                .deref()
859                .iter()
860                .map(|v| <ValueType as Into<&'static str>>::into(*v)),
861        );
862        for (i, v) in set.iter().enumerate() {
863            if i > 0 {
864                res.push_str(", ");
865            }
866            res.push_str(v);
867        }
868        res
869    }
870}