use crate::display::{DisplayFuncType, DisplayValueType};
use anyhow::{Error, bail};
use wasmi::{FuncType, Val, ValType};
pub fn prepare_func_results(ty: &FuncType) -> Box<[Val]> {
ty.results()
.iter()
.copied()
.map(Val::default_for_ty)
.collect()
}
pub fn decode_func_args(ty: &FuncType, args: &[String]) -> Result<Box<[Val]>, Error> {
ty.params()
.iter()
.zip(args)
.enumerate()
.map(|(n, (param_type, arg))| {
decode_func_arg(param_type, arg)
.map_err(|err| err.context(format!("parsing function argument at index {n}")))
})
.collect::<Result<Box<[_]>, _>>()
}
fn decode_func_arg(ty: &ValType, arg: &str) -> Result<Val, Error> {
let val = match ty {
ValType::I32 => {
let val = if arg.starts_with("0x") || arg.starts_with("0X") {
i32::from_str_radix(&arg[2..], 16)
} else {
arg.parse::<i32>()
};
val.map(Val::from).ok()
}
ValType::I64 => {
let val = if arg.starts_with("0x") || arg.starts_with("0X") {
i64::from_str_radix(&arg[2..], 16)
} else {
arg.parse::<i64>()
};
val.map(Val::from).ok()
}
ValType::F32 => arg.parse::<f32>().map(Val::from).ok(),
ValType::F64 => arg.parse::<f64>().map(Val::from).ok(),
ValType::V128 | ValType::FuncRef | ValType::ExternRef => {
let ty = DisplayValueType::from(ty);
bail!("unsupported function argument type: {ty}")
}
};
let Some(val) = val else {
let ty = DisplayValueType::from(ty);
bail!("failed to parse function argument {arg} as type {ty}")
};
Ok(val)
}
pub fn typecheck_args(func_name: &str, func_ty: &FuncType, args: &[Val]) -> Result<(), Error> {
if func_ty.params().len() != args.len() {
bail!(
"invalid amount of arguments given to function {}. expected {} but received {}",
DisplayFuncType::new(func_name, func_ty),
func_ty.params().len(),
args.len()
)
}
Ok(())
}