1use std::rc::Rc;23use jrsonnet_ir::{4 ArgsDesc, Expr, ExprParams,5 function::{FunctionSignature, ParamName},6};7use rustc_hash::FxHashMap;89use crate::{10 Context, Pending, Thunk, Val, bail,11 destructure::destruct,12 error::{ErrorKind::*, Result},13 evaluate, evaluate_named_param,14 gc::WithCapacityExt as _,15};1617fn eval_arg(ctx: Context, arg: &Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {18 if tailstrict {19 Ok(Thunk::evaluated(evaluate(ctx, arg)?))20 } else {21 let arg = arg.clone();22 Ok(Thunk!(move || evaluate(ctx, &arg)))23 }24}25262728293031323334pub(crate) fn parse_function_call(35 ctx: Context,36 body_ctx: Context,37 params: &ExprParams,38 args: &ArgsDesc,39 tailstrict: bool,40) -> Result<Context> {41 let mut passed_args = FxHashMap::with_capacity(params.binds_len());42 if args.unnamed.len() > params.signature.len() {43 bail!(TooManyArgsFunctionHas(44 params.signature.len(),45 params.signature.clone(),46 ))47 }4849 let mut filled_named = 0;50 let mut filled_positionals = 0;5152 for (id, arg) in args.unnamed.iter().enumerate() {53 destruct(54 ¶ms.exprs[id].destruct,55 eval_arg(ctx.clone(), arg, tailstrict)?,56 Pending::new_filled(ctx.clone()),57 &mut passed_args,58 )?;59 filled_positionals += 1;60 }6162 for (name, value) in &args.named {63 64 if !params.exprs.iter().any(|p| &p.destruct.name() == name) {65 bail!(UnknownFunctionParameter(name.clone()));66 }67 if passed_args68 .insert(name.clone(), eval_arg(ctx.clone(), value, tailstrict)?)69 .is_some()70 {71 bail!(BindingParameterASecondTime(name.clone()));72 }73 filled_named += 1;74 }7576 if filled_named + filled_positionals < params.len() {77 78 79 let fctx = Context::new_future();80 let mut defaults =81 FxHashMap::with_capacity(params.binds_len() - filled_named - filled_positionals);8283 for (idx, into, default) in params84 .exprs85 .iter()86 .enumerate()87 .filter_map(|(i, p)| Some((i, &p.destruct, p.default.as_ref()?)))88 {89 if let ParamName::Named(name) = into.name() {90 if passed_args.contains_key(&name) {91 continue;92 }93 } else if idx < filled_positionals {94 continue;95 }9697 destruct(98 into,99 {100 let ctx = fctx.clone();101 let name = into.name();102 let value = default.clone();103 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))104 },105 fctx.clone(),106 &mut defaults,107 )?;108 if into.name().is_named() {109 filled_named += 1;110 } else {111 filled_positionals += 1;112 }113 }114115 116 if filled_named + filled_positionals != params.len() {117 for param in params.exprs.iter().skip(args.unnamed.len()) {118 let mut found = false;119 for (name, _) in &args.named {120 if ¶m.destruct.name() == name {121 found = true;122 }123 }124 if !found {125 bail!(FunctionParameterNotBoundInCall(126 param.destruct.name(),127 params.signature.clone()128 ));129 }130 }131 unreachable!();132 }133134 Ok(body_ctx135 .extend_bindings(passed_args)136 .extend_bindings(defaults)137 .into_future(fctx))138 } else {139 let body_ctx = body_ctx.extend_bindings(passed_args);140 Ok(body_ctx)141 }142}143144145146147148149150151pub fn parse_builtin_call(152 ctx: Context,153 params: FunctionSignature,154 args: &ArgsDesc,155 tailstrict: bool,156) -> Result<Vec<Option<Thunk<Val>>>> {157 let mut passed_args: Vec<Option<Thunk<Val>>> = vec![None; params.len()];158 if args.unnamed.len() > params.len() {159 bail!(TooManyArgsFunctionHas(params.len(), params,))160 }161162 let mut filled_args = 0;163164 for (id, arg) in args.unnamed.iter().enumerate() {165 passed_args[id] = Some(eval_arg(ctx.clone(), arg, tailstrict)?);166 filled_args += 1;167 }168169 for (name, arg) in &args.named {170 171 let id = params172 .iter()173 .position(|p| p.name() == name)174 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;175 if passed_args[id]176 .replace(eval_arg(ctx.clone(), arg, tailstrict)?)177 .is_some()178 {179 bail!(BindingParameterASecondTime(name.clone()));180 }181 filled_args += 1;182 }183184 if filled_args < params.len() {185 for (id, _) in params.iter().enumerate().filter(|(_, p)| p.has_default()) {186 if passed_args[id].is_some() {187 continue;188 }189 filled_args += 1;190 }191192 193 if filled_args != params.len() {194 for param in params.iter().skip(args.unnamed.len()) {195 let mut found = false;196 for (name, _) in &args.named {197 if param.name() == name {198 found = true;199 }200 }201 if !found {202 bail!(FunctionParameterNotBoundInCall(203 param.name().clone(),204 params,205 ));206 }207 }208 unreachable!();209 }210 }211 Ok(passed_args)212}213214215216pub fn parse_default_function_call(body_ctx: Context, params: &ExprParams) -> Result<Context> {217 let fctx = Context::new_future();218219 let mut bindings = FxHashMap::with_capacity(params.binds_len());220221 for param in params.exprs.iter() {222 if let Some(v) = ¶m.default {223 destruct(224 ¶m.destruct.clone(),225 {226 let ctx = fctx.clone();227 let name = param.destruct.name();228 let value = v.clone();229 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))230 },231 fctx.clone(),232 &mut bindings,233 )?;234 } else {235 destruct(236 ¶m.destruct,237 {238 let param_name = param.destruct.name();239 let params = params.clone();240 Thunk!(move || Err(FunctionParameterNotBoundInCall(241 param_name,242 params.signature243 )244 .into()))245 },246 fctx.clone(),247 &mut bindings,248 )?;249 }250 }251252 Ok(body_ctx.extend_bindings(bindings).into_future(fctx))253}