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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs6.2 KiBsourcehistory
1use std::collections::HashMap;23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr};67use crate::{evaluate, typed::Typed, Context, Result, Thunk, Val};89/// Marker for arguments, which can be evaluated with context set to None10pub trait OptionalContext {}1112pub trait ArgLike {13	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;14}1516impl ArgLike for &LocExpr {17	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {18		Ok(if tailstrict {19			Thunk::evaluated(evaluate(ctx, self)?)20		} else {21			let expr = (*self).clone();22			Thunk!(move || evaluate(ctx, &expr))23		})24	}25}2627impl<T> ArgLike for T28where29	T: Typed + Clone,30{31	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {32		if T::provides_lazy() && !tailstrict {33			return Ok(T::into_lazy_untyped(self.clone()));34		}35		let val = T::into_untyped(self.clone())?;36		Ok(Thunk::evaluated(val))37	}38}39impl<T> OptionalContext for T where T: Typed + Clone {}4041#[derive(Clone, Trace)]42pub enum TlaArg {43	String(IStr),44	Code(LocExpr),45	Val(Val),46	Lazy(Thunk<Val>),47}48impl ArgLike for TlaArg {49	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {50		match self {51			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),52			Self::Code(code) => Ok(if tailstrict {53				Thunk::evaluated(evaluate(ctx, code)?)54			} else {55				let code = code.clone();56				Thunk!(move || evaluate(ctx, &code))57			}),58			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),59			Self::Lazy(lazy) => Ok(lazy.clone()),60		}61	}62}6364pub trait ArgsLike {65	fn unnamed_len(&self) -> usize;66	fn unnamed_iter(67		&self,68		ctx: Context,69		tailstrict: bool,70		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,71	) -> Result<()>;72	fn named_iter(73		&self,74		ctx: Context,75		tailstrict: bool,76		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,77	) -> Result<()>;78	fn named_names(&self, handler: &mut dyn FnMut(&IStr));79	fn is_empty(&self) -> bool;80}8182impl ArgsLike for Vec<Val> {83	fn unnamed_len(&self) -> usize {84		self.len()85	}86	fn unnamed_iter(87		&self,88		_ctx: Context,89		_tailstrict: bool,90		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,91	) -> Result<()> {92		for (idx, el) in self.iter().enumerate() {93			handler(idx, Thunk::evaluated(el.clone()))?;94		}95		Ok(())96	}97	fn named_iter(98		&self,99		_ctx: Context,100		_tailstrict: bool,101		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,102	) -> Result<()> {103		Ok(())104	}105	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}106	fn is_empty(&self) -> bool {107		self.is_empty()108	}109}110111impl ArgsLike for ArgsDesc {112	fn unnamed_len(&self) -> usize {113		self.unnamed.len()114	}115116	fn unnamed_iter(117		&self,118		ctx: Context,119		tailstrict: bool,120		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,121	) -> Result<()> {122		for (id, arg) in self.unnamed.iter().enumerate() {123			handler(124				id,125				if tailstrict {126					Thunk::evaluated(evaluate(ctx.clone(), arg)?)127				} else {128					let ctx = ctx.clone();129					let arg = arg.clone();130131					Thunk!(move || evaluate(ctx, &arg))132				},133			)?;134		}135		Ok(())136	}137138	fn named_iter(139		&self,140		ctx: Context,141		tailstrict: bool,142		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,143	) -> Result<()> {144		for (name, arg) in &self.named {145			handler(146				name,147				if tailstrict {148					Thunk::evaluated(evaluate(ctx.clone(), arg)?)149				} else {150					let ctx = ctx.clone();151					let arg = arg.clone();152153					Thunk!(move || evaluate(ctx, &arg))154				},155			)?;156		}157		Ok(())158	}159160	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {161		for (name, _) in &self.named {162			handler(name);163		}164	}165166	fn is_empty(&self) -> bool {167		self.unnamed.is_empty() && self.named.is_empty()168	}169}170171impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {172	fn unnamed_len(&self) -> usize {173		0174	}175176	fn unnamed_iter(177		&self,178		_ctx: Context,179		_tailstrict: bool,180		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,181	) -> Result<()> {182		Ok(())183	}184185	fn named_iter(186		&self,187		ctx: Context,188		tailstrict: bool,189		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,190	) -> Result<()> {191		for (name, value) in self {192			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;193		}194		Ok(())195	}196197	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {198		for (name, _) in self {199			handler(name);200		}201	}202203	fn is_empty(&self) -> bool {204		self.is_empty()205	}206}207impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}208209macro_rules! impl_args_like {210	($count:expr; $($gen:ident)*) => {211		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {212			fn unnamed_len(&self) -> usize {213				$count214			}215			#[allow(non_snake_case, unused_assignments)]216			fn unnamed_iter(217				&self,218				ctx: Context,219				tailstrict: bool,220				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,221			) -> Result<()> {222				let mut i = 0usize;223				let ($($gen,)*) = self;224				$(225					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;226					i+=1;227				)*228				Ok(())229			}230			fn named_iter(231				&self,232				_ctx: Context,233				_tailstrict: bool,234				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,235			) -> Result<()> {236				Ok(())237			}238			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}239240			fn is_empty(&self) -> bool {241				// impl_args_like only implements non-empty tuples.242				false243			}244		}245		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}246	};247	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {248		impl_args_like!($count; $($cur)*);249		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);250	};251	($count:expr; $($cur:ident)* @) => {252		impl_args_like!($count; $($cur)*);253	}254}255impl_args_like! {256	// First argument is already in position, so count starts from 1257	1usize; A @ B C D E F G H I J K L258}259260impl ArgsLike for () {261	fn unnamed_len(&self) -> usize {262		0263	}264265	fn unnamed_iter(266		&self,267		_ctx: Context,268		_tailstrict: bool,269		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,270	) -> Result<()> {271		Ok(())272	}273274	fn named_iter(275		&self,276		_ctx: Context,277		_tailstrict: bool,278		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,279	) -> Result<()> {280		Ok(())281	}282283	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}284	fn is_empty(&self) -> bool {285		true286	}287}288impl OptionalContext for () {}