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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.1 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	fn is_empty(&self) -> bool;95}9697impl ArgsLike for Vec<Val> {98	fn unnamed_len(&self) -> usize {99		self.len()100	}101	fn unnamed_iter(102		&self,103		_ctx: Context,104		_tailstrict: bool,105		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,106	) -> Result<()> {107		for (idx, el) in self.iter().enumerate() {108			handler(idx, Thunk::evaluated(el.clone()))?;109		}110		Ok(())111	}112	fn named_iter(113		&self,114		_ctx: Context,115		_tailstrict: bool,116		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,117	) -> Result<()> {118		Ok(())119	}120	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}121	fn is_empty(&self) -> bool {122		self.is_empty()123	}124}125126impl ArgsLike for ArgsDesc {127	fn unnamed_len(&self) -> usize {128		self.unnamed.len()129	}130131	fn unnamed_iter(132		&self,133		ctx: Context,134		tailstrict: bool,135		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,136	) -> Result<()> {137		for (id, arg) in self.unnamed.iter().enumerate() {138			handler(139				id,140				if tailstrict {141					Thunk::evaluated(evaluate(ctx.clone(), arg)?)142				} else {143					Thunk::new(EvaluateThunk {144						ctx: ctx.clone(),145						expr: arg.clone(),146					})147				},148			)?;149		}150		Ok(())151	}152153	fn named_iter(154		&self,155		ctx: Context,156		tailstrict: bool,157		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,158	) -> Result<()> {159		for (name, arg) in &self.named {160			handler(161				name,162				if tailstrict {163					Thunk::evaluated(evaluate(ctx.clone(), arg)?)164				} else {165					Thunk::new(EvaluateThunk {166						ctx: ctx.clone(),167						expr: arg.clone(),168					})169				},170			)?;171		}172		Ok(())173	}174175	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {176		for (name, _) in &self.named {177			handler(name);178		}179	}180181	fn is_empty(&self) -> bool {182		self.unnamed.is_empty() && self.named.is_empty()183	}184}185186impl<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	}217218	fn is_empty(&self) -> bool {219		self.is_empty()220	}221}222impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}223224impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {225	fn unnamed_len(&self) -> usize {226		self.0.unnamed_len()227	}228229	fn unnamed_iter(230		&self,231		ctx: Context,232		tailstrict: bool,233		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,234	) -> Result<()> {235		self.0.unnamed_iter(ctx, tailstrict, handler)236	}237238	fn named_iter(239		&self,240		ctx: Context,241		tailstrict: bool,242		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,243	) -> Result<()> {244		self.0.named_iter(ctx, tailstrict, handler)245	}246247	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {248		self.0.named_names(handler);249	}250251	fn is_empty(&self) -> bool {252		self.0.is_empty()253	}254}255256macro_rules! impl_args_like {257	($count:expr; $($gen:ident)*) => {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)) {}286287			fn is_empty(&self) -> bool {288				// impl_args_like only implements non-empty tuples.289				false290			}291		}292		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}293	};294	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {295		impl_args_like!($count; $($cur)*);296		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);297	};298	($count:expr; $($cur:ident)* @) => {299		impl_args_like!($count; $($cur)*);300	}301}302impl_args_like! {303	// First argument is already in position, so count starts from 1304	1usize; A @ B C D E F G H I J K L305}306307impl ArgsLike for () {308	fn unnamed_len(&self) -> usize {309		0310	}311312	fn unnamed_iter(313		&self,314		_ctx: Context,315		_tailstrict: bool,316		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,317	) -> Result<()> {318		Ok(())319	}320321	fn named_iter(322		&self,323		_ctx: Context,324		_tailstrict: bool,325		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,326	) -> Result<()> {327		Ok(())328	}329330	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}331	fn is_empty(&self) -> bool {332		true333	}334}335impl OptionalContext for () {}