swamp_program_analyzer/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use source_map_cache::SourceMap;
6use swamp_analyzer::Analyzer;
7use swamp_analyzer::prelude::Program;
8use swamp_dep_loader::{DependencyParser, ParsedAstModule, parse_local_modules_and_get_order};
9use swamp_modules::prelude::*;
10use swamp_modules::symtbl::SymbolTableRef;
11use swamp_semantic::prelude::Error;
12use swamp_semantic::{InternalMainExpression, ProgramState, SemanticError};
13use time_dilation::ScopedTimer;
14use tracing::debug;
15
16#[derive(Debug)]
17pub enum LoaderErr {
18    CouldNotLoad,
19    SemanticError(SemanticError),
20    AnalyzerError(Error),
21}
22
23impl From<Error> for LoaderErr {
24    fn from(value: Error) -> Self {
25        Self::AnalyzerError(value)
26    }
27}
28
29/// # Errors
30///
31pub fn analyze_module(
32    state: &mut ProgramState,
33    default_lookup_symbol_table: &SymbolTable,
34    modules: &mut Modules,
35    core_symbol_table: &SymbolTableRef,
36    source_map: &SourceMap,
37    module_path: &[String],
38    ast_module: &ParsedAstModule,
39) -> Result<(SymbolTable, Vec<Error>, Option<InternalMainExpression>), LoaderErr> {
40    //debug!(?module_path, "analyze module");
41    let debug_string = format!("analyze module {module_path:?}");
42    let _analyze_timer = ScopedTimer::new(&debug_string);
43
44    let mut analyzer = Analyzer::new(
45        state,
46        modules,
47        core_symbol_table.clone(),
48        source_map,
49        module_path,
50        ast_module.file_id,
51    );
52
53    analyzer.shared.lookup_table = default_lookup_symbol_table.clone();
54
55    let statements = {
56        for ast_def in ast_module.ast_module.definitions() {
57            //debug!(?ast_def, "analyze definition");
58            analyzer.analyze_definition(ast_def);
59        }
60
61        if let Some(expr) = ast_module.ast_module.expression() {
62            let internal_main = analyzer.analyze_main_expression(expr);
63            Some(internal_main)
64        } else {
65            None
66        }
67    };
68
69    Ok((
70        analyzer.shared.definition_table,
71        analyzer.shared.state.errors().clone(),
72        statements,
73    ))
74}
75
76/// # Errors
77///
78/// # Panics
79///
80pub fn analyze_modules_in_order(
81    state: &mut ProgramState,
82    default_lookup_symbol_table: &SymbolTable,
83    modules: &mut Modules,
84    core_symbol_table: &SymbolTableRef,
85    source_map: &SourceMap,
86    module_paths_in_order: &[Vec<String>],
87    parsed_modules: &DependencyParser,
88) -> Result<(), LoaderErr> {
89    debug!(?module_paths_in_order, "analyzing modules in order");
90    for module_path in module_paths_in_order {
91        if *module_path == ["core"] || *module_path == ["std"] {
92            continue;
93        }
94        if let Some(parse_module) = parsed_modules.get_parsed_module(module_path) {
95            //let process_span = span!(Level::TRACE, "analyze mod", path = ?module_path);
96            //let _enter = process_span.enter();
97
98            let (analyzed_symbol_table, errors, maybe_expression) = analyze_module(
99                state,
100                default_lookup_symbol_table,
101                modules,
102                core_symbol_table,
103                source_map,
104                module_path,
105                parse_module,
106            )?;
107            let analyzed_module = Module::new(analyzed_symbol_table, errors, maybe_expression);
108            modules.add(analyzed_module.into());
109        } else {
110            panic!("could not load")
111        }
112    }
113    Ok(())
114}
115
116/// # Errors
117///
118/// # Panics
119///
120pub fn compile_and_analyze_all_modules(
121    module_path: &[String],
122    resolved_program: &mut Program,
123    source_map: &mut SourceMap,
124    core_symbol_table: &SymbolTableRef,
125) -> Result<(), LoaderErr> {
126    let mut dependency_parser = DependencyParser::new();
127
128    let module_paths_in_order =
129        parse_local_modules_and_get_order(module_path, &mut dependency_parser, source_map).unwrap(); // TODO: FIX THIS
130
131    analyze_modules_in_order(
132        &mut resolved_program.state,
133        &resolved_program.default_symbol_table,
134        &mut resolved_program.modules,
135        core_symbol_table,
136        source_map,
137        &module_paths_in_order,
138        &dependency_parser,
139    )?;
140
141    Ok(())
142}