use cljrs_env::env::Env;
use cljrs_env::error::EvalResult;
use cljrs_gc::GcPtr;
use cljrs_interp::apply::select_arity;
use cljrs_value::{CljxFn, PersistentList, Value};
pub(crate) fn eager_lower_enabled() -> bool {
thread_local! {
static ENABLED: bool = std::env::var("CLJRS_EAGER_LOWER").is_ok()
&& std::env::var("CLJRS_NO_IR").is_err();
}
ENABLED.with(|e| *e)
}
pub fn call_cljrs_fn(f: &CljxFn, args: &[Value], caller_env: &mut Env) -> EvalResult {
let arity = select_arity(f, args.len())?;
if !f.is_macro
&& let Some(result) = try_ir_path(f, arity, args, caller_env)
{
return result;
}
cljrs_interp::apply::call_cljrs_fn(f, args, caller_env)
}
thread_local! {
pub static IR_LOWERING_ACTIVE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
fn try_ir_path(
f: &CljxFn,
arity: &cljrs_value::CljxFnArity,
args: &[Value],
caller_env: &mut Env,
) -> Option<EvalResult> {
let arity_id = arity.ir_arity_id;
let ir_func = crate::ir_cache::get_cached(arity_id)?;
Some(execute_ir(f, arity, &ir_func, args, caller_env))
}
fn execute_ir(
f: &CljxFn,
arity: &cljrs_value::CljxFnArity,
ir_func: &cljrs_ir::IrFunction,
args: &[Value],
caller_env: &mut Env,
) -> EvalResult {
let _caller_root = cljrs_env::gc_roots::push_env_root(caller_env);
let mut env = Env::with_closure(caller_env.globals.clone(), &f.defining_ns, f);
env.push_frame();
cljrs_interp::apply::bind_fn_params(arity, args, &mut env)?;
if let Some(ref name) = f.name {
let self_val = Value::Fn(GcPtr::new(f.clone()));
env.bind(name.clone(), self_val);
}
cljrs_env::callback::push_eval_context(&env);
let ir_args = if arity.rest_param.is_some() {
let n = arity.params.len();
let mut ir_args = args[..n.min(args.len())].to_vec();
let rest_items: Vec<Value> = args[n.min(args.len())..].to_vec();
let rest_val = if rest_items.is_empty() {
Value::Nil
} else {
Value::List(GcPtr::new(PersistentList::from_iter(rest_items)))
};
ir_args.push(rest_val);
ir_args
} else {
args.to_vec()
};
let result = crate::ir_interp::interpret_ir(
ir_func,
ir_args,
&caller_env.globals,
&f.defining_ns,
&mut env,
);
cljrs_env::callback::pop_eval_context();
env.pop_frame();
result
}