use std::{collections::BTreeMap, sync::Arc};
use sim_kernel::{Args, Cx, Error, Ref, Result, Shape, Symbol, Value};
use sim_lib_binding::{LexicalEnv, eval_let, lexical_function_value};
use sim_lib_control::{
Condition, ConditionHandler, ConditionStack, ContinuationValue, ControlResultValue, Restart,
RestartStack, invoke_restart, signal_condition,
};
use sim_lib_dispatch::{
DispatchMethod, GenericFunction, MethodBody, MethodRole, MethodSpecificity,
};
use sim_lib_mutation::{Cell, cell_value};
use sim_lib_namespace::{Namespace, NamespaceKind};
use crate::cl_lite_package_symbol;
pub type ClFunctionBody =
Arc<dyn Fn(&mut Cx, &LexicalEnv, Vec<Value>) -> Result<Value> + Send + Sync + 'static>;
pub struct ClLiteRuntime {
env: LexicalEnv,
macros: BTreeMap<Symbol, Value>,
variables: BTreeMap<Symbol, Value>,
package: Namespace,
}
impl ClLiteRuntime {
pub fn new() -> Result<Self> {
Ok(Self {
env: LexicalEnv::new(),
macros: BTreeMap::new(),
variables: BTreeMap::new(),
package: cl_lite_package()?,
})
}
pub fn environment(&self) -> &LexicalEnv {
&self.env
}
pub fn package(&self) -> &Namespace {
&self.package
}
pub fn defun(&mut self, cx: &mut Cx, name: Symbol, body: ClFunctionBody) -> Result<Value> {
let value = lexical_function_value(cx, name.clone(), self.env.clone(), body)?;
self.env.define(name, value.clone())?;
Ok(value)
}
pub fn function(&self, name: &Symbol) -> Result<Value> {
self.env.lookup(name)
}
pub fn defmacro(&mut self, cx: &mut Cx, name: Symbol, body: ClFunctionBody) -> Result<Value> {
let value = lexical_function_value(cx, name.clone(), self.env.clone(), body)?;
self.macros.insert(name, value.clone());
Ok(value)
}
pub fn macro_function(&self, name: &Symbol) -> Option<Value> {
self.macros.get(name).cloned()
}
pub fn let_form(
&self,
cx: &mut Cx,
bindings: Vec<(Symbol, Value)>,
body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
) -> Result<Value> {
eval_let(cx, &self.env, bindings, body)
}
pub fn define_variable(&mut self, cx: &mut Cx, name: Symbol, initial: Value) -> Result<Value> {
let cell = cell_value(cx, initial)?;
self.variables.insert(name, cell.clone());
Ok(cell)
}
pub fn setq(&mut self, cx: &mut Cx, name: &Symbol, value: Value) -> Result<Value> {
let cell_value = self
.variables
.get(name)
.ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not defined")))?;
let cell = cell_value
.object()
.downcast_ref::<Cell>()
.ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not mutable")))?;
cell.set(cx, value.clone())?;
Ok(value)
}
pub fn variable_value(&self, name: &Symbol) -> Result<Value> {
let cell_value = self
.variables
.get(name)
.ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not defined")))?;
let cell = cell_value
.object()
.downcast_ref::<Cell>()
.ok_or_else(|| Error::Eval(format!("CL-lite variable {name} is not mutable")))?;
cell.get()
}
pub fn setf_cell(&mut self, cx: &mut Cx, cell: &Cell, value: Value) -> Result<Value> {
cell.set(cx, value.clone())?;
Ok(value)
}
}
pub fn call_cl_value(cx: &mut Cx, value: &Value, args: Vec<Value>) -> Result<Value> {
let callable = value
.object()
.as_callable()
.ok_or_else(|| Error::Eval("CL-lite value is not callable".to_owned()))?;
callable.call(cx, Args::new(args))
}
pub struct ClLiteControlScope {
conditions: ConditionStack,
restarts: RestartStack,
}
impl Default for ClLiteControlScope {
fn default() -> Self {
Self::new()
}
}
impl ClLiteControlScope {
pub fn new() -> Self {
Self {
conditions: ConditionStack::new(),
restarts: RestartStack::new(),
}
}
pub fn push_handler(&mut self, handler: ConditionHandler) {
self.conditions.push(handler);
}
pub fn pop_handler(&mut self) -> Option<ConditionHandler> {
self.conditions.pop()
}
pub fn handler_case(
&self,
cx: &mut Cx,
kind: Symbol,
payload: Ref,
) -> Result<ContinuationValue> {
signal_condition(cx, &self.conditions, Condition::new(kind, payload))
}
pub fn push_restart(&mut self, name: Symbol, continuation: ContinuationValue) {
self.restarts.push(Restart::new(name, continuation));
}
pub fn pop_restart(&mut self) -> Option<Restart> {
self.restarts.pop()
}
pub fn restart_case(
&self,
cx: &mut Cx,
name: &Symbol,
value: Ref,
) -> Result<ControlResultValue> {
invoke_restart(cx, &self.restarts, name, value)
}
}
pub struct ClGenericFunction {
generic: GenericFunction,
}
impl ClGenericFunction {
pub fn new(name: Symbol) -> Self {
Self {
generic: GenericFunction::new(name),
}
}
pub fn name(&self) -> &Symbol {
self.generic.name()
}
pub fn add_primary_method(
&mut self,
id: Symbol,
parameter_shapes: Vec<Arc<dyn Shape>>,
body: MethodBody,
) -> Result<()> {
self.generic.add_method(DispatchMethod::new(
id,
MethodRole::Primary,
parameter_shapes,
body,
))
}
pub fn select_primary(&self, cx: &mut Cx, args: &[Value]) -> Result<MethodSpecificity> {
self.generic.select_primary(cx, args)
}
pub fn dispatch_order(&self, cx: &mut Cx, args: &[Value]) -> Result<Vec<Symbol>> {
self.generic.dispatch_order(cx, args)
}
pub fn call(&self, cx: &mut Cx, args: &[Value]) -> Result<Value> {
self.generic
.call_for_profile(cx, &crate::cl_lite_profile_symbol(), args)
}
}
pub fn cl_lite_package() -> Result<Namespace> {
let mut package = Namespace::package(cl_lite_package_symbol());
for name in [
"defun",
"defmacro",
"let",
"setq",
"handler-case",
"restart-case",
"defgeneric",
"defmethod",
"defpackage",
"in-package",
"setf",
] {
let local = Symbol::new(name);
package.define(local.clone(), Symbol::qualified("cl", name))?;
package.export(local)?;
}
debug_assert_eq!(package.kind(), NamespaceKind::Package);
Ok(package)
}