use crate::analyzer::{FunctionSignature, OwnershipMode, SignatureRegistry};
use std::fs;
use std::path::Path;
pub fn populate_runtime_signatures(registry: &mut SignatureRegistry) -> Result<(), String> {
let runtime_path = Path::new("crates/windjammer-runtime/src");
if !runtime_path.exists() {
return populate_fallback_signatures(registry);
}
scan_directory(runtime_path, registry)?;
Ok(())
}
fn scan_directory(path: &Path, registry: &mut SignatureRegistry) -> Result<(), String> {
if !path.is_dir() {
return Ok(());
}
for entry in fs::read_dir(path).map_err(|e| format!("Failed to read directory: {}", e))? {
let entry = entry.map_err(|e| format!("Failed to read entry: {}", e))?;
let path = entry.path();
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("rs") {
scan_rust_file(&path, registry)?;
}
}
Ok(())
}
fn scan_rust_file(path: &Path, registry: &mut SignatureRegistry) -> Result<(), String> {
let content = fs::read_to_string(path)
.map_err(|e| format!("Failed to read {}: {}", path.display(), e))?;
let module_name = path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("unknown");
if module_name == "lib" {
return Ok(());
}
for line in content.lines() {
if let Some(sig) = parse_function_signature(line, module_name) {
registry.add_function(sig.name.clone(), sig);
}
}
Ok(())
}
fn parse_function_signature(line: &str, module: &str) -> Option<FunctionSignature> {
let line = line.trim();
if !line.starts_with("pub fn ") {
return None;
}
let after_fn = line.strip_prefix("pub fn ")?;
let name_end = after_fn.find('(')?;
let func_name = &after_fn[..name_end];
let params_start = after_fn.find('(')?;
let params_end = after_fn.find(')')?;
let params_str = &after_fn[params_start + 1..params_end];
let param_ownership = parse_parameters(params_str);
let full_name = format!("{}::{}", module, func_name);
Some(FunctionSignature {
name: full_name,
param_types: vec![], param_ownership,
return_type: None, return_ownership: OwnershipMode::Owned, has_self_receiver: false, is_extern: false, })
}
fn parse_parameters(params_str: &str) -> Vec<OwnershipMode> {
if params_str.trim().is_empty() {
return Vec::new();
}
params_str
.split(',')
.map(|param| {
let param = param.trim();
if param.contains("&mut ") {
OwnershipMode::MutBorrowed
}
else if param.contains('&') && !param.contains("&mut") {
OwnershipMode::Borrowed
}
else {
OwnershipMode::Owned
}
})
.collect()
}
fn populate_fallback_signatures(registry: &mut SignatureRegistry) -> Result<(), String> {
use crate::parser::Type;
use OwnershipMode::*;
registry.add_function(
"println".to_string(),
FunctionSignature {
name: "println".to_string(),
param_types: vec![Type::Reference(Box::new(Type::String))], param_ownership: vec![Borrowed],
return_type: None,
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"game::create_entity".to_string(),
FunctionSignature {
name: "game::create_entity".to_string(),
param_types: vec![],
param_ownership: vec![MutBorrowed],
return_type: None,
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"game::add_transform".to_string(),
FunctionSignature {
name: "game::add_transform".to_string(),
param_types: vec![],
param_ownership: vec![MutBorrowed, Owned, Owned],
return_type: None,
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"game::add_velocity".to_string(),
FunctionSignature {
name: "game::add_velocity".to_string(),
param_types: vec![],
param_ownership: vec![MutBorrowed, Owned, Owned],
return_type: None,
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"game::add_mesh".to_string(),
FunctionSignature {
name: "game::add_mesh".to_string(),
param_types: vec![],
param_ownership: vec![MutBorrowed, Owned, Owned],
return_type: None,
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"split".to_string(),
FunctionSignature {
name: "split".to_string(),
param_types: vec![],
param_ownership: vec![Borrowed, Borrowed],
return_type: Some(Type::Vec(Box::new(Type::String))),
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
registry.add_function(
"strings::split".to_string(),
FunctionSignature {
name: "strings::split".to_string(),
param_types: vec![],
param_ownership: vec![Borrowed, Borrowed],
return_type: Some(Type::Vec(Box::new(Type::String))),
return_ownership: Owned,
has_self_receiver: false,
is_extern: false,
},
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_function_signature() {
let line = "pub fn create_entity(world: &mut World) -> EntityId {";
let sig = parse_function_signature(line, "game").unwrap();
assert_eq!(sig.name, "game::create_entity");
assert_eq!(sig.param_ownership.len(), 1);
assert_eq!(sig.param_ownership[0], OwnershipMode::MutBorrowed);
}
#[test]
fn test_parse_multiple_params() {
let line =
"pub fn add_component(world: &mut World, entity: EntityId, component: Transform) {";
let sig = parse_function_signature(line, "game").unwrap();
assert_eq!(sig.param_ownership.len(), 3);
assert_eq!(sig.param_ownership[0], OwnershipMode::MutBorrowed);
assert_eq!(sig.param_ownership[1], OwnershipMode::Owned);
assert_eq!(sig.param_ownership[2], OwnershipMode::Owned);
}
#[test]
fn test_parse_borrowed_param() {
let line = "pub fn query(world: &World) -> Vec<EntityId> {";
let sig = parse_function_signature(line, "game").unwrap();
assert_eq!(sig.param_ownership.len(), 1);
assert_eq!(sig.param_ownership[0], OwnershipMode::Borrowed);
}
}