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