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

difftreelog

source

crates/jrsonnet-evaluator/src/function/arglike.rs7.3 KiBsourcehistory
1use std::collections::HashMap;2use std::rc::Rc;34use jrsonnet_gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};78use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};910pub trait ArgLike {11	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;12}1314impl ArgLike for &Rc<Spanned<Expr>> {15	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {16		Ok(if tailstrict {17			Thunk::evaluated(evaluate(ctx, self)?)18		} else {19			let expr = (*self).clone();20			Thunk!(move || evaluate(ctx, &expr))21		})22	}23}2425impl<T> ArgLike for T26where27	T: Typed + Clone,28{29	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30		if T::provides_lazy() && !tailstrict {31			return Ok(T::into_lazy_untyped(self.clone()));32		}33		let val = T::into_untyped(self.clone())?;34		Ok(Thunk::evaluated(val))35	}36}3738#[derive(Clone, Trace)]39pub enum TlaArg {40	String(IStr),41	Val(Val),42	Lazy(Thunk<Val>),43	Import(String),44	ImportStr(String),45	InlineCode(String),46}47impl TlaArg {48	pub fn evaluate_tailstrict(&self) -> Result<Val> {49		match self {50			Self::String(s) => Ok(Val::string(s.clone())),51			Self::Val(val) => Ok(val.clone()),52			Self::Lazy(lazy) => Ok(lazy.evaluate()?),53			Self::Import(p) => with_state(|s| {54				let resolved = s.resolve_from_default(&p.as_str())?;55				s.import_resolved(resolved)56			}),57			Self::ImportStr(p) => with_state(|s| {58				let resolved = s.resolve_from_default(&p.as_str())?;59				s.import_resolved_str(resolved).map(Val::string)60			}),61			Self::InlineCode(p) => with_state(|s| {62				let resolved =63					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));64				s.import_resolved(resolved)65			}),66		}67	}68	pub fn evaluate(&self) -> Result<Thunk<Val>> {69		match self {70			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),71			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),72			Self::Lazy(lazy) => Ok(lazy.clone()),73			Self::Import(p) => with_state(|s| {74				let resolved = s.resolve_from_default(&p.as_str())?;75				Ok(Thunk!(move || s.import_resolved(resolved)))76			}),77			Self::ImportStr(p) => with_state(|s| {78				let resolved = s.resolve_from_default(&p.as_str())?;79				Ok(Thunk!(move || s80					.import_resolved_str(resolved)81					.map(Val::string)))82			}),83			Self::InlineCode(p) => with_state(|s| {84				let resolved =85					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));86				Ok(Thunk!(move || s.import_resolved(resolved)))87			}),88		}89	}90}9192// TODO: Is this implementation really required, as there is no Context to use?93// Maybe something a bit stricter is possible to add, especially with precompiled calls?94impl ArgLike for TlaArg {95	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {96		if tailstrict {97			self.evaluate_tailstrict().map(Thunk::evaluated)98		} else {99			self.evaluate()100		}101	}102}103104pub trait ArgsLike {105	fn unnamed_len(&self) -> usize;106	fn unnamed_iter(107		&self,108		ctx: Context,109		tailstrict: bool,110		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,111	) -> Result<()>;112	fn named_iter(113		&self,114		ctx: Context,115		tailstrict: bool,116		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,117	) -> Result<()>;118	fn named_names(&self, handler: &mut dyn FnMut(&IStr));119	fn is_empty(&self) -> bool;120}121122impl ArgsLike for Vec<Val> {123	fn unnamed_len(&self) -> usize {124		self.len()125	}126	fn unnamed_iter(127		&self,128		_ctx: Context,129		_tailstrict: bool,130		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,131	) -> Result<()> {132		for (idx, el) in self.iter().enumerate() {133			handler(idx, Thunk::evaluated(el.clone()))?;134		}135		Ok(())136	}137	fn named_iter(138		&self,139		_ctx: Context,140		_tailstrict: bool,141		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,142	) -> Result<()> {143		Ok(())144	}145	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}146	fn is_empty(&self) -> bool {147		self.is_empty()148	}149}150151impl ArgsLike for ArgsDesc {152	fn unnamed_len(&self) -> usize {153		self.unnamed.len()154	}155156	fn unnamed_iter(157		&self,158		ctx: Context,159		tailstrict: bool,160		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,161	) -> Result<()> {162		for (id, arg) in self.unnamed.iter().enumerate() {163			handler(164				id,165				if tailstrict {166					Thunk::evaluated(evaluate(ctx.clone(), arg)?)167				} else {168					let ctx = ctx.clone();169					let arg = arg.clone();170171					Thunk!(move || evaluate(ctx, &arg))172				},173			)?;174		}175		Ok(())176	}177178	fn named_iter(179		&self,180		ctx: Context,181		tailstrict: bool,182		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,183	) -> Result<()> {184		for (name, arg) in &self.named {185			handler(186				name,187				if tailstrict {188					Thunk::evaluated(evaluate(ctx.clone(), arg)?)189				} else {190					let ctx = ctx.clone();191					let arg = arg.clone();192193					Thunk!(move || evaluate(ctx, &arg))194				},195			)?;196		}197		Ok(())198	}199200	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {201		for (name, _) in &self.named {202			handler(name);203		}204	}205206	fn is_empty(&self) -> bool {207		self.unnamed.is_empty() && self.named.is_empty()208	}209}210211impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {212	fn unnamed_len(&self) -> usize {213		0214	}215216	fn unnamed_iter(217		&self,218		_ctx: Context,219		_tailstrict: bool,220		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,221	) -> Result<()> {222		Ok(())223	}224225	fn named_iter(226		&self,227		ctx: Context,228		tailstrict: bool,229		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,230	) -> Result<()> {231		for (name, value) in self {232			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;233		}234		Ok(())235	}236237	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {238		for name in self.keys() {239			handler(name);240		}241	}242243	fn is_empty(&self) -> bool {244		self.is_empty()245	}246}247248macro_rules! impl_args_like {249	($count:expr; $($gen:ident)*) => {250		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {251			fn unnamed_len(&self) -> usize {252				$count253			}254			#[allow(non_snake_case, unused_assignments)]255			fn unnamed_iter(256				&self,257				ctx: Context,258				tailstrict: bool,259				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,260			) -> Result<()> {261				let mut i = 0usize;262				let ($($gen,)*) = self;263				$(264					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;265					i+=1;266				)*267				Ok(())268			}269			fn named_iter(270				&self,271				_ctx: Context,272				_tailstrict: bool,273				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,274			) -> Result<()> {275				Ok(())276			}277			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}278279			fn is_empty(&self) -> bool {280				// impl_args_like only implements non-empty tuples.281				false282			}283		}284	};285	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {286		impl_args_like!($count; $($cur)*);287		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);288	};289	($count:expr; $($cur:ident)* @) => {290		impl_args_like!($count; $($cur)*);291	}292}293impl_args_like! {294	// First argument is already in position, so count starts from 1295	1usize; A @ B C D E F G H I J K L296}297298impl ArgsLike for () {299	fn unnamed_len(&self) -> usize {300		0301	}302303	fn unnamed_iter(304		&self,305		_ctx: Context,306		_tailstrict: bool,307		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,308	) -> Result<()> {309		Ok(())310	}311312	fn named_iter(313		&self,314		_ctx: Context,315		_tailstrict: bool,316		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,317	) -> Result<()> {318		Ok(())319	}320321	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}322	fn is_empty(&self) -> bool {323		true324	}325}