1use jrsonnet_parser::function::FunctionSignature;2use jrsonnet_parser::{ExprParams, IStr};3use rustc_hash::{FxHashMap, FxHashSet};45use crate::destructure::destruct;6use crate::gc::WithCapacityExt;7use crate::{bail, error::ErrorKind::*, Result};8use crate::{evaluate_named_param, Context, ContextBuilder, Pending, Thunk, Val};910pub struct PreparedCall {11 12 named: Vec<(usize, usize)>,13 defaults: Vec<usize>,14}1516pub fn prepare_call(17 params: FunctionSignature,18 unnamed: usize,19 named: &[IStr],20) -> Result<PreparedCall> {21 if unnamed > params.len() {22 bail!(TooManyArgsFunctionHas(params.len(), params))23 }2425 let expected_defaults = params.len() - unnamed - named.len();26 let mut ops = PreparedCall {27 named: Vec::with_capacity(named.len()),28 defaults: Vec::with_capacity(expected_defaults),29 };3031 32 let mut passed: FxHashSet<usize> = (0..unnamed).collect();3334 for (input_id, name) in named.iter().enumerate() {35 36 let Some(param_idx) = params.iter().position(|p| p.name() == name) else {37 bail!(UnknownFunctionParameter(name.clone()));38 };39 if !passed.insert(param_idx) {40 bail!(BindingParameterASecondTime(name.clone()));41 }42 ops.named.push((param_idx, input_id));43 }4445 if named.len() + unnamed < params.len() {46 let mut defaults = 0;4748 for (param_id, param) in params49 .iter()50 .enumerate()51 .skip(unnamed)52 .filter(|p| p.1.has_default())53 {54 55 if !param.name().is_anonymous() && passed.contains(¶m_id) {56 continue;57 }58 defaults += 1;5960 ops.defaults.push(param_id);61 }6263 64 if defaults != expected_defaults {65 for param in params.iter().skip(unnamed) {66 let mut found = false;67 for name in named {68 if param.name() == name {69 found = true;70 }71 }72 if !found {73 bail!(FunctionParameterNotBoundInCall(74 param.name().clone(),75 params76 ));77 }78 }79 unreachable!();80 }81 }8283 Ok(ops)84}85pub fn parse_prepared_function_call(86 body_ctx: Context,87 prepared: &PreparedCall,88 params: &ExprParams,89 unnamed: &[Thunk<Val>],90 named: &[Thunk<Val>],91) -> Result<Context> {92 let mut passed_args = FxHashMap::with_capacity(params.binds_len());9394 let destruct_ctx = Pending::new();9596 for (param_idx, unnamed) in unnamed.iter().enumerate() {97 destruct(98 ¶ms.exprs[param_idx].destruct,99 unnamed.clone(),100 destruct_ctx.clone(),101 &mut passed_args,102 )?;103 }104105 for (param_idx, arg_idx) in prepared.named.iter().copied() {106 destruct(107 ¶ms.exprs[param_idx].destruct,108 named[arg_idx].clone(),109 destruct_ctx.clone(),110 &mut passed_args,111 )?;112 }113114 if prepared.defaults.is_empty() {115 let body_ctx = body_ctx116 .extend_bindings(passed_args)117 .into_future(destruct_ctx);118 Ok(body_ctx)119 } else {120 let fctx = Context::new_future();121 let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());122 for param_idx in prepared.defaults.iter().copied() {123 124 destruct(125 ¶ms.exprs[param_idx].destruct,126 {127 let ctx = fctx.clone();128 let params = params.clone();129 Thunk!(move || {130 let param = ¶ms.exprs[param_idx];131 let name = param.destruct.name();132 let value = param.default.as_ref().expect("default exists");133 evaluate_named_param(ctx.unwrap(), value, name)134 })135 },136 fctx.clone(),137 &mut defaults,138 )?;139 }140141 let mut ctx = ContextBuilder::extend(body_ctx);142 ctx.binds(passed_args);143 ctx.binds(defaults);144 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))145 }146}147pub fn parse_prepared_builtin_call(148 prepared: &PreparedCall,149 params: FunctionSignature,150 unnamed: &[Thunk<Val>],151 named: &[Thunk<Val>],152) -> Result<Vec<Option<Thunk<Val>>>> {153 let mut passed_args = vec![None; params.len()];154155 for (param_idx, unnamed) in unnamed.iter().enumerate() {156 passed_args[param_idx] = Some(unnamed.clone());157 }158159 for (param_idx, arg_idx) in prepared.named.iter().copied() {160 passed_args[param_idx] = Some(named[arg_idx].clone());161 }162163 Ok(passed_args)164}