1use crate::{2 dynamic_wrapper, evaluate, evaluate_method, BoxedContextCreator, Context, FunctionDefault,3 FunctionRhs, ObjValue,4};5use crate::{Binding, BoxedBinding, BoxedFunctionDefault, BoxedFunctionRhs, FutureContext};6use jsonnet_parser::{ArgsDesc, Expr, LiteralType, Param, ParamsDesc};7use std::{8 collections::HashMap,9 fmt::{Debug, Display},10 ops::Deref,11 rc::Rc,12};1314pub trait LazyVal: Debug {15 fn evaluate(&self) -> Val;16}17dynamic_wrapper!(LazyVal, BoxedLazyVal);1819#[derive(Debug)]20pub struct PlainLazyVal {21 pub expr: Expr,22 pub context: Context,23}24impl LazyVal for PlainLazyVal {25 fn evaluate(&self) -> Val {26 evaluate(self.context.clone(), &self.expr)27 }28}2930#[derive(Debug)]31pub struct NoArgsBindingLazyVal {32 pub expr: Expr,33 pub context_creator: BoxedContextCreator,3435 pub this: Option<ObjValue>,36 pub super_obj: Option<ObjValue>,37}38impl LazyVal for NoArgsBindingLazyVal {39 fn evaluate(&self) -> Val {40 evaluate(41 self.context_creator42 .create_context(&self.this, &self.super_obj),43 &self.expr,44 )45 }46}4748#[derive(Debug)]49pub struct ArgsBindingLazyVal {50 pub expr: Expr,51 pub args: ParamsDesc,52 pub context_creator: BoxedContextCreator,5354 pub this: Option<ObjValue>,55 pub super_obj: Option<ObjValue>,56}57impl LazyVal for ArgsBindingLazyVal {58 fn evaluate(&self) -> Val {59 evaluate_method(60 self.context_creator61 .create_context(&self.this, &self.super_obj),62 &self.expr,63 self.args.clone(),64 )65 }66}6768#[derive(Debug)]69pub struct FunctionDefaultBinding {70 eval: BoxedFunctionDefault,71 default: Expr,72 ctx: FutureContext,73}74impl Binding for FunctionDefaultBinding {75 fn evaluate(&self, _this: Option<ObjValue>, _super_obj: Option<ObjValue>) -> Val {76 self.eval77 .default(self.ctx.clone().unwrap(), self.default.clone())78 }79}8081#[derive(Debug)]82pub struct ValBinding {83 val: Val,84}85impl Binding for ValBinding {86 fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {87 self.val.clone()88 }89}9091#[derive(Debug, PartialEq, Clone)]92pub struct FuncDesc {93 pub ctx: Context,94 pub params: ParamsDesc,95 pub eval_rhs: BoxedFunctionRhs,96 pub eval_default: BoxedFunctionDefault,97}98impl FuncDesc {99 100 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {101 let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();102 let future_ctx = Context::new_future();103104 self.params105 .with_defaults()106 .into_iter()107 .for_each(|Param(name, default)| {108 new_bindings.insert(109 name,110 Rc::new(FunctionDefaultBinding {111 eval: self.eval_default.clone(),112 default: *default.unwrap().clone(),113 ctx: future_ctx.clone(),114 }),115 );116 });117 for (name, val) in args.iter().filter(|e| e.0.is_some()) {118 new_bindings.insert(119 name.as_ref().unwrap().clone(),120 Rc::new(ValBinding { val: val.clone() }),121 );122 }123 for (i, param) in self.params.0.iter().enumerate() {124 if let Some((None, val)) = args.get(i) {125 new_bindings.insert(param.0.clone(), Rc::new(ValBinding { val: val.clone() }));126 }127 }128 let ctx = self129 .ctx130 .extend(new_bindings, None, None, None)131 .into_future(future_ctx);132 self.eval_rhs.evaluate(ctx)133 }134}135136#[derive(Debug, PartialEq, Clone)]137pub enum Val {138 Literal(LiteralType),139 Str(String),140 Num(f64),141 Lazy(BoxedLazyVal),142 Arr(Vec<Val>),143 Obj(ObjValue),144 Func(FuncDesc),145}146impl Val {147 pub fn unwrap_if_lazy(self) -> Self {148 if let Val::Lazy(v) = self {149 v.evaluate().unwrap_if_lazy()150 } else {151 self152 }153 }154 pub fn type_of(&self) -> &'static str {155 match self {156 Val::Str(..) => "string",157 Val::Num(..) => "number",158 Val::Arr(..) => "array",159 Val::Obj(..) => "object",160 Val::Func(..) => "function",161 _ => panic!("no native type found"),162 }163 }164}165impl Display for Val {166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {167 match self {168 Val::Literal(v) => write!(f, "{}", v)?,169 Val::Str(str) => write!(f, "\"{}\"", str)?,170 Val::Num(n) => write!(f, "{}", n)?,171 Val::Arr(values) => {172 write!(f, "[")?;173 let mut first = true;174 for value in values {175 if first {176 first = false;177 } else {178 write!(f, ",")?;179 }180 write!(f, "{}", value)?;181 }182 write!(f, "]")?;183 }184 Val::Obj(value) => {185 write!(f, "{{")?;186 let mut first = true;187 for field in value.fields() {188 if first {189 first = false;190 } else {191 write!(f, ",")?;192 }193 write!(f, "\"{}\":", field)?;194 write!(f, "{}", value.get_raw(&field, None).unwrap())?;195 }196 write!(f, "}}")?;197 }198 Val::Lazy(lazy) => {199 write!(f, "{}", lazy.evaluate())?;200 }201 Val::Func(_) => {202 write!(f, "<<FUNC>>")?;203 }204 v => panic!("no json equivalent for {:?}", v),205 };206 Ok(())207 }208}209210pub fn bool_val(v: bool) -> Val {211 if v {212 Val::Literal(LiteralType::True)213 } else {214 Val::Literal(LiteralType::False)215 }216}