sim_lib_lang_clojure/
data.rs1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, Expr, NumberLiteral, Result, Symbol, Value};
4use sim_lib_namespace::{Namespace, NamespaceKind};
5use sim_lib_sequence::{TransducerPipeline, persistent_list, sequence_for_profile, transduce};
6
7use crate::{clojure_core_namespace_symbol, clojure_core_profile_symbol};
8
9pub type ClojureReducer =
13 Arc<dyn Fn(&mut Cx, Value, Value) -> Result<Value> + Send + Sync + 'static>;
14
15pub fn edn_expr_to_value(cx: &mut Cx, expr: &Expr) -> Result<Value> {
20 match expr {
21 Expr::Nil => cx.factory().nil(),
22 Expr::Bool(value) => cx.factory().bool(*value),
23 Expr::Number(NumberLiteral { domain, canonical }) => cx
24 .factory()
25 .number_literal(domain.clone(), canonical.clone()),
26 Expr::Symbol(symbol) => cx.factory().symbol(symbol.clone()),
27 Expr::String(value) => cx.factory().string(value.clone()),
28 Expr::Bytes(value) => cx.factory().bytes(value.clone()),
29 Expr::List(items) => {
30 let values = exprs_to_values(cx, items)?;
31 sim_lib_sequence::persistent_list(cx, values)
32 }
33 Expr::Vector(items) => {
34 let values = exprs_to_values(cx, items)?;
35 sim_lib_sequence::persistent_vector(cx, values)
36 }
37 Expr::Set(items) => {
38 let values = exprs_to_values(cx, items)?;
39 sim_lib_sequence::persistent_set(cx, values)
40 }
41 Expr::Map(entries) => {
42 let entries = entries
43 .iter()
44 .map(|(key, value)| Ok((map_key(key)?, edn_expr_to_value(cx, value)?)))
45 .collect::<Result<Vec<_>>>()?;
46 sim_lib_sequence::persistent_map(cx, entries)
47 }
48 other => cx.factory().expr(other.clone()),
49 }
50}
51
52pub fn clojure_persistent_data(cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
54 sim_lib_sequence::persistent_vector(cx, items)
55}
56
57pub fn clojure_profile_sequence(cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
61 let list = persistent_list(cx, items)?;
62 let sequence = sim_lib_sequence::sequence_from_list_value(cx, list)?;
63 sequence_for_profile(cx, clojure_core_profile_symbol(), sequence)
64}
65
66pub fn clojure_transduce(
71 cx: &mut Cx,
72 source: &Value,
73 pipeline: TransducerPipeline,
74 init: Value,
75 reducer: ClojureReducer,
76) -> Result<Value> {
77 transduce(cx, source, pipeline, init, reducer)
78}
79
80pub fn clojure_core_namespace() -> Result<Namespace> {
85 let mut namespace = Namespace::new(clojure_core_namespace_symbol(), NamespaceKind::Module);
86 namespace.define(Symbol::new("map"), Symbol::qualified("sequence", "map.v1"))?;
87 namespace.define(
88 Symbol::new("transduce"),
89 Symbol::qualified("sequence", "transduce.v1"),
90 )?;
91 namespace.define(
92 Symbol::new("recur"),
93 Symbol::qualified("control", "abort.v1"),
94 )?;
95 for exported in [
96 Symbol::new("map"),
97 Symbol::new("transduce"),
98 Symbol::new("recur"),
99 ] {
100 namespace.export(exported)?;
101 }
102 Ok(namespace)
103}
104
105fn exprs_to_values(cx: &mut Cx, items: &[Expr]) -> Result<Vec<Value>> {
106 items
107 .iter()
108 .map(|item| edn_expr_to_value(cx, item))
109 .collect()
110}
111
112fn map_key(expr: &Expr) -> Result<Symbol> {
113 match expr {
114 Expr::Symbol(symbol) => Ok(symbol.clone()),
115 Expr::String(value) => Ok(Symbol::new(value.clone())),
116 _ => Err(Error::TypeMismatch {
117 expected: "EDN symbol, keyword, or string map key",
118 found: expr_kind(expr),
119 }),
120 }
121}
122
123use sim_value::kind::expr_kind;