1use std::sync::Arc;
9
10use cljrs_ir::IrFunction;
11use cljrs_reader::Form;
12use cljrs_value::Value;
13
14use cljrs_env::env::Env;
15
16#[derive(Debug)]
19pub enum LowerError {
20 NotReady,
22 LowerFailed(String),
24 ConvertFailed(String),
26}
27
28impl std::fmt::Display for LowerError {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 LowerError::NotReady => write!(f, "compiler not ready"),
32 LowerError::LowerFailed(msg) => write!(f, "lowering failed: {msg}"),
33 LowerError::ConvertFailed(msg) => write!(f, "IR conversion failed: {msg}"),
34 }
35 }
36}
37
38pub fn lower_arity(
46 name: Option<&str>,
47 params: &[Arc<str>],
48 rest_param: Option<&Arc<str>>,
49 body: &[Form],
50 ns: &Arc<str>,
51 env: &mut Env,
52) -> Result<IrFunction, LowerError> {
53 if !env
55 .globals
56 .compiler_ready
57 .load(std::sync::atomic::Ordering::Acquire)
58 {
59 return Err(LowerError::NotReady);
60 }
61
62 lower_arity_inner(name, params, rest_param, body, ns, env)
63}
64
65fn lower_arity_inner(
66 name: Option<&str>,
67 params: &[Arc<str>],
68 rest_param: Option<&Arc<str>>,
69 body: &[Form],
70 ns: &Arc<str>,
71 env: &mut Env,
72) -> Result<IrFunction, LowerError> {
73 use cljrs_gc::GcPtr;
74 use cljrs_value::collections::vector::PersistentVector;
75
76 let globals = &env.globals;
77
78 let lower_fn = globals
80 .lookup_var_in_ns("cljrs.compiler.anf", "lower-fn-body")
81 .ok_or_else(|| {
82 LowerError::LowerFailed("cljrs.compiler.anf/lower-fn-body not found".to_string())
83 })?;
84 let lower_fn_val = lower_fn.get().deref().unwrap_or(Value::Nil);
85
86 let expanded_body: Vec<Form> = body
91 .iter()
92 .map(|f| cljrs_interp::macros::macroexpand_all(f, env).unwrap_or_else(|_| f.clone()))
93 .collect();
94 let body = expanded_body.as_slice();
95
96 let fname_val = match name {
99 Some(n) => Value::string(n.to_string()),
100 None => Value::Nil,
101 };
102
103 let ns_val = Value::string(ns.to_string());
105
106 let mut param_strs: Vec<Value> = params
108 .iter()
109 .map(|p| Value::string(p.to_string()))
110 .collect();
111 if let Some(rest) = rest_param {
112 param_strs.push(Value::string(rest.to_string()));
115 }
116 let params_val = Value::Vector(GcPtr::new(PersistentVector::from_iter(param_strs)));
117
118 let body_forms_val = Value::Vector(GcPtr::new(PersistentVector::from_iter(
120 body.iter().map(cljrs_builtins::form::form_to_value),
121 )));
122
123 cljrs_env::callback::push_eval_context(env);
125
126 use crate::apply::IR_LOWERING_ACTIVE;
129 let was_active = IR_LOWERING_ACTIVE.get();
130 IR_LOWERING_ACTIVE.set(true);
131
132 let ir_data = cljrs_env::callback::invoke(
134 &lower_fn_val,
135 vec![fname_val, ns_val, params_val, body_forms_val],
136 );
137
138 IR_LOWERING_ACTIVE.with(|c| c.set(was_active));
140 cljrs_env::callback::pop_eval_context();
141
142 let ir_data = ir_data.map_err(|e| LowerError::LowerFailed(format!("{e:?}")))?;
143
144 crate::ir_convert::value_to_ir_function(&ir_data)
146 .map_err(|e| LowerError::ConvertFailed(format!("{e}")))
147}