use source_map_cache::SourceMap;
use swamp_analyzer::prelude::Program;
use swamp_analyzer::{Analyzer, AnalyzerOptions};
use swamp_dep_loader::{DependencyParser, ParsedAstModule, parse_local_modules_and_get_order};
use swamp_modules::prelude::*;
use swamp_modules::symtbl::SymbolTableRef;
use swamp_semantic::prelude::Error;
use swamp_semantic::{InternalMainExpression, ProgramState, SemanticError};
use time_dilation::ScopedTimer;
use tracing::debug;
#[derive(Debug)]
pub enum LoaderErr {
CouldNotLoad,
SemanticError(SemanticError),
AnalyzerError(Error),
}
impl From<Error> for LoaderErr {
fn from(value: Error) -> Self {
Self::AnalyzerError(value)
}
}
pub fn analyze_module(
state: &mut ProgramState,
default_lookup_symbol_table: &DefinitionTable,
modules: &mut Modules,
core_symbol_table: &SymbolTableRef,
source_map: &SourceMap,
module_path: &[String],
ast_module: &ParsedAstModule,
options: AnalyzerOptions,
) -> Result<(DefinitionTable, Vec<Error>, Option<InternalMainExpression>), LoaderErr> {
let debug_string = format!("analyze module {module_path:?}");
let _analyze_timer = ScopedTimer::new(&debug_string);
let mut analyzer = Analyzer::new(
state,
modules,
core_symbol_table.clone(),
source_map,
module_path,
ast_module.file_id,
options,
);
analyzer.shared.lookup_table = default_lookup_symbol_table.clone();
let statements = {
for ast_def in ast_module.ast_module.definitions() {
analyzer.analyze_definition(ast_def);
}
if let Some(expr) = ast_module.ast_module.expression() {
let internal_main = analyzer.analyze_main_expression(expr);
Some(internal_main)
} else {
None
}
};
Ok((
analyzer.shared.definition_table,
analyzer.shared.state.errors().clone(),
statements,
))
}
pub fn analyze_modules_in_order(
state: &mut ProgramState,
default_lookup_symbol_table: &DefinitionTable,
modules: &mut Modules,
core_symbol_table: &SymbolTableRef,
source_map: &SourceMap,
module_paths_in_order: &[Vec<String>],
parsed_modules: &DependencyParser,
options: AnalyzerOptions,
) -> Result<(), LoaderErr> {
debug!(?module_paths_in_order, "analyzing modules in order");
for module_path in module_paths_in_order {
if *module_path == ["core"] || *module_path == ["std"] {
continue;
}
if let Some(parse_module) = parsed_modules.get_parsed_module(module_path) {
let (analyzed_symbol_table, errors, maybe_expression) = analyze_module(
state,
default_lookup_symbol_table,
modules,
core_symbol_table,
source_map,
module_path,
parse_module,
options,
)?;
let analyzed_module = Module::new(
analyzed_symbol_table,
errors,
maybe_expression,
parse_module.file_id,
);
modules.add(analyzed_module.into());
} else {
panic!("could not load")
}
}
Ok(())
}
pub fn compile_and_analyze_all_modules(
module_path: &[String],
resolved_program: &mut Program,
source_map: &mut SourceMap,
core_symbol_table: &SymbolTableRef,
options: AnalyzerOptions,
) -> Result<(), LoaderErr> {
let mut dependency_parser = DependencyParser::new();
let module_paths_in_order =
parse_local_modules_and_get_order(module_path, &mut dependency_parser, source_map).unwrap();
analyze_modules_in_order(
&mut resolved_program.state,
&resolved_program.default_symbol_table,
&mut resolved_program.modules,
core_symbol_table,
source_map,
&module_paths_in_order,
&dependency_parser,
options,
)?;
Ok(())
}