kb/
val.rs

1use super::Code;
2use super::GenObj;
3use super::RcStr;
4use std::cell::Ref;
5use std::cell::RefCell;
6use std::cell::RefMut;
7use std::cmp;
8use std::fmt;
9use std::rc::Rc;
10
11#[derive(Clone, PartialEq)]
12pub enum Val {
13    /// E.g. to check for usage before assignment
14    Invalid,
15
16    Nil,
17    Bool(bool),
18    Number(f64),
19
20    /// Use of RcStr over Rc<str> is by design --
21    /// this allows kb to interoperate with rest of mtots
22    /// without copying the String all over the place
23    String(RcStr),
24
25    List(Rc<List>),
26
27    Func(Func),
28
29    GenObj(GenObjPtr),
30}
31
32impl Val {
33    pub fn truthy(&self) -> bool {
34        match self {
35            Self::Invalid => panic!("Val::Invalid.truthy()"),
36            Self::Nil => false,
37            Self::Bool(x) => *x,
38            Self::Number(x) => *x != 0.0,
39            Self::String(x) => x.len() > 0,
40            Self::List(x) => x.borrow().len() > 0,
41            Self::Func(_) | Self::GenObj(_) => true,
42        }
43    }
44    pub fn number(&self) -> Option<f64> {
45        if let Self::Number(x) = self {
46            Some(*x)
47        } else {
48            None
49        }
50    }
51    pub fn expect_number(&self) -> Result<f64, Val> {
52        if let Some(x) = self.number() {
53            Ok(x)
54        } else {
55            Err(Val::String("Expected number".to_owned().into()))
56        }
57    }
58    pub fn list(&self) -> Option<&List> {
59        if let Self::List(x) = self {
60            Some(x)
61        } else {
62            None
63        }
64    }
65    pub fn expect_list(&self) -> Result<&List, Val> {
66        if let Some(x) = self.list() {
67            Ok(x)
68        } else {
69            Err(Val::String("Expected list".to_owned().into()))
70        }
71    }
72    pub fn func(&self) -> Option<&Rc<Code>> {
73        if let Self::Func(x) = self {
74            Some(&x.0)
75        } else {
76            None
77        }
78    }
79    pub fn expect_func(&self) -> Result<&Rc<Code>, Val> {
80        if let Some(x) = self.func() {
81            Ok(x)
82        } else {
83            Err(Val::String("Expected func".to_owned().into()))
84        }
85    }
86    pub fn genobj(&self) -> Option<&GenObjPtr> {
87        if let Self::GenObj(x) = self {
88            Some(x)
89        } else {
90            None
91        }
92    }
93    pub fn expect_genobj(&self) -> Result<&GenObjPtr, Val> {
94        if let Some(x) = self.genobj() {
95            Ok(x)
96        } else {
97            Err(Val::String("Expected generator object".to_owned().into()))
98        }
99    }
100    pub fn lt(&self, other: &Self) -> Result<bool, Val> {
101        match (self, other) {
102            (Self::Number(a), Self::Number(b)) => Ok(a < b),
103            (Self::String(a), Self::String(b)) => Ok(a < b),
104            (Self::List(a), Self::List(b)) => Ok({
105                let a = a.borrow();
106                let b = b.borrow();
107                for (x, y) in a.iter().zip(b.iter()) {
108                    if x.lt(y)? {
109                        return Ok(true);
110                    } else if y.lt(x)? {
111                        return Ok(false);
112                    }
113                }
114                a.len() < b.len()
115            }),
116            _ => Err(Val::String(
117                format!("{} and {} are not comparable", self, other).into(),
118            )),
119        }
120    }
121}
122
123impl From<bool> for Val {
124    fn from(x: bool) -> Self {
125        Self::Bool(x)
126    }
127}
128
129impl From<&str> for Val {
130    fn from(s: &str) -> Self {
131        Self::String(s.into())
132    }
133}
134
135impl From<String> for Val {
136    fn from(s: String) -> Self {
137        Self::String(s.into())
138    }
139}
140
141impl From<&RcStr> for Val {
142    fn from(s: &RcStr) -> Self {
143        Self::String(s.clone())
144    }
145}
146
147impl From<RcStr> for Val {
148    fn from(s: RcStr) -> Self {
149        Self::String(s.into())
150    }
151}
152
153impl From<Vec<Val>> for Val {
154    fn from(vec: Vec<Val>) -> Self {
155        Self::List(
156            List {
157                vec: RefCell::new(vec),
158            }
159            .into(),
160        )
161    }
162}
163
164impl fmt::Debug for Val {
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        match self {
167            Val::Invalid => write!(f, "<invalid>"),
168            Val::Nil => write!(f, "nil"),
169            Val::Bool(x) => write!(f, "{}", if *x { "true" } else { "false" }),
170            Val::Number(x) => write!(f, "{}", x),
171            Val::String(x) => {
172                write!(f, "\"")?;
173                for c in x.chars() {
174                    match c {
175                        '\\' => write!(f, "\\\\")?,
176                        '\"' => write!(f, "\\\"")?,
177                        '\'' => write!(f, "\\\'")?,
178                        '\n' => write!(f, "\\\n")?,
179                        '\r' => write!(f, "\\\r")?,
180                        '\t' => write!(f, "\\\t")?,
181                        _ => write!(f, "{}", c)?,
182                    }
183                }
184                write!(f, "\"")
185            }
186            Val::List(xs) => {
187                write!(f, "[")?;
188                for (i, x) in xs.borrow().iter().enumerate() {
189                    if i > 0 {
190                        write!(f, ", ")?;
191                    }
192                    write!(f, "{:?}", x)?;
193                }
194                write!(f, "]")
195            }
196            Val::Func(func) => write!(f, "<func {}>", func.0.name()),
197            Val::GenObj(_) => write!(f, "<genobj>"),
198        }
199    }
200}
201
202impl fmt::Display for Val {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        match self {
205            Val::String(x) => write!(f, "{}", x),
206            _ => write!(f, "{:?}", self),
207        }
208    }
209}
210
211/// Wrapper around RefCell<Vec<Val>>
212/// Having a wrapper keeps the possibility open for e.g.
213/// caching hash values, or mutability locks
214pub struct List {
215    vec: RefCell<Vec<Val>>,
216}
217
218impl List {
219    pub fn borrow(&self) -> Ref<Vec<Val>> {
220        self.vec.borrow()
221    }
222    pub fn borrow_mut(&self) -> RefMut<Vec<Val>> {
223        self.vec.borrow_mut()
224    }
225}
226
227impl cmp::PartialEq for List {
228    fn eq(&self, other: &Self) -> bool {
229        self.vec.eq(&other.vec)
230    }
231}
232
233impl cmp::Eq for List {}
234
235#[derive(Clone)]
236pub struct Func(pub Rc<Code>);
237
238impl cmp::PartialEq for Func {
239    fn eq(&self, other: &Self) -> bool {
240        Rc::as_ptr(&self.0) == Rc::as_ptr(&other.0)
241    }
242}
243
244impl cmp::Eq for Func {}
245
246#[derive(Clone)]
247pub struct GenObjPtr(pub Rc<RefCell<GenObj>>);
248
249impl cmp::PartialEq for GenObjPtr {
250    fn eq(&self, other: &Self) -> bool {
251        Rc::as_ptr(&self.0) == Rc::as_ptr(&other.0)
252    }
253}
254
255impl cmp::Eq for GenObjPtr {}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260
261    #[test]
262    fn val_size() {
263        assert_eq!(std::mem::size_of::<Val>(), 2 * std::mem::size_of::<usize>());
264    }
265}