use prometeu_compiler::frontends::pbs::*; use prometeu_compiler::common::files::FileManager; use prometeu_compiler::common::spans::Span; use std::path::PathBuf; fn setup_test(source: &str) -> (ast::FileNode, usize) { let mut fm = FileManager::new(); let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string()); let mut parser = parser::Parser::new(source, file_id); (parser.parse_file().expect("Parsing failed"), file_id) } #[test] fn test_duplicate_symbols() { let source = " declare struct Foo {} declare struct Foo {} "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let result = collector.collect(&ast); assert!(result.is_err()); let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()))); } #[test] fn test_namespace_collision() { let source = " declare struct Foo {} fn Foo() {} "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let result = collector.collect(&ast); assert!(result.is_err()); let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_NAMESPACE_COLLISION".to_string()))); } #[test] fn test_undefined_identifier() { let source = " fn main() { let x = y; } "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; struct EmptyProvider; impl ModuleProvider for EmptyProvider { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } let mut resolver = Resolver::new(&ms, &EmptyProvider); let result = resolver.resolve(&ast); assert!(result.is_err()); let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_UNDEFINED".to_string()))); } #[test] fn test_local_variable_resolution() { let source = " fn main() { let x = 10; let y = x; } "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; struct EmptyProvider; impl ModuleProvider for EmptyProvider { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } let mut resolver = Resolver::new(&ms, &EmptyProvider); let result = resolver.resolve(&ast); assert!(result.is_ok()); } #[test] fn test_visibility_error() { let source = " import PrivateType from \"./other.pbs\" fn main() {} "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; struct MockProvider { other: ModuleSymbols, } impl ModuleProvider for MockProvider { fn get_module_symbols(&self, path: &str) -> Option<&ModuleSymbols> { if path == "./other.pbs" { Some(&self.other) } else { None } } } let mut other_ts = SymbolTable::new(); other_ts.insert(Symbol { name: "PrivateType".to_string(), kind: SymbolKind::Struct, namespace: Namespace::Type, visibility: Visibility::FilePrivate, ty: None, is_host: false, span: Span::new(1, 0, 0), }).unwrap(); let mock_provider = MockProvider { other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() }, }; let mut resolver = Resolver::new(&ms, &mock_provider); let result = resolver.resolve(&ast); assert!(result.is_err()); let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_VISIBILITY".to_string()))); } #[test] fn test_import_resolution() { let source = " import PubType from \"./other.pbs\" fn main() { let x: PubType = 10; } "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; struct MockProvider { other: ModuleSymbols, } impl ModuleProvider for MockProvider { fn get_module_symbols(&self, path: &str) -> Option<&ModuleSymbols> { if path == "./other.pbs" { Some(&self.other) } else { None } } } let mut other_ts = SymbolTable::new(); other_ts.insert(Symbol { name: "PubType".to_string(), kind: SymbolKind::Struct, namespace: Namespace::Type, visibility: Visibility::Pub, ty: None, is_host: false, span: Span::new(1, 0, 0), }).unwrap(); let mock_provider = MockProvider { other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() }, }; let mut resolver = Resolver::new(&ms, &mock_provider); let result = resolver.resolve(&ast); assert!(result.is_ok()); } #[test] fn test_invalid_import_module_not_found() { let source = " import NonExistent from \"./missing.pbs\" fn main() {} "; let (ast, _) = setup_test(source); let mut collector = SymbolCollector::new(); let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; struct EmptyProvider; impl ModuleProvider for EmptyProvider { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } let mut resolver = Resolver::new(&ms, &EmptyProvider); let result = resolver.resolve(&ast); assert!(result.is_err()); let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_INVALID_IMPORT".to_string()))); }