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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.2 KiBsourcehistory
1use std::collections::HashMap;23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr};67use crate::{error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, Thunk, Val};89/// Marker for arguments, which can be evaluated with context set to None10pub trait OptionalContext {}1112#[derive(Trace)]13struct EvaluateThunk {14	ctx: Context,15	expr: LocExpr,16}17impl ThunkValue for EvaluateThunk {18	type Output = Val;19	fn get(self: Box<Self>) -> Result<Val> {20		evaluate(self.ctx, &self.expr)21	}22}2324pub trait ArgLike {25	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;26}2728impl ArgLike for &LocExpr {29	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30		Ok(if tailstrict {31			Thunk::evaluated(evaluate(ctx, self)?)32		} else {33			Thunk::new(tb!(EvaluateThunk {34				ctx,35				expr: (*self).clone(),36			}))37		})38	}39}4041impl<T> ArgLike for T42where43	T: Typed + Clone,44{45	fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {46		let val = T::into_untyped(self.clone())?;47		Ok(Thunk::evaluated(val))48	}49}50impl<T> OptionalContext for T where T: Typed + Clone {}5152#[derive(Clone, Trace)]53pub enum TlaArg {54	String(IStr),55	Code(LocExpr),56	Val(Val),57}58impl ArgLike for TlaArg {59	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {60		match self {61			TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),62			TlaArg::Code(code) => Ok(if tailstrict {63				Thunk::evaluated(evaluate(ctx, code)?)64			} else {65				Thunk::new(tb!(EvaluateThunk {66					ctx,67					expr: code.clone(),68				}))69			}),70			TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),71		}72	}73}7475mod sealed {76	/// Implemented for `ArgsLike`, where only unnamed arguments present77	pub trait Unnamed {}78	/// Implemented for `ArgsLike`, where only named arguments present79	pub trait Named {}80}8182pub trait ArgsLike {83	fn unnamed_len(&self) -> usize;84	fn unnamed_iter(85		&self,86		ctx: Context,87		tailstrict: bool,88		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,89	) -> Result<()>;90	fn named_iter(91		&self,92		ctx: Context,93		tailstrict: bool,94		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,95	) -> Result<()>;96	fn named_names(&self, handler: &mut dyn FnMut(&IStr));97}9899impl ArgsLike for Vec<Val> {100	fn unnamed_len(&self) -> usize {101		self.len()102	}103	fn unnamed_iter(104		&self,105		_ctx: Context,106		_tailstrict: bool,107		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,108	) -> Result<()> {109		for (idx, el) in self.iter().enumerate() {110			handler(idx, Thunk::evaluated(el.clone()))?;111		}112		Ok(())113	}114	fn named_iter(115		&self,116		_ctx: Context,117		_tailstrict: bool,118		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,119	) -> Result<()> {120		Ok(())121	}122	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}123}124impl OptionalContext for Vec<Val> {}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(tb!(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(tb!(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	}180}181182impl<A: ArgLike, S> sealed::Named for HashMap<IStr, A, S> {}183impl<A: ArgLike, S> ArgsLike for HashMap<IStr, A, S> {184	fn unnamed_len(&self) -> usize {185		0186	}187188	fn unnamed_iter(189		&self,190		_ctx: Context,191		_tailstrict: bool,192		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,193	) -> Result<()> {194		Ok(())195	}196197	fn named_iter(198		&self,199		ctx: Context,200		tailstrict: bool,201		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,202	) -> Result<()> {203		for (name, value) in self.iter() {204			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;205		}206		Ok(())207	}208209	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {210		for (name, _) in self.iter() {211			handler(name);212		}213	}214}215impl<A, S> OptionalContext for HashMap<IStr, A, S> where A: ArgLike + OptionalContext {}216217macro_rules! impl_args_like {218	($count:expr; $($gen:ident)*) => {219		impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}220		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {221			fn unnamed_len(&self) -> usize {222				$count223			}224			#[allow(non_snake_case, unused_assignments)]225			fn unnamed_iter(226				&self,227				ctx: Context,228				tailstrict: bool,229				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,230			) -> Result<()> {231				let mut i = 0usize;232				let ($($gen,)*) = self;233				$(234					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;235					i+=1;236				)*237				Ok(())238			}239			fn named_iter(240				&self,241				_ctx: Context,242				_tailstrict: bool,243				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,244			) -> Result<()> {245				Ok(())246			}247			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}248		}249		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}250251		impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}252		impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {253			fn unnamed_len(&self) -> usize {254				0255			}256			fn unnamed_iter(257				&self,258				_ctx: Context,259				_tailstrict: bool,260				_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,261			) -> Result<()> {262				Ok(())263			}264			#[allow(non_snake_case)]265			fn named_iter(266				&self,267				ctx: Context,268				tailstrict: bool,269				handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,270			) -> Result<()> {271				let ($($gen,)*) = self;272				$(273					handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;274				)*275				Ok(())276			}277			#[allow(non_snake_case)]278			fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {279				let ($($gen,)*) = self;280				$(281					handler(&$gen.0);282				)*283			}284		}285		impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}286	};287	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {288		impl_args_like!($count; $($cur)*);289		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);290	};291	($count:expr; $($cur:ident)* @) => {292		impl_args_like!($count; $($cur)*);293	}294}295impl_args_like! {296	// First argument is already in position, so count starts from 1297	1usize; A @ B C D E F G H I J K L298}299300impl ArgsLike for () {301	fn unnamed_len(&self) -> usize {302		0303	}304305	fn unnamed_iter(306		&self,307		_ctx: Context,308		_tailstrict: bool,309		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,310	) -> Result<()> {311		Ok(())312	}313314	fn named_iter(315		&self,316		_ctx: Context,317		_tailstrict: bool,318		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,319	) -> Result<()> {320		Ok(())321	}322323	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}324}325impl OptionalContext for () {}