use std::collections::HashSet;
use crate::{
expression::Expression, function::Function, module::Module, prune::module_graph::ModuleGraph,
statement::Statement, structure::Struct,
};
pub fn find_struct<'a>(module: &'a Module, name: &str) -> Option<&'a Struct> {
module
.body
.statements
.iter()
.chain(module.symbols.iter().map(|symbol| &symbol.statement))
.find_map(|statement| match statement {
Statement::StructDecl(struct_decl) if struct_decl.name == name => Some(struct_decl),
_ => None,
})
}
pub fn struct_exists(module: &Module, name: &str) -> bool {
find_struct(module, name).is_some()
}
pub fn find_struct_method<'a>(
module: &'a Module,
struct_name: &str,
method_name: &str,
) -> Option<&'a Function> {
find_struct(module, struct_name).and_then(|struct_decl| {
struct_decl
.methods
.iter()
.find(|method| method.name == method_name)
})
}
pub fn find_struct_constant<'a>(
module: &'a Module,
struct_name: &str,
constant_name: &str,
) -> Option<&'a Expression> {
find_struct(module, struct_name).and_then(|struct_decl| {
struct_decl
.constants
.iter()
.find_map(|(name, value)| (name == constant_name).then_some(value))
})
}
pub fn struct_has_constant(module: &Module, struct_name: &str, constant_name: &str) -> bool {
find_struct_constant(module, struct_name, constant_name).is_some()
}
pub fn struct_has_method(module: &Module, struct_name: &str, method_name: &str) -> bool {
find_struct_method(module, struct_name, method_name).is_some()
}
pub fn struct_owner_module(graph: &ModuleGraph<'_>, module: &Module, struct_name: &str) -> String {
if struct_exists(module, struct_name) {
return module.name.clone();
}
for import in &module.imports {
for item in &import.items {
if item.name == struct_name || item.local == struct_name {
return import.module.clone();
}
}
if module_defines_struct(graph, &import.module, struct_name) {
return import.module.clone();
}
}
module.name.clone()
}
pub fn module_defines_struct(
graph: &ModuleGraph<'_>,
module_name: &str,
struct_name: &str,
) -> bool {
let mut stack = vec![module_name.to_string()];
let mut seen = HashSet::new();
while let Some(current) = stack.pop() {
if !seen.insert(current.clone()) {
continue;
}
if let Some(module) = graph.get(¤t)
&& struct_exists(module, struct_name)
{
return true;
}
if let Some(module) = graph.get(¤t) {
for child in graph.child_modules(&module.name) {
stack.push((*child).to_string());
}
}
}
false
}
pub fn find_struct_method_in_module_tree<'a>(
graph: &ModuleGraph<'a>,
module_name: &str,
struct_name: &str,
method_name: &str,
) -> Option<(String, &'a Function)> {
let mut stack = vec![module_name.to_string()];
let mut seen = HashSet::new();
while let Some(current) = stack.pop() {
if !seen.insert(current.clone()) {
continue;
}
let Some(module) = graph.get(¤t) else {
continue;
};
if let Some(method) = find_struct_method(module, struct_name, method_name) {
return Some((current, method));
}
for child in graph.child_modules(¤t) {
stack.push((*child).to_string());
}
}
None
}
pub fn find_struct_constant_in_module_tree<'a>(
graph: &ModuleGraph<'a>,
module_name: &str,
struct_name: &str,
constant_name: &str,
) -> Option<(String, &'a Expression)> {
let mut stack = vec![module_name.to_string()];
let mut seen = HashSet::new();
while let Some(current) = stack.pop() {
if !seen.insert(current.clone()) {
continue;
}
let Some(module) = graph.get(¤t) else {
continue;
};
if let Some(value) = find_struct_constant(module, struct_name, constant_name) {
return Some((current, value));
}
for child in graph.child_modules(¤t) {
stack.push((*child).to_string());
}
}
None
}