1use std::rc::Rc;23use jrsonnet_gcmodule::{Acyclic, Trace};4use jrsonnet_ir::function::FunctionSignature;5use jrsonnet_ir::{ExprParams, IStr};6use rustc_hash::{FxHashMap, FxHashSet};78use crate::destructure::destruct;9use crate::gc::WithCapacityExt;10use crate::{bail, error::ErrorKind::*, Result};11use crate::{evaluate_named_param, Context, ContextBuilder, Pending, Thunk, Val};1213use super::{CallLocation, FuncVal};1415#[derive(Debug, Trace, Clone)]16pub struct PreparedFuncVal {17 fun: FuncVal,18 prepared: Rc<PreparedCall>,19}2021impl PreparedFuncVal {22 pub fn new(fun: FuncVal, unnamed: usize, named: &[IStr]) -> Result<Self> {23 let prepared = prepare_call(fun.params(), unnamed, named)?;24 Ok(Self {25 fun,26 prepared: Rc::new(prepared),27 })28 }29 pub fn call(30 &self,31 loc: CallLocation<'_>,32 unnamed: &[Thunk<Val>],33 named: &[Thunk<Val>],34 ) -> Result<Val> {35 self.fun36 .evaluate_prepared(&self.prepared, loc, unnamed, named, false)37 }38}3940#[derive(Acyclic, Debug)]41pub struct PreparedCall {42 43 named: Vec<(usize, usize)>,44 defaults: Vec<usize>,45}4647pub fn prepare_call(48 params: FunctionSignature,49 unnamed: usize,50 named: &[IStr],51) -> Result<PreparedCall> {52 if unnamed > params.len() {53 bail!(TooManyArgsFunctionHas(params.len(), params))54 }5556 let expected_defaults = params.len() - unnamed - named.len();57 let mut ops = PreparedCall {58 named: Vec::with_capacity(named.len()),59 defaults: Vec::with_capacity(expected_defaults),60 };6162 63 let mut passed: FxHashSet<usize> = (0..unnamed).collect();6465 for (input_id, name) in named.iter().enumerate() {66 67 let Some(param_idx) = params.iter().position(|p| p.name() == name) else {68 bail!(UnknownFunctionParameter(name.clone()));69 };70 if !passed.insert(param_idx) {71 bail!(BindingParameterASecondTime(name.clone()));72 }73 ops.named.push((param_idx, input_id));74 }7576 if named.len() + unnamed < params.len() {77 let mut defaults = 0;7879 for (param_id, param) in params80 .iter()81 .enumerate()82 .skip(unnamed)83 .filter(|p| p.1.has_default())84 {85 86 if !param.name().is_anonymous() && passed.contains(¶m_id) {87 continue;88 }89 defaults += 1;9091 ops.defaults.push(param_id);92 }9394 95 if defaults != expected_defaults {96 for param in params.iter().skip(unnamed) {97 let mut found = false;98 for name in named {99 if param.name() == name {100 found = true;101 }102 }103 if !found {104 bail!(FunctionParameterNotBoundInCall(105 param.name().clone(),106 params107 ));108 }109 }110 unreachable!();111 }112 }113114 Ok(ops)115}116pub fn parse_prepared_function_call(117 body_ctx: Context,118 prepared: &PreparedCall,119 params: &ExprParams,120 unnamed: &[Thunk<Val>],121 named: &[Thunk<Val>],122) -> Result<Context> {123 let mut passed_args = FxHashMap::with_capacity(params.binds_len());124125 let destruct_ctx = Pending::new();126127 for (param_idx, unnamed) in unnamed.iter().enumerate() {128 destruct(129 ¶ms.exprs[param_idx].destruct,130 unnamed.clone(),131 destruct_ctx.clone(),132 &mut passed_args,133 )?;134 }135136 for (param_idx, arg_idx) in prepared.named.iter().copied() {137 destruct(138 ¶ms.exprs[param_idx].destruct,139 named[arg_idx].clone(),140 destruct_ctx.clone(),141 &mut passed_args,142 )?;143 }144145 if prepared.defaults.is_empty() {146 let body_ctx = body_ctx147 .extend_bindings(passed_args)148 .into_future(destruct_ctx);149 Ok(body_ctx)150 } else {151 let fctx = Context::new_future();152 let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());153 for param_idx in prepared.defaults.iter().copied() {154 155 destruct(156 ¶ms.exprs[param_idx].destruct,157 {158 let ctx = fctx.clone();159 let params = params.clone();160 Thunk!(move || {161 let param = ¶ms.exprs[param_idx];162 let name = param.destruct.name();163 let value = param.default.as_ref().expect("default exists");164 evaluate_named_param(ctx.unwrap(), value, name)165 })166 },167 fctx.clone(),168 &mut defaults,169 )?;170 }171172 let mut ctx = ContextBuilder::extend(body_ctx);173 ctx.binds(passed_args);174 ctx.binds(defaults);175 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))176 }177}178pub fn parse_prepared_builtin_call(179 prepared: &PreparedCall,180 params: FunctionSignature,181 unnamed: &[Thunk<Val>],182 named: &[Thunk<Val>],183) -> Vec<Option<Thunk<Val>>> {184 let mut passed_args = vec![None; params.len()];185186 for (param_idx, unnamed) in unnamed.iter().enumerate() {187 passed_args[param_idx] = Some(unnamed.clone());188 }189190 for (param_idx, arg_idx) in prepared.named.iter().copied() {191 passed_args[param_idx] = Some(named[arg_idx].clone());192 }193194 passed_args195}