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::prelude::Program;
7use swamp_analyzer::{Analyzer, AnalyzerOptions};
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: &DefinitionTable,
34    modules: &mut Modules,
35    core_symbol_table: &SymbolTableRef,
36    source_map: &SourceMap,
37    module_path: &[String],
38    ast_module: &ParsedAstModule,
39    options: AnalyzerOptions,
40) -> Result<(DefinitionTable, Vec<Error>, Option<InternalMainExpression>), LoaderErr> {
41    //debug!(?module_path, "analyze module");
42    let debug_string = format!("analyze module {module_path:?}");
43    let _analyze_timer = ScopedTimer::new(&debug_string);
44
45    let mut analyzer = Analyzer::new(
46        state,
47        modules,
48        core_symbol_table.clone(),
49        source_map,
50        module_path,
51        ast_module.file_id,
52        options,
53    );
54
55    analyzer.shared.lookup_table = default_lookup_symbol_table.clone();
56
57    let statements = {
58        for ast_def in ast_module.ast_module.definitions() {
59            //debug!(?ast_def, "analyze definition");
60            analyzer.analyze_definition(ast_def);
61        }
62
63        if let Some(expr) = ast_module.ast_module.expression() {
64            let internal_main = analyzer.analyze_main_expression(expr);
65            Some(internal_main)
66        } else {
67            None
68        }
69    };
70
71    Ok((
72        analyzer.shared.definition_table,
73        analyzer.shared.state.errors().clone(),
74        statements,
75    ))
76}
77
78/// # Errors
79///
80/// # Panics
81///
82pub fn analyze_modules_in_order(
83    state: &mut ProgramState,
84    default_lookup_symbol_table: &DefinitionTable,
85    modules: &mut Modules,
86    core_symbol_table: &SymbolTableRef,
87    source_map: &SourceMap,
88    module_paths_in_order: &[Vec<String>],
89    parsed_modules: &DependencyParser,
90    options: AnalyzerOptions,
91) -> Result<(), LoaderErr> {
92    debug!(?module_paths_in_order, "analyzing modules in order");
93    for module_path in module_paths_in_order {
94        if *module_path == ["core"] || *module_path == ["std"] {
95            continue;
96        }
97        if let Some(parse_module) = parsed_modules.get_parsed_module(module_path) {
98            //let process_span = span!(Level::TRACE, "analyze mod", path = ?module_path);
99            //let _enter = process_span.enter();
100
101            let (analyzed_symbol_table, errors, maybe_expression) = analyze_module(
102                state,
103                default_lookup_symbol_table,
104                modules,
105                core_symbol_table,
106                source_map,
107                module_path,
108                parse_module,
109                options,
110            )?;
111
112            let analyzed_module = Module::new(
113                analyzed_symbol_table,
114                errors,
115                maybe_expression,
116                parse_module.file_id,
117            );
118            modules.add(analyzed_module.into());
119        } else {
120            panic!("could not load")
121        }
122    }
123    Ok(())
124}
125
126/// # Errors
127///
128/// # Panics
129///
130pub fn compile_and_analyze_all_modules(
131    module_path: &[String],
132    resolved_program: &mut Program,
133    source_map: &mut SourceMap,
134    core_symbol_table: &SymbolTableRef,
135    options: AnalyzerOptions,
136) -> Result<(), LoaderErr> {
137    let mut dependency_parser = DependencyParser::new();
138
139    let module_paths_in_order =
140        parse_local_modules_and_get_order(module_path, &mut dependency_parser, source_map).unwrap(); // TODO: FIX THIS
141
142    analyze_modules_in_order(
143        &mut resolved_program.state,
144        &resolved_program.default_symbol_table,
145        &mut resolved_program.modules,
146        core_symbol_table,
147        source_map,
148        &module_paths_in_order,
149        &dependency_parser,
150        options,
151    )?;
152
153    Ok(())
154}