1use std::{
2 collections::BTreeMap,
3 sync::{Arc, OnceLock},
4};
5
6use sim_kernel::{
7 Args, Callable, Cx, Error, Expr, Object, ObjectCompat, Result, Shape, Symbol, Value,
8};
9
10use crate::{AdtShape, VariantShape};
11
12#[derive(Clone)]
19pub struct PatternField {
20 name: Symbol,
21 shape: Arc<dyn Shape>,
22}
23
24impl PatternField {
25 pub fn new(name: Symbol, shape: Arc<dyn Shape>) -> Self {
27 Self { name, shape }
28 }
29
30 pub fn name(&self) -> &Symbol {
32 &self.name
33 }
34
35 pub fn shape(&self) -> &Arc<dyn Shape> {
37 &self.shape
38 }
39}
40
41#[derive(Clone)]
43pub struct VariantDeclaration {
44 symbol: Symbol,
45 fields: Vec<PatternField>,
46}
47
48impl VariantDeclaration {
49 pub fn new(symbol: Symbol, fields: Vec<PatternField>) -> Self {
51 Self { symbol, fields }
52 }
53
54 pub fn nullary(symbol: Symbol) -> Self {
56 Self {
57 symbol,
58 fields: Vec::new(),
59 }
60 }
61
62 pub fn symbol(&self) -> &Symbol {
64 &self.symbol
65 }
66
67 pub fn fields(&self) -> &[PatternField] {
69 &self.fields
70 }
71}
72
73#[derive(Clone)]
102pub struct AlgebraicDataType {
103 symbol: Symbol,
104 variants: BTreeMap<Symbol, VariantDeclaration>,
105}
106
107impl AlgebraicDataType {
108 pub fn new(symbol: Symbol, variants: Vec<VariantDeclaration>) -> Result<Self> {
114 let mut by_symbol = BTreeMap::new();
115 for variant in variants {
116 if by_symbol
117 .insert(variant.symbol().clone(), variant.clone())
118 .is_some()
119 {
120 return Err(Error::Eval(format!(
121 "duplicate ADT variant {}",
122 variant.symbol()
123 )));
124 }
125 }
126 Ok(Self {
127 symbol,
128 variants: by_symbol,
129 })
130 }
131
132 pub fn symbol(&self) -> &Symbol {
134 &self.symbol
135 }
136
137 pub fn variants(&self) -> impl Iterator<Item = &VariantDeclaration> {
139 self.variants.values()
140 }
141
142 pub fn constructor(&self, variant: &Symbol) -> Option<VariantConstructor> {
144 self.variants
145 .get(variant)
146 .cloned()
147 .map(|variant| VariantConstructor::new(self.symbol.clone(), variant))
148 }
149
150 pub fn constructors(&self) -> Vec<VariantConstructor> {
152 self.variants
153 .values()
154 .cloned()
155 .map(|variant| VariantConstructor::new(self.symbol.clone(), variant))
156 .collect()
157 }
158
159 pub fn shape(&self) -> Arc<dyn Shape> {
161 Arc::new(AdtShape::new(
162 self.symbol.clone(),
163 self.constructors()
164 .into_iter()
165 .map(|constructor| constructor.variant_shape())
166 .collect(),
167 ))
168 }
169}
170
171#[derive(Clone)]
177pub struct VariantConstructor {
178 adt: Symbol,
179 variant: VariantDeclaration,
180}
181
182impl VariantConstructor {
183 pub fn new(adt: Symbol, variant: VariantDeclaration) -> Self {
185 Self { adt, variant }
186 }
187
188 pub fn adt(&self) -> &Symbol {
190 &self.adt
191 }
192
193 pub fn variant(&self) -> &Symbol {
195 self.variant.symbol()
196 }
197
198 pub fn fields(&self) -> &[PatternField] {
200 self.variant.fields()
201 }
202
203 pub fn variant_shape(&self) -> VariantShape {
205 VariantShape::new(
206 self.adt.clone(),
207 self.variant.symbol().clone(),
208 self.variant.fields().to_vec(),
209 )
210 }
211
212 pub fn shape(&self) -> Arc<dyn Shape> {
214 Arc::new(self.variant_shape())
215 }
216
217 pub fn construct(&self, cx: &mut Cx, fields: Vec<Value>) -> Result<Value> {
224 if fields.len() != self.variant.fields().len() {
225 return Err(Error::Eval(format!(
226 "constructor {} expected {} fields, got {}",
227 self.variant.symbol(),
228 self.variant.fields().len(),
229 fields.len()
230 )));
231 }
232 for (field, value) in self.variant.fields().iter().zip(fields.iter()) {
233 let matched = field.shape().check_value(cx, value.clone())?;
234 if !matched.accepted {
235 return Err(Error::Eval(format!(
236 "constructor {} rejected field {}: {}",
237 self.variant.symbol(),
238 field.name(),
239 diagnostic_summary(&matched.diagnostics)
240 )));
241 }
242 }
243 let fields = self
244 .variant
245 .fields()
246 .iter()
247 .map(|field| field.name().clone())
248 .zip(fields)
249 .collect();
250 cx.factory().opaque(Arc::new(TaggedValue::new(
251 self.adt.clone(),
252 self.variant.symbol().clone(),
253 fields,
254 )))
255 }
256
257 pub fn as_value(&self, cx: &mut Cx) -> Result<Value> {
259 cx.factory().opaque(Arc::new(self.clone()))
260 }
261}
262
263impl Object for VariantConstructor {
264 fn display(&self, _cx: &mut Cx) -> Result<String> {
265 Ok(format!("#<constructor {}>", self.variant.symbol()))
266 }
267
268 fn as_any(&self) -> &dyn std::any::Any {
269 self
270 }
271}
272
273impl ObjectCompat for VariantConstructor {
274 fn as_callable(&self) -> Option<&dyn Callable> {
275 Some(self)
276 }
277
278 fn as_table(&self, cx: &mut Cx) -> Result<Value> {
279 cx.factory().table(vec![
280 (Symbol::new("adt"), cx.factory().symbol(self.adt().clone())?),
281 (
282 Symbol::new("variant"),
283 cx.factory().symbol(self.variant().clone())?,
284 ),
285 (
286 Symbol::new("arity"),
287 cx.factory().number_literal(
288 Symbol::qualified("numbers", "f64"),
289 self.fields().len().to_string(),
290 )?,
291 ),
292 ])
293 }
294}
295
296impl Callable for VariantConstructor {
297 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
298 self.construct(cx, args.into_vec())
299 }
300}
301
302#[sim_citizen_derive::non_citizen(
303 reason = "dynamic ADT variant value; canonical data is the variant symbol and field table",
304 kind = "marker"
305)]
306#[derive(Clone)]
312pub struct TaggedValue {
313 adt: Symbol,
314 variant: Symbol,
315 fields: Vec<(Symbol, Value)>,
316 header: OnceLock<sim_kernel::ObjectHeader>,
317}
318
319impl TaggedValue {
320 pub fn new(adt: Symbol, variant: Symbol, fields: Vec<(Symbol, Value)>) -> Self {
322 Self {
323 adt,
324 variant,
325 fields,
326 header: OnceLock::new(),
327 }
328 }
329
330 pub fn adt(&self) -> &Symbol {
332 &self.adt
333 }
334
335 pub fn variant(&self) -> &Symbol {
337 &self.variant
338 }
339
340 pub fn fields(&self) -> &[(Symbol, Value)] {
342 &self.fields
343 }
344
345 pub fn field(&self, name: &Symbol) -> Option<&Value> {
347 self.fields
348 .iter()
349 .find_map(|(field, value)| (field == name).then_some(value))
350 }
351}
352
353impl Object for TaggedValue {
354 fn header(&self) -> &sim_kernel::ObjectHeader {
355 self.header.get_or_init(|| sim_kernel::ObjectHeader {
356 id: sim_kernel::Ref::Symbol(self.variant.clone()),
357 kind: Symbol::qualified("pattern", "tagged-value"),
358 trust: sim_kernel::TrustLevel::HostInternal,
359 })
360 }
361
362 fn display(&self, _cx: &mut Cx) -> Result<String> {
363 Ok(format!("#<{} {}>", self.adt, self.variant))
364 }
365
366 fn as_any(&self) -> &dyn std::any::Any {
367 self
368 }
369}
370
371impl ObjectCompat for TaggedValue {
372 fn as_table(&self, cx: &mut Cx) -> Result<Value> {
373 let fields = self
374 .fields
375 .iter()
376 .map(|(name, value)| (name.clone(), value.clone()))
377 .collect();
378 let fields = cx.factory().table(fields)?;
379 cx.factory().table(vec![
380 (Symbol::new("adt"), cx.factory().symbol(self.adt.clone())?),
381 (
382 Symbol::new("variant"),
383 cx.factory().symbol(self.variant.clone())?,
384 ),
385 (Symbol::new("fields"), fields),
386 ])
387 }
388
389 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
390 let args = self
391 .fields
392 .iter()
393 .map(|(_, value)| value.object().as_expr(cx))
394 .collect::<Result<Vec<_>>>()?;
395 Ok(Expr::Call {
396 operator: Box::new(Expr::Symbol(self.variant.clone())),
397 args,
398 })
399 }
400}
401
402pub fn tagged_value(value: &Value) -> Option<&TaggedValue> {
404 value.object().downcast_ref::<TaggedValue>()
405}
406
407fn diagnostic_summary(diagnostics: &[sim_kernel::Diagnostic]) -> String {
408 diagnostics
409 .first()
410 .map(|diagnostic| diagnostic.message.clone())
411 .unwrap_or_else(|| "field shape rejected value".to_owned())
412}