1use std::{fmt::Debug, rc::Rc};23use educe::Educe;4use jrsonnet_gcmodule::{Cc, Trace};5use jrsonnet_interner::IStr;6use jrsonnet_ir::Span;7pub use jrsonnet_macros::builtin;89use self::{10 builtin::Builtin,11 prepared::{PreparedCall, parse_prepared_builtin_call},12};13use crate::{14 Context, ContextBuilder, Result, Thunk, Val,15 analyze::{LDestruct, LExpr, LFunction},16 evaluate::{destructure::destruct, ensure_sufficient_stack, evaluate, evaluate_trivial},17 function::builtin::BuiltinFunc,18};1920pub mod builtin;21mod native;22pub(crate) mod prepared;2324pub use jrsonnet_ir::function::*;25pub use native::NativeFn;26pub(crate) use prepared::PreparedFuncVal;27282930#[derive(Clone, Copy)]31pub struct CallLocation<'l>(pub Option<&'l Span>);32impl<'l> CallLocation<'l> {33 34 pub const fn new(loc: &'l Span) -> Self {35 Self(Some(loc))36 }37}38impl CallLocation<'static> {39 40 pub const fn native() -> Self {41 Self(None)42 }43}444546#[derive(Trace, Educe)]47#[educe(Debug, PartialEq)]48pub struct FuncDesc {49 50 51 52 53 54 55 56 57 58 pub name: IStr,59 60 61 62 63 64 65 66 67 68 pub ctx: Context,6970 #[educe(PartialEq(method = Rc::ptr_eq))]71 pub func: Rc<LFunction>,72}7374impl FuncDesc {75 pub fn signature(&self) -> FunctionSignature {76 self.func.signature.clone()77 }7879 pub fn call(80 &self,81 unnamed: &[Thunk<Val>],82 named: &[Thunk<Val>],83 prepared: &PreparedCall,84 ) -> Result<Val> {85 let has_defaults = !prepared.defaults().is_empty();86 let mut builder = ContextBuilder::extend(self.ctx.clone(), self.func.params.len());8788 let fctx = Context::new_future();89 for (param_idx, thunk) in unnamed.iter().enumerate() {90 destruct(91 &self.func.params[param_idx].destruct,92 thunk.clone(),93 fctx.clone(),94 &mut builder,95 );96 }9798 for &(param_idx, arg_idx) in prepared.named() {99 destruct(100 &self.func.params[param_idx].destruct,101 named[arg_idx].clone(),102 fctx.clone(),103 &mut builder,104 );105 }106107 if has_defaults {108 for ¶m_idx in prepared.defaults() {109 let param = &self.func.params[param_idx];110 if let Some(default_expr) = ¶m.default {111 let default_expr = default_expr.clone();112 let fctxc = fctx.clone();113 let thunk = Thunk!(move || {114 let ctx = fctxc.unwrap();115 evaluate(ctx, &default_expr)116 });117 destruct(¶m.destruct, thunk, fctx.clone(), &mut builder);118 }119 }120 };121 let ctx = builder.build().into_future(fctx);122 ensure_sufficient_stack(|| evaluate(ctx, &self.func.body))123 }124125 pub fn evaluate_trivial(&self) -> Option<Val> {126 evaluate_trivial(&self.func.body)127 }128}129130131#[allow(clippy::module_name_repetitions)]132#[derive(Trace, Clone)]133pub enum FuncVal {134 135 Normal(Cc<FuncDesc>),136 137 Builtin(BuiltinFunc),138}139140impl Debug for FuncVal {141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {142 match self {143 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),144 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),145 }146 }147}148149#[allow(clippy::unnecessary_wraps)]150#[builtin]151pub const fn builtin_id(x: Thunk<Val>) -> Thunk<Val> {152 x153}154155impl FuncVal {156 pub fn builtin(builtin: impl Builtin) -> Self {157 Self::Builtin(BuiltinFunc::new(builtin))158 }159160 pub fn params(&self) -> FunctionSignature {161 match self {162 Self::Builtin(i) => i.params(),163 Self::Normal(p) => p.signature(),164 }165 }166 167 pub fn params_len(&self) -> u32 {168 self.params().iter().filter(|p| !p.has_default()).count() as u32169 }170 171 pub fn name(&self) -> IStr {172 match self {173 Self::Normal(normal) => normal.name.clone(),174 Self::Builtin(builtin) => builtin.name().into(),175 }176 }177178 pub(crate) fn evaluate_prepared(179 &self,180 prepared: &PreparedCall,181 loc: CallLocation<'_>,182 unnamed: &[Thunk<Val>],183 named: &[Thunk<Val>],184 _tailstrict: bool,185 ) -> Result<Val> {186 match self {187 FuncVal::Normal(func) => func.call(unnamed, named, prepared),188 FuncVal::Builtin(b) => {189 let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);190 b.call(loc, &args)191 }192 }193 }194195 196 197 198 199 200 pub fn is_identity(&self) -> bool {201 match self {202 Self::Builtin(b) => b.as_any().downcast_ref::<builtin_id>().is_some(),203 Self::Normal(desc) => {204 if desc.func.params.len() != 1 {205 return false;206 }207 let param = &desc.func.params[0];208 if param.default.is_some() {209 return false;210 }211 #[allow(irrefutable_let_patterns, reason = "refutable with exp-destruct")]212 let LDestruct::Full(id) = ¶m.destruct else {213 return false;214 };215 matches!(&*desc.func.body, LExpr::Local(v) if v == id)216 }217 }218 }219220 pub fn evaluate_trivial(&self) -> Option<Val> {221 match self {222 Self::Normal(n) => n.evaluate_trivial(),223 Self::Builtin(_) => None,224 }225 }226}227228impl<T> From<T> for FuncVal229where230 T: Builtin,231{232 fn from(value: T) -> Self {233 Self::builtin(value)234 }235}