git.delta.rocks / jrsonnet / refs/commits / 974f2c15c0a2

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	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 {}5758#[derive(Clone, Trace)]59pub enum TlaArg {60	String(IStr),61	Code(LocExpr),62	Val(Val),63}64impl ArgLike for TlaArg {65	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {66		match self {67			TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),68			TlaArg::Code(code) => Ok(if tailstrict {69				Thunk::evaluated(evaluate(ctx, code)?)70			} else {71				Thunk::new(EvaluateThunk {72					ctx,73					expr: code.clone(),74				})75			}),76			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),77		}78	}79}8081mod sealed {82	/// Implemented for `ArgsLike`, where only unnamed arguments present83	pub trait Unnamed {}84	/// Implemented for `ArgsLike`, where only named arguments present85	pub trait Named {}86}8788pub trait ArgsLike {89	fn unnamed_len(&self) -> usize;90	fn unnamed_iter(91		&self,92		ctx: Context,93		tailstrict: bool,94		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,95	) -> Result<()>;96	fn named_iter(97		&self,98		ctx: Context,99		tailstrict: bool,100		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,101	) -> Result<()>;102	fn named_names(&self, handler: &mut dyn FnMut(&IStr));103}104105impl ArgsLike for Vec<Val> {106	fn unnamed_len(&self) -> usize {107		self.len()108	}109	fn unnamed_iter(110		&self,111		_ctx: Context,112		_tailstrict: bool,113		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,114	) -> Result<()> {115		for (idx, el) in self.iter().enumerate() {116			handler(idx, Thunk::evaluated(el.clone()))?;117		}118		Ok(())119	}120	fn named_iter(121		&self,122		_ctx: Context,123		_tailstrict: bool,124		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,125	) -> Result<()> {126		Ok(())127	}128	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}129}130131impl ArgsLike for ArgsDesc {132	fn unnamed_len(&self) -> usize {133		self.unnamed.len()134	}135136	fn unnamed_iter(137		&self,138		ctx: Context,139		tailstrict: bool,140		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,141	) -> Result<()> {142		for (id, arg) in self.unnamed.iter().enumerate() {143			handler(144				id,145				if tailstrict {146					Thunk::evaluated(evaluate(ctx.clone(), arg)?)147				} else {148					Thunk::new(EvaluateThunk {149						ctx: ctx.clone(),150						expr: arg.clone(),151					})152				},153			)?;154		}155		Ok(())156	}157158	fn named_iter(159		&self,160		ctx: Context,161		tailstrict: bool,162		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,163	) -> Result<()> {164		for (name, arg) in &self.named {165			handler(166				name,167				if tailstrict {168					Thunk::evaluated(evaluate(ctx.clone(), arg)?)169				} else {170					Thunk::new(EvaluateThunk {171						ctx: ctx.clone(),172						expr: arg.clone(),173					})174				},175			)?;176		}177		Ok(())178	}179180	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {181		for (name, _) in &self.named {182			handler(name);183		}184	}185}186187impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}188impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {189	fn unnamed_len(&self) -> usize {190		0191	}192193	fn unnamed_iter(194		&self,195		_ctx: Context,196		_tailstrict: bool,197		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,198	) -> Result<()> {199		Ok(())200	}201202	fn named_iter(203		&self,204		ctx: Context,205		tailstrict: bool,206		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,207	) -> Result<()> {208		for (name, value) in self.iter() {209			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;210		}211		Ok(())212	}213214	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {215		for (name, _) in self.iter() {216			handler(name);217		}218	}219}220impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}221222impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {223	fn unnamed_len(&self) -> usize {224		self.0.unnamed_len()225	}226227	fn unnamed_iter(228		&self,229		ctx: Context,230		tailstrict: bool,231		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,232	) -> Result<()> {233		self.0.unnamed_iter(ctx, tailstrict, handler)234	}235236	fn named_iter(237		&self,238		ctx: Context,239		tailstrict: bool,240		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,241	) -> Result<()> {242		self.0.named_iter(ctx, tailstrict, handler)243	}244245	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {246		self.0.named_names(handler);247	}248}249250macro_rules! impl_args_like {251	($count:expr; $($gen:ident)*) => {252		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}253		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {254			fn unnamed_len(&self) -> usize {255				$count256			}257			#[allow(non_snake_case, unused_assignments)]258			fn unnamed_iter(259				&self,260				ctx: Context,261				tailstrict: bool,262				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,263			) -> Result<()> {264				let mut i = 0usize;265				let ($($gen,)*) = self;266				$(267					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;268					i+=1;269				)*270				Ok(())271			}272			fn named_iter(273				&self,274				_ctx: Context,275				_tailstrict: bool,276				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,277			) -> Result<()> {278				Ok(())279			}280			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}281		}282		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}283284		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}285		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {286			fn unnamed_len(&self) -> usize {287				0288			}289			fn unnamed_iter(290				&self,291				_ctx: Context,292				_tailstrict: bool,293				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,294			) -> Result<()> {295				Ok(())296			}297			#[allow(non_snake_case)]298			fn named_iter(299				&self,300				ctx: Context,301				tailstrict: bool,302				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,303			) -> Result<()> {304				let ($($gen,)*) = self;305				$(306					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;307				)*308				Ok(())309			}310			#[allow(non_snake_case)]311			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {312				let ($($gen,)*) = self;313				$(314					handler(&$gen.0);315				)*316			}317		}318		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}319	};320	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {321		impl_args_like!($count; $($cur)*);322		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);323	};324	($count:expr; $($cur:ident)* @) => {325		impl_args_like!($count; $($cur)*);326	}327}328impl_args_like! {329	// First argument is already in position, so count starts from 1330	1usize; A @ B C D E F G H I J K L331}332333impl ArgsLike for () {334	fn unnamed_len(&self) -> usize {335		0336	}337338	fn unnamed_iter(339		&self,340		_ctx: Context,341		_tailstrict: bool,342		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,343	) -> Result<()> {344		Ok(())345	}346347	fn named_iter(348		&self,349		_ctx: Context,350		_tailstrict: bool,351		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,352	) -> Result<()> {353		Ok(())354	}355356	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}357}358impl OptionalContext for () {}