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 "cljrs.compiler.escape",
74 "cljrs.compiler.optimize",
75 ] {
76 let require_form = cljrs_reader::Form::new(
77 cljrs_reader::form::FormKind::List(vec![
78 cljrs_reader::Form::new(
79 cljrs_reader::form::FormKind::Symbol("require".into()),
80 span(),
81 ),
82 cljrs_reader::Form::new(
83 cljrs_reader::form::FormKind::Quote(Box::new(cljrs_reader::Form::new(
84 cljrs_reader::form::FormKind::Symbol((*ns_name).into()),
85 span(),
86 ))),
87 span(),
88 ),
89 ]),
90 span(),
91 );
92 if let Err(e) = eval(&require_form, env) {
93 eprintln!("[compiler-load warning] failed to load {ns_name}: {e:?}");
94 LOADING.store(false, std::sync::atomic::Ordering::Release);
95 return false;
96 }
97 }
98
99 globals
100 .compiler_ready
101 .store(true, std::sync::atomic::Ordering::Release);
102 LOADING.store(false, std::sync::atomic::Ordering::Release);
103 true
104}
105
106pub fn standard_env_minimal() -> Arc<GlobalEnv> {
107 cljrs_interp::standard_env_minimal(Some(eval), Some(apply::call_cljrs_fn), Some(eager_lower_fn))
108}
109
110pub fn standard_env() -> Arc<GlobalEnv> {
111 let globals = standard_env_minimal();
112 register_compiler_sources(&globals);
113 globals
114}
115
116pub fn standard_env_with_paths(source_paths: Vec<std::path::PathBuf>) -> Arc<GlobalEnv> {
117 let globals = standard_env();
118 globals.set_source_paths(source_paths);
119 globals
120}
121
122pub fn load_prebuilt_ir(globals: &Arc<GlobalEnv>, bundle: &cljrs_ir::IrBundle) -> usize {
131 use cljrs_value::Value;
132
133 let ns_map = globals.namespaces.read().unwrap();
134 let mut loaded = 0usize;
135
136 for (ns_name, ns_ptr) in ns_map.iter() {
137 let interns = ns_ptr.get().interns.lock().unwrap();
138 for (var_name, var) in interns.iter() {
139 let val = var.get().deref().unwrap_or(Value::Nil);
140 let f = match &val {
141 Value::Fn(gc_fn) => gc_fn.get(),
142 _ => continue,
143 };
144 if f.is_macro {
145 continue;
146 }
147
148 for arity in &f.arities {
149 let key = if arity.rest_param.is_some() {
150 format!("{ns_name}/{var_name}:{}+", arity.params.len())
151 } else {
152 format!("{ns_name}/{var_name}:{}", arity.params.len())
153 };
154
155 if let Some(ir_func) = bundle.get(&key) {
156 ir_cache::store_cached(arity.ir_arity_id, Arc::new(ir_func.clone()));
157 loaded += 1;
158 }
159 }
160 }
161 }
162
163 loaded
164}