git.delta.rocks / jrsonnet / refs/commits / 5585b94101d8

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs6.7 KiBsourcehistory
1use std::collections::HashMap;23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath};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	Val(Val),45	Lazy(Thunk<Val>),46	Import(String),47	ImportStr(String),48	InlineCode(String),49}50impl ArgLike for TlaArg {51	fn evaluate_arg(&self, ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {52		match self {53			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),54			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),55			Self::Lazy(lazy) => Ok(lazy.clone()),56			Self::Import(p) => {57				let resolved = ctx.state().resolve_from_default(&p.as_str())?;58				Ok(Thunk!(move || ctx.state().import_resolved(resolved)))59			}60			Self::ImportStr(p) => {61				let resolved = ctx.state().resolve_from_default(&p.as_str())?;62				Ok(Thunk!(move || ctx63					.state()64					.import_resolved_str(resolved)65					.map(Val::string)))66			}67			Self::InlineCode(p) => {68				let resolved =69					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));70				Ok(Thunk!(move || ctx.state().import_resolved(resolved)))71			}72		}73	}74}7576pub trait ArgsLike {77	fn unnamed_len(&self) -> usize;78	fn unnamed_iter(79		&self,80		ctx: Context,81		tailstrict: bool,82		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,83	) -> Result<()>;84	fn named_iter(85		&self,86		ctx: Context,87		tailstrict: bool,88		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,89	) -> Result<()>;90	fn named_names(&self, handler: &mut dyn FnMut(&IStr));91	fn is_empty(&self) -> bool;92}9394impl ArgsLike for Vec<Val> {95	fn unnamed_len(&self) -> usize {96		self.len()97	}98	fn unnamed_iter(99		&self,100		_ctx: Context,101		_tailstrict: bool,102		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,103	) -> Result<()> {104		for (idx, el) in self.iter().enumerate() {105			handler(idx, Thunk::evaluated(el.clone()))?;106		}107		Ok(())108	}109	fn named_iter(110		&self,111		_ctx: Context,112		_tailstrict: bool,113		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,114	) -> Result<()> {115		Ok(())116	}117	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}118	fn is_empty(&self) -> bool {119		self.is_empty()120	}121}122123impl ArgsLike for ArgsDesc {124	fn unnamed_len(&self) -> usize {125		self.unnamed.len()126	}127128	fn unnamed_iter(129		&self,130		ctx: Context,131		tailstrict: bool,132		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,133	) -> Result<()> {134		for (id, arg) in self.unnamed.iter().enumerate() {135			handler(136				id,137				if tailstrict {138					Thunk::evaluated(evaluate(ctx.clone(), arg)?)139				} else {140					let ctx = ctx.clone();141					let arg = arg.clone();142143					Thunk!(move || evaluate(ctx, &arg))144				},145			)?;146		}147		Ok(())148	}149150	fn named_iter(151		&self,152		ctx: Context,153		tailstrict: bool,154		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,155	) -> Result<()> {156		for (name, arg) in &self.named {157			handler(158				name,159				if tailstrict {160					Thunk::evaluated(evaluate(ctx.clone(), arg)?)161				} else {162					let ctx = ctx.clone();163					let arg = arg.clone();164165					Thunk!(move || evaluate(ctx, &arg))166				},167			)?;168		}169		Ok(())170	}171172	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {173		for (name, _) in &self.named {174			handler(name);175		}176	}177178	fn is_empty(&self) -> bool {179		self.unnamed.is_empty() && self.named.is_empty()180	}181}182183impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, 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 {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 {211			handler(name);212		}213	}214215	fn is_empty(&self) -> bool {216		self.is_empty()217	}218}219impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}220221macro_rules! impl_args_like {222	($count:expr; $($gen:ident)*) => {223		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {224			fn unnamed_len(&self) -> usize {225				$count226			}227			#[allow(non_snake_case, unused_assignments)]228			fn unnamed_iter(229				&self,230				ctx: Context,231				tailstrict: bool,232				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,233			) -> Result<()> {234				let mut i = 0usize;235				let ($($gen,)*) = self;236				$(237					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;238					i+=1;239				)*240				Ok(())241			}242			fn named_iter(243				&self,244				_ctx: Context,245				_tailstrict: bool,246				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,247			) -> Result<()> {248				Ok(())249			}250			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}251252			fn is_empty(&self) -> bool {253				// impl_args_like only implements non-empty tuples.254				false255			}256		}257		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}258	};259	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {260		impl_args_like!($count; $($cur)*);261		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);262	};263	($count:expr; $($cur:ident)* @) => {264		impl_args_like!($count; $($cur)*);265	}266}267impl_args_like! {268	// First argument is already in position, so count starts from 1269	1usize; A @ B C D E F G H I J K L270}271272impl ArgsLike for () {273	fn unnamed_len(&self) -> usize {274		0275	}276277	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	}285286	fn named_iter(287		&self,288		_ctx: Context,289		_tailstrict: bool,290		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,291	) -> Result<()> {292		Ok(())293	}294295	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}296	fn is_empty(&self) -> bool {297		true298	}299}300impl OptionalContext for () {}