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, PackedContextSupThis, Result, Thunk, Val,15 analyze::LFunction,16 arr::arridx,17 ensure_sufficient_stack,18 evaluate::{destructure::destruct, evaluate, evaluate_trivial},19 function::builtin::BuiltinFunc,20};2122pub mod builtin;23mod native;24pub(crate) mod prepared;2526pub use jrsonnet_ir::function::*;27pub use native::NativeFn;28pub(crate) use prepared::PreparedFuncVal;29303132#[derive(Clone, Copy)]33pub struct CallLocation<'l>(pub Option<&'l Span>);34impl<'l> CallLocation<'l> {35 36 pub const fn new(loc: &'l Span) -> Self {37 Self(Some(loc))38 }39}40impl CallLocation<'static> {41 42 pub const fn native() -> Self {43 Self(None)44 }45}464748#[derive(Trace, Educe)]49#[educe(Debug, PartialEq)]50pub struct FuncDesc {51 52 53 54 55 56 57 58 59 60 pub name: IStr,61 pub(crate) body_captures: PackedContextSupThis,6263 #[educe(PartialEq(method = Rc::ptr_eq))]64 pub func: Rc<LFunction>,65}6667impl FuncDesc {68 pub fn signature(&self) -> FunctionSignature {69 self.func.signature.clone()70 }7172 fn call(73 &self,74 unnamed: &[Thunk<Val>],75 named: &[Thunk<Val>],76 prepared: &PreparedCall,77 ) -> Result<Val> {78 let body_ctx = self.body_captures.clone().enter(|fill, ctx| {79 80 for (param_idx, thunk) in unnamed.iter().enumerate() {81 destruct(82 &self.func.params[param_idx].destruct,83 fill,84 thunk.clone(),85 ctx,86 );87 }88 for &(param_idx, arg_idx) in prepared.named() {89 destruct(90 &self.func.params[param_idx].destruct,91 fill,92 named[arg_idx].clone(),93 ctx,94 );95 }9697 for ¶m_idx in prepared.defaults() {98 let param = &self.func.params[param_idx];99 let (shape, expr) = param.default.as_ref().expect("default exists");100 let expr = expr.clone();101 let env = Context::enter_using(ctx, shape);102103 destruct(104 ¶m.destruct,105 fill,106 Thunk!(move || evaluate(env, &expr)),107 ctx,108 );109 }110 });111112 ensure_sufficient_stack(|| evaluate(body_ctx, &self.func.body))113 }114115 pub fn evaluate_trivial(&self) -> Option<Val> {116 evaluate_trivial(&self.func.body)117 }118}119120121#[allow(clippy::module_name_repetitions)]122#[derive(Trace, Clone)]123pub enum FuncVal {124 125 Normal(Cc<FuncDesc>),126 127 Builtin(BuiltinFunc),128}129130impl Debug for FuncVal {131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {132 match self {133 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),134 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),135 }136 }137}138139#[allow(clippy::unnecessary_wraps)]140#[builtin]141pub const fn builtin_id(x: Thunk<Val>) -> Thunk<Val> {142 x143}144145impl FuncVal {146 pub fn builtin(builtin: impl Builtin) -> Self {147 Self::Builtin(BuiltinFunc::new(builtin))148 }149150 pub fn identity() -> Self {151 Self::builtin(builtin_id {})152 }153154 pub fn params(&self) -> FunctionSignature {155 match self {156 Self::Builtin(i) => i.params(),157 Self::Normal(p) => p.signature(),158 }159 }160 161 pub fn params_len32(&self) -> u32 {162 arridx(self.params().iter().filter(|p| !p.has_default()).count())163 }164 165 pub fn name(&self) -> IStr {166 match self {167 Self::Normal(normal) => normal.name.clone(),168 Self::Builtin(builtin) => builtin.name().into(),169 }170 }171172 pub(crate) fn evaluate_prepared(173 &self,174 prepared: &PreparedCall,175 loc: CallLocation<'_>,176 unnamed: &[Thunk<Val>],177 named: &[Thunk<Val>],178 _tailstrict: bool,179 ) -> Result<Val> {180 match self {181 FuncVal::Normal(func) => func.call(unnamed, named, prepared),182 FuncVal::Builtin(b) => {183 let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);184 b.call(loc, &args)185 }186 }187 }188189 190 191 192 pub fn is_identity(&self) -> bool {193 match self {194 Self::Builtin(b) => b.as_any().downcast_ref::<builtin_id>().is_some(),195 Self::Normal(_) => false,196 }197 }198199 pub fn evaluate_trivial(&self) -> Option<Val> {200 match self {201 Self::Normal(n) => n.evaluate_trivial(),202 Self::Builtin(_) => None,203 }204 }205}206207impl<T> From<T> for FuncVal208where209 T: Builtin,210{211 fn from(value: T) -> Self {212 Self::builtin(value)213 }214}