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 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 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 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 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
230macro_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);