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 evaluate::{destructure::destruct, ensure_sufficient_stack, evaluate, evaluate_trivial},18 function::builtin::BuiltinFunc,19};2021pub mod builtin;22mod native;23pub(crate) mod prepared;2425pub use jrsonnet_ir::function::*;26pub use native::NativeFn;27pub(crate) use prepared::PreparedFuncVal;28293031#[derive(Clone, Copy)]32pub struct CallLocation<'l>(pub Option<&'l Span>);33impl<'l> CallLocation<'l> {34 35 pub const fn new(loc: &'l Span) -> Self {36 Self(Some(loc))37 }38}39impl CallLocation<'static> {40 41 pub const fn native() -> Self {42 Self(None)43 }44}454647#[derive(Trace, Educe)]48#[educe(Debug, PartialEq)]49pub struct FuncDesc {50 51 52 53 54 55 56 57 58 59 pub name: IStr,60 pub(crate) body_captures: PackedContextSupThis,6162 #[educe(PartialEq(method = Rc::ptr_eq))]63 pub func: Rc<LFunction>,64}6566impl FuncDesc {67 pub fn signature(&self) -> FunctionSignature {68 self.func.signature.clone()69 }7071 pub fn call(72 &self,73 unnamed: &[Thunk<Val>],74 named: &[Thunk<Val>],75 prepared: &PreparedCall,76 ) -> Result<Val> {77 let body_ctx = self.body_captures.clone().enter(|fill, ctx| {78 79 for (param_idx, thunk) in unnamed.iter().enumerate() {80 destruct(81 &self.func.params[param_idx].destruct,82 fill,83 thunk.clone(),84 ctx,85 );86 }87 for &(param_idx, arg_idx) in prepared.named() {88 destruct(89 &self.func.params[param_idx].destruct,90 fill,91 named[arg_idx].clone(),92 ctx,93 );94 }9596 for ¶m_idx in prepared.defaults() {97 let param = &self.func.params[param_idx];98 let (shape, expr) = param.default.as_ref().expect("default exists");99 let expr = expr.clone();100 let env = Context::enter_using(ctx, shape);101102 destruct(103 ¶m.destruct,104 fill,105 Thunk!(move || evaluate(env, &expr)),106 ctx,107 );108 }109 });110111 ensure_sufficient_stack(|| evaluate(body_ctx, &self.func.body))112 }113114 pub fn evaluate_trivial(&self) -> Option<Val> {115 evaluate_trivial(&self.func.body)116 }117}118119120#[allow(clippy::module_name_repetitions)]121#[derive(Trace, Clone)]122pub enum FuncVal {123 124 Normal(Cc<FuncDesc>),125 126 Builtin(BuiltinFunc),127}128129impl Debug for FuncVal {130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {131 match self {132 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),133 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),134 }135 }136}137138#[allow(clippy::unnecessary_wraps)]139#[builtin]140pub const fn builtin_id(x: Thunk<Val>) -> Thunk<Val> {141 x142}143144impl FuncVal {145 pub fn builtin(builtin: impl Builtin) -> Self {146 Self::Builtin(BuiltinFunc::new(builtin))147 }148149 pub fn identity() -> Self {150 Self::builtin(builtin_id {})151 }152153 pub fn params(&self) -> FunctionSignature {154 match self {155 Self::Builtin(i) => i.params(),156 Self::Normal(p) => p.signature(),157 }158 }159 160 pub fn params_len32(&self) -> u32 {161 arridx(self.params().iter().filter(|p| !p.has_default()).count())162 }163 164 pub fn name(&self) -> IStr {165 match self {166 Self::Normal(normal) => normal.name.clone(),167 Self::Builtin(builtin) => builtin.name().into(),168 }169 }170171 pub(crate) fn evaluate_prepared(172 &self,173 prepared: &PreparedCall,174 loc: CallLocation<'_>,175 unnamed: &[Thunk<Val>],176 named: &[Thunk<Val>],177 _tailstrict: bool,178 ) -> Result<Val> {179 match self {180 FuncVal::Normal(func) => func.call(unnamed, named, prepared),181 FuncVal::Builtin(b) => {182 let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);183 b.call(loc, &args)184 }185 }186 }187188 189 190 191 pub fn is_identity(&self) -> bool {192 match self {193 Self::Builtin(b) => b.as_any().downcast_ref::<builtin_id>().is_some(),194 Self::Normal(_) => false,195 }196 }197198 pub fn evaluate_trivial(&self) -> Option<Val> {199 match self {200 Self::Normal(n) => n.evaluate_trivial(),201 Self::Builtin(_) => None,202 }203 }204}205206impl<T> From<T> for FuncVal207where208 T: Builtin,209{210 fn from(value: T) -> Self {211 Self::builtin(value)212 }213}