201 lines
6.1 KiB
Rust
201 lines
6.1 KiB
Rust
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())));
|
|
}
|