git.delta.rocks / jrsonnet / refs/commits / 067b138a5c9b

difftreelog

source

crates/jsonnet-evaluator/src/val.rs4.7 KiBsourcehistory
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	// TODO: Check for unset variables100	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}