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, Heap, 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
117 other @ (Value::Int(_)
118 | Value::Bool(_)
119 | Value::Unit(_)
120 | Value::Str(_)
121 | Value::Type(_)
122 | Value::Iterator(_)
123 | Value::Box(_)
124 | Value::Array(_)
125 | Value::Range(_)
126 | Value::Map(_)
127 | Value::Module(_)) => other,
128 }
129 }
130
131 pub fn resolved(self) -> SourceResult<Self> {
132 match self {
133 Value::Func(f) => {
134 f.resolve()?;
135 Ok(Value::Func(f))
136 }
137 _ => Ok(self),
138 }
139 }
140
141 pub fn field(&self, field: &str, access_span: Span, sink: &mut Sink) -> StrResult<Value> {
143 let field_value = match self {
144 Self::Func(func) => func.field(field, access_span, sink).cloned(),
145 Self::Type(ty) => ty.field(field, access_span, sink).cloned(),
146 _ => Err(error!(
147 "no field or method named `{}` on `{}`",
148 field,
149 self.ty()
150 )),
151 };
152
153 if let Ok(field_value) = field_value {
154 return Ok(field_value);
155 }
156
157 let type_field_value = self.ty().field(field, access_span, sink).cloned();
159 if let Ok(type_field_value) = type_field_value {
160 return Ok(type_field_value);
161 }
162
163 let self_field_value = Value::scope()
165 .get(field)
166 .map(|b| b.read_checked(access_span, sink))
167 .cloned();
168
169 match self_field_value {
170 None => bail!("no field or method named `{}` on `{}`", field, self.ty()),
171 Some(v) => Ok(v),
172 }
173 }
174
175 pub fn index(&self, index: Value, target_span: Span, index_span: Span, heap: &Heap) -> SourceResult<Option<Value>> {
176 match self {
177 Value::Array(arr) => arr.index(index, index_span, heap),
178 _ => bail!(target_span, "cannot index into `{}`", self.ty()),
179 }
180 }
181
182 pub fn path(
184 &self,
185 path: &str,
186 access_span: Span,
187 sink: &mut Sink,
188 ctx: &SyntaxContext,
189 ) -> SourceResult<Value> {
190 match self {
191 Self::Type(ty) => ty.path(path, access_span, sink).cloned().at(access_span),
192 Self::Func(func) => func.path(path, access_span, sink).cloned().at(access_span),
193 Self::Module(module) => module.path(path, access_span, sink, ctx).cloned(),
194 _ => bail!(
195 access_span,
196 "no associated field or method named `{}` on `{}`",
197 path,
198 self.ty()
199 ),
200 }
201 }
202
203}
204
205impl fmt::Display for Value {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 match self {
208 Value::Int(v) => write!(f, "{}", v),
209 Value::Bool(v) => write!(f, "{}", v),
210 Value::Unit(_) => write!(f, "()"),
211 Value::Str(v) => write!(f, "{}", v),
212 Value::Func(v) => write!(f, "{}", v),
213 Value::Type(v) => write!(f, "{}", v),
214 Value::Iterator(v) => write!(f, "{:?}", v),
215 Value::Box(v) => write!(f, "{}", v),
216 Value::Array(v) => write!(f, "{:?}", v),
217 Value::Range(v) => write!(f, "{:?}", v),
218 Value::Map(v) => write!(f, "{:?}", v),
219 Value::Module(v) => write!(f, "{}", v.name()),
220 }
221 }
222}
223
224impl Repr for Value {
225 fn repr(&self, vm: &dyn Vm) -> EcoString {
226 match self {
227 Value::Int(v) => eco_format!("{v}"),
228 Value::Bool(v) => eco_format!("{v}"),
229 Value::Unit(_) => eco_format!("()"),
230 Value::Str(v) => v.repr(vm),
231 Value::Func(v) => eco_format!("{v}"),
232 Value::Type(v) => eco_format!("{v}"),
233 Value::Iterator(v) => eco_format!("iterator({v:?})"),
234 Value::Box(v) => eco_format!("{v}"),
235 Value::Array(v) => v.repr(vm),
236 Value::Range(r) => r.repr(vm),
237 Value::Map(m) => m.repr(vm),
238 Value::Module(m) => m.name().clone(),
239 }
240 }
241}
242
243impl Default for Value {
244 fn default() -> Self {
245 Value::Unit(UnitValue)
246 }
247}
248
249macro_rules! primitive {
251 (
252 $ty:ty: $name:literal, $variant:ident
253 $(, $other:ident$(($binding:ident))? => $out:expr)*
254 ) => {
255 impl Reflect for $ty {
256 fn input() -> CastInfo {
257 CastInfo::Type(Type::of::<Self>())
258 }
259
260 fn output() -> CastInfo {
261 CastInfo::Type(Type::of::<Self>())
262 }
263
264 fn castable(value: &Value) -> bool {
265 matches!(value, Value::$variant(_)
266 $(| primitive!(@$other $(($binding))?))*)
267 }
268 }
269
270 impl IntoValue for $ty {
271 fn into_value(self) -> Value {
272 Value::$variant(self)
273 }
274 }
275
276 impl FromValue for $ty {
277 fn from_value(value: Value) -> StrResult<Self> {
278 match value {
279 Value::$variant(v) => Ok(v),
280 $(Value::$other$(($binding))? => Ok($out),)*
281 v => Err(<Self as Reflect>::error(&v)),
282 }
283 }
284 }
285 };
286
287 (@$other:ident($binding:ident)) => { Value::$other(_) };
288 (@$other:ident) => { Value::$other };
289}
290
291primitive!(i64: "Int", Int);
292primitive!(bool: "Bool", Bool);
293primitive!(Str: "Str", Str);
294primitive!(Func: "Func", Func);
295primitive!(Type: "Type", Type);
296primitive!(UnitValue: "Unit", Unit);
297primitive!(IterValue: "Iterator", Iterator);
298primitive!(Boxed: "Box", Box);
299primitive!(ArrayValue: "Array", Array);
300primitive!(RangeValue: "Range", Range);
301primitive!(MapValue: "Map", Map);
302primitive!(Module: "Module", Module);