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

difftreelog

source

crates/jrsonnet-evaluator/src/function/builtin.rs4.0 KiBsourcehistory
1use std::any::Any;23use jrsonnet_gcmodule::{cc_dyn, Acyclic, Trace, TraceBox};4use jrsonnet_interner::IStr;56use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};7use crate::{Context, Result, Val};89#[derive(Clone, Acyclic)]10pub struct ParamName(Option<IStr>);11impl ParamName {12	pub const ANONYMOUS: Self = Self(None);13	pub fn new(name: IStr) -> Self {14		Self(Some(name))15	}16	pub fn as_str(&self) -> Option<&str> {17		self.0.as_deref()18	}19	pub fn is_anonymous(&self) -> bool {20		self.0.is_none()21	}22}23impl PartialEq<IStr> for ParamName {24	fn eq(&self, other: &IStr) -> bool {25		self.026			.as_ref()27			.map_or(false, |s| s.as_bytes() == other.as_bytes())28	}29}3031#[derive(Clone, Copy, Debug, Acyclic)]32pub enum ParamDefault {33	None,34	Exists,35	Literal(&'static str),36}37impl ParamDefault {38	pub const fn exists(is_exists: bool) -> Self {39		if is_exists {40			Self::Exists41		} else {42			Self::None43		}44	}45}4647#[macro_export]48macro_rules! params {49	(@name unnamed) => { ParamName::ANONYMOUS };50	(@name named $name:literal) => { ParamName::new($crate::IStr::from($name)) };51	($($(#[$meta:meta])* [$kind:ident $(($lit:literal))? => $default:expr]),* $(,)?) => {52		thread_local! {53			static PARAMS: [ParamParse; { const N: usize = <[u8]>::len(&[$($(#[$meta])* 0u8),*]); N }] = [54				$($(#[$meta])* ParamParse::new(params!(@name $kind $($lit)?), $default)),*55			];56		}57	};58}5960#[derive(Clone, Acyclic)]61pub struct ParamParse {62	name: ParamName,63	default: ParamDefault,64}65impl ParamParse {66	pub fn new(name: ParamName, default: ParamDefault) -> Self {67		Self { name, default }68	}69	/// Parameter name for named call parsing70	pub fn name(&self) -> &ParamName {71		&self.name72	}73	pub fn default(&self) -> ParamDefault {74		self.default75	}76	pub fn has_default(&self) -> bool {77		!matches!(self.default, ParamDefault::None)78	}79}8081cc_dyn!(82	#[derive(Clone)]83	BuiltinFunc,84	Builtin,85	pub(crate) fn new() {...}86);87impl Builtin for BuiltinFunc {88	fn name(&self) -> &str {89		self.0.name()90	}9192	fn params(&self) -> &[ParamParse] {93		self.0.params()94	}9596	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {97		self.0.call(ctx, loc, args)98	}99100	fn as_any(&self) -> &dyn Any {101		self.0.as_any()102	}103}104105/// Description of function defined by native code106///107/// Prefer to use #[builtin] macro, instead of manual implementation of this trait108pub trait Builtin: Trace {109	/// Function name to be used in stack traces110	fn name(&self) -> &str;111	/// Parameter names for named calls112	fn params(&self) -> &[ParamParse];113	/// Call the builtin114	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;115116	fn as_any(&self) -> &dyn Any;117}118119pub trait StaticBuiltin: Builtin + Send + Sync120where121	Self: 'static,122{123	// In impl, to make it object safe:124	// const INST: &'static Self;125}126127#[derive(Trace)]128pub struct NativeCallback {129	pub(crate) params: Vec<ParamParse>,130	handler: TraceBox<dyn NativeCallbackHandler>,131}132impl NativeCallback {133	#[deprecated = "prefer using builtins directly, use this interface only for bindings"]134	pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {135		Self {136			params: params137				.into_iter()138				.map(|n| ParamParse {139					name: ParamName::new(n.into()),140					default: ParamDefault::None,141				})142				.collect(),143			handler: TraceBox(Box::new(handler)),144		}145	}146}147148impl Builtin for NativeCallback {149	fn name(&self) -> &str {150		// TODO: standard natives gets their names from definition151		// But builitins should already have them152		"<native>"153	}154155	fn params(&self) -> &[ParamParse] {156		&self.params157	}158159	fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {160		let args = parse_builtin_call(ctx, &self.params, args, true)?;161		let args = args162			.into_iter()163			.map(|a| a.expect("legacy natives have no default params"))164			.map(|a| a.evaluate())165			.collect::<Result<Vec<Val>>>()?;166		self.handler.call(&args)167	}168169	fn as_any(&self) -> &dyn Any {170		self171	}172}173174pub trait NativeCallbackHandler: Trace {175	fn call(&self, args: &[Val]) -> Result<Val>;176}