1use std::any::Any;23use jrsonnet_gcmodule::{Trace, TraceBox, cc_dyn};4use jrsonnet_ir::function::{FunctionSignature, ParamDefault, ParamName, ParamParse};56use super::CallLocation;7use crate::{Result, Thunk, Val};89#[macro_export]10macro_rules! params {11 (@name unnamed) => { ParamName::Unnamed };12 (@name named $name:literal) => { ParamName::Named($crate::IStr::from($name)) };13 ($($(#[$meta:meta])* [$kind:ident $(($lit:literal))? => $default:expr]),* $(,)?) => {14 thread_local! {15 static PARAMS: FunctionSignature = FunctionSignature::new([16 $($(#[$meta])* ParamParse::new(params!(@name $kind $($lit)?), $default)),*17 ].into());18 }19 };20}2122#[macro_export]23macro_rules! names {24 ($($name:ident: $val:literal),* $(,)?) => {25 struct Names {26 $($name: $crate::IStr,)*27 }28 thread_local! {29 static NAMES: Names = Names {30 $($name: $crate::IStr::from($val)),*31 };32 }33 $(pub fn $name() -> $crate::IStr {34 NAMES.with(|n| n.$name.clone())35 })*36 }37}3839cc_dyn!(40 #[derive(Clone)]41 BuiltinFunc,42 Builtin,43 pub(crate) fn new() {...}44);45impl Builtin for BuiltinFunc {46 fn name(&self) -> &str {47 self.0.name()48 }4950 fn params(&self) -> FunctionSignature {51 self.0.params()52 }5354 fn call(&self, loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val> {55 self.0.call(loc, args)56 }5758 fn as_any(&self) -> &dyn Any {59 self.0.as_any()60 }61}6263646566pub trait Builtin: Trace {67 68 fn name(&self) -> &str;69 70 fn params(&self) -> FunctionSignature;71 72 fn call(&self, loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val>;7374 fn as_any(&self) -> &dyn Any;75}7677#[derive(Trace)]78pub struct NativeCallback {79 pub(crate) params: FunctionSignature,80 handler: TraceBox<dyn NativeCallbackHandler>,81}82impl NativeCallback {83 #[deprecated = "prefer using builtins directly, use this interface only for bindings"]84 pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {85 Self {86 params: FunctionSignature::new(87 params88 .into_iter()89 .map(|n| ParamParse::new(ParamName::Named(n.into()), ParamDefault::None))90 .collect(),91 ),92 handler: TraceBox(Box::new(handler)),93 }94 }95}9697impl Builtin for NativeCallback {98 fn name(&self) -> &'static str {99 100 101 "<native>"102 }103104 fn params(&self) -> FunctionSignature {105 self.params.clone()106 }107108 fn call(&self, _loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val> {109 let args = args110 .iter()111 .map(|a| a.as_ref().expect("legacy natives have no default params"))112 .map(Thunk::evaluate)113 .collect::<Result<Vec<Val>>>()?;114 self.handler.call(&args)115 }116117 fn as_any(&self) -> &dyn Any {118 self119 }120}121122pub trait NativeCallbackHandler: Trace {123 fn call(&self, args: &[Val]) -> Result<Val>;124}