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
17#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct GuestProfileEvidence {
24 pub profile: Symbol,
26 pub reader: Symbol,
28 pub lowering: Symbol,
30 pub eval_policy: Symbol,
32 pub organs: Vec<Symbol>,
34 pub capabilities: Vec<CapabilityName>,
36 pub gaps: Vec<Symbol>,
38}
39
40impl OrganUse {
41 pub fn new(organ: Symbol) -> Self {
43 Self {
44 organ,
45 options: Vec::new(),
46 }
47 }
48
49 pub fn with_option(mut self, key: Symbol, value: Expr) -> Self {
51 self.options.push((key, value));
52 self
53 }
54
55 pub fn to_expr(&self) -> Expr {
57 Expr::List(vec![
58 Expr::Symbol(self.organ.clone()),
59 Expr::Map(
60 self.options
61 .iter()
62 .map(|(key, value)| (Expr::Symbol(key.clone()), value.clone()))
63 .collect(),
64 ),
65 ])
66 }
67
68 pub fn from_expr(expr: &Expr) -> sim_kernel::Result<Self> {
70 let Expr::List(items) = expr else {
71 return Err(sim_kernel::Error::TypeMismatch {
72 expected: "organ-use list",
73 found: expr_kind(expr),
74 });
75 };
76 let [organ, options] = items.as_slice() else {
77 return Err(sim_kernel::Error::Eval(
78 "organ use expects organ symbol and option map".to_owned(),
79 ));
80 };
81 let Expr::Map(entries) = options else {
82 return Err(sim_kernel::Error::TypeMismatch {
83 expected: "organ-use option map",
84 found: expr_kind(options),
85 });
86 };
87 Ok(Self {
88 organ: symbol_from_expr(organ, "organ symbol")?,
89 options: entries
90 .iter()
91 .map(|(key, value)| Ok((symbol_from_expr(key, "option symbol")?, value.clone())))
92 .collect::<sim_kernel::Result<Vec<_>>>()?,
93 })
94 }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
118pub struct LanguageProfile {
119 pub symbol: Symbol,
121 pub reader: Symbol,
123 pub lowering: Symbol,
125 pub eval_policy: Symbol,
127 pub organs: Vec<OrganUse>,
129 pub backing_requirements: Vec<Symbol>,
132 pub numeric_tower: Option<Symbol>,
134 pub capabilities: Vec<CapabilityName>,
136 pub unsupported_forms: Vec<Symbol>,
138 pub conformance_tests: Vec<Symbol>,
140 pub fidelity_badges: Vec<FidelityBadge>,
142}
143
144impl LanguageProfile {
145 pub fn new(symbol: Symbol) -> Self {
148 Self {
149 symbol,
150 reader: unspecified_symbol("reader"),
151 lowering: unspecified_symbol("lowering"),
152 eval_policy: unspecified_symbol("eval-policy"),
153 organs: Vec::new(),
154 backing_requirements: Vec::new(),
155 numeric_tower: None,
156 capabilities: Vec::new(),
157 unsupported_forms: Vec::new(),
158 conformance_tests: Vec::new(),
159 fidelity_badges: Vec::new(),
160 }
161 }
162
163 pub fn with_reader(mut self, reader: Symbol) -> Self {
165 self.reader = reader;
166 self
167 }
168
169 pub fn with_lowering(mut self, lowering: Symbol) -> Self {
171 self.lowering = lowering;
172 self
173 }
174
175 pub fn with_eval_policy(mut self, eval_policy: Symbol) -> Self {
177 self.eval_policy = eval_policy;
178 self
179 }
180
181 pub fn with_organ(mut self, organ: OrganUse) -> Self {
183 self.organs.push(organ);
184 self
185 }
186
187 pub fn with_backing_requirement(mut self, manifest: Symbol) -> Self {
189 self.backing_requirements.push(manifest);
190 self
191 }
192
193 pub fn with_numeric_tower(mut self, numeric_tower: Symbol) -> Self {
195 self.numeric_tower = Some(numeric_tower);
196 self
197 }
198
199 pub fn requiring(mut self, capability: CapabilityName) -> Self {
201 self.capabilities.push(capability);
202 self
203 }
204
205 pub fn with_unsupported_form(mut self, form: Symbol) -> Self {
207 self.unsupported_forms.push(form);
208 self
209 }
210
211 pub fn with_conformance_test(mut self, test: Symbol) -> Self {
213 self.conformance_tests.push(test);
214 self
215 }
216
217 pub fn with_fidelity_badge(mut self, badge: FidelityBadge) -> Self {
219 self.fidelity_badges.push(badge);
220 self
221 }
222
223 pub fn checked_guest_evidence(&self) -> sim_kernel::Result<GuestProfileEvidence> {
229 for (field, symbol) in [
230 ("reader", &self.reader),
231 ("lowering", &self.lowering),
232 ("eval policy", &self.eval_policy),
233 ] {
234 if symbol.namespace.as_deref() == Some("standard/unspecified") {
235 return Err(sim_kernel::Error::Eval(format!(
236 "guest profile {} has no declared {field}",
237 self.symbol
238 )));
239 }
240 }
241 if self.organs.is_empty() {
242 return Err(sim_kernel::Error::Eval(format!(
243 "guest profile {} declares no shared organ uses",
244 self.symbol
245 )));
246 }
247 if self.capabilities.is_empty() {
248 return Err(sim_kernel::Error::Eval(format!(
249 "guest profile {} declares no capability boundary",
250 self.symbol
251 )));
252 }
253 if self.unsupported_forms.is_empty() {
254 return Err(sim_kernel::Error::Eval(format!(
255 "guest profile {} declares no explicit gaps",
256 self.symbol
257 )));
258 }
259 Ok(GuestProfileEvidence {
260 profile: self.symbol.clone(),
261 reader: self.reader.clone(),
262 lowering: self.lowering.clone(),
263 eval_policy: self.eval_policy.clone(),
264 organs: self.organs.iter().map(|use_| use_.organ.clone()).collect(),
265 capabilities: self.capabilities.clone(),
266 gaps: self.unsupported_forms.clone(),
267 })
268 }
269
270 pub fn to_constructor_args(&self) -> Vec<Expr> {
272 vec![
273 Expr::Symbol(self.symbol.clone()),
274 Expr::Symbol(self.reader.clone()),
275 Expr::Symbol(self.lowering.clone()),
276 Expr::Symbol(self.eval_policy.clone()),
277 Expr::List(self.organs.iter().map(OrganUse::to_expr).collect()),
278 Expr::List(
279 self.backing_requirements
280 .iter()
281 .cloned()
282 .map(Expr::Symbol)
283 .collect(),
284 ),
285 self.numeric_tower
286 .clone()
287 .map(Expr::Symbol)
288 .unwrap_or(Expr::Nil),
289 Expr::List(
290 self.capabilities
291 .iter()
292 .map(|capability| Expr::String(capability.as_str().to_owned()))
293 .collect(),
294 ),
295 Expr::List(
296 self.unsupported_forms
297 .iter()
298 .cloned()
299 .map(Expr::Symbol)
300 .collect(),
301 ),
302 Expr::List(
303 self.conformance_tests
304 .iter()
305 .cloned()
306 .map(Expr::Symbol)
307 .collect(),
308 ),
309 Expr::List(
310 self.fidelity_badges
311 .iter()
312 .map(|badge| Expr::Call {
313 operator: Box::new(Expr::Symbol(crate::fidelity_badge_class_symbol())),
314 args: badge.to_constructor_args(),
315 })
316 .collect(),
317 ),
318 ]
319 }
320
321 pub fn from_constructor_args(args: Vec<Expr>) -> sim_kernel::Result<Self> {
323 let [
324 symbol,
325 reader,
326 lowering,
327 eval_policy,
328 organs,
329 backing_requirements,
330 numeric_tower,
331 capabilities,
332 unsupported_forms,
333 conformance_tests,
334 fidelity_badges,
335 ] = args.as_slice()
336 else {
337 return Err(sim_kernel::Error::Eval(
338 "standard/Profile expects eleven constructor arguments".to_owned(),
339 ));
340 };
341
342 Ok(Self {
343 symbol: symbol_from_expr(symbol, "profile symbol")?,
344 reader: symbol_from_expr(reader, "reader symbol")?,
345 lowering: symbol_from_expr(lowering, "lowering symbol")?,
346 eval_policy: symbol_from_expr(eval_policy, "eval policy symbol")?,
347 organs: organ_uses_from_expr(organs)?,
348 backing_requirements: symbols_from_expr(
349 backing_requirements,
350 "backing library symbol",
351 )?,
352 numeric_tower: optional_symbol(numeric_tower)?,
353 capabilities: capabilities_from_expr(capabilities)?,
354 unsupported_forms: symbols_from_expr(unsupported_forms, "unsupported form")?,
355 conformance_tests: symbols_from_expr(conformance_tests, "conformance test")?,
356 fidelity_badges: badges_from_expr(fidelity_badges)?,
357 })
358 }
359}
360
361pub fn language_profile_class_symbol() -> Symbol {
363 Symbol::qualified("standard", "Profile")
364}
365
366pub fn sim_expression_profile_symbol() -> Symbol {
368 Symbol::qualified("lang", "sim-expression/v1")
369}
370
371pub fn sim_expression_profile() -> LanguageProfile {
374 let profile = sim_expression_profile_symbol();
375 let test = Symbol::qualified("test", "sim-expression-core");
376 LanguageProfile::new(profile.clone())
377 .with_reader(Symbol::qualified("codec", "lisp"))
378 .with_lowering(Symbol::qualified("standard", "identity-lowering"))
379 .with_eval_policy(Symbol::qualified("eval", "default"))
380 .with_organ(OrganUse::new(standard_control_organ_symbol()))
381 .with_organ(OrganUse::new(standard_binding_organ_symbol()))
382 .with_organ(OrganUse::new(standard_sequence_organ_symbol()))
383 .with_organ(OrganUse::new(standard_pattern_organ_symbol()))
384 .with_numeric_tower(Symbol::qualified("numbers", "sim-expression"))
385 .with_conformance_test(test.clone())
386 .with_fidelity_badge(FidelityBadge::new(
387 Ref::Symbol(profile),
388 Symbol::qualified("standard", "host-native"),
389 1,
390 Ref::Symbol(test),
391 ))
392}
393
394pub fn standard_control_organ_symbol() -> Symbol {
396 Symbol::qualified("organ", "control")
397}
398
399pub fn standard_binding_organ_symbol() -> Symbol {
401 Symbol::qualified("organ", "binding")
402}
403
404pub fn standard_sequence_organ_symbol() -> Symbol {
406 Symbol::qualified("organ", "sequence")
407}
408
409pub fn standard_pattern_organ_symbol() -> Symbol {
411 Symbol::qualified("organ", "pattern")
412}
413
414fn unspecified_symbol(name: &str) -> Symbol {
415 Symbol::qualified("standard/unspecified", name.to_owned())
416}
417
418fn optional_symbol(expr: &Expr) -> sim_kernel::Result<Option<Symbol>> {
419 match expr {
420 Expr::Nil => Ok(None),
421 Expr::Symbol(symbol) => Ok(Some(symbol.clone())),
422 _ => Err(sim_kernel::Error::TypeMismatch {
423 expected: "optional symbol",
424 found: expr_kind(expr),
425 }),
426 }
427}
428
429fn organ_uses_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<OrganUse>> {
430 let Expr::List(items) = expr else {
431 return Err(sim_kernel::Error::TypeMismatch {
432 expected: "organ-use list",
433 found: expr_kind(expr),
434 });
435 };
436 items.iter().map(OrganUse::from_expr).collect()
437}
438
439fn capabilities_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<CapabilityName>> {
440 capability_names_from_expr(expr)
441}
442
443fn symbols_from_expr(expr: &Expr, expected: &'static str) -> sim_kernel::Result<Vec<Symbol>> {
444 let Expr::List(items) = expr else {
445 return Err(sim_kernel::Error::TypeMismatch {
446 expected: "symbol list",
447 found: expr_kind(expr),
448 });
449 };
450 items
451 .iter()
452 .map(|item| symbol_from_expr(item, expected))
453 .collect()
454}
455
456fn badges_from_expr(expr: &Expr) -> sim_kernel::Result<Vec<FidelityBadge>> {
457 let Expr::List(items) = expr else {
458 return Err(sim_kernel::Error::TypeMismatch {
459 expected: "fidelity badge list",
460 found: expr_kind(expr),
461 });
462 };
463 items
464 .iter()
465 .map(|item| match item {
466 Expr::Call { operator, args } => {
467 let class = symbol_from_expr(operator, "badge class")?;
468 if class != crate::fidelity_badge_class_symbol() {
469 return Err(sim_kernel::Error::Eval(format!(
470 "expected standard/FidelityBadge, found {class}"
471 )));
472 }
473 FidelityBadge::from_constructor_args(args.clone())
474 }
475 _ => Err(sim_kernel::Error::TypeMismatch {
476 expected: "fidelity badge constructor call",
477 found: expr_kind(item),
478 }),
479 })
480 .collect()
481}