git.delta.rocks / jrsonnet / refs/commits / 54c4db58ad3d

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.8 KiBsourcehistory
1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{7	error::Result,8	evaluate,9	gc::GcHashMap,10	tb,11	typed::Typed,12	val::{StrValue, ThunkValue},13	Context, Thunk, Val,14};1516/// Marker for arguments, which can be evaluated with context set to None17pub trait OptionalContext {}1819#[derive(Trace)]20struct EvaluateThunk {21	ctx: Context,22	expr: LocExpr,23}24impl ThunkValue for EvaluateThunk {25	type Output = Val;26	fn get(self: Box<Self>) -> Result<Val> {27		evaluate(self.ctx, &self.expr)28	}29}3031pub trait ArgLike {32	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;33}3435impl ArgLike for &LocExpr {36	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {37		Ok(if tailstrict {38			Thunk::evaluated(evaluate(ctx, self)?)39		} else {40			Thunk::new(tb!(EvaluateThunk {41				ctx,42				expr: (*self).clone(),43			}))44		})45	}46}4748impl<T> ArgLike for T49where50	T: Typed + Clone,51{52	fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {53		let val = T::into_untyped(self.clone())?;54		Ok(Thunk::evaluated(val))55	}56}57impl<T> OptionalContext for T where T: Typed + Clone {}5859#[derive(Clone, Trace)]60pub enum TlaArg {61	String(IStr),62	Code(LocExpr),63	Val(Val),64}65impl ArgLike for TlaArg {66	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {67		match self {68			TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),69			TlaArg::Code(code) => Ok(if tailstrict {70				Thunk::evaluated(evaluate(ctx, code)?)71			} else {72				Thunk::new(tb!(EvaluateThunk {73					ctx,74					expr: code.clone(),75				}))76			}),77			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),78		}79	}80}8182mod sealed {83	/// Implemented for `ArgsLike`, where only unnamed arguments present84	pub trait Unnamed {}85	/// Implemented for `ArgsLike`, where only named arguments present86	pub trait Named {}87}8889pub trait ArgsLike {90	fn unnamed_len(&self) -> usize;91	fn unnamed_iter(92		&self,93		ctx: Context,94		tailstrict: bool,95		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,96	) -> Result<()>;97	fn named_iter(98		&self,99		ctx: Context,100		tailstrict: bool,101		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,102	) -> Result<()>;103	fn named_names(&self, handler: &mut dyn FnMut(&IStr));104}105106impl ArgsLike for Vec<Val> {107	fn unnamed_len(&self) -> usize {108		self.len()109	}110	fn unnamed_iter(111		&self,112		_ctx: Context,113		_tailstrict: bool,114		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,115	) -> Result<()> {116		for (idx, el) in self.iter().enumerate() {117			handler(idx, Thunk::evaluated(el.clone()))?;118		}119		Ok(())120	}121	fn named_iter(122		&self,123		_ctx: Context,124		_tailstrict: bool,125		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,126	) -> Result<()> {127		Ok(())128	}129	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}130}131impl OptionalContext for Vec<Val> {}132133impl ArgsLike for ArgsDesc {134	fn unnamed_len(&self) -> usize {135		self.unnamed.len()136	}137138	fn unnamed_iter(139		&self,140		ctx: Context,141		tailstrict: bool,142		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,143	) -> Result<()> {144		for (id, arg) in self.unnamed.iter().enumerate() {145			handler(146				id,147				if tailstrict {148					Thunk::evaluated(evaluate(ctx.clone(), arg)?)149				} else {150					Thunk::new(tb!(EvaluateThunk {151						ctx: ctx.clone(),152						expr: arg.clone(),153					}))154				},155			)?;156		}157		Ok(())158	}159160	fn named_iter(161		&self,162		ctx: Context,163		tailstrict: bool,164		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,165	) -> Result<()> {166		for (name, arg) in &self.named {167			handler(168				name,169				if tailstrict {170					Thunk::evaluated(evaluate(ctx.clone(), arg)?)171				} else {172					Thunk::new(tb!(EvaluateThunk {173						ctx: ctx.clone(),174						expr: arg.clone(),175					}))176				},177			)?;178		}179		Ok(())180	}181182	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {183		for (name, _) in &self.named {184			handler(name);185		}186	}187}188189impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}190impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {191	fn unnamed_len(&self) -> usize {192		0193	}194195	fn unnamed_iter(196		&self,197		_ctx: Context,198		_tailstrict: bool,199		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,200	) -> Result<()> {201		Ok(())202	}203204	fn named_iter(205		&self,206		ctx: Context,207		tailstrict: bool,208		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,209	) -> Result<()> {210		for (name, value) in self.iter() {211			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;212		}213		Ok(())214	}215216	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {217		for (name, _) in self.iter() {218			handler(name);219		}220	}221}222impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}223224impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {225	fn unnamed_len(&self) -> usize {226		self.0.unnamed_len()227	}228229	fn unnamed_iter(230		&self,231		ctx: Context,232		tailstrict: bool,233		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,234	) -> Result<()> {235		self.0.unnamed_iter(ctx, tailstrict, handler)236	}237238	fn named_iter(239		&self,240		ctx: Context,241		tailstrict: bool,242		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,243	) -> Result<()> {244		self.0.named_iter(ctx, tailstrict, handler)245	}246247	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {248		self.0.named_names(handler);249	}250}251252macro_rules! impl_args_like {253	($count:expr; $($gen:ident)*) => {254		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}255		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {256			fn unnamed_len(&self) -> usize {257				$count258			}259			#[allow(non_snake_case, unused_assignments)]260			fn unnamed_iter(261				&self,262				ctx: Context,263				tailstrict: bool,264				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,265			) -> Result<()> {266				let mut i = 0usize;267				let ($($gen,)*) = self;268				$(269					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;270					i+=1;271				)*272				Ok(())273			}274			fn named_iter(275				&self,276				_ctx: Context,277				_tailstrict: bool,278				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,279			) -> Result<()> {280				Ok(())281			}282			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}283		}284		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}285286		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}287		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {288			fn unnamed_len(&self) -> usize {289				0290			}291			fn unnamed_iter(292				&self,293				_ctx: Context,294				_tailstrict: bool,295				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,296			) -> Result<()> {297				Ok(())298			}299			#[allow(non_snake_case)]300			fn named_iter(301				&self,302				ctx: Context,303				tailstrict: bool,304				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,305			) -> Result<()> {306				let ($($gen,)*) = self;307				$(308					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;309				)*310				Ok(())311			}312			#[allow(non_snake_case)]313			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {314				let ($($gen,)*) = self;315				$(316					handler(&$gen.0);317				)*318			}319		}320		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}321	};322	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {323		impl_args_like!($count; $($cur)*);324		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);325	};326	($count:expr; $($cur:ident)* @) => {327		impl_args_like!($count; $($cur)*);328	}329}330impl_args_like! {331	// First argument is already in position, so count starts from 1332	1usize; A @ B C D E F G H I J K L333}334335impl ArgsLike for () {336	fn unnamed_len(&self) -> usize {337		0338	}339340	fn unnamed_iter(341		&self,342		_ctx: Context,343		_tailstrict: bool,344		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,345	) -> Result<()> {346		Ok(())347	}348349	fn named_iter(350		&self,351		_ctx: Context,352		_tailstrict: bool,353		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,354	) -> Result<()> {355		Ok(())356	}357358	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}359}360impl OptionalContext for () {}