use golem_wasm_ast::analysis::{AnalysedExport, AnalysedFunction, AnalysedInstance};
use rib::{ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite};
fn instances(exports: &Vec<AnalysedExport>) -> Vec<AnalysedInstance> {
let mut instances = vec![];
for export in exports {
if let AnalysedExport::Instance(instance) = export {
instances.push(instance.clone())
}
}
instances
}
fn functions(exports: &Vec<AnalysedExport>) -> Vec<AnalysedFunction> {
let mut functions = vec![];
for export in exports {
if let AnalysedExport::Function(function) = export {
functions.push(function.clone())
}
}
functions
}
pub fn function_by_name(
exports: &Vec<AnalysedExport>,
name: &str,
) -> Result<Option<AnalysedFunction>, String> {
let parsed = ParsedFunctionName::parse(name)?;
match &parsed.site().interface_name() {
None => Ok(functions(exports).iter().find(|f| f.name == *name).cloned()),
Some(interface_name) => {
let exported_function = instances(exports)
.iter()
.find(|instance| instance.name == *interface_name)
.and_then(|instance| {
instance
.functions
.iter()
.find(|f| f.name == parsed.function().function_name())
.cloned()
});
if exported_function.is_none() {
match parsed.method_as_static() {
Some(parsed_static) => Ok(instances(exports)
.iter()
.find(|instance| instance.name == *interface_name)
.and_then(|instance| {
instance
.functions
.iter()
.find(|f| f.name == parsed_static.function().function_name())
.cloned()
})),
None => Ok(None),
}
} else {
Ok(exported_function)
}
}
}
}
pub fn find_resource_site(
exports: &[AnalysedExport],
resource_name: &str,
) -> Option<ParsedFunctionSite> {
fn find_resource_site_impl(
site: ParsedFunctionSite,
functions: &[AnalysedFunction],
resource_name: &str,
) -> Option<ParsedFunctionSite> {
let constructor = ParsedFunctionName::new(
site.clone(),
ParsedFunctionReference::RawResourceConstructor {
resource: resource_name.to_string(),
},
);
if functions
.iter()
.any(|f| f.name == constructor.function().function_name())
{
Some(site)
} else {
None
}
}
let global_functions = exports
.iter()
.filter_map(|export| {
if let AnalysedExport::Function(f) = export {
Some(f.clone())
} else {
None
}
})
.collect::<Vec<AnalysedFunction>>();
if let Some(result) =
find_resource_site_impl(ParsedFunctionSite::Global, &global_functions, resource_name)
{
Some(result)
} else {
for export in exports {
if let AnalysedExport::Instance(instance) = export {
if let Some(result) = find_resource_site_impl(
ParsedFunctionSite::Interface {
name: instance.name.clone(),
},
&instance.functions,
resource_name,
) {
return Some(result);
}
}
}
None
}
}