git.delta.rocks / jrsonnet / refs/commits / 7cdcae351387

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.5 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			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),65			Self::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			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),74			Self::Lazy(lazy) => Ok(lazy.clone()),75		}76	}77}7879pub trait ArgsLike {80	fn unnamed_len(&self) -> usize;81	fn unnamed_iter(82		&self,83		ctx: Context,84		tailstrict: bool,85		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,86	) -> Result<()>;87	fn named_iter(88		&self,89		ctx: Context,90		tailstrict: bool,91		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,92	) -> Result<()>;93	fn named_names(&self, handler: &mut dyn FnMut(&IStr));94}9596impl ArgsLike for Vec<Val> {97	fn unnamed_len(&self) -> usize {98		self.len()99	}100	fn unnamed_iter(101		&self,102		_ctx: Context,103		_tailstrict: bool,104		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,105	) -> Result<()> {106		for (idx, el) in self.iter().enumerate() {107			handler(idx, Thunk::evaluated(el.clone()))?;108		}109		Ok(())110	}111	fn named_iter(112		&self,113		_ctx: Context,114		_tailstrict: bool,115		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,116	) -> Result<()> {117		Ok(())118	}119	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}120}121122impl ArgsLike for ArgsDesc {123	fn unnamed_len(&self) -> usize {124		self.unnamed.len()125	}126127	fn unnamed_iter(128		&self,129		ctx: Context,130		tailstrict: bool,131		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,132	) -> Result<()> {133		for (id, arg) in self.unnamed.iter().enumerate() {134			handler(135				id,136				if tailstrict {137					Thunk::evaluated(evaluate(ctx.clone(), arg)?)138				} else {139					Thunk::new(EvaluateThunk {140						ctx: ctx.clone(),141						expr: arg.clone(),142					})143				},144			)?;145		}146		Ok(())147	}148149	fn named_iter(150		&self,151		ctx: Context,152		tailstrict: bool,153		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,154	) -> Result<()> {155		for (name, arg) in &self.named {156			handler(157				name,158				if tailstrict {159					Thunk::evaluated(evaluate(ctx.clone(), arg)?)160				} else {161					Thunk::new(EvaluateThunk {162						ctx: ctx.clone(),163						expr: arg.clone(),164					})165				},166			)?;167		}168		Ok(())169	}170171	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {172		for (name, _) in &self.named {173			handler(name);174		}175	}176}177178impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {179	fn unnamed_len(&self) -> usize {180		0181	}182183	fn unnamed_iter(184		&self,185		_ctx: Context,186		_tailstrict: bool,187		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,188	) -> Result<()> {189		Ok(())190	}191192	fn named_iter(193		&self,194		ctx: Context,195		tailstrict: bool,196		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,197	) -> Result<()> {198		for (name, value) in self {199			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;200		}201		Ok(())202	}203204	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {205		for (name, _) in self {206			handler(name);207		}208	}209}210impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}211212impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {213	fn unnamed_len(&self) -> usize {214		self.0.unnamed_len()215	}216217	fn unnamed_iter(218		&self,219		ctx: Context,220		tailstrict: bool,221		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,222	) -> Result<()> {223		self.0.unnamed_iter(ctx, tailstrict, handler)224	}225226	fn named_iter(227		&self,228		ctx: Context,229		tailstrict: bool,230		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,231	) -> Result<()> {232		self.0.named_iter(ctx, tailstrict, handler)233	}234235	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {236		self.0.named_names(handler);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)) {}270		}271		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}272273		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {274			fn unnamed_len(&self) -> usize {275				0276			}277			fn unnamed_iter(278				&self,279				_ctx: Context,280				_tailstrict: bool,281				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,282			) -> Result<()> {283				Ok(())284			}285			#[allow(non_snake_case)]286			fn named_iter(287				&self,288				ctx: Context,289				tailstrict: bool,290				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,291			) -> Result<()> {292				let ($($gen,)*) = self;293				$(294					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;295				)*296				Ok(())297			}298			#[allow(non_snake_case)]299			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {300				let ($($gen,)*) = self;301				$(302					handler(&$gen.0);303				)*304			}305		}306		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}307	};308	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {309		impl_args_like!($count; $($cur)*);310		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);311	};312	($count:expr; $($cur:ident)* @) => {313		impl_args_like!($count; $($cur)*);314	}315}316impl_args_like! {317	// First argument is already in position, so count starts from 1318	1usize; A @ B C D E F G H I J K L319}320321impl ArgsLike for () {322	fn unnamed_len(&self) -> usize {323		0324	}325326	fn unnamed_iter(327		&self,328		_ctx: Context,329		_tailstrict: bool,330		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,331	) -> Result<()> {332		Ok(())333	}334335	fn named_iter(336		&self,337		_ctx: Context,338		_tailstrict: bool,339		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,340	) -> Result<()> {341		Ok(())342	}343344	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}345}346impl OptionalContext for () {}