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}333435#[derive(Debug, PartialEq, Trace)]36pub struct FuncDesc {37 38 39 40 41 42 43 44 45 46 pub name: IStr,47 48 49 50 51 52 53 54 55 pub ctx: Context,5657 pub params: ParamsDesc,58 pub body: LocExpr,59}60impl FuncDesc {61 62 pub fn default_body_context(&self) -> Result<Context> {63 parse_default_function_call(self.ctx.clone(), &self.params)64 }6566 67 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}848586#[allow(clippy::module_name_repetitions)]87#[derive(Trace, Clone)]88pub enum FuncVal {89 90 Id,91 92 Normal(Cc<FuncDesc>),93 94 StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),95 96 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}