1use std::rc::Rc;23use jrsonnet_ir::{4 function::{FunctionSignature, ParamName},5 ArgsDesc, Expr, ExprParams, Spanned,6};7use rustc_hash::FxHashMap;89use crate::{10 bail,11 destructure::destruct,12 error::{ErrorKind::*, Result},13 evaluate, evaluate_named_param,14 gc::WithCapacityExt as _,15 Context, Pending, Thunk, Val,16};1718fn eval_arg(ctx: Context, arg: &Rc<Spanned<Expr>>, tailstrict: bool) -> Result<Thunk<Val>> {19 if tailstrict {20 Ok(Thunk::evaluated(evaluate(ctx, arg)?))21 } else {22 let arg = arg.clone();23 Ok(Thunk!(move || evaluate(ctx, &arg)))24 }25}26272829303132333435pub(crate) fn parse_function_call(36 ctx: Context,37 body_ctx: Context,38 params: &ExprParams,39 args: &ArgsDesc,40 tailstrict: bool,41) -> Result<Context> {42 let mut passed_args = FxHashMap::with_capacity(params.binds_len());43 if args.unnamed.len() > params.signature.len() {44 bail!(TooManyArgsFunctionHas(45 params.signature.len(),46 params.signature.clone(),47 ))48 }4950 let mut filled_named = 0;51 let mut filled_positionals = 0;5253 for (id, arg) in args.unnamed.iter().enumerate() {54 destruct(55 ¶ms.exprs[id].destruct,56 eval_arg(ctx.clone(), arg, tailstrict)?,57 Pending::new_filled(ctx.clone()),58 &mut passed_args,59 )?;60 filled_positionals += 1;61 }6263 for (name, value) in &args.named {64 65 if !params.exprs.iter().any(|p| &p.destruct.name() == name) {66 bail!(UnknownFunctionParameter(name.clone()));67 }68 if passed_args69 .insert(name.clone(), eval_arg(ctx.clone(), value, tailstrict)?)70 .is_some()71 {72 bail!(BindingParameterASecondTime(name.clone()));73 }74 filled_named += 1;75 }7677 if filled_named + filled_positionals < params.len() {78 79 80 let fctx = Context::new_future();81 let mut defaults =82 FxHashMap::with_capacity(params.binds_len() - filled_named - filled_positionals);8384 for (idx, into, default) in params85 .exprs86 .iter()87 .enumerate()88 .filter_map(|(i, p)| Some((i, &p.destruct, p.default.as_ref()?)))89 {90 if let ParamName::Named(name) = into.name() {91 if passed_args.contains_key(&name) {92 continue;93 }94 } else if idx < filled_positionals {95 continue;96 }9798 destruct(99 into,100 {101 let ctx = fctx.clone();102 let name = into.name();103 let value = default.clone();104 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))105 },106 fctx.clone(),107 &mut defaults,108 )?;109 if into.name().is_named() {110 filled_named += 1;111 } else {112 filled_positionals += 1;113 }114 }115116 117 if filled_named + filled_positionals != params.len() {118 for param in params.exprs.iter().skip(args.unnamed.len()) {119 let mut found = false;120 for (name, _) in &args.named {121 if ¶m.destruct.name() == name {122 found = true;123 }124 }125 if !found {126 bail!(FunctionParameterNotBoundInCall(127 param.destruct.name(),128 params.signature.clone()129 ));130 }131 }132 unreachable!();133 }134135 Ok(body_ctx136 .extend_bindings(passed_args)137 .extend_bindings(defaults)138 .into_future(fctx))139 } else {140 let body_ctx = body_ctx.extend_bindings(passed_args);141 Ok(body_ctx)142 }143}144145146147148149150151152pub fn parse_builtin_call(153 ctx: Context,154 params: FunctionSignature,155 args: &ArgsDesc,156 tailstrict: bool,157) -> Result<Vec<Option<Thunk<Val>>>> {158 let mut passed_args: Vec<Option<Thunk<Val>>> = vec![None; params.len()];159 if args.unnamed.len() > params.len() {160 bail!(TooManyArgsFunctionHas(params.len(), params,))161 }162163 let mut filled_args = 0;164165 for (id, arg) in args.unnamed.iter().enumerate() {166 passed_args[id] = Some(eval_arg(ctx.clone(), arg, tailstrict)?);167 filled_args += 1;168 }169170 for (name, arg) in &args.named {171 172 let id = params173 .iter()174 .position(|p| p.name() == name)175 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;176 if passed_args[id]177 .replace(eval_arg(ctx.clone(), arg, tailstrict)?)178 .is_some()179 {180 bail!(BindingParameterASecondTime(name.clone()));181 }182 filled_args += 1;183 }184185 if filled_args < params.len() {186 for (id, _) in params.iter().enumerate().filter(|(_, p)| p.has_default()) {187 if passed_args[id].is_some() {188 continue;189 }190 filled_args += 1;191 }192193 194 if filled_args != params.len() {195 for param in params.iter().skip(args.unnamed.len()) {196 let mut found = false;197 for (name, _) in &args.named {198 if param.name() == name {199 found = true;200 }201 }202 if !found {203 bail!(FunctionParameterNotBoundInCall(204 param.name().clone(),205 params,206 ));207 }208 }209 unreachable!();210 }211 }212 Ok(passed_args)213}214215216217pub fn parse_default_function_call(body_ctx: Context, params: &ExprParams) -> Result<Context> {218 let fctx = Context::new_future();219220 let mut bindings = FxHashMap::with_capacity(params.binds_len());221222 for param in params.exprs.iter() {223 if let Some(v) = ¶m.default {224 destruct(225 ¶m.destruct.clone(),226 {227 let ctx = fctx.clone();228 let name = param.destruct.name();229 let value = v.clone();230 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))231 },232 fctx.clone(),233 &mut bindings,234 )?;235 } else {236 destruct(237 ¶m.destruct,238 {239 let param_name = param.destruct.name();240 let params = params.clone();241 Thunk!(move || Err(FunctionParameterNotBoundInCall(242 param_name,243 params.signature244 )245 .into()))246 },247 fctx.clone(),248 &mut bindings,249 )?;250 }251 }252253 Ok(body_ctx.extend_bindings(bindings).into_future(fctx))254}