sim_shape/primitives/combinators/
capture.rs1use std::sync::Arc;
4
5use sim_kernel::{Cx, Expr, Result, ShapeRef, Symbol, Value, shape_is_subshape_of};
6
7use crate::base::{Shape, ShapeDoc, ShapeMatch};
8use crate::diagnostics::{binding_failure_diagnostic, expr_actual_label};
9
10pub struct CaptureShape {
16 name: Symbol,
17 inner: Arc<dyn Shape>,
18}
19
20impl CaptureShape {
21 pub fn new(name: Symbol, inner: Arc<dyn Shape>) -> Self {
23 Self { name, inner }
24 }
25
26 pub fn name(&self) -> &Symbol {
28 &self.name
29 }
30
31 pub fn inner(&self) -> &Arc<dyn Shape> {
33 &self.inner
34 }
35}
36
37impl Shape for CaptureShape {
38 fn parents(&self, _cx: &mut Cx) -> Result<Vec<ShapeRef>> {
39 Ok(vec![crate::functions::shape_value(
40 Symbol::qualified("shape-capture-parent", self.name.to_string()),
41 self.inner.clone(),
42 )])
43 }
44
45 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
46 shape_is_subshape_of(cx, self.inner.as_ref(), parent).map(Some)
47 }
48
49 fn is_total(&self) -> bool {
50 self.inner.is_total()
51 }
52
53 fn is_effectful(&self) -> bool {
54 self.inner.is_effectful()
55 }
56
57 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
58 let mut matched = self.inner.check_value(cx, value.clone())?;
59 if matched.accepted {
60 matched.captures.bind_value(self.name.clone(), value);
61 if !self.inner.is_total()
62 && let Ok(expr) = matched
63 .captures
64 .values()
65 .last()
66 .expect("just bound value capture")
67 .1
68 .object()
69 .as_expr(cx)
70 {
71 matched.captures.bind_expr(self.name.clone(), expr);
72 }
73 } else {
74 matched.diagnostics.insert(
75 0,
76 binding_failure_diagnostic(&self.name, "captured value", "rejected value"),
77 );
78 }
79 Ok(matched)
80 }
81
82 fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
83 let mut matched = self.inner.check_expr(cx, expr)?;
84 if matched.accepted {
85 matched.captures.bind_expr(self.name.clone(), expr.clone());
86 } else {
87 matched.diagnostics.insert(
88 0,
89 binding_failure_diagnostic(
90 &self.name,
91 "captured expression",
92 expr_actual_label(expr),
93 ),
94 );
95 }
96 Ok(matched)
97 }
98
99 fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
100 let inner = self.inner.describe(cx)?;
101 Ok(ShapeDoc::new(format!("capture {}", self.name)).with_detail(inner.name))
102 }
103}