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

difftreelog

source

crates/jrsonnet-evaluator/src/function/mod.rs4.1 KiBsourcehistory
1use std::fmt::Debug;23pub use arglike::{ArgLike, ArgsLike, TlaArg};4use jrsonnet_gcmodule::{Cc, Trace};5use jrsonnet_interner::IStr;6pub use jrsonnet_macros::builtin;7use jrsonnet_parser::{ExprLocation, LocExpr, ParamsDesc};89use self::{10	builtin::{Builtin, StaticBuiltin},11	native::NativeDesc,12	parse::{parse_default_function_call, parse_function_call},13};14use crate::{evaluate, gc::TraceBox, typed::Any, Context, Result, State, Val};1516pub mod arglike;17pub mod builtin;18pub mod native;19pub mod parse;2021#[derive(Clone, Copy)]22pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);23impl<'l> CallLocation<'l> {24	pub const fn new(loc: &'l ExprLocation) -> Self {25		Self(Some(loc))26	}27}28impl CallLocation<'static> {29	pub const fn native() -> Self {30		Self(None)31	}32}3334/// Function implemented in jsonnet35#[derive(Debug, PartialEq, Trace)]36pub struct FuncDesc {37	/// In expressions like38	/// ```jsonnet39	/// local a = function() ...40	/// local a() ...41	/// { a: function() ... }42	/// { a() = ... }43	/// ```44	///45	/// Deducted to `a`, unspecified otherwise46	pub name: IStr,47	/// Context, in which this function was evaluated48	///49	/// I.e in50	/// ```jsonnet51	/// local a = 2;52	/// function() ...53	/// ```54	/// context will contain `a`55	pub ctx: Context,5657	pub params: ParamsDesc,58	pub body: LocExpr,59}60impl FuncDesc {61	/// Create body context, but fill arguments without defaults with lazy error62	pub fn default_body_context(&self) -> Result<Context> {63		parse_default_function_call(self.ctx.clone(), &self.params)64	}6566	/// Create context, with which body code will run67	pub fn call_body_context(68		&self,69		s: State,70		call_ctx: Context,71		args: &dyn ArgsLike,72		tailstrict: bool,73	) -> Result<Context> {74		parse_function_call(75			s,76			call_ctx,77			self.ctx.clone(),78			&self.params,79			args,80			tailstrict,81		)82	}83}8485/// Any possible function value, including plain functions and user-provided builtins86#[allow(clippy::module_name_repetitions)]87#[derive(Trace, Clone)]88pub enum FuncVal {89	/// std.id90	Id,91	/// Plain function implemented in jsonnet92	Normal(Cc<FuncDesc>),93	/// Standard library function94	StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),95	/// User-provided function96	Builtin(Cc<TraceBox<dyn Builtin>>),97}9899impl Debug for FuncVal {100	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {101		match self {102			Self::Id => f.debug_tuple("Id").finish(),103			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),104			Self::StaticBuiltin(arg0) => {105				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()106			}107			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),108		}109	}110}111112impl FuncVal {113	pub fn into_native<D: NativeDesc>(self) -> D::Value {114		D::into_native(self)115	}116	pub fn params_len(&self) -> usize {117		match self {118			Self::Id => 1,119			Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),120			Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),121			Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),122		}123	}124	pub fn name(&self) -> IStr {125		match self {126			Self::Id => "id".into(),127			Self::Normal(normal) => normal.name.clone(),128			Self::StaticBuiltin(builtin) => builtin.name().into(),129			Self::Builtin(builtin) => builtin.name().into(),130		}131	}132	pub fn evaluate(133		&self,134		s: State,135		call_ctx: Context,136		loc: CallLocation,137		args: &dyn ArgsLike,138		tailstrict: bool,139	) -> Result<Val> {140		match self {141			Self::Id => {142				#[allow(clippy::unnecessary_wraps)]143				#[builtin]144				const fn builtin_id(v: Any) -> Result<Any> {145					Ok(v)146				}147				static ID: &builtin_id = &builtin_id {};148149				ID.call(s, call_ctx, loc, args)150			}151			Self::Normal(func) => {152				let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;153				evaluate(s, body_ctx, &func.body)154			}155			Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),156			Self::Builtin(b) => b.call(s, call_ctx, loc, args),157		}158	}159	pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {160		self.evaluate(s, Context::default(), CallLocation::native(), args, true)161	}162163	pub const fn is_identity(&self) -> bool {164		matches!(self, Self::Id)165	}166	pub const fn identity() -> Self {167		Self::Id168	}169}