1#![allow(clippy::result_large_err)]
17#![allow(clippy::type_complexity)]
19
20pub mod apply;
21pub mod ir_cache;
22pub mod ir_convert;
23pub mod ir_interp;
24pub mod lower;
25
26pub use cljrs_env::callback::invoke;
27pub use cljrs_env::env::{Env, GlobalEnv};
28pub use cljrs_env::error::{EvalError, EvalResult};
29pub use cljrs_env::loader::load_ns;
30pub use cljrs_interp::eval::eval;
31
32use crate::ir_interp::eager_lower_fn;
33use std::sync::Arc;
34
35pub fn register_compiler_sources(globals: &Arc<GlobalEnv>) {
36 globals.register_builtin_source("cljrs.compiler.ir", cljrs_ir::COMPILER_IR_SOURCE);
37 globals.register_builtin_source("cljrs.compiler.known", cljrs_ir::COMPILER_KNOWN_SOURCE);
38 globals.register_builtin_source("cljrs.compiler.anf", cljrs_ir::COMPILER_ANF_SOURCE);
39 globals.register_builtin_source("cljrs.compiler.escape", cljrs_ir::COMPILER_ESCAPE_SOURCE);
40 globals.register_builtin_source(
41 "cljrs.compiler.optimize",
42 cljrs_ir::COMPILER_OPTIMIZE_SOURCE,
43 );
44}
45
46pub fn ensure_compiler_loaded(globals: &Arc<GlobalEnv>, env: &mut Env) -> bool {
49 if globals
51 .compiler_ready
52 .load(std::sync::atomic::Ordering::Acquire)
53 {
54 return true;
55 }
56
57 if std::env::var("CLJRS_NO_IR").is_ok() {
59 return false;
60 }
61
62 static LOADING: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
64 if LOADING.swap(true, std::sync::atomic::Ordering::AcqRel) {
65 return false; }
67
68 let span = || cljrs_types::span::Span::new(Arc::new("<compiler-load>".to_string()), 0, 0, 1, 1);
69 for ns_name in &[
70 "cljrs.compiler.ir",
71 "cljrs.compiler.known",
72 "cljrs.compiler.anf",
73 ] {
74 let require_form = cljrs_reader::Form::new(
75 cljrs_reader::form::FormKind::List(vec![
76 cljrs_reader::Form::new(
77 cljrs_reader::form::FormKind::Symbol("require".into()),
78 span(),
79 ),
80 cljrs_reader::Form::new(
81 cljrs_reader::form::FormKind::Quote(Box::new(cljrs_reader::Form::new(
82 cljrs_reader::form::FormKind::Symbol((*ns_name).into()),
83 span(),
84 ))),
85 span(),
86 ),
87 ]),
88 span(),
89 );
90 if let Err(e) = eval(&require_form, env) {
91 eprintln!("[compiler-load warning] failed to load {ns_name}: {e:?}");
92 LOADING.store(false, std::sync::atomic::Ordering::Release);
93 return false;
94 }
95 }
96
97 globals
98 .compiler_ready
99 .store(true, std::sync::atomic::Ordering::Release);
100 LOADING.store(false, std::sync::atomic::Ordering::Release);
101 true
102}
103
104pub fn standard_env_minimal() -> Arc<GlobalEnv> {
105 cljrs_interp::standard_env_minimal(Some(eval), Some(apply::call_cljrs_fn), Some(eager_lower_fn))
106}
107
108pub fn standard_env() -> Arc<GlobalEnv> {
109 let globals = standard_env_minimal();
110 register_compiler_sources(&globals);
111 globals
112}
113
114pub fn standard_env_with_paths(source_paths: Vec<std::path::PathBuf>) -> Arc<GlobalEnv> {
115 let globals = standard_env();
116 globals.set_source_paths(source_paths);
117 globals
118}
119
120pub fn load_prebuilt_ir(globals: &Arc<GlobalEnv>, bundle: &cljrs_ir::IrBundle) -> usize {
129 use cljrs_value::Value;
130
131 let ns_map = globals.namespaces.read().unwrap();
132 let mut loaded = 0usize;
133
134 for (ns_name, ns_ptr) in ns_map.iter() {
135 let interns = ns_ptr.get().interns.lock().unwrap();
136 for (var_name, var) in interns.iter() {
137 let val = var.get().deref().unwrap_or(Value::Nil);
138 let f = match &val {
139 Value::Fn(gc_fn) => gc_fn.get(),
140 _ => continue,
141 };
142 if f.is_macro {
143 continue;
144 }
145
146 for arity in &f.arities {
147 let key = if arity.rest_param.is_some() {
148 format!("{ns_name}/{var_name}:{}+", arity.params.len())
149 } else {
150 format!("{ns_name}/{var_name}:{}", arity.params.len())
151 };
152
153 if let Some(ir_func) = bundle.get(&key) {
154 ir_cache::store_cached(arity.ir_arity_id, Arc::new(ir_func.clone()));
155 loaded += 1;
156 }
157 }
158 }
159 }
160
161 loaded
162}