git.delta.rocks / jrsonnet / refs/commits / a292d3c2f0f5

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs8.0 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	typed::Typed,11	val::{StrValue, ThunkValue},12	Context, Thunk, Val,13};1415/// Marker for arguments, which can be evaluated with context set to None16pub trait OptionalContext {}1718#[derive(Trace)]19struct EvaluateThunk {20	ctx: Context,21	expr: LocExpr,22}23impl ThunkValue for EvaluateThunk {24	type Output = Val;25	fn get(self: Box<Self>) -> Result<Val> {26		evaluate(self.ctx, &self.expr)27	}28}2930pub trait ArgLike {31	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;32}3334impl ArgLike for &LocExpr {35	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {36		Ok(if tailstrict {37			Thunk::evaluated(evaluate(ctx, self)?)38		} else {39			Thunk::new(EvaluateThunk {40				ctx,41				expr: (*self).clone(),42			})43		})44	}45}4647impl<T> ArgLike for T48where49	T: Typed + Clone,50{51	fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {52		let val = T::into_untyped(self.clone())?;53		Ok(Thunk::evaluated(val))54	}55}56impl<T> OptionalContext for T where T: Typed + Clone {}5758impl ArgLike for Thunk<Val> {59	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {60		if tailstrict {61			self.force()?;62		}63		Ok(self.clone())64	}65}66impl OptionalContext for Thunk<Val> {}6768#[derive(Clone, Trace)]69pub enum TlaArg {70	String(IStr),71	Code(LocExpr),72	Val(Val),73}74impl ArgLike for TlaArg {75	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {76		match self {77			TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),78			TlaArg::Code(code) => Ok(if tailstrict {79				Thunk::evaluated(evaluate(ctx, code)?)80			} else {81				Thunk::new(EvaluateThunk {82					ctx,83					expr: code.clone(),84				})85			}),86			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),87		}88	}89}9091mod sealed {92	/// Implemented for `ArgsLike`, where only unnamed arguments present93	pub trait Unnamed {}94	/// Implemented for `ArgsLike`, where only named arguments present95	pub trait Named {}96}9798pub trait ArgsLike {99	fn unnamed_len(&self) -> usize;100	fn unnamed_iter(101		&self,102		ctx: Context,103		tailstrict: bool,104		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,105	) -> Result<()>;106	fn named_iter(107		&self,108		ctx: Context,109		tailstrict: bool,110		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,111	) -> Result<()>;112	fn named_names(&self, handler: &mut dyn FnMut(&IStr));113}114115impl ArgsLike for Vec<Val> {116	fn unnamed_len(&self) -> usize {117		self.len()118	}119	fn unnamed_iter(120		&self,121		_ctx: Context,122		_tailstrict: bool,123		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,124	) -> Result<()> {125		for (idx, el) in self.iter().enumerate() {126			handler(idx, Thunk::evaluated(el.clone()))?;127		}128		Ok(())129	}130	fn named_iter(131		&self,132		_ctx: Context,133		_tailstrict: bool,134		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,135	) -> Result<()> {136		Ok(())137	}138	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}139}140141impl ArgsLike for ArgsDesc {142	fn unnamed_len(&self) -> usize {143		self.unnamed.len()144	}145146	fn unnamed_iter(147		&self,148		ctx: Context,149		tailstrict: bool,150		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,151	) -> Result<()> {152		for (id, arg) in self.unnamed.iter().enumerate() {153			handler(154				id,155				if tailstrict {156					Thunk::evaluated(evaluate(ctx.clone(), arg)?)157				} else {158					Thunk::new(EvaluateThunk {159						ctx: ctx.clone(),160						expr: arg.clone(),161					})162				},163			)?;164		}165		Ok(())166	}167168	fn named_iter(169		&self,170		ctx: Context,171		tailstrict: bool,172		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,173	) -> Result<()> {174		for (name, arg) in &self.named {175			handler(176				name,177				if tailstrict {178					Thunk::evaluated(evaluate(ctx.clone(), arg)?)179				} else {180					Thunk::new(EvaluateThunk {181						ctx: ctx.clone(),182						expr: arg.clone(),183					})184				},185			)?;186		}187		Ok(())188	}189190	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {191		for (name, _) in &self.named {192			handler(name);193		}194	}195}196197impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}198impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {199	fn unnamed_len(&self) -> usize {200		0201	}202203	fn unnamed_iter(204		&self,205		_ctx: Context,206		_tailstrict: bool,207		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,208	) -> Result<()> {209		Ok(())210	}211212	fn named_iter(213		&self,214		ctx: Context,215		tailstrict: bool,216		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,217	) -> Result<()> {218		for (name, value) in self.iter() {219			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;220		}221		Ok(())222	}223224	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {225		for (name, _) in self.iter() {226			handler(name);227		}228	}229}230impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}231232impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {233	fn unnamed_len(&self) -> usize {234		self.0.unnamed_len()235	}236237	fn unnamed_iter(238		&self,239		ctx: Context,240		tailstrict: bool,241		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,242	) -> Result<()> {243		self.0.unnamed_iter(ctx, tailstrict, handler)244	}245246	fn named_iter(247		&self,248		ctx: Context,249		tailstrict: bool,250		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,251	) -> Result<()> {252		self.0.named_iter(ctx, tailstrict, handler)253	}254255	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {256		self.0.named_names(handler);257	}258}259260macro_rules! impl_args_like {261	($count:expr; $($gen:ident)*) => {262		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}263		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {264			fn unnamed_len(&self) -> usize {265				$count266			}267			#[allow(non_snake_case, unused_assignments)]268			fn unnamed_iter(269				&self,270				ctx: Context,271				tailstrict: bool,272				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,273			) -> Result<()> {274				let mut i = 0usize;275				let ($($gen,)*) = self;276				$(277					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;278					i+=1;279				)*280				Ok(())281			}282			fn named_iter(283				&self,284				_ctx: Context,285				_tailstrict: bool,286				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,287			) -> Result<()> {288				Ok(())289			}290			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}291		}292		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}293294		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}295		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {296			fn unnamed_len(&self) -> usize {297				0298			}299			fn unnamed_iter(300				&self,301				_ctx: Context,302				_tailstrict: bool,303				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,304			) -> Result<()> {305				Ok(())306			}307			#[allow(non_snake_case)]308			fn named_iter(309				&self,310				ctx: Context,311				tailstrict: bool,312				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,313			) -> Result<()> {314				let ($($gen,)*) = self;315				$(316					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;317				)*318				Ok(())319			}320			#[allow(non_snake_case)]321			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {322				let ($($gen,)*) = self;323				$(324					handler(&$gen.0);325				)*326			}327		}328		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}329	};330	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {331		impl_args_like!($count; $($cur)*);332		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);333	};334	($count:expr; $($cur:ident)* @) => {335		impl_args_like!($count; $($cur)*);336	}337}338impl_args_like! {339	// First argument is already in position, so count starts from 1340	1usize; A @ B C D E F G H I J K L341}342343impl ArgsLike for () {344	fn unnamed_len(&self) -> usize {345		0346	}347348	fn unnamed_iter(349		&self,350		_ctx: Context,351		_tailstrict: bool,352		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,353	) -> Result<()> {354		Ok(())355	}356357	fn named_iter(358		&self,359		_ctx: Context,360		_tailstrict: bool,361		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,362	) -> Result<()> {363		Ok(())364	}365366	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}367}368impl OptionalContext for () {}