diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index ded6b200..53e38363 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -766,6 +766,9 @@ pub fn gen_call<'ctx, G: CodeGenerator>( let param_vals; let is_extern; + // Ensure that the function object only contains up to 1 vararg parameter + debug_assert!(fun.0.args.iter().filter(|arg| arg.is_vararg).count() <= 1); + let symbol = { // make sure this lock guard is dropped at the end of this scope... let def = definition.read(); @@ -782,18 +785,46 @@ pub fn gen_call<'ctx, G: CodeGenerator>( is_extern = instance_to_stmt.is_empty(); let old_key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), fun.0, None); let mut keys = fun.0.args.clone(); - let mut mapping = HashMap::new(); + let mut mapping = HashMap::<_, Vec>::new(); + for (key, value) in params { - mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value); + // Find the matching argument + let matching_param = fun + .0 + .args + .iter() + .find_or_last(|p| key.is_some_and(|k| k == p.name)) + .unwrap(); + if matching_param.is_vararg { + if key.is_none() && !keys.is_empty() { + keys.remove(0); + } + + if let Some(param) = mapping.get_mut(&matching_param.name) { + param.push(value); + } else { + mapping.insert(key.unwrap_or(matching_param.name), vec![value]); + } + } else { + mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), vec![value]); + } } + // default value handling for k in keys { if mapping.contains_key(&k.name) { continue; } + mapping.insert( k.name, - ctx.gen_symbol_val(generator, &k.default_value.unwrap(), k.ty).into(), + if k.is_vararg { + Vec::default() + } else { + vec![ctx + .gen_symbol_val(generator, &k.default_value.unwrap(), k.ty) + .into()] + }, ); } // reorder the parameters @@ -804,13 +835,15 @@ pub fn gen_call<'ctx, G: CodeGenerator>( .map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty)) .collect_vec(); if let Some(obj) = &obj { - real_params.insert(0, (obj.1.clone(), obj.0)); + real_params.insert(0, (vec![obj.1.clone()], obj.0)); } let static_params = real_params .iter() .enumerate() .filter_map(|(i, (v, _))| { - if let ValueEnum::Static(s) = v { + if v.len() != 1 { + None + } else if let ValueEnum::Static(s) = &v[0] { Some((i, s.clone())) } else { None @@ -840,8 +873,13 @@ pub fn gen_call<'ctx, G: CodeGenerator>( }; param_vals = real_params .into_iter() - .map(|(p, t)| p.to_basic_value_enum(ctx, generator, t)) - .collect::, String>>()?; + .map(|(ps, t)| { + ps.into_iter().map(|p| p.to_basic_value_enum(ctx, generator, t)).collect() + }) + .collect::>, _>>()? + .into_iter() + .flatten() + .collect::>(); instance_to_symbol.get(&key).cloned().ok_or_else(String::new) } TopLevelDef::Class { .. } => {