#![allow(dead_code)]
use std::cell::Cell;
use std::sync::Arc;
use cljrs_reader::Parser;
use cljrs_runtime::env::env::{Env, GlobalEnv};
use cljrs_value::Value;
thread_local! {
static GLOBALS: Arc<GlobalEnv> = build_globals_in(cljrs_runtime::ExecutionMode::TreeWalk);
static TIERED_GLOBALS: Arc<GlobalEnv> =
build_globals_in(cljrs_runtime::ExecutionMode::Tiered);
static NEXT_NS: Cell<u64> = const { Cell::new(0) };
}
fn build_globals_in(mode: cljrs_runtime::ExecutionMode) -> Arc<GlobalEnv> {
cljrs_runtime::Runtime::builder()
.execution_mode(mode)
.eager_clojure_test(true)
.build()
.expect("runtime")
.into_globals()
}
pub fn shared_globals() -> Arc<GlobalEnv> {
GLOBALS.with(|g| g.clone())
}
pub fn shared_globals_in(mode: cljrs_runtime::ExecutionMode) -> Arc<GlobalEnv> {
match mode {
cljrs_runtime::ExecutionMode::TreeWalk => GLOBALS.with(|g| g.clone()),
_ => TIERED_GLOBALS.with(|g| g.clone()),
}
}
pub fn fresh_env() -> (Arc<GlobalEnv>, Env) {
fresh_env_in(cljrs_runtime::ExecutionMode::TreeWalk)
}
pub fn fresh_env_in(mode: cljrs_runtime::ExecutionMode) -> (Arc<GlobalEnv>, Env) {
let globals = shared_globals_in(mode);
let n = NEXT_NS.with(|c| {
let n = c.get();
c.set(n + 1);
n
});
let ns = format!("prop-case-{n}");
globals.get_or_create_ns(&ns);
globals.refer_core(&ns);
let env = Env::new(globals.clone(), &ns);
(globals, env)
}
pub fn reset_env_in(mode: cljrs_runtime::ExecutionMode, ns: &str) -> (Arc<GlobalEnv>, Env) {
let globals = shared_globals_in(mode);
globals.namespaces.write().unwrap().remove(ns);
globals.get_or_create_ns(ns);
globals.refer_core(ns);
let env = Env::new(globals.clone(), ns);
(globals, env)
}
pub fn eval_in(env: &mut Env, src: &str) -> Result<Value, String> {
let mut parser = Parser::new(src.to_string(), "<test>".to_string());
let forms = parser.parse_all().map_err(|e| format!("parse: {e:?}"))?;
let mut result = Value::Nil;
for form in forms {
result =
cljrs_runtime::interp::eval::eval(&form, env).map_err(|e| format!("eval: {e:?}"))?;
}
Ok(result)
}
pub fn eval_fresh(src: &str) -> Result<Value, String> {
let (_g, mut env) = fresh_env();
eval_in(&mut env, src)
}