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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs6.8 KiBsourcehistory
1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{evaluate, gc::GcHashMap, typed::Typed, Context, Result, Thunk, Val};78/// Marker for arguments, which can be evaluated with context set to None9pub trait OptionalContext {}1011pub trait ArgLike {12	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;13}1415impl ArgLike for &LocExpr {16	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {17		Ok(if tailstrict {18			Thunk::evaluated(evaluate(ctx, self)?)19		} else {20			let expr = (*self).clone();21			Thunk!(move || evaluate(ctx, &expr))22		})23	}24}2526impl<T> ArgLike for T27where28	T: Typed + Clone,29{30	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {31		if T::provides_lazy() && !tailstrict {32			return Ok(T::into_lazy_untyped(self.clone()));33		}34		let val = T::into_untyped(self.clone())?;35		Ok(Thunk::evaluated(val))36	}37}38impl<T> OptionalContext for T where T: Typed + Clone {}3940#[derive(Clone, Trace)]41pub enum TlaArg {42	String(IStr),43	Code(LocExpr),44	Val(Val),45	Lazy(Thunk<Val>),46}47impl ArgLike for TlaArg {48	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {49		match self {50			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),51			Self::Code(code) => Ok(if tailstrict {52				Thunk::evaluated(evaluate(ctx, code)?)53			} else {54				let code = code.clone();55				Thunk!(move || evaluate(ctx, &code))56			}),57			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),58			Self::Lazy(lazy) => Ok(lazy.clone()),59		}60	}61}6263pub trait ArgsLike {64	fn unnamed_len(&self) -> usize;65	fn unnamed_iter(66		&self,67		ctx: Context,68		tailstrict: bool,69		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,70	) -> Result<()>;71	fn named_iter(72		&self,73		ctx: Context,74		tailstrict: bool,75		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,76	) -> Result<()>;77	fn named_names(&self, handler: &mut dyn FnMut(&IStr));78	fn is_empty(&self) -> bool;79}8081impl ArgsLike for Vec<Val> {82	fn unnamed_len(&self) -> usize {83		self.len()84	}85	fn unnamed_iter(86		&self,87		_ctx: Context,88		_tailstrict: bool,89		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,90	) -> Result<()> {91		for (idx, el) in self.iter().enumerate() {92			handler(idx, Thunk::evaluated(el.clone()))?;93		}94		Ok(())95	}96	fn named_iter(97		&self,98		_ctx: Context,99		_tailstrict: bool,100		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,101	) -> Result<()> {102		Ok(())103	}104	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}105	fn is_empty(&self) -> bool {106		self.is_empty()107	}108}109110impl ArgsLike for ArgsDesc {111	fn unnamed_len(&self) -> usize {112		self.unnamed.len()113	}114115	fn unnamed_iter(116		&self,117		ctx: Context,118		tailstrict: bool,119		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,120	) -> Result<()> {121		for (id, arg) in self.unnamed.iter().enumerate() {122			handler(123				id,124				if tailstrict {125					Thunk::evaluated(evaluate(ctx.clone(), arg)?)126				} else {127					let ctx = ctx.clone();128					let arg = arg.clone();129130					Thunk!(move || evaluate(ctx, &arg))131				},132			)?;133		}134		Ok(())135	}136137	fn named_iter(138		&self,139		ctx: Context,140		tailstrict: bool,141		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,142	) -> Result<()> {143		for (name, arg) in &self.named {144			handler(145				name,146				if tailstrict {147					Thunk::evaluated(evaluate(ctx.clone(), arg)?)148				} else {149					let ctx = ctx.clone();150					let arg = arg.clone();151152					Thunk!(move || evaluate(ctx, &arg))153				},154			)?;155		}156		Ok(())157	}158159	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {160		for (name, _) in &self.named {161			handler(name);162		}163	}164165	fn is_empty(&self) -> bool {166		self.unnamed.is_empty() && self.named.is_empty()167	}168}169170impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {171	fn unnamed_len(&self) -> usize {172		0173	}174175	fn unnamed_iter(176		&self,177		_ctx: Context,178		_tailstrict: bool,179		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,180	) -> Result<()> {181		Ok(())182	}183184	fn named_iter(185		&self,186		ctx: Context,187		tailstrict: bool,188		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,189	) -> Result<()> {190		for (name, value) in self {191			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;192		}193		Ok(())194	}195196	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {197		for (name, _) in self {198			handler(name);199		}200	}201202	fn is_empty(&self) -> bool {203		self.is_empty()204	}205}206impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}207208impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {209	fn unnamed_len(&self) -> usize {210		self.0.unnamed_len()211	}212213	fn unnamed_iter(214		&self,215		ctx: Context,216		tailstrict: bool,217		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,218	) -> Result<()> {219		self.0.unnamed_iter(ctx, tailstrict, handler)220	}221222	fn named_iter(223		&self,224		ctx: Context,225		tailstrict: bool,226		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,227	) -> Result<()> {228		self.0.named_iter(ctx, tailstrict, handler)229	}230231	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {232		self.0.named_names(handler);233	}234235	fn is_empty(&self) -> bool {236		self.0.is_empty()237	}238}239240macro_rules! impl_args_like {241	($count:expr; $($gen:ident)*) => {242		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {243			fn unnamed_len(&self) -> usize {244				$count245			}246			#[allow(non_snake_case, unused_assignments)]247			fn unnamed_iter(248				&self,249				ctx: Context,250				tailstrict: bool,251				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,252			) -> Result<()> {253				let mut i = 0usize;254				let ($($gen,)*) = self;255				$(256					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;257					i+=1;258				)*259				Ok(())260			}261			fn named_iter(262				&self,263				_ctx: Context,264				_tailstrict: bool,265				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,266			) -> Result<()> {267				Ok(())268			}269			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}270271			fn is_empty(&self) -> bool {272				// impl_args_like only implements non-empty tuples.273				false274			}275		}276		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}277	};278	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {279		impl_args_like!($count; $($cur)*);280		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);281	};282	($count:expr; $($cur:ident)* @) => {283		impl_args_like!($count; $($cur)*);284	}285}286impl_args_like! {287	// First argument is already in position, so count starts from 1288	1usize; A @ B C D E F G H I J K L289}290291impl ArgsLike for () {292	fn unnamed_len(&self) -> usize {293		0294	}295296	fn unnamed_iter(297		&self,298		_ctx: Context,299		_tailstrict: bool,300		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,301	) -> Result<()> {302		Ok(())303	}304305	fn named_iter(306		&self,307		_ctx: Context,308		_tailstrict: bool,309		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,310	) -> Result<()> {311		Ok(())312	}313314	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}315	fn is_empty(&self) -> bool {316		true317	}318}319impl OptionalContext for () {}