Skip to main content

sim_lib_lang_cl/
runtime.rs

1use std::{collections::BTreeMap, sync::Arc};
2
3use sim_kernel::{Args, Cx, Error, Ref, Result, Shape, Symbol, Value};
4use sim_lib_binding::{LexicalEnv, eval_let, lexical_function_value};
5use sim_lib_control::{
6    Condition, ConditionHandler, ConditionStack, ContinuationValue, ControlResultValue, Restart,
7    RestartStack, invoke_restart, signal_condition,
8};
9use sim_lib_dispatch::{
10    DispatchMethod, GenericFunction, MethodBody, MethodRole, MethodSpecificity,
11};
12use sim_lib_mutation::{Cell, cell_value};
13use sim_lib_namespace::{Namespace, NamespaceKind};
14
15use crate::cl_lite_package_symbol;
16
17/// Native body of a CL-lite function or macro.
18///
19/// Receives the call context, the captured lexical environment, and the
20/// argument values, and returns a runtime [`Value`].
21pub type ClFunctionBody =
22    Arc<dyn Fn(&mut Cx, &LexicalEnv, Vec<Value>) -> Result<Value> + Send + Sync + 'static>;
23
24/// CL-lite evaluation state: lexical environment, macro table, special-variable
25/// cells, and the current package.
26///
27/// Each surface form delegates to a shared runtime organ rather than
28/// reimplementing behavior.
29pub struct ClLiteRuntime {
30    env: LexicalEnv,
31    macros: BTreeMap<Symbol, Value>,
32    variables: BTreeMap<Symbol, Value>,
33    package: Namespace,
34}
35
36impl ClLiteRuntime {
37    /// Creates an empty runtime with the CL-lite package installed.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use sim_lib_lang_cl::ClLiteRuntime;
43    ///
44    /// let runtime = ClLiteRuntime::new().unwrap();
45    /// assert_eq!(runtime.package().symbol().to_string(), "common-lisp/lite");
46    /// ```
47    pub fn new() -> Result<Self> {
48        Ok(Self {
49            env: LexicalEnv::new(),
50            macros: BTreeMap::new(),
51            variables: BTreeMap::new(),
52            package: cl_lite_package()?,
53        })
54    }
55
56    /// Returns the runtime's lexical environment.
57    pub fn environment(&self) -> &LexicalEnv {
58        &self.env
59    }
60
61    /// Returns the runtime's current package namespace.
62    pub fn package(&self) -> &Namespace {
63        &self.package
64    }
65
66    /// Defines a function in the lexical environment via the binding organ.
67    pub fn defun(&mut self, cx: &mut Cx, name: Symbol, body: ClFunctionBody) -> Result<Value> {
68        let value = lexical_function_value(cx, name.clone(), self.env.clone(), body)?;
69        self.env.define(name, value.clone())?;
70        Ok(value)
71    }
72
73    /// Looks up a defined function by name in the lexical environment.
74    pub fn function(&self, name: &Symbol) -> Result<Value> {
75        self.env.lookup(name)
76    }
77
78    /// Defines a macro function in the macro table via the binding organ.
79    pub fn defmacro(&mut self, cx: &mut Cx, name: Symbol, body: ClFunctionBody) -> Result<Value> {
80        let value = lexical_function_value(cx, name.clone(), self.env.clone(), body)?;
81        self.macros.insert(name, value.clone());
82        Ok(value)
83    }
84
85    /// Looks up a macro function by name, if one is defined.
86    pub fn macro_function(&self, name: &Symbol) -> Option<Value> {
87        self.macros.get(name).cloned()
88    }
89
90    /// Evaluates `body` in a lexical frame extended with `bindings`.
91    ///
92    /// Delegates to the binding organ's `let` evaluation.
93    pub fn let_form(
94        &self,
95        cx: &mut Cx,
96        bindings: Vec<(Symbol, Value)>,
97        body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
98    ) -> Result<Value> {
99        eval_let(cx, &self.env, bindings, body)
100    }
101
102    /// Defines a special variable backed by a mutation cell.
103    pub fn define_variable(&mut self, cx: &mut Cx, name: Symbol, initial: Value) -> Result<Value> {
104        let cell = cell_value(cx, initial)?;
105        self.variables.insert(name, cell.clone());
106        Ok(cell)
107    }
108
109    /// Updates a defined variable's cell; requires the mutation capability.
110    pub fn setq(&mut self, cx: &mut Cx, name: &Symbol, value: Value) -> Result<Value> {
111        let cell_value = self
112            .variables
113            .get(name)
114            .ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not defined")))?;
115        let cell = cell_value
116            .object()
117            .downcast_ref::<Cell>()
118            .ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not mutable")))?;
119        cell.set(cx, value.clone())?;
120        Ok(value)
121    }
122
123    /// Reads the current value of a defined variable's cell.
124    pub fn variable_value(&self, name: &Symbol) -> Result<Value> {
125        let cell_value = self
126            .variables
127            .get(name)
128            .ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not defined")))?;
129        let cell = cell_value
130            .object()
131            .downcast_ref::<Cell>()
132            .ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not mutable")))?;
133        cell.get()
134    }
135
136    /// Updates a generalized place by writing into its mutation cell.
137    pub fn setf_cell(&mut self, cx: &mut Cx, cell: &Cell, value: Value) -> Result<Value> {
138        cell.set(cx, value.clone())?;
139        Ok(value)
140    }
141}
142
143/// Calls a callable runtime value with the given arguments.
144///
145/// Errors if `value` is not callable.
146pub fn call_cl_value(cx: &mut Cx, value: &Value, args: Vec<Value>) -> Result<Value> {
147    let callable = value
148        .object()
149        .as_callable()
150        .ok_or_else(|| Error::Eval("CL-lite value is not callable".to_owned()))?;
151    callable.call(cx, Args::new(args))
152}
153
154/// Condition-and-restart scope for CL-lite `handler-case` / `restart-case`.
155///
156/// Holds the active handler and restart stacks; all signaling delegates to the
157/// control organ.
158pub struct ClLiteControlScope {
159    conditions: ConditionStack,
160    restarts: RestartStack,
161}
162
163impl Default for ClLiteControlScope {
164    fn default() -> Self {
165        Self::new()
166    }
167}
168
169impl ClLiteControlScope {
170    /// Creates an empty control scope with no handlers or restarts.
171    pub fn new() -> Self {
172        Self {
173            conditions: ConditionStack::new(),
174            restarts: RestartStack::new(),
175        }
176    }
177
178    /// Pushes a condition handler onto the handler stack.
179    pub fn push_handler(&mut self, handler: ConditionHandler) {
180        self.conditions.push(handler);
181    }
182
183    /// Pops the most recently pushed condition handler.
184    pub fn pop_handler(&mut self) -> Option<ConditionHandler> {
185        self.conditions.pop()
186    }
187
188    /// Signals a condition to the nearest matching handler.
189    pub fn handler_case(
190        &self,
191        cx: &mut Cx,
192        kind: Symbol,
193        payload: Ref,
194    ) -> Result<ContinuationValue> {
195        signal_condition(cx, &self.conditions, Condition::new(kind, payload))
196    }
197
198    /// Pushes a named restart with its resumption continuation.
199    pub fn push_restart(&mut self, name: Symbol, continuation: ContinuationValue) {
200        self.restarts.push(Restart::new(name, continuation));
201    }
202
203    /// Pops the most recently pushed restart.
204    pub fn pop_restart(&mut self) -> Option<Restart> {
205        self.restarts.pop()
206    }
207
208    /// Invokes a named restart with a resumption value.
209    pub fn restart_case(
210        &self,
211        cx: &mut Cx,
212        name: &Symbol,
213        value: Ref,
214    ) -> Result<ControlResultValue> {
215        invoke_restart(cx, &self.restarts, name, value)
216    }
217}
218
219/// CL-lite generic function (`defgeneric` / `defmethod`) over the dispatch organ.
220pub struct ClGenericFunction {
221    generic: GenericFunction,
222}
223
224impl ClGenericFunction {
225    /// Creates a named generic function with no methods.
226    pub fn new(name: Symbol) -> Self {
227        Self {
228            generic: GenericFunction::new(name),
229        }
230    }
231
232    /// Returns the generic function's name.
233    pub fn name(&self) -> &Symbol {
234        self.generic.name()
235    }
236
237    /// Adds a primary method keyed by its parameter shapes.
238    pub fn add_primary_method(
239        &mut self,
240        id: Symbol,
241        parameter_shapes: Vec<Arc<dyn Shape>>,
242        body: MethodBody,
243    ) -> Result<()> {
244        self.generic.add_method(DispatchMethod::new(
245            id,
246            MethodRole::Primary,
247            parameter_shapes,
248            body,
249        ))
250    }
251
252    /// Selects the most specific primary method for the given arguments.
253    pub fn select_primary(&self, cx: &mut Cx, args: &[Value]) -> Result<MethodSpecificity> {
254        self.generic.select_primary(cx, args)
255    }
256
257    /// Returns the applicable methods in dispatch order for the arguments.
258    pub fn dispatch_order(&self, cx: &mut Cx, args: &[Value]) -> Result<Vec<Symbol>> {
259        self.generic.dispatch_order(cx, args)
260    }
261
262    /// Dispatches and calls the generic function under the CL-lite profile.
263    pub fn call(&self, cx: &mut Cx, args: &[Value]) -> Result<Value> {
264        self.generic
265            .call_for_profile(cx, &crate::cl_lite_profile_symbol(), args)
266    }
267}
268
269/// Builds the CL-lite package namespace exporting the surface form symbols.
270pub fn cl_lite_package() -> Result<Namespace> {
271    let mut package = Namespace::package(cl_lite_package_symbol());
272    for name in [
273        "defun",
274        "defmacro",
275        "let",
276        "setq",
277        "handler-case",
278        "restart-case",
279        "defgeneric",
280        "defmethod",
281        "defpackage",
282        "in-package",
283        "setf",
284    ] {
285        let local = Symbol::new(name);
286        package.define(local.clone(), Symbol::qualified("cl", name))?;
287        package.export(local)?;
288    }
289    debug_assert_eq!(package.kind(), NamespaceKind::Package);
290    Ok(package)
291}