vyder_core/value/
mod.rs

1use enum_downcast::EnumDowncast;
2
3use crate::prelude::*;
4
5pub mod values;
6
7/// The token type.
8#[derive(Clone, Debug, PartialEq)]
9pub struct Value {
10    /// The type of value.
11    pub value: ValueEnum,
12    /// The location of the value.
13    pub span: Span,
14}
15
16impl Value {
17    pub fn new_value(value: ValueEnum, span: Span) -> Value {
18        Self { value, span }
19    }
20
21    pub fn new_ok_value(value: ValueEnum, span: Span) -> ValueResult {
22        ValueResult::Ok(Self { value, span })
23    }
24
25    pub fn new_err_value(value: ValueEnum, span: Span) -> ValueResult {
26        ValueResult::Err(Self { value, span })
27    }
28
29    pub fn expect_integer(&self) -> Result<i64> {
30        let number = self.expect::<values::Number>()?;
31
32        if number.value.fract() != 0.0 {
33            return Err(Error::new(
34                ErrorType::UnexpectedValue {
35                    expected: vec!["Integer".to_string()],
36                    actual: "Float".to_string(),
37                },
38                self.span.clone(),
39            ));
40        }
41
42        Ok(number.value as i64)
43    }
44
45    pub fn expect<T>(&self) -> Result<T>
46    where
47        ValueEnum: enum_downcast::AsVariant<T>,
48        T: Clone,
49    {
50        match self.value.enum_downcast_ref::<T>() {
51            Some(token) => Ok(token.clone()),
52            None => Err(Error::new(
53                {
54                    let expected = std::any::type_name::<T>().split("::").last().unwrap();
55                    let actual = self.value.name();
56
57                    ErrorType::UnexpectedValue {
58                        expected: vec![expected.to_string()],
59                        actual,
60                    }
61                },
62                self.span.clone(),
63            )),
64        }
65    }
66}
67
68#[derive(Clone, Debug)]
69pub enum ValueResult {
70    Ok(Value),
71    Err(Value),
72}
73
74impl ValueResult {
75    pub fn ignore_error(&self) -> &Value {
76        match self {
77            ValueResult::Ok(value) | ValueResult::Err(value) => value,
78        }
79    }
80
81    pub fn expect_non_error(self) -> Result<Value> {
82        match self {
83            ValueResult::Ok(value) => Ok(value),
84            ValueResult::Err(Value { span, .. }) => {
85                Err(Error::new(ErrorType::ExpectedNonErrorValue, span))
86            }
87        }
88    }
89
90    pub fn inner_mut(&mut self) -> &mut Value {
91        match self {
92            ValueResult::Ok(value) | ValueResult::Err(value) => value,
93        }
94    }
95}
96
97impl std::fmt::Display for ValueResult {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        match self {
100            ValueResult::Ok(value) => write!(f, "{}", value),
101            ValueResult::Err(value) => write!(f, "~{}", value),
102        }
103    }
104}
105
106pub trait ExpectValue {
107    fn expect_value(self, expected: &[&str], span: &Span) -> Result<Value>;
108}
109
110impl ExpectValue for Option<&Value> {
111    fn expect_value(self, expected: &[&str], span: &Span) -> Result<Value> {
112        match self {
113            Some(value) => Ok(value.clone()),
114            None => Err(Error::new(
115                ErrorType::UnexpectedValue {
116                    expected: expected.iter().map(|v| v.to_string()).collect(),
117                    actual: "EOF".to_string(),
118                },
119                span.clone(),
120            )),
121        }
122    }
123}
124
125pub trait ExpectArity {
126    fn expect_exact<const N: usize>(&self, span: &Span) -> Result<&[ValueResult; N], Error>;
127    fn expect_min<const N: usize>(
128        &self,
129        span: &Span,
130    ) -> Result<([ValueResult; N], Vec<ValueResult>), Error>;
131}
132
133impl ExpectArity for Vec<ValueResult> {
134    fn expect_exact<const N: usize>(&self, span: &Span) -> Result<&[ValueResult; N], Error> {
135        if self.len() == N {
136            Ok(TryInto::<&[ValueResult; N]>::try_into(self.as_slice()).unwrap())
137        } else {
138            Err(Error::new(
139                ErrorType::UnexpectedAmountOfArguments {
140                    expected: N,
141                    actual: self.len(),
142                },
143                span.clone(),
144            ))
145        }
146    }
147
148    fn expect_min<const N: usize>(
149        &self,
150        span: &Span,
151    ) -> Result<([ValueResult; N], Vec<ValueResult>), Error> {
152        if self.len() >= N {
153            let mut has_minimum = false;
154
155            let mut min = vec![];
156            let mut rest = vec![];
157
158            for argument in self {
159                if !has_minimum {
160                    min.push(argument.clone());
161
162                    if min.len() == N {
163                        has_minimum = true;
164                    }
165                } else {
166                    rest.push(argument.clone());
167                }
168            }
169
170            let min = TryInto::<&[ValueResult; N]>::try_into(min.as_slice()).unwrap();
171
172            Ok((min.clone(), rest))
173        } else {
174            Err(Error::new(
175                ErrorType::NotEnoughArguments {
176                    expected: N,
177                    actual: self.len(),
178                },
179                span.clone(),
180            ))
181        }
182    }
183}
184
185impl std::fmt::Display for Value {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        write!(f, "{}", self.value)
188    }
189}
190
191/// Enum of all values.
192#[derive(Clone, Debug, EnumDowncast, PartialEq)]
193pub enum ValueEnum {
194    Number(values::Number),
195    Bool(values::Bool),
196    Nil(values::Nil),
197    Str(values::Str),
198    Range(values::Range),
199    Map(values::Map),
200    Callable(values::Callable),
201}
202
203impl ValueEnum {
204    /// Get the name of the token for debugging purposes.
205    pub fn name(&self) -> String {
206        use ValueEnum::*;
207
208        match self {
209            Number(_) => "Number",
210            Bool(_) => "Bool",
211            Nil(_) => "Nil",
212            Str(_) => "Str",
213            Range(_) => "Range",
214            Map(_) => "Map",
215            Callable(_) => "Callable",
216        }
217        .to_string()
218    }
219
220    pub fn get_iterator(&self, span: &Span) -> Result<Vec<Value>> {
221        match self {
222            ValueEnum::Range(values::Range::Closed { lhs, rhs }) => {
223                let mut out = vec![];
224
225                for i in { *lhs }..*rhs {
226                    out.push(Value::new_value(
227                        values::Number { value: i as f64 }.into(),
228                        span.clone(),
229                    ));
230                }
231
232                Ok(out)
233            }
234            ValueEnum::Number(values::Number { value }) => {
235                let upper_bound = if value.fract() == 0.0 {
236                    *value as i64
237                } else {
238                    return Err(Error::new(
239                        ErrorType::UnexpectedValue {
240                            expected: vec!["Integer".to_string()],
241                            actual: "Float".to_string(),
242                        },
243                        span.clone(),
244                    ));
245                };
246
247                let mut out = vec![];
248
249                for i in 0..upper_bound {
250                    out.push(Value::new_value(
251                        values::Number { value: i as f64 }.into(),
252                        span.clone(),
253                    ));
254                }
255
256                Ok(out)
257            }
258            ValueEnum::Str(values::Str { value }) => {
259                let mut out = vec![];
260
261                for ch in value.chars() {
262                    out.push(Value::new_value(
263                        values::Str {
264                            value: ch.to_string(),
265                        }
266                        .into(),
267                        span.clone(),
268                    ));
269                }
270
271                Ok(out)
272            }
273            ValueEnum::Map(values::Map { values }) => {
274                let mut out = vec![];
275
276                for (key, value) in values {
277                    out.push(Value::new_value(
278                        values::Map {
279                            values: vec![
280                                (
281                                    values::Str {
282                                        value: "key".to_string(),
283                                    }
284                                    .into(),
285                                    key.clone(),
286                                ),
287                                (
288                                    values::Str {
289                                        value: "value".to_string(),
290                                    }
291                                    .into(),
292                                    value.clone(),
293                                ),
294                            ],
295                        }
296                        .into(),
297                        span.clone(),
298                    ));
299                }
300
301                Ok(out)
302            }
303            value => Err(Error::new(
304                ErrorType::CannotLoopOver(value.name()),
305                span.clone(),
306            )),
307        }
308    }
309}
310
311impl std::fmt::Display for ValueEnum {
312    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313        use ValueEnum::*;
314
315        match self {
316            Number(number) => write!(f, "{}", number.value),
317            Bool(values::Bool { value: true }) => write!(f, "true"),
318            Bool(values::Bool { value: false }) => write!(f, "false"),
319            Nil(_) => write!(f, "nil"),
320            Str(string) => write!(f, "{}", string.value),
321            Range(range) => match range {
322                values::Range::Closed { rhs, lhs } => write!(f, "{}..{}", lhs, rhs),
323                values::Range::From { lhs } => write!(f, "{}..", lhs),
324                values::Range::To { rhs } => write!(f, "{}..", rhs),
325            },
326            Map(map) => {
327                if map.values.is_empty() {
328                    write!(f, "||")
329                } else {
330                    let mut out = "| ".to_string();
331
332                    for (key, value) in &map.values {
333                        out.push_str(&format!("[{}] = {}, ", key, value));
334                    }
335
336                    out.pop();
337                    out.pop();
338
339                    write!(f, "{} |", out)
340                }
341            }
342            Callable(callable) => match callable {
343                values::Callable::User {
344                    parameters,
345                    body: _,
346                } => {
347                    let mut out = "fn(".to_string();
348
349                    for parameter in parameters {
350                        out.push_str(&format!("{}, ", parameter.name()));
351                    }
352
353                    if !parameters.is_empty() {
354                        out.pop();
355                        out.pop();
356                    };
357
358                    out.push(')');
359
360                    write!(f, "{}", out)
361                }
362                &values::Callable::Lib {
363                    function: _,
364                    can_be_error,
365                } => write!(
366                    f,
367                    "<builtin_callable>{}",
368                    if can_be_error { "?" } else { "" }
369                ),
370            },
371        }
372    }
373}