1use std::rc::Rc;23use jrsonnet_gcmodule::{Acyclic, Trace};4use jrsonnet_ir::{ExprParams, IStr, function::FunctionSignature};5use rustc_hash::FxHashSet;67use super::{CallLocation, FuncVal};8use crate::{9 Context, ContextBuilder, Pending, Result, Thunk, Val, bail, destructure::destruct,10 error::ErrorKind::*, evaluate_named_param,11};1213#[derive(Debug, Trace, Clone)]14pub struct PreparedFuncVal {15 fun: FuncVal,16 prepared: Rc<PreparedCall>,17}1819impl PreparedFuncVal {20 pub fn new(fun: FuncVal, unnamed: usize, named: &[IStr]) -> Result<Self> {21 let prepared = prepare_call(fun.params(), unnamed, named)?;22 Ok(Self {23 fun,24 prepared: Rc::new(prepared),25 })26 }27 pub fn call(28 &self,29 loc: CallLocation<'_>,30 unnamed: &[Thunk<Val>],31 named: &[Thunk<Val>],32 ) -> Result<Val> {33 self.fun34 .evaluate_prepared(&self.prepared, loc, unnamed, named, false)35 }36}3738#[derive(Acyclic, Debug)]39pub struct PreparedCall {40 41 named: Vec<(usize, usize)>,42 defaults: Vec<usize>,43}4445pub fn prepare_call(46 params: FunctionSignature,47 unnamed: usize,48 named: &[IStr],49) -> Result<PreparedCall> {50 if unnamed > params.len() {51 bail!(TooManyArgsFunctionHas(params.len(), params))52 }5354 let expected_defaults = (params.len() - unnamed).saturating_sub(named.len());55 let mut ops = PreparedCall {56 named: Vec::with_capacity(named.len()),57 defaults: Vec::with_capacity(expected_defaults),58 };5960 61 let mut passed: FxHashSet<usize> = (0..unnamed).collect();6263 for (input_id, name) in named.iter().enumerate() {64 65 let Some(param_idx) = params.iter().position(|p| p.name() == name) else {66 bail!(UnknownFunctionParameter(name.clone()));67 };68 if !passed.insert(param_idx) {69 bail!(BindingParameterASecondTime(name.clone()));70 }71 ops.named.push((param_idx, input_id));72 }7374 if named.len() + unnamed < params.len() {75 let mut defaults = 0;7677 for (param_id, param) in params78 .iter()79 .enumerate()80 .skip(unnamed)81 .filter(|p| p.1.has_default())82 {83 84 if !param.name().is_anonymous() && passed.contains(¶m_id) {85 continue;86 }87 defaults += 1;8889 ops.defaults.push(param_id);90 }9192 93 if defaults != expected_defaults {94 for param in params.iter().skip(unnamed) {95 let mut found = false;96 for name in named {97 if param.name() == name {98 found = true;99 }100 }101 if !found {102 bail!(FunctionParameterNotBoundInCall(103 param.name().clone(),104 params105 ));106 }107 }108 unreachable!();109 }110 }111112 Ok(ops)113}114pub fn parse_prepared_function_call(115 body_ctx: Context,116 prepared: &PreparedCall,117 params: &ExprParams,118 unnamed: &[Thunk<Val>],119 named: &[Thunk<Val>],120) -> Result<Context> {121 let mut ctx = ContextBuilder::extend(body_ctx);122123 let destruct_ctx = Pending::new();124125 for (param_idx, unnamed) in unnamed.iter().enumerate() {126 destruct(127 ¶ms.exprs[param_idx].destruct,128 unnamed.clone(),129 destruct_ctx.clone(),130 &mut ctx,131 )?;132 }133134 for (param_idx, arg_idx) in prepared.named.iter().copied() {135 destruct(136 ¶ms.exprs[param_idx].destruct,137 named[arg_idx].clone(),138 destruct_ctx.clone(),139 &mut ctx,140 )?;141 }142143 if prepared.defaults.is_empty() {144 let body_ctx = ctx.build().into_future(destruct_ctx);145 Ok(body_ctx)146 } else {147 let fctx = Context::new_future();148 let mut ctx = ctx.commit();149 for param_idx in prepared.defaults.iter().copied() {150 151 destruct(152 ¶ms.exprs[param_idx].destruct,153 {154 let ctx = fctx.clone();155 let params = params.clone();156 Thunk!(move || {157 let param = ¶ms.exprs[param_idx];158 let name = param.destruct.name();159 let value = param.default.as_ref().expect("default exists");160 evaluate_named_param(ctx.unwrap(), value, name)161 })162 },163 fctx.clone(),164 &mut ctx,165 )?;166 }167168 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))169 }170}171pub fn parse_prepared_builtin_call(172 prepared: &PreparedCall,173 params: FunctionSignature,174 unnamed: &[Thunk<Val>],175 named: &[Thunk<Val>],176) -> Vec<Option<Thunk<Val>>> {177 let mut passed_args = vec![None; params.len()];178179 for (param_idx, unnamed) in unnamed.iter().enumerate() {180 passed_args[param_idx] = Some(unnamed.clone());181 }182183 for (param_idx, arg_idx) in prepared.named.iter().copied() {184 passed_args[param_idx] = Some(named[arg_idx].clone());185 }186187 passed_args188}