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 PackedContextSupThis, Result, Thunk, Val,15 analyze::LFunction,16 evaluate::{17 destructure::{build_b_thunk, destruct},18 ensure_sufficient_stack, evaluate, evaluate_trivial,19 },20 function::builtin::BuiltinFunc,21};2223pub mod builtin;24mod native;25pub(crate) mod prepared;2627pub use jrsonnet_ir::function::*;28pub use native::NativeFn;29pub(crate) use prepared::PreparedFuncVal;30313233#[derive(Clone, Copy)]34pub struct CallLocation<'l>(pub Option<&'l Span>);35impl<'l> CallLocation<'l> {36 37 pub const fn new(loc: &'l Span) -> Self {38 Self(Some(loc))39 }40}41impl CallLocation<'static> {42 43 pub const fn native() -> Self {44 Self(None)45 }46}474849#[derive(Trace, Educe)]50#[educe(Debug, PartialEq)]51pub struct FuncDesc {52 53 54 55 56 57 58 59 60 61 pub name: IStr,62 pub(crate) body_captures: PackedContextSupThis,6364 #[educe(PartialEq(method = Rc::ptr_eq))]65 pub func: Rc<LFunction>,66}6768impl FuncDesc {69 pub fn signature(&self) -> FunctionSignature {70 self.func.signature.clone()71 }7273 pub fn call(74 &self,75 unnamed: &[Thunk<Val>],76 named: &[Thunk<Val>],77 prepared: &PreparedCall,78 ) -> Result<Val> {79 let body_ctx = self.body_captures.clone().enter(|fill, ctx| {80 81 for (param_idx, thunk) in unnamed.iter().enumerate() {82 destruct(83 &self.func.params[param_idx].destruct,84 fill,85 thunk.clone(),86 &ctx,87 );88 }89 for &(param_idx, arg_idx) in prepared.named() {90 destruct(91 &self.func.params[param_idx].destruct,92 fill,93 named[arg_idx].clone(),94 &ctx,95 );96 }9798 for ¶m_idx in prepared.defaults() {99 let param = &self.func.params[param_idx];100 let (shape, expr) = param.default.as_ref().expect("default exists");101 let thunk = build_b_thunk(&ctx, shape, expr.clone());102 destruct(¶m.destruct, fill, thunk, &ctx);103 }104 });105106 ensure_sufficient_stack(|| evaluate(body_ctx, &self.func.body))107 }108109 pub fn evaluate_trivial(&self) -> Option<Val> {110 evaluate_trivial(&self.func.body)111 }112}113114115#[allow(clippy::module_name_repetitions)]116#[derive(Trace, Clone)]117pub enum FuncVal {118 119 Normal(Cc<FuncDesc>),120 121 Builtin(BuiltinFunc),122}123124impl Debug for FuncVal {125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {126 match self {127 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),128 Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),129 }130 }131}132133#[allow(clippy::unnecessary_wraps)]134#[builtin]135pub const fn builtin_id(x: Thunk<Val>) -> Thunk<Val> {136 x137}138139impl FuncVal {140 pub fn builtin(builtin: impl Builtin) -> Self {141 Self::Builtin(BuiltinFunc::new(builtin))142 }143144 pub fn identity() -> Self {145 Self::builtin(builtin_id {})146 }147148 pub fn params(&self) -> FunctionSignature {149 match self {150 Self::Builtin(i) => i.params(),151 Self::Normal(p) => p.signature(),152 }153 }154 155 pub fn params_len(&self) -> u32 {156 self.params().iter().filter(|p| !p.has_default()).count() as u32157 }158 159 pub fn name(&self) -> IStr {160 match self {161 Self::Normal(normal) => normal.name.clone(),162 Self::Builtin(builtin) => builtin.name().into(),163 }164 }165166 pub(crate) fn evaluate_prepared(167 &self,168 prepared: &PreparedCall,169 loc: CallLocation<'_>,170 unnamed: &[Thunk<Val>],171 named: &[Thunk<Val>],172 _tailstrict: bool,173 ) -> Result<Val> {174 match self {175 FuncVal::Normal(func) => func.call(unnamed, named, prepared),176 FuncVal::Builtin(b) => {177 let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);178 b.call(loc, &args)179 }180 }181 }182183 184 185 186 pub fn is_identity(&self) -> bool {187 match self {188 Self::Builtin(b) => b.as_any().downcast_ref::<builtin_id>().is_some(),189 Self::Normal(_) => false,190 }191 }192193 pub fn evaluate_trivial(&self) -> Option<Val> {194 match self {195 Self::Normal(n) => n.evaluate_trivial(),196 Self::Builtin(_) => None,197 }198 }199}200201impl<T> From<T> for FuncVal202where203 T: Builtin,204{205 fn from(value: T) -> Self {206 Self::builtin(value)207 }208}