1use std::cell::RefCell;
9use std::sync::Arc;
10
11use cljrs_value::{Value, ValueError, ValueResult};
12
13use crate::env::{Env, GlobalEnv};
14
15struct EvalContext {
18 globals: Arc<GlobalEnv>,
19 current_ns: Arc<str>,
20}
21
22thread_local! {
23 static EVAL_CONTEXT: RefCell<Vec<EvalContext>> = const { RefCell::new(Vec::new()) };
24}
25
26pub fn push_eval_context(env: &Env) {
28 EVAL_CONTEXT.with(|stack| {
29 stack.borrow_mut().push(EvalContext {
30 globals: env.globals.clone(),
31 current_ns: env.current_ns.clone(),
32 });
33 });
34}
35
36pub fn pop_eval_context() {
38 EVAL_CONTEXT.with(|stack| {
39 stack.borrow_mut().pop();
40 });
41}
42
43pub fn capture_eval_context() -> Option<(Arc<GlobalEnv>, Arc<str>)> {
47 EVAL_CONTEXT.with(|stack| {
48 let s = stack.borrow();
49 let ec = s.last()?;
50 Some((ec.globals.clone(), ec.current_ns.clone()))
51 })
52}
53
54pub fn install_eval_context(globals: Arc<GlobalEnv>, ns: Arc<str>) {
58 EVAL_CONTEXT.with(|stack| {
59 stack.borrow_mut().push(EvalContext {
60 globals,
61 current_ns: ns,
62 });
63 });
64}
65
66pub fn with_eval_context<F, R>(f: F) -> Result<R, crate::error::EvalError>
88where
89 F: FnOnce(&mut Env) -> Result<R, crate::error::EvalError>,
90{
91 let (globals, ns) = EVAL_CONTEXT.with(|stack| {
92 let s = stack.borrow();
93 let ec = s.last().ok_or_else(|| {
94 crate::error::EvalError::Runtime(
95 "with_eval_context called outside eval context".to_string(),
96 )
97 })?;
98 Ok::<_, crate::error::EvalError>((ec.globals.clone(), ec.current_ns.clone()))
99 })?;
100 let mut env = Env::new(globals, &ns);
101 f(&mut env)
102}
103
104pub fn invoke(f: &Value, args: Vec<Value>) -> ValueResult<Value> {
105 let (globals, ns) = EVAL_CONTEXT.with(|stack| {
106 let s = stack.borrow();
107 let ec = s
108 .last()
109 .ok_or_else(|| ValueError::Other("invoke called outside eval context".into()))?;
110 Ok((ec.globals.clone(), ec.current_ns.clone()))
111 })?;
112 let mut env = Env::new(globals, &ns);
113 let f = f.unwrap_meta();
117 let result = if let Value::Fn(cljx_fn) = f {
118 env.call_cljrs_fn(cljx_fn.get(), &args)
119 } else {
120 crate::apply::apply_value(f, args, &mut env)
121 };
122 result.map_err(|e| match e {
123 crate::error::EvalError::Thrown(v) => ValueError::Thrown(v),
124 other => ValueError::Other(format!("{other}")),
125 })
126}