dark_vm/values/
value.rs

1use super::value_kinds::ValueKind;
2use crate::{
3    errors::{error::Error, error_kind::ErrorKind},
4    tokens::{token::Token, token_kind::TokenKind},
5};
6use std::fmt;
7
8/// The Value struct maintains both the position where this value is used and its kind.
9/// Maintaining the position is useful because it can be used to produce good error messages.
10
11#[derive(PartialEq)]
12pub struct Value {
13    pub pos: usize,
14    pub kind: ValueKind,
15}
16
17impl Value {
18    /// Constructs a new Value struct with the specified position and kind.
19    ///
20    /// # Arguments
21    /// `pos` - The position where this value is created or called.
22    /// `kind` - The value of this value.
23    pub fn new(pos: usize, kind: ValueKind) -> Value {
24        Value { pos, kind }
25    }
26}
27
28impl Value {
29    /// This function takes the current value and a reference to another value and adds them together.
30    /// Note that this function does not take ownership of either value. Instead, it creates a new value.
31    ///
32    /// # Arguments
33    /// `other` - The other value to add.
34    /// `pos` - The position where this operation was called.
35    pub fn add(&self, other: &Value, pos: usize) -> Result<Value, Error> {
36        match (&self.kind, &other.kind) {
37            (ValueKind::String(val1), ValueKind::String(val2)) => Ok(Value::new(
38                pos,
39                ValueKind::String(format!("{}{}", val1, val2)),
40            )),
41            (_, ValueKind::String(val2)) if self.kind != ValueKind::Void => Ok(Value::new(
42                pos,
43                ValueKind::String(format!("{:#?}{}", self, val2)),
44            )),
45            (ValueKind::String(val1), _) if other.kind != ValueKind::Void => Ok(Value::new(
46                pos,
47                ValueKind::String(format!("{}{:#?}", val1, other)),
48            )),
49
50            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
51                Ok(Value::new(pos, ValueKind::Int(val1 + val2)))
52            }
53            (ValueKind::Int(val1), ValueKind::Float(val2)) => {
54                Ok(Value::new(pos, ValueKind::Float(*val1 as f64 + val2)))
55            }
56            (ValueKind::Float(val1), ValueKind::Int(val2)) => {
57                Ok(Value::new(pos, ValueKind::Float(val1 + *val2 as f64)))
58            }
59            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
60                Ok(Value::new(pos, ValueKind::Float(val1 + val2)))
61            }
62
63            _ => Err(Error::new(
64                ErrorKind::UnsupportedOperation(
65                    "Add".to_owned(),
66                    format!(
67                        "The Value '{}' And The Value '{}'.",
68                        self.kind.get_value_name(),
69                        other.kind.get_value_name()
70                    ),
71                ),
72                pos,
73            )),
74        }
75    }
76
77    /// This function takes the current value and a reference to another value and subtracts them.
78    /// Note that this function does not take ownership of either value. Instead, it creates a new value.
79    ///
80    /// # Arguments
81    /// `other` - The other value to subtract.
82    /// `pos` - The position where this operation was called.
83    pub fn sub(&self, other: &Value, pos: usize) -> Result<Value, Error> {
84        match (&self.kind, &other.kind) {
85            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
86                Ok(Value::new(pos, ValueKind::Int(val1 - val2)))
87            }
88            (ValueKind::Int(val1), ValueKind::Float(val2)) => {
89                Ok(Value::new(pos, ValueKind::Float(*val1 as f64 - val2)))
90            }
91            (ValueKind::Float(val1), ValueKind::Int(val2)) => {
92                Ok(Value::new(pos, ValueKind::Float(val1 - *val2 as f64)))
93            }
94            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
95                Ok(Value::new(pos, ValueKind::Float(val1 - val2)))
96            }
97
98            _ => Err(Error::new(
99                ErrorKind::UnsupportedOperation(
100                    "Sub".to_owned(),
101                    format!(
102                        "The Value '{}' And The Value '{}'.",
103                        self.kind.get_value_name(),
104                        other.kind.get_value_name()
105                    ),
106                ),
107                pos,
108            )),
109        }
110    }
111
112    /// This function takes the current value and a reference to another value and mutliplies them.
113    /// Note that this function does not take ownership of either value. Instead, it creates a new value.
114    ///
115    /// # Arguments
116    /// `other` - The other value to multiply.
117    /// `pos` - The position where this operation was called.
118    pub fn mul(&self, other: &Value, pos: usize) -> Result<Value, Error> {
119        match (&self.kind, &other.kind) {
120            (ValueKind::String(val1), ValueKind::Int(val2)) => Ok(Value::new(
121                pos,
122                ValueKind::String(val1.repeat(val2.abs() as usize)),
123            )),
124            (ValueKind::Int(val1), ValueKind::String(val2)) if self.kind != ValueKind::Void => Ok(
125                Value::new(pos, ValueKind::String(val2.repeat(val1.abs() as usize))),
126            ),
127
128            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
129                Ok(Value::new(pos, ValueKind::Int(val1 * val2)))
130            }
131            (ValueKind::Int(val1), ValueKind::Float(val2)) => {
132                Ok(Value::new(pos, ValueKind::Float(*val1 as f64 * val2)))
133            }
134            (ValueKind::Float(val1), ValueKind::Int(val2)) => {
135                Ok(Value::new(pos, ValueKind::Float(val1 * *val2 as f64)))
136            }
137            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
138                Ok(Value::new(pos, ValueKind::Float(val1 * val2)))
139            }
140
141            _ => Err(Error::new(
142                ErrorKind::UnsupportedOperation(
143                    "Mul".to_owned(),
144                    format!(
145                        "The Value '{}' And The Value '{}'.",
146                        self.kind.get_value_name(),
147                        other.kind.get_value_name()
148                    ),
149                ),
150                pos,
151            )),
152        }
153    }
154
155    /// This function takes the current value and a reference to another value and divides them.
156    /// Note that this function does not take ownership of either value. Instead, it creates a new value.
157    ///
158    /// # Arguments
159    /// `other` - The other value to divide.
160    /// `pos` - The position where this operation was called.
161    pub fn div(&self, other: &Value, pos: usize) -> Result<Value, Error> {
162        match (&self.kind, &other.kind) {
163            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
164                if val2 == &0 {
165                    Err(Error::new(ErrorKind::DivisionByZero, pos))
166                } else {
167                    Ok(Value::new(pos, ValueKind::Int(val1 / val2)))
168                }
169            }
170            (ValueKind::Int(val1), ValueKind::Float(val2)) => {
171                if val2 - 0.0 < std::f64::EPSILON {
172                    Err(Error::new(ErrorKind::DivisionByZero, pos))
173                } else {
174                    Ok(Value::new(pos, ValueKind::Float(*val1 as f64 / val2)))
175                }
176            }
177            (ValueKind::Float(val1), ValueKind::Int(val2)) => {
178                if val1 - 0.0 < std::f64::EPSILON {
179                    Err(Error::new(ErrorKind::DivisionByZero, pos))
180                } else {
181                    Ok(Value::new(pos, ValueKind::Float(val1 / *val2 as f64)))
182                }
183            }
184            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
185                if val2 - 0.0 < std::f64::EPSILON {
186                    Err(Error::new(ErrorKind::DivisionByZero, pos))
187                } else {
188                    Ok(Value::new(pos, ValueKind::Float(val1 / val2)))
189                }
190            }
191
192            _ => Err(Error::new(
193                ErrorKind::UnsupportedOperation(
194                    "Div".to_owned(),
195                    format!(
196                        "The Value '{}' And The Value '{}'.",
197                        self.kind.get_value_name(),
198                        other.kind.get_value_name()
199                    ),
200                ),
201                pos,
202            )),
203        }
204    }
205
206    /// This function takes the current value and a reference to another value and returns if the current value
207    /// is less than the second one. Note that this function does not consume either value.
208    ///
209    /// # Arguments
210    /// `other` - The other value to compare.
211    /// `pos` - The position where this operation was called.
212    pub fn lt(&self, other: &Value, pos: usize) -> Result<Value, Error> {
213        match (&self.kind, &other.kind) {
214            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
215                Ok(Value::new(pos, ValueKind::Boolean(val1 < val2)))
216            }
217            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
218                Ok(Value::new(pos, ValueKind::Boolean(val1 < val2)))
219            }
220            (ValueKind::String(val1), ValueKind::String(val2)) => {
221                Ok(Value::new(pos, ValueKind::Boolean(val1 < val2)))
222            }
223
224            _ => Err(Error::new(
225                ErrorKind::UnsupportedOperation(
226                    "Lt".to_owned(),
227                    format!(
228                        "The Value '{}' And The Value '{}'.",
229                        self.kind.get_value_name(),
230                        other.kind.get_value_name()
231                    ),
232                ),
233                pos,
234            )),
235        }
236    }
237
238    /// This function takes the current value and a reference to another value and returns if the current value
239    /// is less than or equal to the second one. Note that this function does not consume either value.
240    ///
241    /// # Arguments
242    /// `other` - The other value to compare.
243    /// `pos` - The position where this operation was called.
244    pub fn lte(&self, other: &Value, pos: usize) -> Result<Value, Error> {
245        match (&self.kind, &other.kind) {
246            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
247                Ok(Value::new(pos, ValueKind::Boolean(val1 <= val2)))
248            }
249            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
250                Ok(Value::new(pos, ValueKind::Boolean(val1 <= val2)))
251            }
252            (ValueKind::String(val1), ValueKind::String(val2)) => {
253                Ok(Value::new(pos, ValueKind::Boolean(val1 <= val2)))
254            }
255
256            _ => Err(Error::new(
257                ErrorKind::UnsupportedOperation(
258                    "Lte".to_owned(),
259                    format!(
260                        "The Value '{}' And The Value '{}'.",
261                        self.kind.get_value_name(),
262                        other.kind.get_value_name()
263                    ),
264                ),
265                pos,
266            )),
267        }
268    }
269
270    /// This function takes the current value and a reference to another value and returns if the current value
271    /// is greater than the second one. Note that this function does not consume either value.
272    ///
273    /// # Arguments
274    /// `other` - The other value to compare.
275    /// `pos` - The position where this operation was called.
276    pub fn gt(&self, other: &Value, pos: usize) -> Result<Value, Error> {
277        match (&self.kind, &other.kind) {
278            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
279                Ok(Value::new(pos, ValueKind::Boolean(val1 > val2)))
280            }
281            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
282                Ok(Value::new(pos, ValueKind::Boolean(val1 > val2)))
283            }
284            (ValueKind::String(val1), ValueKind::String(val2)) => {
285                Ok(Value::new(pos, ValueKind::Boolean(val1 > val2)))
286            }
287
288            _ => Err(Error::new(
289                ErrorKind::UnsupportedOperation(
290                    "Gt".to_owned(),
291                    format!(
292                        "The Value '{}' And The Value '{}'.",
293                        self.kind.get_value_name(),
294                        other.kind.get_value_name()
295                    ),
296                ),
297                pos,
298            )),
299        }
300    }
301
302    /// This function takes the current value and a reference to another value and returns if the current value
303    /// is greater than or equal to the second one. Note that this function does not consume either value.
304    ///
305    /// # Arguments
306    /// `other` - The other value to compare.
307    /// `pos` - The position where this operation was called.
308    pub fn gte(&self, other: &Value, pos: usize) -> Result<Value, Error> {
309        match (&self.kind, &other.kind) {
310            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
311                Ok(Value::new(pos, ValueKind::Boolean(val1 >= val2)))
312            }
313            (ValueKind::Float(val1), ValueKind::Float(val2)) => {
314                Ok(Value::new(pos, ValueKind::Boolean(val1 >= val2)))
315            }
316            (ValueKind::String(val1), ValueKind::String(val2)) => {
317                Ok(Value::new(pos, ValueKind::Boolean(val1 >= val2)))
318            }
319
320            _ => Err(Error::new(
321                ErrorKind::UnsupportedOperation(
322                    "Gte".to_owned(),
323                    format!(
324                        "The Value '{}' And The Value '{}'.",
325                        self.kind.get_value_name(),
326                        other.kind.get_value_name()
327                    ),
328                ),
329                pos,
330            )),
331        }
332    }
333
334    /// This function takes the current value and a reference to another value and returns if the current value
335    /// is equal to the second one. Note that this function does not consume either value.
336    ///
337    /// # Arguments
338    /// `other` - The other value to compare.
339    /// `pos` - The position where this operation was called.
340    pub fn equal(&self, other: &Value, pos: usize) -> Value {
341        match (&self.kind, &other.kind) {
342            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
343                Value::new(pos, ValueKind::Boolean(val1 == val2))
344            }
345            (ValueKind::Float(val1), ValueKind::Float(val2)) => Value::new(
346                pos,
347                ValueKind::Boolean((val1 - val2).abs() < std::f64::EPSILON),
348            ),
349            (ValueKind::Boolean(val1), ValueKind::Boolean(val2)) => {
350                Value::new(pos, ValueKind::Boolean(val1 == val2))
351            }
352            (ValueKind::String(val1), ValueKind::String(val2)) => {
353                Value::new(pos, ValueKind::Boolean(val1 == val2))
354            }
355
356            _ => Value::new(pos, ValueKind::Boolean(false)),
357        }
358    }
359
360    /// This function takes the current value and a reference to another value and returns if the current value
361    /// is not equal to the second one. Note that this function does not consume either value.
362    ///
363    /// # Arguments
364    /// `other` - The other value to compare.
365    /// `pos` - The position where this operation was called.
366    pub fn not_equal(&self, other: &Value, pos: usize) -> Value {
367        match (&self.kind, &other.kind) {
368            (ValueKind::Int(val1), ValueKind::Int(val2)) => {
369                Value::new(pos, ValueKind::Boolean(val1 != val2))
370            }
371            (ValueKind::Float(val1), ValueKind::Float(val2)) => Value::new(
372                pos,
373                ValueKind::Boolean((val1 - val2).abs() > std::f64::EPSILON),
374            ),
375            (ValueKind::Boolean(val1), ValueKind::Boolean(val2)) => {
376                Value::new(pos, ValueKind::Boolean(val1 != val2))
377            }
378            (ValueKind::String(val1), ValueKind::String(val2)) => {
379                Value::new(pos, ValueKind::Boolean(val1 != val2))
380            }
381
382            _ => Value::new(pos, ValueKind::Boolean(true)),
383        }
384    }
385
386    /// This function takes the current value and returns if it is "truthy".
387    /// This can mean different things for differet values. For ints, it is whether it is not 0.
388    /// For floats, it is whether it is not NAN, infinite, and not 0. For strings, it is whether
389    /// it is not empty. Every other value is considered to be false.
390    pub fn is_truthy(&self) -> bool {
391        match &self.kind {
392            ValueKind::Int(value) => value != &0,
393            ValueKind::Float(value) => value.is_normal(),
394            ValueKind::Boolean(value) => *value,
395            ValueKind::String(value) => !value.is_empty(),
396            _ => false,
397        }
398    }
399}
400
401/// Converts a token into a value. This is used by the Code struct when generating the vector of values.
402impl From<Token> for Value {
403    fn from(token: Token) -> Self {
404        Value {
405            pos: token.pos,
406            kind: match token.kind {
407                TokenKind::Void => ValueKind::Void,
408                TokenKind::Any => ValueKind::Any,
409                TokenKind::IntegerLiteral(value) => ValueKind::Int(value),
410                TokenKind::FloatLiteral(value) => ValueKind::Float(value),
411                TokenKind::BooleanLiteral(value) => ValueKind::Boolean(value),
412                TokenKind::StringLiteral(value) => ValueKind::String(value),
413                TokenKind::Identifier(name) => ValueKind::Identifier(name),
414                TokenKind::Label(name) => ValueKind::Label(name),
415                TokenKind::End => ValueKind::End,
416
417                TokenKind::Push => ValueKind::Push,
418                TokenKind::Pop => ValueKind::Pop,
419                TokenKind::Peek => ValueKind::Peek,
420                TokenKind::Add => ValueKind::Add,
421                TokenKind::Sub => ValueKind::Sub,
422                TokenKind::Mul => ValueKind::Mul,
423                TokenKind::Div => ValueKind::Div,
424                TokenKind::LessThan => ValueKind::LessThan,
425                TokenKind::LessThanEqual => ValueKind::LessThanEqual,
426                TokenKind::GreaterThan => ValueKind::GreaterThan,
427                TokenKind::GreaterThanEqual => ValueKind::GreaterThanEqual,
428                TokenKind::Equal => ValueKind::Equal,
429                TokenKind::NotEqual => ValueKind::NotEqual,
430                TokenKind::Jump => ValueKind::Jump,
431                TokenKind::RelativeJump => ValueKind::RelativeJump,
432                TokenKind::JumpIfTrue => ValueKind::JumpIfTrue,
433                TokenKind::JumpIfFalse => ValueKind::JumpIfFalse,
434                TokenKind::Print => ValueKind::Print,
435                TokenKind::PrintNewLine => ValueKind::PrintNewLine,
436                TokenKind::Set => ValueKind::Set,
437                TokenKind::Call => ValueKind::Call,
438            },
439        }
440    }
441}
442
443impl fmt::Debug for Value {
444    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
445        write!(f, "{:#?}", self.kind)
446    }
447}