forked from M-Labs/nac3
1
0
Fork 0

core/codegen/expr: Implement vararg handling in gen_call

This commit is contained in:
David Mak 2024-07-11 18:01:48 +08:00
parent 72295ccaa5
commit f270019c24
1 changed files with 45 additions and 7 deletions

View File

@ -766,6 +766,9 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
let param_vals; let param_vals;
let is_extern; 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 = { let symbol = {
// make sure this lock guard is dropped at the end of this scope... // make sure this lock guard is dropped at the end of this scope...
let def = definition.read(); let def = definition.read();
@ -782,18 +785,46 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
is_extern = instance_to_stmt.is_empty(); 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 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 keys = fun.0.args.clone();
let mut mapping = HashMap::new(); let mut mapping = HashMap::<_, Vec<ValueEnum>>::new();
for (key, value) in params { 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 // default value handling
for k in keys { for k in keys {
if mapping.contains_key(&k.name) { if mapping.contains_key(&k.name) {
continue; continue;
} }
mapping.insert( mapping.insert(
k.name, 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 // reorder the parameters
@ -804,13 +835,15 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
.map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty)) .map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty))
.collect_vec(); .collect_vec();
if let Some(obj) = &obj { 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 let static_params = real_params
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, (v, _))| { .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())) Some((i, s.clone()))
} else { } else {
None None
@ -840,8 +873,13 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
}; };
param_vals = real_params param_vals = real_params
.into_iter() .into_iter()
.map(|(p, t)| p.to_basic_value_enum(ctx, generator, t)) .map(|(ps, t)| {
.collect::<Result<Vec<_>, String>>()?; ps.into_iter().map(|p| p.to_basic_value_enum(ctx, generator, t)).collect()
})
.collect::<Result<Vec<Vec<_>>, _>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>();
instance_to_symbol.get(&key).cloned().ok_or_else(String::new) instance_to_symbol.get(&key).cloned().ok_or_else(String::new)
} }
TopLevelDef::Class { .. } => { TopLevelDef::Class { .. } => {