1use std::sync::Arc;
8
9use cljrs_ir::lower::CoreShadows;
10use cljrs_ir::{IrFunction, Repr};
11use cljrs_reader::Form;
12use cljrs_value::TypeHint;
13
14use crate::builtins::form::resolve_auto_forms;
15use crate::env::env::{Env, GlobalEnv};
16
17pub fn seed_reprs_from_hints(param_hints: &[Option<TypeHint>]) -> Vec<Repr> {
24 if !param_hints.iter().any(|h| {
25 matches!(
26 h,
27 Some(
28 TypeHint::Long
29 | TypeHint::Int
30 | TypeHint::Double
31 | TypeHint::Float
32 | TypeHint::Bool
33 | TypeHint::LongArray
34 | TypeHint::DoubleArray
35 )
36 )
37 }) {
38 return Vec::new();
39 }
40 param_hints
41 .iter()
42 .map(|h| match h {
43 Some(TypeHint::Long | TypeHint::Int) => Repr::Long,
44 Some(TypeHint::Double | TypeHint::Float) => Repr::Double,
45 Some(TypeHint::Bool) => Repr::Bool,
46 Some(TypeHint::LongArray) => Repr::LongArray,
48 Some(TypeHint::DoubleArray) => Repr::DoubleArray,
49 _ => Repr::Boxed,
52 })
53 .collect()
54}
55
56pub fn core_shadows_for(globals: &GlobalEnv, ns: &str) -> CoreShadows {
62 CoreShadows::new(globals.core_shadowed_names(ns))
63}
64
65#[derive(Debug)]
68pub enum LowerError {
69 LowerFailed(String),
71}
72
73impl std::fmt::Display for LowerError {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 match self {
76 LowerError::LowerFailed(msg) => write!(f, "lowering failed: {msg}"),
77 }
78 }
79}
80
81#[allow(clippy::too_many_arguments)]
91pub fn lower_arity(
92 name: Option<&str>,
93 params: &[Arc<str>],
94 rest_param: Option<&Arc<str>>,
95 destructure_params: &[(usize, Form)],
96 destructure_rest: Option<&Form>,
97 body: &[Form],
98 ns: &Arc<str>,
99 env: &mut Env,
100 is_async: bool,
101) -> Result<IrFunction, LowerError> {
102 lower_arity_inner(
103 name,
104 params,
105 rest_param,
106 destructure_params,
107 destructure_rest,
108 body,
109 ns,
110 env,
111 false,
112 is_async,
113 )
114 .map(|(ir, _)| ir)
115}
116
117#[allow(clippy::too_many_arguments)]
119pub fn lower_and_optimize_arity(
120 name: Option<&str>,
121 params: &[Arc<str>],
122 rest_param: Option<&Arc<str>>,
123 destructure_params: &[(usize, Form)],
124 destructure_rest: Option<&Form>,
125 body: &[Form],
126 ns: &Arc<str>,
127 env: &mut Env,
128 is_async: bool,
129) -> Result<IrFunction, LowerError> {
130 lower_and_optimize_arity_tracked(
131 name,
132 params,
133 rest_param,
134 destructure_params,
135 destructure_rest,
136 body,
137 ns,
138 env,
139 is_async,
140 )
141 .map(|(ir, _)| ir)
142}
143
144#[allow(clippy::too_many_arguments)]
148pub fn lower_and_optimize_arity_tracked(
149 name: Option<&str>,
150 params: &[Arc<str>],
151 rest_param: Option<&Arc<str>>,
152 destructure_params: &[(usize, Form)],
153 destructure_rest: Option<&Form>,
154 body: &[Form],
155 ns: &Arc<str>,
156 env: &mut Env,
157 is_async: bool,
158) -> Result<(IrFunction, Vec<(Arc<str>, Arc<str>)>), LowerError> {
159 lower_arity_inner(
160 name,
161 params,
162 rest_param,
163 destructure_params,
164 destructure_rest,
165 body,
166 ns,
167 env,
168 true,
169 is_async,
170 )
171}
172
173#[allow(clippy::too_many_arguments)]
174fn lower_arity_inner(
175 name: Option<&str>,
176 params: &[Arc<str>],
177 rest_param: Option<&Arc<str>>,
178 destructure_params: &[(usize, Form)],
179 destructure_rest: Option<&Form>,
180 body: &[Form],
181 ns: &Arc<str>,
182 env: &mut Env,
183 do_optimize: bool,
184 is_async: bool,
185) -> Result<(IrFunction, Vec<(Arc<str>, Arc<str>)>), LowerError> {
186 let prev_ns = std::mem::replace(&mut env.current_ns, ns.clone());
189 let expanded_body = macroexpand_body(body, env);
190 let resolved: Result<Vec<Form>, _> = expanded_body
194 .iter()
195 .map(|f| resolve_auto_forms(f, env))
196 .collect();
197 let expanded_body = resolved.unwrap_or(expanded_body);
198 env.current_ns = prev_ns;
199 let shadows = core_shadows_for(&env.globals, ns);
200 lower_expanded_arity(
201 name,
202 params,
203 rest_param,
204 destructure_params,
205 destructure_rest,
206 &expanded_body,
207 ns,
208 &shadows,
209 env.globals.id(),
210 None,
211 do_optimize,
212 is_async,
213 )
214}
215
216pub fn macroexpand_body(body: &[Form], env: &mut Env) -> Vec<Form> {
223 use crate::tiered::apply::IR_LOWERING_ACTIVE;
225 let was_active = IR_LOWERING_ACTIVE.get();
226 IR_LOWERING_ACTIVE.set(true);
227
228 let expanded_body: Vec<Form> = body
229 .iter()
230 .map(|f| crate::interp::macros::macroexpand_all(f, env).unwrap_or_else(|_| f.clone()))
231 .collect();
232
233 IR_LOWERING_ACTIVE.with(|c| c.set(was_active));
234 expanded_body
235}
236
237#[allow(clippy::too_many_arguments)]
254pub fn lower_expanded_arity(
255 name: Option<&str>,
256 params: &[Arc<str>],
257 rest_param: Option<&Arc<str>>,
258 destructure_params: &[(usize, Form)],
259 destructure_rest: Option<&Form>,
260 expanded_body: &[Form],
261 ns: &Arc<str>,
262 shadows: &CoreShadows,
263 globals_id: u64,
264 arity_id: Option<u64>,
265 do_optimize: bool,
266 is_async: bool,
267) -> Result<(IrFunction, Vec<(Arc<str>, Arc<str>)>), LowerError> {
268 tracing::debug!(
269 target: "lower",
270 "lowering {:?}/{:?} optimize? {}",
271 ns,
272 name,
273 do_optimize
274 );
275
276 let mut all_params: Vec<Arc<str>> = params.to_vec();
278 if let Some(rest) = rest_param {
279 all_params.push(rest.clone());
280 }
281
282 let mut destructures: Vec<(usize, Form)> = destructure_params.to_vec();
286 if let Some(rest_pat) = destructure_rest {
287 destructures.push((params.len(), rest_pat.clone()));
288 }
289
290 let kwargs_rest_index = destructure_rest
291 .filter(|pat| pat.is_kwargs_rest_pattern())
292 .map(|_| params.len());
293 let ir = cljrs_ir::lower::lower_fn_body_shadowed_kwargs(
294 name,
295 ns,
296 &all_params,
297 &destructures,
298 kwargs_rest_index,
299 expanded_body,
300 is_async,
301 shadows,
302 )
303 .map_err(|e| LowerError::LowerFailed(format!("{e:?}")))?;
304
305 if !do_optimize {
306 return Ok((ir, Vec::new()));
307 }
308
309 let referenced = referenced_globals(&ir);
313 let externals = match arity_id {
314 Some(id) => crate::tiered::defn_registry::snapshot_externals(globals_id, id, &referenced),
315 None => crate::tiered::defn_registry::externals_for(globals_id, &referenced),
316 };
317 let (ir, used) = cljrs_ir::lower::optimize_with_externals(ir, &externals);
318 Ok((ir, used.into_iter().collect()))
319}
320
321fn referenced_globals(ir: &IrFunction) -> std::collections::HashSet<(Arc<str>, Arc<str>)> {
324 use cljrs_ir::Inst;
325 let mut out = std::collections::HashSet::new();
326 fn walk(f: &IrFunction, out: &mut std::collections::HashSet<(Arc<str>, Arc<str>)>) {
327 for block in &f.blocks {
328 for inst in block.phis.iter().chain(block.insts.iter()) {
329 if let Inst::LoadGlobal(_, ns, name) | Inst::LoadVar(_, ns, name) = inst {
330 out.insert((ns.clone(), name.clone()));
331 }
332 }
333 }
334 for sub in &f.subfunctions {
335 walk(sub, out);
336 }
337 }
338 walk(ir, &mut out);
339 out
340}