sim_lib_lang_islisp/
generic.rs1use std::{collections::BTreeMap, sync::Arc};
2
3use sim_kernel::{Cx, Expr, Object, ObjectCompat, Result, Shape, Symbol, Value};
4use sim_lib_dispatch::{
5 DispatchMethod, GenericFunction, MethodBody, MethodRole, MethodSpecificity,
6};
7
8#[sim_citizen_derive::non_citizen(
9 reason = "dynamic ISLISP instance shell; canonical data is the class symbol and slot table",
10 kind = "marker"
11)]
12#[derive(Clone, Debug)]
17pub struct IslispObject {
18 class: Symbol,
19 slots: BTreeMap<Symbol, Value>,
20}
21
22impl IslispObject {
23 pub fn new(class: Symbol, slots: BTreeMap<Symbol, Value>) -> Self {
25 Self { class, slots }
26 }
27
28 pub fn class(&self) -> &Symbol {
30 &self.class
31 }
32
33 pub fn slots(&self) -> &BTreeMap<Symbol, Value> {
35 &self.slots
36 }
37}
38
39impl Object for IslispObject {
40 fn display(&self, _cx: &mut Cx) -> Result<String> {
41 Ok(format!("#<islisp-object {}>", self.class))
42 }
43
44 fn as_any(&self) -> &dyn std::any::Any {
45 self
46 }
47}
48
49impl ObjectCompat for IslispObject {
50 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
51 let slots = self
52 .slots
53 .iter()
54 .map(|(slot, value)| Ok((Expr::Symbol(slot.clone()), value.object().as_expr(cx)?)))
55 .collect::<Result<Vec<_>>>()?;
56 Ok(Expr::Map(vec![
57 (
58 Expr::Symbol(Symbol::new("class")),
59 Expr::Symbol(self.class.clone()),
60 ),
61 (Expr::Symbol(Symbol::new("slots")), Expr::Map(slots)),
62 ]))
63 }
64
65 fn truth(&self, _cx: &mut Cx) -> Result<bool> {
66 Ok(true)
67 }
68}
69
70pub fn islisp_object_value(
75 cx: &mut Cx,
76 class: Symbol,
77 slots: BTreeMap<Symbol, Value>,
78) -> Result<Value> {
79 cx.factory()
80 .opaque(Arc::new(IslispObject::new(class, slots)))
81}
82
83pub struct IslispGeneric {
89 generic: GenericFunction,
90}
91
92impl IslispGeneric {
93 pub fn new(name: Symbol) -> Self {
95 Self {
96 generic: GenericFunction::new(name),
97 }
98 }
99
100 pub fn name(&self) -> &Symbol {
102 self.generic.name()
103 }
104
105 pub fn add_primary_method(
107 &mut self,
108 id: Symbol,
109 parameter_shapes: Vec<Arc<dyn Shape>>,
110 body: MethodBody,
111 ) -> Result<()> {
112 self.generic.add_method(DispatchMethod::new(
113 id,
114 MethodRole::Primary,
115 parameter_shapes,
116 body,
117 ))
118 }
119
120 pub fn select_primary(&self, cx: &mut Cx, args: &[Value]) -> Result<MethodSpecificity> {
122 self.generic.select_primary(cx, args)
123 }
124
125 pub fn dispatch_order(&self, cx: &mut Cx, args: &[Value]) -> Result<Vec<Symbol>> {
127 self.generic.dispatch_order(cx, args)
128 }
129
130 pub fn call(&self, cx: &mut Cx, args: &[Value]) -> Result<Value> {
132 self.generic.call(cx, args)
133 }
134}