qanglang_core/frontend/
analyzer.rs1use crate::{
2 AstNodeArena, ErrorReporter, QangPipelineError,
3 frontend::{
4 module_map::ModuleMap, semantic_validator::SemanticValidator,
5 symbol_resolver::SymbolResolver,
6 },
7 memory::StringInterner,
8};
9
10#[derive(Debug, Clone, Copy)]
11pub struct AnalysisPipelineConfig {
12 pub strict_mode: bool,
13}
14
15impl Default for AnalysisPipelineConfig {
16 fn default() -> Self {
17 Self { strict_mode: true }
18 }
19}
20
21pub struct AnalysisPipeline<'a> {
22 strings: &'a mut StringInterner,
23 config: AnalysisPipelineConfig,
24}
25
26impl<'a> AnalysisPipeline<'a> {
27 pub fn new(strings: &'a mut StringInterner) -> Self {
28 Self {
29 strings,
30 config: AnalysisPipelineConfig::default(),
31 }
32 }
33
34 pub fn with_config(mut self, config: AnalysisPipelineConfig) -> Self {
35 self.config = config;
36 self
37 }
38
39 pub fn analyze(
40 self,
41 modules: &mut ModuleMap,
42 nodes: &mut AstNodeArena,
43 errors: &mut ErrorReporter,
44 ) -> Result<(), QangPipelineError> {
45 let mut symbol_tables = Vec::new();
46 for (path, module) in modules.iter() {
47 let module_node = nodes.get_program_node(module.node);
48 let resolver = SymbolResolver::new(nodes, self.strings);
49 let symbol_table = resolver.resolve_module(module_node);
50 symbol_tables.push((path.to_path_buf(), symbol_table));
51 }
52
53 for (path, symbol_table) in symbol_tables {
54 if let Some(module) = modules.get(&path) {
55 let node = module.node;
56 let source_map = module.source_map.clone();
57 modules.insert_with_symbols(&path, node, source_map, symbol_table);
58 }
59 }
60
61 for (_, module) in modules.iter() {
62 SemanticValidator::new(self.strings, module.source_map.clone()).analyze(
63 module.node,
64 nodes,
65 errors,
66 );
67 }
68
69 if self.config.strict_mode && errors.has_errors() {
70 let errors = errors.take_errors();
71
72 return Err(QangPipelineError::new(errors));
73 }
74
75 Ok(())
76 }
77}