1use crate::{2 create_error, lazy_binding, Context, Error, FunctionDefault, FunctionRhs, LazyBinding,3 ObjValue, Result,4};5use closure::closure;6use jsonnet_parser::{Param, ParamsDesc};7use std::{8 cell::RefCell,9 collections::HashMap,10 fmt::{Debug, Display},11 rc::Rc,12};1314struct LazyValInternals {15 pub f: Box<dyn Fn() -> Result<Val>>,16 pub cached: RefCell<Option<Val>>,17}18#[derive(Clone)]19pub struct LazyVal(Rc<LazyValInternals>);20impl LazyVal {21 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {22 LazyVal(Rc::new(LazyValInternals {23 f,24 cached: RefCell::new(None),25 }))26 }27 pub fn evaluate(&self) -> Result<Val> {28 {29 let cached = self.0.cached.borrow();30 if cached.is_some() {31 return Ok(cached.clone().unwrap());32 }33 }34 let result = (self.0.f)()?;35 self.0.cached.borrow_mut().replace(result.clone());36 Ok(result)37 }38}39#[macro_export]40macro_rules! lazy_val {41 ($f: expr) => {42 $crate::LazyVal::new(Box::new($f))43 };44}45impl Debug for LazyVal {46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {47 if self.0.cached.borrow().is_some() {48 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())49 } else {50 write!(f, "Lazy")51 }52 }53}54impl PartialEq for LazyVal {55 fn eq(&self, other: &Self) -> bool {56 Rc::ptr_eq(&self.0, &other.0)57 }58}5960#[derive(Debug, PartialEq, Clone)]61pub struct FuncDesc {62 pub ctx: Context,63 pub params: ParamsDesc,64 pub eval_rhs: FunctionRhs,65 pub eval_default: FunctionDefault,66}67impl FuncDesc {68 69 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Result<Val> {70 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();71 let future_ctx = Context::new_future();7273 for Param(name, default) in self.params.with_defaults() {74 let default = default.unwrap();75 let eval_default = self.eval_default.clone();76 new_bindings.insert(77 name,78 lazy_binding!(closure!(clone future_ctx, clone default, clone eval_default, |_, _| Ok(lazy_val!(closure!(clone future_ctx, clone eval_default, clone default, || (eval_default.clone()).079 (future_ctx.clone().unwrap(), default.clone())))))),80 );81 }82 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {83 new_bindings.insert(84 name.as_ref().unwrap().clone(),85 lazy_binding!(86 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))87 ),88 );89 }90 for (i, param) in self.params.0.iter().enumerate() {91 if let Some((None, val)) = args.get(i) {92 new_bindings.insert(93 param.0.clone(),94 lazy_binding!(95 closure!(clone val, |_, _| Ok(lazy_val!(closure!(clone val, || Ok(val.clone())))))96 ),97 );98 }99 }100 let ctx = self101 .ctx102 .extend(new_bindings, None, None, None)?103 .into_future(future_ctx);104 self.eval_rhs.0(ctx)105 }106}107108#[derive(Debug)]109pub enum ValType {110 Bool,111 Null,112 Str,113 Num,114 Arr,115 Obj,116 Func,117}118impl ValType {119 pub fn name(&self) -> &'static str {120 use ValType::*;121 match self {122 Bool => "boolean",123 Null => "null",124 Str => "string",125 Num => "number",126 Arr => "array",127 Obj => "object",128 Func => "function",129 }130 }131}132impl Display for ValType {133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {134 write!(f, "{}", self.name())135 }136}137138#[derive(Debug, PartialEq, Clone)]139pub enum Val {140 Bool(bool),141 Null,142 Str(String),143 Num(f64),144 Lazy(LazyVal),145 Arr(Vec<Val>),146 Obj(ObjValue),147 Func(FuncDesc),148149 150 Intristic(String, String),151}152impl Val {153 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {154 match self.unwrap_if_lazy()? {155 Val::Bool(v) => Ok(v),156 v => create_error(Error::TypeMismatch(157 context,158 vec![ValType::Bool],159 v.value_type()?,160 )),161 }162 }163 pub fn try_cast_str(self, context: &'static str) -> Result<String> {164 match self.unwrap_if_lazy()? {165 Val::Str(v) => Ok(v),166 v => create_error(Error::TypeMismatch(167 context,168 vec![ValType::Str],169 v.value_type()?,170 )),171 }172 }173 pub fn unwrap_if_lazy(self) -> Result<Self> {174 Ok(if let Val::Lazy(v) = self {175 v.evaluate()?.unwrap_if_lazy()?176 } else {177 self178 })179 }180 pub fn value_type(&self) -> Result<ValType> {181 Ok(match self {182 Val::Str(..) => ValType::Str,183 Val::Num(..) => ValType::Num,184 Val::Arr(..) => ValType::Arr,185 Val::Obj(..) => ValType::Obj,186 Val::Func(..) => ValType::Func,187 Val::Bool(_) => ValType::Bool,188 Val::Null => ValType::Null,189 Val::Intristic(_, _) => ValType::Func,190 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,191 })192 }193}