1use sim_kernel::{CapabilityName, Expr, Ref, Symbol};
4use sim_value::capability_names_from_expr;
5
6use crate::fidelity::{FidelityBadge, expr_kind, symbol_from_expr};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct OrganUse {
11 pub organ: Symbol,
13 pub options: Vec<(Symbol, Expr)>,
15}
16
17impl OrganUse {
18 pub fn new(organ: Symbol) -> Self {
20 Self {
21 organ,
22 options: Vec::new(),
23 }
24 }
25
26 pub fn with_option(mut self, key: Symbol, value: Expr) -> Self {
28 self.options.push((key, value));
29 self
30 }
31
32 pub fn to_expr(&self) -> Expr {
34 Expr::List(vec![
35 Expr::Symbol(self.organ.clone()),
36 Expr::Map(
37 self.options
38 .iter()
39 .map(|(key, value)| (Expr::Symbol(key.clone()), value.clone()))
40 .collect(),
41 ),
42 ])
43 }
44
45 pub fn from_expr(expr: &Expr) -> sim_kernel::Result<Self> {
47 let Expr::List(items) = expr else {
48 return Err(sim_kernel::Error::TypeMismatch {
49 expected: "organ-use list",
50 found: expr_kind(expr),
51 });
52 };
53 let [organ, options] = items.as_slice() else {
54 return Err(sim_kernel::Error::Eval(
55 "organ use expects organ symbol and option map".to_owned(),
56 ));
57 };
58 let Expr::Map(entries) = options else {
59 return Err(sim_kernel::Error::TypeMismatch {
60 expected: "organ-use option map",
61 found: expr_kind(options),
62 });
63 };
64 Ok(Self {
65 organ: symbol_from_expr(organ, "organ symbol")?,
66 options: entries
67 .iter()
68 .map(|(key, value)| Ok((symbol_from_expr(key, "option symbol")?, value.clone())))
69 .collect::<sim_kernel::Result<Vec<_>>>()?,
70 })
71 }
72}
73
74#[derive(Clone, Debug, PartialEq, Eq)]
95pub struct LanguageProfile {
96 pub symbol: Symbol,
98 pub reader: Symbol,
100 pub lowering: Symbol,
102 pub eval_policy: Symbol,
104 pub organs: Vec<OrganUse>,
106 pub backing_requirements: Vec<Symbol>,
109 pub numeric_tower: Option<Symbol>,
111 pub capabilities: Vec<CapabilityName>,
113 pub unsupported_forms: Vec<Symbol>,
115 pub conformance_tests: Vec<Symbol>,
117 pub fidelity_badges: Vec<FidelityBadge>,
119}
120
121impl LanguageProfile {
122 pub fn new(symbol: Symbol) -> Self {
125 Self {
126 symbol,
127 reader: unspecified_symbol("reader"),
128 lowering: unspecified_symbol("lowering"),
129 eval_policy: unspecified_symbol("eval-policy"),
130 organs: Vec::new(),
131 backing_requirements: Vec::new(),
132 numeric_tower: None,
133 capabilities: Vec::new(),
134 unsupported_forms: Vec::new(),
135 conformance_tests: Vec::new(),
136 fidelity_badges: Vec::new(),
137 }
138 }
139
140 pub fn with_reader(mut self, reader: Symbol) -> Self {
142 self.reader = reader;
143 self
144 }
145
146 pub fn with_lowering(mut self, lowering: Symbol) -> Self {
148 self.lowering = lowering;
149 self
150 }
151
152 pub fn with_eval_policy(mut self, eval_policy: Symbol) -> Self {
154 self.eval_policy = eval_policy;
155 self
156 }
157
158 pub fn with_organ(mut self, organ: OrganUse) -> Self {
160 self.organs.push(organ);
161 self
162 }
163
164 pub fn with_backing_requirement(mut self, manifest: Symbol) -> Self {
166 self.backing_requirements.push(manifest);
167 self
168 }
169
170 pub fn with_numeric_tower(mut self, numeric_tower: Symbol) -> Self {
172 self.numeric_tower = Some(numeric_tower);
173 self
174 }
175
176 pub fn requiring(mut self, capability: CapabilityName) -> Self {
178 self.capabilities.push(capability);
179 self
180 }
181
182 pub fn with_unsupported_form(mut self, form: Symbol) -> Self {
184 self.unsupported_forms.push(form);
185 self
186 }
187
188 pub fn with_conformance_test(mut self, test: Symbol) -> Self {
190 self.conformance_tests.push(test);
191 self
192 }
193
194 pub fn with_fidelity_badge(mut self, badge: FidelityBadge) -> Self {
196 self.fidelity_badges.push(badge);
197 self
198 }
199
200 pub fn to_constructor_args(&self) -> Vec<Expr> {
202 vec![
203 Expr::Symbol(self.symbol.clone()),
204 Expr::Symbol(self.reader.clone()),
205 Expr::Symbol(self.lowering.clone()),
206 Expr::Symbol(self.eval_policy.clone()),
207 Expr::List(self.organs.iter().map(OrganUse::to_expr).collect()),
208 Expr::List(
209 self.backing_requirements
210 .iter()
211 .cloned()
212 .map(Expr::Symbol)
213 .collect(),
214 ),
215 self.numeric_tower
216 .clone()
217 .map(Expr::Symbol)
218 .unwrap_or(Expr::Nil),
219 Expr::List(
220 self.capabilities
221 .iter()
222 .map(|capability| Expr::String(capability.as_str().to_owned()))
223 .collect(),
224 ),
225 Expr::List(
226 self.unsupported_forms
227 .iter()
228 .cloned()
229 .map(Expr::Symbol)
230 .collect(),
231 ),
232 Expr::List(
233 self.conformance_tests
234 .iter()
235 .cloned()
236 .map(Expr::Symbol)
237 .collect(),
238 ),
239 Expr::List(
240 self.fidelity_badges
241 .iter()
242 .map(|badge| Expr::Call {
243 operator: Box::new(Expr::Symbol(crate::fidelity_badge_class_symbol())),
244 args: badge.to_constructor_args(),
245 })
246 .collect(),
247 ),
248 ]
249 }
250
251 pub fn from_constructor_args(args: Vec<Expr>) -> sim_kernel::Result<Self> {
253 let [
254 symbol,
255 reader,
256 lowering,
257 eval_policy,
258 organs,
259 backing_requirements,
260 numeric_tower,
261 capabilities,
262 unsupported_forms,
263 conformance_tests,
264 fidelity_badges,
265 ] = args.as_slice()
266 else {
267 return Err(sim_kernel::Error::Eval(
268 "standard/Profile expects eleven constructor arguments".to_owned(),
269 ));
270 };
271
272 Ok(Self {
273 symbol: symbol_from_expr(symbol, "profile symbol")?,
274 reader: symbol_from_expr(reader, "reader symbol")?,
275 lowering: symbol_from_expr(lowering, "lowering symbol")?,
276 eval_policy: symbol_from_expr(eval_policy, "eval policy symbol")?,
277 organs: organ_uses_from_expr(organs)?,
278 backing_requirements: symbols_from_expr(
279 backing_requirements,
280 "backing library symbol",
281 )?,
282 numeric_tower: optional_symbol(numeric_tower)?,
283 capabilities: capabilities_from_expr(capabilities)?,
284 unsupported_forms: symbols_from_expr(unsupported_forms, "unsupported form")?,
285 conformance_tests: symbols_from_expr(conformance_tests, "conformance test")?,
286 fidelity_badges: badges_from_expr(fidelity_badges)?,
287 })
288 }
289}
290
291pub fn language_profile_class_symbol() -> Symbol {
293 Symbol::qualified("standard", "Profile")
294}
295
296pub fn sim_expression_profile_symbol() -> Symbol {
298 Symbol::qualified("lang", "sim-expression/v1")
299}
300
301pub fn sim_expression_profile() -> LanguageProfile {
304 let profile = sim_expression_profile_symbol();
305 let test = Symbol::qualified("test", "sim-expression-core");
306 LanguageProfile::new(profile.clone())
307 .with_reader(Symbol::qualified("codec", "lisp"))
308 .with_lowering(Symbol::qualified("standard", "identity-lowering"))
309 .with_eval_policy(Symbol::qualified("eval", "default"))
310 .with_organ(OrganUse::new(standard_control_organ_symbol()))
311 .with_organ(OrganUse::new(standard_binding_organ_symbol()))
312 .with_organ(OrganUse::new(standard_sequence_organ_symbol()))
313 .with_organ(OrganUse::new(standard_pattern_organ_symbol()))
314 .with_numeric_tower(Symbol::qualified("numbers", "sim-expression"))
315 .with_conformance_test(test.clone())
316 .with_fidelity_badge(FidelityBadge::new(
317 Ref::Symbol(profile),
318 Symbol::qualified("standard", "host-native"),
319 1,
320 Ref::Symbol(test),
321 ))
322}
323
324pub fn standard_control_organ_symbol() -> Symbol {
326 Symbol::qualified("organ", "control")
327}
328
329pub fn standard_binding_organ_symbol() -> Symbol {
331 Symbol::qualified("organ", "binding")
332}
333
334pub fn standard_sequence_organ_symbol() -> Symbol {
336 Symbol::qualified("organ", "sequence")
337}
338
339pub fn standard_pattern_organ_symbol() -> Symbol {
341 Symbol::qualified("organ", "pattern")
342}
343
344fn unspecified_symbol(name: &str) -> Symbol {
345 Symbol::qualified("standard/unspecified", name.to_owned())
346}
347
348fn optional_symbol(expr: &Expr) -> sim_kernel::Result<Option<Symbol>> {
349 match expr {
350 Expr::Nil => Ok(None),
351 Expr::Symbol(symbol) => Ok(Some(symbol.clone())),
352 _ => Err(sim_kernel::Error::TypeMismatch {
353 expected: "optional symbol",
354 found: expr_kind(expr),
355 }),
356 }
357}
358
359fn organ_uses_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<OrganUse>> {
360 let Expr::List(items) = expr else {
361 return Err(sim_kernel::Error::TypeMismatch {
362 expected: "organ-use list",
363 found: expr_kind(expr),
364 });
365 };
366 items.iter().map(OrganUse::from_expr).collect()
367}
368
369fn capabilities_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<CapabilityName>> {
370 capability_names_from_expr(expr)
371}
372
373fn symbols_from_expr(expr: &Expr, expected: &'static str) -> sim_kernel::Result<Vec<Symbol>> {
374 let Expr::List(items) = expr else {
375 return Err(sim_kernel::Error::TypeMismatch {
376 expected: "symbol list",
377 found: expr_kind(expr),
378 });
379 };
380 items
381 .iter()
382 .map(|item| symbol_from_expr(item, expected))
383 .collect()
384}
385
386fn badges_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<FidelityBadge>> {
387 let Expr::List(items) = expr else {
388 return Err(sim_kernel::Error::TypeMismatch {
389 expected: "fidelity badge list",
390 found: expr_kind(expr),
391 });
392 };
393 items
394 .iter()
395 .map(|item| match item {
396 Expr::Call { operator, args } => {
397 let class = symbol_from_expr(operator, "badge class")?;
398 if class != crate::fidelity_badge_class_symbol() {
399 return Err(sim_kernel::Error::Eval(format!(
400 "expected standard/FidelityBadge, found {class}"
401 )));
402 }
403 FidelityBadge::from_constructor_args(args.clone())
404 }
405 _ => Err(sim_kernel::Error::TypeMismatch {
406 expected: "fidelity badge constructor call",
407 found: expr_kind(item),
408 }),
409 })
410 .collect()
411}