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;20212223#[derive(Clone, Copy)]24pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);25impl<'l> CallLocation<'l> {26 27 pub const fn new(loc: &'l ExprLocation) -> Self {28 Self(Some(loc))29 }30}31impl CallLocation<'static> {32 33 pub const fn native() -> Self {34 Self(None)35 }36}373839#[derive(Debug, PartialEq, Trace)]40pub struct FuncDesc {41 42 43 44 45 46 47 48 49 50 pub name: IStr,51 52 53 54 55 56 57 58 59 60 pub ctx: Context,6162 63 pub params: ParamsDesc,64 65 pub body: LocExpr,66}67impl FuncDesc {68 69 pub fn default_body_context(&self) -> Result<Context> {70 parse_default_function_call(self.ctx.clone(), &self.params)71 }7273 74 pub fn call_body_context(75 &self,76 s: State,77 call_ctx: Context,78 args: &dyn ArgsLike,79 tailstrict: bool,80 ) -> Result<Context> {81 parse_function_call(82 s,83 call_ctx,84 self.ctx.clone(),85 &self.params,86 args,87 tailstrict,88 )89 }90}919293#[allow(clippy::module_name_repetitions)]94#[derive(Trace, Clone)]95pub enum FuncVal {96 97 Id,98 99 Normal(Cc<FuncDesc>),100 101 StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),102 103 Builtin(Cc<TraceBox<dyn Builtin>>),104}105106impl Debug for FuncVal {107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {108 match self {109 Self::Id => f.debug_tuple("Id").finish(),110 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),111 Self::StaticBuiltin(arg0) => {112 f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()113 }114 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),115 }116 }117}118119impl FuncVal {120 121 pub fn params_len(&self) -> usize {122 match self {123 Self::Id => 1,124 Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),125 Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),126 Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),127 }128 }129 130 pub fn name(&self) -> IStr {131 match self {132 Self::Id => "id".into(),133 Self::Normal(normal) => normal.name.clone(),134 Self::StaticBuiltin(builtin) => builtin.name().into(),135 Self::Builtin(builtin) => builtin.name().into(),136 }137 }138 139 140 141 pub fn evaluate(142 &self,143 s: State,144 call_ctx: Context,145 loc: CallLocation<'_>,146 args: &dyn ArgsLike,147 tailstrict: bool,148 ) -> Result<Val> {149 match self {150 Self::Id => {151 #[allow(clippy::unnecessary_wraps)]152 #[builtin]153 const fn builtin_id(v: Any) -> Result<Any> {154 Ok(v)155 }156 static ID: &builtin_id = &builtin_id {};157158 ID.call(s, call_ctx, loc, args)159 }160 Self::Normal(func) => {161 let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;162 evaluate(s, body_ctx, &func.body)163 }164 Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),165 Self::Builtin(b) => b.call(s, call_ctx, loc, args),166 }167 }168 169 pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {170 self.evaluate(s, Context::default(), CallLocation::native(), args, true)171 }172 173 pub fn into_native<D: NativeDesc>(self) -> D::Value {174 D::into_native(self)175 }176177 178 179 180 pub const fn is_identity(&self) -> bool {181 matches!(self, Self::Id)182 }183 184 pub const fn identity() -> Self {185 Self::Id186 }187}