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

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::{evaluate, gc::GcHashMap, typed::Typed, val::ThunkValue, Context, Result, Thunk, Val};78/// Marker for arguments, which can be evaluated with context set to None9pub trait OptionalContext {}1011#[derive(Trace)]12struct EvaluateThunk {13	ctx: Context,14	expr: LocExpr,15}16impl ThunkValue for EvaluateThunk {17	type Output = Val;18	fn get(self: Box<Self>) -> Result<Val> {19		evaluate(self.ctx, &self.expr)20	}21}2223pub trait ArgLike {24	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25}2627impl ArgLike for &LocExpr {28	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29		Ok(if tailstrict {30			Thunk::evaluated(evaluate(ctx, self)?)31		} else {32			Thunk::new(EvaluateThunk {33				ctx,34				expr: (*self).clone(),35			})36		})37	}38}3940impl<T> ArgLike for T41where42	T: Typed + Clone,43{44	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {45		if T::provides_lazy() && !tailstrict {46			return Ok(T::into_lazy_untyped(self.clone()));47		}48		let val = T::into_untyped(self.clone())?;49		Ok(Thunk::evaluated(val))50	}51}52impl<T> OptionalContext for T where T: Typed + Clone {}5354#[derive(Clone, Trace)]55pub enum TlaArg {56	String(IStr),57	Code(LocExpr),58	Val(Val),59	Lazy(Thunk<Val>),60}61impl ArgLike for TlaArg {62	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {63		match self {64			TlaArg::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),65			TlaArg::Code(code) => Ok(if tailstrict {66				Thunk::evaluated(evaluate(ctx, code)?)67			} else {68				Thunk::new(EvaluateThunk {69					ctx,70					expr: code.clone(),71				})72			}),73			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),74			TlaArg::Lazy(lazy) => Ok(lazy.clone()),75		}76	}77}7879mod sealed {80	/// Implemented for `ArgsLike`, where only unnamed arguments present81	pub trait Unnamed {}82	/// Implemented for `ArgsLike`, where only named arguments present83	pub trait Named {}84}8586pub trait ArgsLike {87	fn unnamed_len(&self) -> usize;88	fn unnamed_iter(89		&self,90		ctx: Context,91		tailstrict: bool,92		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,93	) -> Result<()>;94	fn named_iter(95		&self,96		ctx: Context,97		tailstrict: bool,98		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,99	) -> Result<()>;100	fn named_names(&self, handler: &mut dyn FnMut(&IStr));101}102103impl ArgsLike for Vec<Val> {104	fn unnamed_len(&self) -> usize {105		self.len()106	}107	fn unnamed_iter(108		&self,109		_ctx: Context,110		_tailstrict: bool,111		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,112	) -> Result<()> {113		for (idx, el) in self.iter().enumerate() {114			handler(idx, Thunk::evaluated(el.clone()))?;115		}116		Ok(())117	}118	fn named_iter(119		&self,120		_ctx: Context,121		_tailstrict: bool,122		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,123	) -> Result<()> {124		Ok(())125	}126	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}127}128129impl ArgsLike for ArgsDesc {130	fn unnamed_len(&self) -> usize {131		self.unnamed.len()132	}133134	fn unnamed_iter(135		&self,136		ctx: Context,137		tailstrict: bool,138		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,139	) -> Result<()> {140		for (id, arg) in self.unnamed.iter().enumerate() {141			handler(142				id,143				if tailstrict {144					Thunk::evaluated(evaluate(ctx.clone(), arg)?)145				} else {146					Thunk::new(EvaluateThunk {147						ctx: ctx.clone(),148						expr: arg.clone(),149					})150				},151			)?;152		}153		Ok(())154	}155156	fn named_iter(157		&self,158		ctx: Context,159		tailstrict: bool,160		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,161	) -> Result<()> {162		for (name, arg) in &self.named {163			handler(164				name,165				if tailstrict {166					Thunk::evaluated(evaluate(ctx.clone(), arg)?)167				} else {168					Thunk::new(EvaluateThunk {169						ctx: ctx.clone(),170						expr: arg.clone(),171					})172				},173			)?;174		}175		Ok(())176	}177178	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {179		for (name, _) in &self.named {180			handler(name);181		}182	}183}184185impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}186impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {187	fn unnamed_len(&self) -> usize {188		0189	}190191	fn unnamed_iter(192		&self,193		_ctx: Context,194		_tailstrict: bool,195		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,196	) -> Result<()> {197		Ok(())198	}199200	fn named_iter(201		&self,202		ctx: Context,203		tailstrict: bool,204		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,205	) -> Result<()> {206		for (name, value) in self {207			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;208		}209		Ok(())210	}211212	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {213		for (name, _) in self {214			handler(name);215		}216	}217}218impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}219220impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {221	fn unnamed_len(&self) -> usize {222		self.0.unnamed_len()223	}224225	fn unnamed_iter(226		&self,227		ctx: Context,228		tailstrict: bool,229		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,230	) -> Result<()> {231		self.0.unnamed_iter(ctx, tailstrict, handler)232	}233234	fn named_iter(235		&self,236		ctx: Context,237		tailstrict: bool,238		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,239	) -> Result<()> {240		self.0.named_iter(ctx, tailstrict, handler)241	}242243	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {244		self.0.named_names(handler);245	}246}247248macro_rules! impl_args_like {249	($count:expr; $($gen:ident)*) => {250		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}251		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {252			fn unnamed_len(&self) -> usize {253				$count254			}255			#[allow(non_snake_case, unused_assignments)]256			fn unnamed_iter(257				&self,258				ctx: Context,259				tailstrict: bool,260				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,261			) -> Result<()> {262				let mut i = 0usize;263				let ($($gen,)*) = self;264				$(265					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;266					i+=1;267				)*268				Ok(())269			}270			fn named_iter(271				&self,272				_ctx: Context,273				_tailstrict: bool,274				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,275			) -> Result<()> {276				Ok(())277			}278			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}279		}280		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}281282		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}283		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {284			fn unnamed_len(&self) -> usize {285				0286			}287			fn unnamed_iter(288				&self,289				_ctx: Context,290				_tailstrict: bool,291				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,292			) -> Result<()> {293				Ok(())294			}295			#[allow(non_snake_case)]296			fn named_iter(297				&self,298				ctx: Context,299				tailstrict: bool,300				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,301			) -> Result<()> {302				let ($($gen,)*) = self;303				$(304					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;305				)*306				Ok(())307			}308			#[allow(non_snake_case)]309			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {310				let ($($gen,)*) = self;311				$(312					handler(&$gen.0);313				)*314			}315		}316		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}317	};318	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {319		impl_args_like!($count; $($cur)*);320		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);321	};322	($count:expr; $($cur:ident)* @) => {323		impl_args_like!($count; $($cur)*);324	}325}326impl_args_like! {327	// First argument is already in position, so count starts from 1328	1usize; A @ B C D E F G H I J K L329}330331impl ArgsLike for () {332	fn unnamed_len(&self) -> usize {333		0334	}335336	fn unnamed_iter(337		&self,338		_ctx: Context,339		_tailstrict: bool,340		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,341	) -> Result<()> {342		Ok(())343	}344345	fn named_iter(346		&self,347		_ctx: Context,348		_tailstrict: bool,349		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,350	) -> Result<()> {351		Ok(())352	}353354	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}355}356impl OptionalContext for () {}