arithmetic_eval/values/
mod.rs

1//! Values used by the interpreter.
2
3use hashbrown::HashMap;
4
5use core::{
6    any::{type_name, Any},
7    fmt,
8};
9
10use crate::{
11    alloc::{vec, Rc, String, Vec},
12    fns,
13};
14use arithmetic_parser::{MaybeSpanned, StripCode};
15
16mod env;
17mod function;
18mod ops;
19mod variable_map;
20
21pub use self::{
22    env::Environment,
23    function::{CallContext, Function, InterpretedFn, NativeFn},
24    variable_map::{Assertions, Comparisons, Prelude, VariableMap},
25};
26
27/// Possible high-level types of [`Value`]s.
28#[derive(Debug, Clone, Copy, PartialEq)]
29#[non_exhaustive]
30pub enum ValueType {
31    /// Primitive type other than `Bool`ean.
32    Prim,
33    /// Boolean value.
34    Bool,
35    /// Function value.
36    Function,
37    /// Tuple of a specific size.
38    Tuple(usize),
39    /// Object.
40    Object,
41    /// Array (a tuple of arbitrary size).
42    ///
43    /// This variant is never returned from [`Value::value_type()`]; at the same time, it is
44    /// used for error reporting etc.
45    Array,
46    /// Opaque reference to a value.
47    Ref,
48}
49
50impl fmt::Display for ValueType {
51    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match self {
53            Self::Prim => formatter.write_str("primitive value"),
54            Self::Bool => formatter.write_str("boolean value"),
55            Self::Function => formatter.write_str("function"),
56            Self::Tuple(1) => formatter.write_str("tuple with 1 element"),
57            Self::Object => formatter.write_str("object"),
58            Self::Tuple(size) => write!(formatter, "tuple with {} elements", size),
59            Self::Array => formatter.write_str("array"),
60            Self::Ref => formatter.write_str("reference"),
61        }
62    }
63}
64
65/// Opaque reference to a native value.
66///
67/// The references cannot be created by interpreted code, but can be used as function args
68/// or return values of native functions. References are [`Rc`]'d, thus can easily be cloned.
69///
70/// References are comparable among each other:
71///
72/// - If the wrapped value implements [`PartialEq`], this implementation will be used
73///   for comparison.
74/// - If `PartialEq` is not implemented, the comparison is by the `Rc` pointer.
75pub struct OpaqueRef {
76    value: Rc<dyn Any>,
77    type_name: &'static str,
78    dyn_eq: fn(&dyn Any, &dyn Any) -> bool,
79    dyn_fmt: fn(&dyn Any, &mut fmt::Formatter<'_>) -> fmt::Result,
80}
81
82#[allow(renamed_and_removed_lints, clippy::unknown_clippy_lints)]
83// ^ `missing_panics_doc` is newer than MSRV, and `clippy::unknown_clippy_lints` is removed
84// since Rust 1.51.
85impl OpaqueRef {
86    /// Creates a reference to `value` that implements equality comparison.
87    ///
88    /// Prefer using this method if the wrapped type implements [`PartialEq`].
89    #[allow(clippy::missing_panics_doc)] // false positive; `unwrap()`s never panic
90    pub fn new<T>(value: T) -> Self
91    where
92        T: Any + fmt::Debug + PartialEq,
93    {
94        Self {
95            value: Rc::new(value),
96            type_name: type_name::<T>(),
97
98            dyn_eq: |this, other| {
99                let this_cast = this.downcast_ref::<T>().unwrap();
100                other
101                    .downcast_ref::<T>()
102                    .map_or(false, |other_cast| other_cast == this_cast)
103            },
104            dyn_fmt: |this, formatter| {
105                let this_cast = this.downcast_ref::<T>().unwrap();
106                fmt::Debug::fmt(this_cast, formatter)
107            },
108        }
109    }
110
111    /// Creates a reference to `value` with the identity comparison: values are considered
112    /// equal iff they point to the same data.
113    ///
114    /// Prefer [`Self::new()`] when possible.
115    #[allow(clippy::missing_panics_doc)] // false positive; `unwrap()`s never panic
116    pub fn with_identity_eq<T>(value: T) -> Self
117    where
118        T: Any + fmt::Debug,
119    {
120        Self {
121            value: Rc::new(value),
122            type_name: type_name::<T>(),
123
124            dyn_eq: |this, other| {
125                let this_data = (this as *const dyn Any).cast::<()>();
126                let other_data = (other as *const dyn Any).cast::<()>();
127                this_data == other_data
128            },
129            dyn_fmt: |this, formatter| {
130                let this_cast = this.downcast_ref::<T>().unwrap();
131                fmt::Debug::fmt(this_cast, formatter)
132            },
133        }
134    }
135
136    /// Tries to downcast this reference to a specific type.
137    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
138        self.value.downcast_ref()
139    }
140}
141
142impl Clone for OpaqueRef {
143    fn clone(&self) -> Self {
144        Self {
145            value: Rc::clone(&self.value),
146            type_name: self.type_name,
147            dyn_eq: self.dyn_eq,
148            dyn_fmt: self.dyn_fmt,
149        }
150    }
151}
152
153impl PartialEq for OpaqueRef {
154    fn eq(&self, other: &Self) -> bool {
155        (self.dyn_eq)(self.value.as_ref(), other.value.as_ref())
156    }
157}
158
159impl fmt::Debug for OpaqueRef {
160    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
161        formatter
162            .debug_tuple("OpaqueRef")
163            .field(&self.value.as_ref())
164            .finish()
165    }
166}
167
168impl fmt::Display for OpaqueRef {
169    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
170        write!(formatter, "{}::", self.type_name)?;
171        (self.dyn_fmt)(self.value.as_ref(), formatter)
172    }
173}
174
175/// Values produced by expressions during their interpretation.
176#[derive(Debug)]
177#[non_exhaustive]
178pub enum Value<'a, T> {
179    /// Primitive value, such as a number. This does not include Boolean values,
180    /// which are a separate variant.
181    ///
182    /// Literals must necessarily map to primitive values, but there may be some primitive values
183    /// not representable as literals.
184    Prim(T),
185    /// Boolean value.
186    Bool(bool),
187    /// Function.
188    Function(Function<'a, T>),
189    /// Tuple of zero or more values.
190    Tuple(Vec<Value<'a, T>>),
191    /// Object with zero or more named fields.
192    Object(HashMap<String, Value<'a, T>>),
193    /// Opaque reference to a native value.
194    Ref(OpaqueRef),
195}
196
197/// Value together with a span that has produced it.
198pub type SpannedValue<'a, T> = MaybeSpanned<'a, Value<'a, T>>;
199
200impl<'a, T> Value<'a, T> {
201    /// Creates a value for a native function.
202    pub fn native_fn(function: impl NativeFn<T> + 'static) -> Self {
203        Self::Function(Function::Native(Rc::new(function)))
204    }
205
206    /// Creates a [wrapped function](fns::FnWrapper).
207    ///
208    /// Calling this method is equivalent to [`wrap`](fns::wrap)ping a function and calling
209    /// [`Self::native_fn()`] on it. Thanks to type inference magic, the Rust compiler
210    /// will usually be able to extract the `Args` type param from the function definition,
211    /// provided that type of function arguments and its return type are defined explicitly
212    /// or can be unequivocally inferred from the declaration.
213    pub fn wrapped_fn<Args, F>(fn_to_wrap: F) -> Self
214    where
215        fns::FnWrapper<Args, F>: NativeFn<T> + 'static,
216    {
217        let wrapped = fns::wrap::<Args, _>(fn_to_wrap);
218        Self::native_fn(wrapped)
219    }
220
221    /// Creates a value for an interpreted function.
222    pub(crate) fn interpreted_fn(function: InterpretedFn<'a, T>) -> Self {
223        Self::Function(Function::Interpreted(Rc::new(function)))
224    }
225
226    /// Creates a void value (an empty tuple).
227    pub fn void() -> Self {
228        Self::Tuple(vec![])
229    }
230
231    /// Creates a reference to a native variable.
232    pub fn opaque_ref(value: impl Any + fmt::Debug + PartialEq) -> Self {
233        Self::Ref(OpaqueRef::new(value))
234    }
235
236    /// Returns the type of this value.
237    pub fn value_type(&self) -> ValueType {
238        match self {
239            Self::Prim(_) => ValueType::Prim,
240            Self::Bool(_) => ValueType::Bool,
241            Self::Function(_) => ValueType::Function,
242            Self::Tuple(elements) => ValueType::Tuple(elements.len()),
243            Self::Object(_) => ValueType::Object,
244            Self::Ref(_) => ValueType::Ref,
245        }
246    }
247
248    /// Checks if this value is void (an empty tuple).
249    pub fn is_void(&self) -> bool {
250        matches!(self, Self::Tuple(tuple) if tuple.is_empty())
251    }
252
253    /// Checks if this value is a function.
254    pub fn is_function(&self) -> bool {
255        matches!(self, Self::Function(_))
256    }
257}
258
259impl<T: Clone> Clone for Value<'_, T> {
260    fn clone(&self) -> Self {
261        match self {
262            Self::Prim(lit) => Self::Prim(lit.clone()),
263            Self::Bool(bool) => Self::Bool(*bool),
264            Self::Function(function) => Self::Function(function.clone()),
265            Self::Tuple(tuple) => Self::Tuple(tuple.clone()),
266            Self::Object(fields) => Self::Object(fields.clone()),
267            Self::Ref(reference) => Self::Ref(reference.clone()),
268        }
269    }
270}
271
272impl<T: 'static + Clone> StripCode for Value<'_, T> {
273    type Stripped = Value<'static, T>;
274
275    fn strip_code(self) -> Self::Stripped {
276        match self {
277            Self::Prim(lit) => Value::Prim(lit),
278            Self::Bool(bool) => Value::Bool(bool),
279            Self::Function(function) => Value::Function(function.strip_code()),
280            Self::Tuple(tuple) => {
281                Value::Tuple(tuple.into_iter().map(StripCode::strip_code).collect())
282            }
283            Self::Object(fields) => Value::Object(
284                fields
285                    .into_iter()
286                    .map(|(name, value)| (name, value.strip_code()))
287                    .collect(),
288            ),
289            Self::Ref(reference) => Value::Ref(reference),
290        }
291    }
292}
293
294impl<'a, T: Clone> From<&Value<'a, T>> for Value<'a, T> {
295    fn from(reference: &Value<'a, T>) -> Self {
296        reference.clone()
297    }
298}
299
300impl<T: PartialEq> PartialEq for Value<'_, T> {
301    fn eq(&self, rhs: &Self) -> bool {
302        match (self, rhs) {
303            (Self::Prim(this), Self::Prim(other)) => this == other,
304            (Self::Bool(this), Self::Bool(other)) => this == other,
305            (Self::Tuple(this), Self::Tuple(other)) => this == other,
306            (Self::Object(this), Self::Object(other)) => this == other,
307            (Self::Function(this), Self::Function(other)) => this.is_same_function(other),
308            (Self::Ref(this), Self::Ref(other)) => this == other,
309            _ => false,
310        }
311    }
312}
313
314impl<T: fmt::Display> fmt::Display for Value<'_, T> {
315    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
316        match self {
317            Self::Prim(value) => fmt::Display::fmt(value, formatter),
318            Self::Bool(true) => formatter.write_str("true"),
319            Self::Bool(false) => formatter.write_str("false"),
320            Self::Ref(opaque_ref) => fmt::Display::fmt(opaque_ref, formatter),
321            Self::Function(_) => formatter.write_str("[function]"),
322            Self::Object(fields) => {
323                formatter.write_str("#{ ")?;
324                for (name, value) in fields.iter() {
325                    write!(formatter, "{} = {}; ", name, value)?;
326                }
327                formatter.write_str("}")
328            }
329            Self::Tuple(elements) => {
330                formatter.write_str("(")?;
331                for (i, element) in elements.iter().enumerate() {
332                    fmt::Display::fmt(element, formatter)?;
333                    if i + 1 < elements.len() {
334                        formatter.write_str(", ")?;
335                    }
336                }
337                formatter.write_str(")")
338            }
339        }
340    }
341}
342
343#[cfg(test)]
344mod tests {
345    use super::*;
346
347    use core::cmp::Ordering;
348
349    #[test]
350    fn opaque_ref_equality() {
351        let value = Value::<f32>::opaque_ref(Ordering::Less);
352        let same_value = Value::<f32>::opaque_ref(Ordering::Less);
353        assert_eq!(value, same_value);
354        assert_eq!(value, value.clone());
355        let other_value = Value::<f32>::opaque_ref(Ordering::Greater);
356        assert_ne!(value, other_value);
357    }
358
359    #[test]
360    fn opaque_ref_formatting() {
361        let value = OpaqueRef::new(Ordering::Less);
362        assert_eq!(value.to_string(), "core::cmp::Ordering::Less");
363    }
364}