Skip to main content

qanglang_core/frontend/
analyzer.rs

1use 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}