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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.9 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		if T::provides_lazy() && !tailstrict {53			return Ok(T::into_lazy_untyped(self.clone()));54		}55		let val = T::into_untyped(self.clone())?;56		Ok(Thunk::evaluated(val))57	}58}59impl<T> OptionalContext for T where T: Typed + Clone {}6061#[derive(Clone, Trace)]62pub enum TlaArg {63	String(IStr),64	Code(LocExpr),65	Val(Val),66	Lazy(Thunk<Val>),67}68impl ArgLike for TlaArg {69	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {70		match self {71			TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),72			TlaArg::Code(code) => Ok(if tailstrict {73				Thunk::evaluated(evaluate(ctx, code)?)74			} else {75				Thunk::new(EvaluateThunk {76					ctx,77					expr: code.clone(),78				})79			}),80			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),81			TlaArg::Lazy(lazy) => Ok(lazy.clone()),82		}83	}84}8586mod sealed {87	/// Implemented for `ArgsLike`, where only unnamed arguments present88	pub trait Unnamed {}89	/// Implemented for `ArgsLike`, where only named arguments present90	pub trait Named {}91}9293pub trait ArgsLike {94	fn unnamed_len(&self) -> usize;95	fn unnamed_iter(96		&self,97		ctx: Context,98		tailstrict: bool,99		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,100	) -> Result<()>;101	fn named_iter(102		&self,103		ctx: Context,104		tailstrict: bool,105		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,106	) -> Result<()>;107	fn named_names(&self, handler: &mut dyn FnMut(&IStr));108}109110impl ArgsLike for Vec<Val> {111	fn unnamed_len(&self) -> usize {112		self.len()113	}114	fn unnamed_iter(115		&self,116		_ctx: Context,117		_tailstrict: bool,118		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,119	) -> Result<()> {120		for (idx, el) in self.iter().enumerate() {121			handler(idx, Thunk::evaluated(el.clone()))?;122		}123		Ok(())124	}125	fn named_iter(126		&self,127		_ctx: Context,128		_tailstrict: bool,129		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,130	) -> Result<()> {131		Ok(())132	}133	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}134}135136impl ArgsLike for ArgsDesc {137	fn unnamed_len(&self) -> usize {138		self.unnamed.len()139	}140141	fn unnamed_iter(142		&self,143		ctx: Context,144		tailstrict: bool,145		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,146	) -> Result<()> {147		for (id, arg) in self.unnamed.iter().enumerate() {148			handler(149				id,150				if tailstrict {151					Thunk::evaluated(evaluate(ctx.clone(), arg)?)152				} else {153					Thunk::new(EvaluateThunk {154						ctx: ctx.clone(),155						expr: arg.clone(),156					})157				},158			)?;159		}160		Ok(())161	}162163	fn named_iter(164		&self,165		ctx: Context,166		tailstrict: bool,167		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,168	) -> Result<()> {169		for (name, arg) in &self.named {170			handler(171				name,172				if tailstrict {173					Thunk::evaluated(evaluate(ctx.clone(), arg)?)174				} else {175					Thunk::new(EvaluateThunk {176						ctx: ctx.clone(),177						expr: arg.clone(),178					})179				},180			)?;181		}182		Ok(())183	}184185	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {186		for (name, _) in &self.named {187			handler(name);188		}189	}190}191192impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}193impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {194	fn unnamed_len(&self) -> usize {195		0196	}197198	fn unnamed_iter(199		&self,200		_ctx: Context,201		_tailstrict: bool,202		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,203	) -> Result<()> {204		Ok(())205	}206207	fn named_iter(208		&self,209		ctx: Context,210		tailstrict: bool,211		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,212	) -> Result<()> {213		for (name, value) in self {214			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;215		}216		Ok(())217	}218219	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {220		for (name, _) in self {221			handler(name);222		}223	}224}225impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}226227impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {228	fn unnamed_len(&self) -> usize {229		self.0.unnamed_len()230	}231232	fn unnamed_iter(233		&self,234		ctx: Context,235		tailstrict: bool,236		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,237	) -> Result<()> {238		self.0.unnamed_iter(ctx, tailstrict, handler)239	}240241	fn named_iter(242		&self,243		ctx: Context,244		tailstrict: bool,245		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,246	) -> Result<()> {247		self.0.named_iter(ctx, tailstrict, handler)248	}249250	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {251		self.0.named_names(handler);252	}253}254255macro_rules! impl_args_like {256	($count:expr; $($gen:ident)*) => {257		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}258		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {259			fn unnamed_len(&self) -> usize {260				$count261			}262			#[allow(non_snake_case, unused_assignments)]263			fn unnamed_iter(264				&self,265				ctx: Context,266				tailstrict: bool,267				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,268			) -> Result<()> {269				let mut i = 0usize;270				let ($($gen,)*) = self;271				$(272					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;273					i+=1;274				)*275				Ok(())276			}277			fn named_iter(278				&self,279				_ctx: Context,280				_tailstrict: bool,281				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,282			) -> Result<()> {283				Ok(())284			}285			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}286		}287		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}288289		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}290		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {291			fn unnamed_len(&self) -> usize {292				0293			}294			fn unnamed_iter(295				&self,296				_ctx: Context,297				_tailstrict: bool,298				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,299			) -> Result<()> {300				Ok(())301			}302			#[allow(non_snake_case)]303			fn named_iter(304				&self,305				ctx: Context,306				tailstrict: bool,307				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,308			) -> Result<()> {309				let ($($gen,)*) = self;310				$(311					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;312				)*313				Ok(())314			}315			#[allow(non_snake_case)]316			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {317				let ($($gen,)*) = self;318				$(319					handler(&$gen.0);320				)*321			}322		}323		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}324	};325	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {326		impl_args_like!($count; $($cur)*);327		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);328	};329	($count:expr; $($cur:ident)* @) => {330		impl_args_like!($count; $($cur)*);331	}332}333impl_args_like! {334	// First argument is already in position, so count starts from 1335	1usize; A @ B C D E F G H I J K L336}337338impl ArgsLike for () {339	fn unnamed_len(&self) -> usize {340		0341	}342343	fn unnamed_iter(344		&self,345		_ctx: Context,346		_tailstrict: bool,347		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,348	) -> Result<()> {349		Ok(())350	}351352	fn named_iter(353		&self,354		_ctx: Context,355		_tailstrict: bool,356		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,357	) -> Result<()> {358		Ok(())359	}360361	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}362}363impl OptionalContext for () {}