#![allow(clippy::result_large_err)]
#![allow(clippy::type_complexity)]
pub mod apply;
pub mod ir_cache;
pub mod ir_convert;
pub mod ir_interp;
pub mod lower;
pub use cljrs_env::callback::invoke;
pub use cljrs_env::env::{Env, GlobalEnv};
pub use cljrs_env::error::{EvalError, EvalResult};
pub use cljrs_env::loader::load_ns;
pub use cljrs_interp::eval::eval;
use crate::ir_interp::eager_lower_fn;
use std::sync::Arc;
pub fn register_compiler_sources(globals: &Arc<GlobalEnv>) {
globals.register_builtin_source("cljrs.compiler.ir", cljrs_ir::COMPILER_IR_SOURCE);
globals.register_builtin_source("cljrs.compiler.known", cljrs_ir::COMPILER_KNOWN_SOURCE);
globals.register_builtin_source("cljrs.compiler.anf", cljrs_ir::COMPILER_ANF_SOURCE);
globals.register_builtin_source("cljrs.compiler.escape", cljrs_ir::COMPILER_ESCAPE_SOURCE);
globals.register_builtin_source(
"cljrs.compiler.optimize",
cljrs_ir::COMPILER_OPTIMIZE_SOURCE,
);
}
pub fn ensure_compiler_loaded(globals: &Arc<GlobalEnv>, env: &mut Env) -> bool {
if globals
.compiler_ready
.load(std::sync::atomic::Ordering::Acquire)
{
return true;
}
if std::env::var("CLJRS_NO_IR").is_ok() {
return false;
}
static LOADING: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
if LOADING.swap(true, std::sync::atomic::Ordering::AcqRel) {
return false; }
let span = || cljrs_types::span::Span::new(Arc::new("<compiler-load>".to_string()), 0, 0, 1, 1);
for ns_name in &[
"cljrs.compiler.ir",
"cljrs.compiler.known",
"cljrs.compiler.anf",
] {
let require_form = cljrs_reader::Form::new(
cljrs_reader::form::FormKind::List(vec![
cljrs_reader::Form::new(
cljrs_reader::form::FormKind::Symbol("require".into()),
span(),
),
cljrs_reader::Form::new(
cljrs_reader::form::FormKind::Quote(Box::new(cljrs_reader::Form::new(
cljrs_reader::form::FormKind::Symbol((*ns_name).into()),
span(),
))),
span(),
),
]),
span(),
);
if let Err(e) = eval(&require_form, env) {
eprintln!("[compiler-load warning] failed to load {ns_name}: {e:?}");
LOADING.store(false, std::sync::atomic::Ordering::Release);
return false;
}
}
globals
.compiler_ready
.store(true, std::sync::atomic::Ordering::Release);
LOADING.store(false, std::sync::atomic::Ordering::Release);
true
}
pub fn standard_env_minimal() -> Arc<GlobalEnv> {
cljrs_interp::standard_env_minimal(Some(eval), Some(apply::call_cljrs_fn), Some(eager_lower_fn))
}
pub fn standard_env() -> Arc<GlobalEnv> {
let globals = standard_env_minimal();
register_compiler_sources(&globals);
globals
}
pub fn standard_env_with_paths(source_paths: Vec<std::path::PathBuf>) -> Arc<GlobalEnv> {
let globals = standard_env();
globals.set_source_paths(source_paths);
globals
}
pub fn load_prebuilt_ir(globals: &Arc<GlobalEnv>, bundle: &cljrs_ir::IrBundle) -> usize {
use cljrs_value::Value;
let ns_map = globals.namespaces.read().unwrap();
let mut loaded = 0usize;
for (ns_name, ns_ptr) in ns_map.iter() {
let interns = ns_ptr.get().interns.lock().unwrap();
for (var_name, var) in interns.iter() {
let val = var.get().deref().unwrap_or(Value::Nil);
let f = match &val {
Value::Fn(gc_fn) => gc_fn.get(),
_ => continue,
};
if f.is_macro {
continue;
}
for arity in &f.arities {
let key = if arity.rest_param.is_some() {
format!("{ns_name}/{var_name}:{}+", arity.params.len())
} else {
format!("{ns_name}/{var_name}:{}", arity.params.len())
};
if let Some(ir_func) = bundle.get(&key) {
ir_cache::store_cached(arity.ir_arity_id, Arc::new(ir_func.clone()));
loaded += 1;
}
}
}
}
loaded
}