compose_library/foundations/
value.rs

1use crate::diag::{At, SourceResult, Spanned};
2use crate::foundations::boxed::Boxed;
3use crate::{CastInfo, Str, SyntaxContext, UnitValue};
4use crate::{FromValue, Func};
5use crate::{IntoValue, Vm};
6use crate::{NativeScope, Reflect};
7use crate::{Sink, Type};
8use compose_library::diag::{StrResult, bail, error};
9use compose_library::foundations::range::RangeValue;
10use compose_library::repr::Repr;
11use compose_library::{Args, ArrayValue, IterValue, MapValue, Module};
12use compose_macros::func;
13use compose_macros::scope;
14use compose_syntax::Span;
15use ecow::{EcoString, eco_format};
16use std::{fmt, iter};
17
18#[derive(Debug, Clone, PartialEq)]
19pub enum Value {
20    Int(i64),
21    Bool(bool),
22    Unit(UnitValue),
23    Str(Str),
24    Func(Func),
25    Type(Type),
26    Iterator(IterValue),
27    Box(Boxed),
28    Array(ArrayValue),
29    Range(RangeValue),
30    Map(MapValue),
31    Module(Module),
32}
33
34#[scope]
35impl Value {
36    #[func(name = "to_string")]
37    pub fn to_string(self, vm: &dyn Vm) -> EcoString {
38        self.repr(vm)
39    }
40
41    #[func(name = "clone")]
42    pub fn shallow_clone(self, vm: &mut dyn Vm) -> StrResult<Self> {
43        Ok(match self {
44            Value::Int(v) => Value::Int(v),
45            Value::Bool(v) => Value::Bool(v),
46            Value::Unit(v) => Value::Unit(v),
47            Value::Str(v) => Value::Str(v),
48            Value::Func(v) => Value::Func(v),
49            Value::Type(v) => Value::Type(v),
50            Value::Iterator(v) => Value::Iterator(v.shallow_clone(vm)),
51            Value::Box(v) => Value::Box(v.shallow_clone(vm)),
52            Value::Array(v) => Value::Array(v.shallow_clone(vm)),
53            Value::Range(v) => Value::Range(v),
54            Value::Map(v) => Value::Map(v.shallow_clone(vm)),
55            Value::Module(v) => Value::Module(v.clone()),
56        })
57    }
58
59    #[func]
60    pub fn tap(self, vm: &mut dyn Vm, side_effect: Func) -> SourceResult<Self> {
61        vm.call_func(
62            &side_effect,
63            Args::new(side_effect.span, iter::once(self.clone())),
64        )?;
65        Ok(self)
66    }
67
68    #[func]
69    pub fn pipe(self, vm: &mut dyn Vm, transform: Func) -> SourceResult<Self> {
70        vm.call_func(&transform, Args::new(transform.span, iter::once(self)))
71    }
72}
73
74impl Value {
75    pub fn is_box(&self) -> bool {
76        matches!(self, Value::Box(_))
77    }
78}
79
80impl Value {
81    pub fn ty(&self) -> Type {
82        match self {
83            Value::Int(_) => Type::of::<i64>(),
84            Value::Bool(_) => Type::of::<bool>(),
85            Value::Unit(_) => Type::of::<UnitValue>(),
86            Value::Str(_) => Type::of::<Str>(),
87            Value::Func(_) => Type::of::<Func>(),
88            Value::Type(_) => Type::of::<Type>(),
89            Value::Iterator(_) => Type::of::<IterValue>(),
90            Value::Box(_) => Type::of::<Boxed>(),
91            Value::Array(_) => Type::of::<ArrayValue>(),
92            Value::Range(_) => Type::of::<RangeValue>(),
93            Value::Map(_) => Type::of::<MapValue>(),
94            Value::Module(_) => Type::of::<Module>(),
95        }
96    }
97
98    pub fn unit() -> Value {
99        Value::Unit(UnitValue)
100    }
101
102    pub fn cast<T: FromValue>(self) -> StrResult<T> {
103        T::from_value(self)
104    }
105
106    pub fn spanned(self, span: Span) -> Self {
107        match self {
108            Value::Func(v) => Value::Func(v.spanned(span)),
109            _ => self,
110        }
111    }
112
113    pub fn named(self, name: Spanned<EcoString>) -> Self {
114        match self {
115            Value::Func(v) => Value::Func(v.named(name)),
116            _ => self,
117        }
118    }
119
120    pub fn resolved(self) -> SourceResult<Self> {
121        match self {
122            Value::Func(f) => {
123                f.resolve()?;
124                Ok(Value::Func(f))
125            }
126            _ => Ok(self),
127        }
128    }
129
130    /// Access a field on this value (with dot syntax) `a.b`
131    pub fn field(&self, field: &str, access_span: Span, sink: &mut Sink) -> StrResult<Value> {
132        let field_value = match self {
133            Self::Func(func) => func.field(field, access_span, sink).cloned(),
134            Self::Type(ty) => ty.field(field, access_span, sink).cloned(),
135            _ => Err(error!(
136                "no field or method named `{}` on `{}`",
137                field,
138                self.ty()
139            )),
140        };
141
142        if let Ok(field_value) = field_value {
143            return Ok(field_value);
144        }
145
146        // Get the field from the type
147        let type_field_value = self.ty().field(field, access_span, sink).cloned();
148        if let Ok(type_field_value) = type_field_value {
149            return Ok(type_field_value);
150        }
151
152        // Try and get the type from Value itself
153        let self_field_value = Value::scope()
154            .get(field)
155            .map(|b| b.read_checked(access_span, sink))
156            .cloned();
157
158        match self_field_value {
159            None => bail!("no field or method named `{}` on `{}`", field, self.ty()),
160            Some(v) => Ok(v),
161        }
162    }
163
164    /// Access an associated value of this value by path syntax `a::b`
165    pub fn path(
166        &self,
167        path: &str,
168        access_span: Span,
169        sink: &mut Sink,
170        ctx: &SyntaxContext,
171    ) -> SourceResult<Value> {
172        match self {
173            Self::Type(ty) => ty.path(path, access_span, sink).cloned().at(access_span),
174            Self::Func(func) => func.path(path, access_span, sink).cloned().at(access_span),
175            Self::Module(module) => module.path(path, access_span, sink, ctx).cloned(),
176            _ => bail!(
177                access_span,
178                "no associated field or method named `{}` on `{}`",
179                path,
180                self.ty()
181            ),
182        }
183    }
184}
185
186impl fmt::Display for Value {
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188        match self {
189            Value::Int(v) => write!(f, "{}", v),
190            Value::Bool(v) => write!(f, "{}", v),
191            Value::Unit(_) => write!(f, "()"),
192            Value::Str(v) => write!(f, "{}", v),
193            Value::Func(v) => write!(f, "{}", v),
194            Value::Type(v) => write!(f, "{}", v),
195            Value::Iterator(v) => write!(f, "{:?}", v),
196            Value::Box(v) => write!(f, "{}", v),
197            Value::Array(v) => write!(f, "{:?}", v),
198            Value::Range(v) => write!(f, "{:?}", v),
199            Value::Map(v) => write!(f, "{:?}", v),
200            Value::Module(v) => write!(f, "{}", v.name()),
201        }
202    }
203}
204
205impl Repr for Value {
206    fn repr(&self, vm: &dyn Vm) -> EcoString {
207        match self {
208            Value::Int(v) => eco_format!("{v}"),
209            Value::Bool(v) => eco_format!("{v}"),
210            Value::Unit(_) => eco_format!("()"),
211            Value::Str(v) => v.repr(vm),
212            Value::Func(v) => eco_format!("{v}"),
213            Value::Type(v) => eco_format!("{v}"),
214            Value::Iterator(v) => eco_format!("iterator({v:?})"),
215            Value::Box(v) => eco_format!("{v}"),
216            Value::Array(v) => v.repr(vm),
217            Value::Range(r) => r.repr(vm),
218            Value::Map(m) => m.repr(vm),
219            Value::Module(m) => m.name().clone(),
220        }
221    }
222}
223
224impl Default for Value {
225    fn default() -> Self {
226        Value::Unit(UnitValue)
227    }
228}
229
230/// Implements traits for primitives (Value enum variants).
231macro_rules! primitive {
232    (
233        $ty:ty: $name:literal, $variant:ident
234        $(, $other:ident$(($binding:ident))? => $out:expr)*
235    ) => {
236        impl Reflect for $ty {
237            fn input() -> CastInfo {
238                CastInfo::Type(Type::of::<Self>())
239            }
240
241            fn output() -> CastInfo {
242                CastInfo::Type(Type::of::<Self>())
243            }
244
245            fn castable(value: &Value) -> bool {
246                matches!(value, Value::$variant(_)
247                    $(|  primitive!(@$other $(($binding))?))*)
248            }
249        }
250
251        impl IntoValue for $ty {
252            fn into_value(self) -> Value {
253                Value::$variant(self)
254            }
255        }
256
257        impl FromValue for $ty {
258            fn from_value(value: Value) -> StrResult<Self> {
259                match value {
260                    Value::$variant(v) => Ok(v),
261                    $(Value::$other$(($binding))? => Ok($out),)*
262                    v => Err(<Self as Reflect>::error(&v)),
263                }
264            }
265        }
266    };
267
268    (@$other:ident($binding:ident)) => { Value::$other(_) };
269    (@$other:ident) => { Value::$other };
270}
271
272primitive!(i64: "Int", Int);
273primitive!(bool: "Bool", Bool);
274primitive!(Str: "Str", Str);
275primitive!(Func: "Func", Func);
276primitive!(Type: "Type", Type);
277primitive!(UnitValue: "Unit", Unit);
278primitive!(IterValue: "Iterator", Iterator);
279primitive!(Boxed: "Box", Box);
280primitive!(ArrayValue: "Array", Array);
281primitive!(RangeValue: "Range", Range);
282primitive!(MapValue: "Map", Map);
283primitive!(Module: "Module", Module);