1use std::sync::Arc;
5
6use sim_kernel::{
7 Args, Callable, ClassRef, Cx, DefaultFactory, Expr, Factory, Object, ObjectEncode,
8 ObjectEncoding, RawArgs, Result, ShapeRef, Symbol, Value,
9};
10
11use crate::base::{Shape, ShapeDoc, ShapeMatch};
12
13struct NamedShape {
14 symbol: Symbol,
15 shape: Arc<dyn Shape>,
16}
17
18impl NamedShape {
19 fn new(symbol: Symbol, shape: Arc<dyn Shape>) -> Self {
20 Self { symbol, shape }
21 }
22}
23
24impl Shape for NamedShape {
25 fn id(&self) -> Option<sim_kernel::ShapeId> {
26 self.shape.id()
27 }
28
29 fn symbol(&self) -> Option<Symbol> {
30 Some(self.symbol.clone())
31 }
32
33 fn parents(&self, cx: &mut Cx) -> Result<Vec<ShapeRef>> {
34 self.shape.parents(cx)
35 }
36
37 fn is_effectful(&self) -> bool {
38 self.shape.is_effectful()
39 }
40
41 fn is_total(&self) -> bool {
42 self.shape.is_total()
43 }
44
45 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
46 let parent = parent
47 .as_any()
48 .downcast_ref::<NamedShape>()
49 .map(|parent| parent.shape.as_ref())
50 .unwrap_or(parent);
51 self.shape.is_subshape_of(cx, parent)
52 }
53
54 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
55 self.shape.check_value(cx, value)
56 }
57
58 fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
59 self.shape.check_expr(cx, expr)
60 }
61
62 fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
63 self.shape.describe(cx)
64 }
65}
66
67#[derive(Clone)]
71pub struct ShapeObject {
72 pub symbol: Symbol,
74 pub shape: Arc<dyn Shape>,
76 pub encoding: Option<ObjectEncoding>,
78}
79
80impl ShapeObject {
81 pub fn new(symbol: Symbol, shape: Arc<dyn Shape>) -> Self {
83 Self {
84 symbol,
85 shape,
86 encoding: None,
87 }
88 }
89
90 pub fn with_encoding(symbol: Symbol, shape: Arc<dyn Shape>, encoding: ObjectEncoding) -> Self {
92 Self {
93 symbol,
94 shape,
95 encoding: Some(encoding),
96 }
97 }
98
99 pub fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
101 self.shape.describe(cx)
102 }
103}
104
105impl Object for ShapeObject {
106 fn display(&self, cx: &mut Cx) -> Result<String> {
107 let doc = self.shape.describe(cx)?;
108 Ok(format!("#<shape {} {}>", self.symbol, doc.name))
109 }
110
111 fn as_any(&self) -> &dyn std::any::Any {
112 self
113 }
114}
115
116impl sim_kernel::ObjectCompat for ShapeObject {
117 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
118 if let Some(value) = cx.registry().class_by_symbol(&self.symbol) {
119 return Ok(value.clone());
120 }
121 if let Some(value) = cx
122 .registry()
123 .class_by_symbol(&Symbol::qualified("core", "Shape"))
124 {
125 return Ok(value.clone());
126 }
127 cx.factory().class_stub(
128 sim_kernel::CORE_SHAPE_CLASS_ID,
129 Symbol::qualified("core", "Shape"),
130 )
131 }
132 fn as_expr(&self, _cx: &mut Cx) -> Result<sim_kernel::Expr> {
133 match &self.encoding {
134 Some(ObjectEncoding::Constructor { class, args }) => Ok(sim_kernel::Expr::Call {
135 operator: Box::new(sim_kernel::Expr::Symbol(class.clone())),
136 args: args.clone(),
137 }),
138 _ => Ok(sim_kernel::Expr::Symbol(self.symbol.clone())),
139 }
140 }
141 fn as_table(&self, cx: &mut Cx) -> Result<Value> {
142 let doc = self.shape.describe(cx)?;
143 let mut entries = vec![
144 (Symbol::new("name"), cx.factory().string(doc.name)?),
145 (
146 Symbol::new("effectful"),
147 cx.factory().bool(self.shape.is_effectful())?,
148 ),
149 (
150 Symbol::new("total"),
151 cx.factory().bool(self.shape.is_total())?,
152 ),
153 ];
154 for (index, detail) in doc.details.into_iter().enumerate() {
155 entries.push((
156 Symbol::qualified("detail", index.to_string()),
157 cx.factory().string(detail)?,
158 ));
159 }
160 cx.factory().table(entries)
161 }
162 fn as_shape(&self) -> Option<&dyn Shape> {
163 Some(self.shape.as_ref())
164 }
165 fn as_callable(&self) -> Option<&dyn Callable> {
166 Some(self)
167 }
168 fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
169 self.encoding.as_ref().map(|_| self as &dyn ObjectEncode)
170 }
171}
172
173impl ObjectEncode for ShapeObject {
174 fn object_encoding(&self, _cx: &mut Cx) -> Result<ObjectEncoding> {
175 self.encoding.clone().ok_or_else(|| {
176 sim_kernel::Error::Eval(format!("shape {} has no constructor encoding", self.symbol))
177 })
178 }
179}
180
181impl Callable for ShapeObject {
182 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
183 let [value] = args.values() else {
184 return Err(sim_kernel::Error::Eval(
185 "shape call expects 1 argument".to_owned(),
186 ));
187 };
188 sim_kernel::call_shape(
189 cx,
190 self.shape.as_ref(),
191 sim_kernel::ShapeCallTarget::Value(value.clone()),
192 )
193 }
194
195 fn call_exprs(&self, cx: &mut Cx, args: RawArgs) -> Result<Value> {
196 let [expr] = args.exprs() else {
197 return Err(sim_kernel::Error::Eval(
198 "shape call expects 1 expression".to_owned(),
199 ));
200 };
201 sim_kernel::call_shape(
202 cx,
203 self.shape.as_ref(),
204 sim_kernel::ShapeCallTarget::Expr(expr.clone()),
205 )
206 }
207}
208
209pub fn shape_value(symbol: Symbol, shape: Arc<dyn Shape>) -> Value {
222 DefaultFactory
223 .opaque(Arc::new(ShapeObject::new(
224 symbol.clone(),
225 Arc::new(NamedShape::new(symbol, shape)),
226 )))
227 .expect("shape object should always be boxable")
228}
229
230pub fn shape_value_with_encoding(
233 symbol: Symbol,
234 shape: Arc<dyn Shape>,
235 encoding: ObjectEncoding,
236) -> Value {
237 DefaultFactory
238 .opaque(Arc::new(ShapeObject::with_encoding(
239 symbol, shape, encoding,
240 )))
241 .expect("shape object should always be boxable")
242}