use crate::define::Result;
use crate::function::InnerFunction;
use crate::value::Value;
use core::clone::Clone;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub enum ContextValue {
Variable(Value),
Function(Arc<InnerFunction>),
}
pub struct Context(pub Arc<Mutex<HashMap<String, ContextValue>>>);
impl Context {
pub fn new() -> Self {
Context(Arc::new(Mutex::new(HashMap::new())))
}
pub fn set_func(&mut self, name: &str, func: Arc<InnerFunction>) {
self.set(name, ContextValue::Function(func.clone()));
}
pub fn set_variable(&mut self, name: &str, value: Value) {
self.set(name, ContextValue::Variable(value));
}
pub fn set(&mut self, name: &str, v: ContextValue) {
self.0.lock().unwrap().insert(name.to_string(), v);
}
pub fn get_func(&self, name: &str) -> Option<Arc<InnerFunction>> {
let value = self.get(name)?;
match value {
ContextValue::Function(func) => Some(func.clone()),
ContextValue::Variable(_) => None,
}
}
pub fn get_variable(&self, name: &str) -> Option<Value> {
let value = self.get(name)?;
match value {
ContextValue::Variable(v) => Some(v.clone()),
ContextValue::Function(_) => None,
}
}
pub fn get(&self, name: &str) -> Option<ContextValue> {
let binding = self.0.lock().unwrap();
let value = binding.get(name)?;
Some(value.clone())
}
pub fn value(&self, name: &str) -> Result<Value> {
let binding = self.0.lock().unwrap();
if binding.get(name).is_none() {
return Ok(Value::None);
}
let value = binding.get(name).unwrap();
match value {
ContextValue::Variable(v) => Ok(v.clone()),
ContextValue::Function(func) => func(Vec::new()),
}
}
}
#[macro_export]
macro_rules! create_context {
(($ctx:expr) $k:expr => Arc::new($($v:tt)*), $($tt:tt)*) => {{
$ctx.set_func($k, Arc::new($($v)*));
$crate::create_context!(($ctx) $($tt)*);
}};
(($ctx:expr) $k:expr => $v:expr, $($tt:tt)*) => {{
$ctx.set_variable($k, Value::from($v));
$crate::create_context!(($ctx) $($tt)*);
}};
(($ctx:expr) $k:expr => Arc::new($($v:tt)*)) => {{
$ctx.set_func($k, Arc::new($($v)*));
}};
(($ctx:expr) $k:expr => $v:expr) => {{
$ctx.set_variable($k, Value::from($v));
}};
(($ctx:expr)) => {};
($($tt:tt)*) => {{
use std::sync::Arc;
let mut ctx = $crate::Context::new();
$crate::create_context!((&mut ctx) $($tt)*);
ctx
}};
}