1use std::sync::Arc;
8
9use cljrs_ir::IrFunction;
10use cljrs_reader::Form;
11
12use cljrs_env::env::Env;
13
14#[derive(Debug)]
17pub enum LowerError {
18 LowerFailed(String),
20 ConvertFailed(String),
22 NotReady,
25}
26
27impl std::fmt::Display for LowerError {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 LowerError::NotReady => write!(f, "compiler not ready"),
31 LowerError::LowerFailed(msg) => write!(f, "lowering failed: {msg}"),
32 LowerError::ConvertFailed(msg) => write!(f, "IR conversion failed: {msg}"),
33 }
34 }
35}
36
37pub fn lower_arity(
41 name: Option<&str>,
42 params: &[Arc<str>],
43 rest_param: Option<&Arc<str>>,
44 body: &[Form],
45 ns: &Arc<str>,
46 env: &mut Env,
47) -> Result<IrFunction, LowerError> {
48 lower_arity_inner(name, params, rest_param, body, ns, env, false)
49}
50
51pub fn lower_and_optimize_arity(
53 name: Option<&str>,
54 params: &[Arc<str>],
55 rest_param: Option<&Arc<str>>,
56 body: &[Form],
57 ns: &Arc<str>,
58 env: &mut Env,
59) -> Result<IrFunction, LowerError> {
60 lower_arity_inner(name, params, rest_param, body, ns, env, true)
61}
62
63fn lower_arity_inner(
64 name: Option<&str>,
65 params: &[Arc<str>],
66 rest_param: Option<&Arc<str>>,
67 body: &[Form],
68 ns: &Arc<str>,
69 env: &mut Env,
70 do_optimize: bool,
71) -> Result<IrFunction, LowerError> {
72 cljrs_logging::feat_debug!(
73 "lower",
74 "lowering {:?}/{:?} optimize? {}",
75 ns,
76 name,
77 do_optimize
78 );
79
80 use crate::apply::IR_LOWERING_ACTIVE;
83 let was_active = IR_LOWERING_ACTIVE.get();
84 IR_LOWERING_ACTIVE.set(true);
85
86 let expanded_body: Vec<Form> = body
87 .iter()
88 .map(|f| cljrs_interp::macros::macroexpand_all(f, env).unwrap_or_else(|_| f.clone()))
89 .collect();
90
91 IR_LOWERING_ACTIVE.with(|c| c.set(was_active));
92
93 let mut all_params: Vec<Arc<str>> = params.to_vec();
95 if let Some(rest) = rest_param {
96 all_params.push(rest.clone());
97 }
98
99 let ir = cljrs_ir::lower::lower_fn_body(name, ns, &all_params, &expanded_body)
100 .map_err(|e| LowerError::LowerFailed(format!("{e:?}")))?;
101
102 Ok(if do_optimize {
103 cljrs_ir::lower::optimize(ir)
104 } else {
105 ir
106 })
107}