pub(crate) mod import_graph;
pub mod module_resolver;
pub mod node_finder;
pub mod position;
pub mod queries;
pub mod symbol_table;
pub(crate) mod type_graph;
mod circular;
mod helpers;
mod imports;
mod inference;
mod module_collect;
mod pass1_symbols;
mod pattern_types;
pub mod sem_type;
mod trait_check;
mod type_resolution;
mod validation;
#[cfg(test)]
mod tests;
pub use symbol_table::{
EnumInfo, LetInfo, ModuleInfo, StructInfo, SymbolKind, SymbolTable, TraitInfo,
};
pub(crate) use helpers::is_primitive_name;
pub(super) use helpers::{collect_bindings_from_pattern, strip_array_type};
use module_resolver::ModuleResolver;
use pattern_types::GenericScope;
use sem_type::SemType;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use crate::ast::{File, ParamConvention};
use crate::error::CompilerError;
use import_graph::ImportGraph;
pub struct SemanticAnalyzer<R: ModuleResolver> {
symbols: SymbolTable,
errors: Vec<CompilerError>,
resolver: R,
import_graph: ImportGraph,
module_cache: HashMap<PathBuf, (File, SymbolTable)>,
module_ir_cache: HashMap<PathBuf, crate::ir::IrModule>,
current_file: Option<PathBuf>,
generic_scopes: Vec<GenericScope>,
current_impl_struct: Option<String>,
loop_var_scopes: Vec<HashSet<String>>,
closure_param_scopes: Vec<HashSet<String>>,
local_let_bindings: HashMap<String, (SemType, bool)>,
consumed_bindings: HashSet<String>,
pub(super) inference_scope_stack: std::cell::RefCell<Vec<HashMap<String, SemType>>>,
closure_binding_conventions: HashMap<String, Vec<ParamConvention>>,
pub(super) closure_binding_captures: HashMap<String, Vec<String>>,
pub(super) fn_scope_closure_captures: HashMap<String, Vec<String>>,
pub(super) current_fn_param_conventions: HashMap<String, ParamConvention>,
validate_expr_depth: usize,
}
impl<R: ModuleResolver> std::fmt::Debug for SemanticAnalyzer<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SemanticAnalyzer")
.field("symbols", &self.symbols)
.field("errors", &self.errors)
.finish_non_exhaustive()
}
}
impl<R: ModuleResolver> SemanticAnalyzer<R> {
pub fn new(resolver: R) -> Self {
Self {
symbols: SymbolTable::new(),
errors: Vec::new(),
resolver,
import_graph: ImportGraph::new(),
module_cache: HashMap::new(),
module_ir_cache: HashMap::new(),
current_file: None,
generic_scopes: Vec::new(),
current_impl_struct: None,
loop_var_scopes: Vec::new(),
closure_param_scopes: Vec::new(),
local_let_bindings: HashMap::new(),
consumed_bindings: HashSet::new(),
inference_scope_stack: std::cell::RefCell::new(Vec::new()),
closure_binding_conventions: HashMap::new(),
closure_binding_captures: HashMap::new(),
fn_scope_closure_captures: HashMap::new(),
current_fn_param_conventions: HashMap::new(),
validate_expr_depth: 0,
}
}
pub fn new_with_file(resolver: R, file_path: PathBuf) -> Self {
Self {
symbols: SymbolTable::new(),
errors: Vec::new(),
resolver,
import_graph: ImportGraph::new(),
module_cache: HashMap::new(),
module_ir_cache: HashMap::new(),
current_file: Some(file_path),
generic_scopes: Vec::new(),
current_impl_struct: None,
loop_var_scopes: Vec::new(),
closure_param_scopes: Vec::new(),
local_let_bindings: HashMap::new(),
consumed_bindings: HashSet::new(),
inference_scope_stack: std::cell::RefCell::new(Vec::new()),
closure_binding_conventions: HashMap::new(),
closure_binding_captures: HashMap::new(),
fn_scope_closure_captures: HashMap::new(),
current_fn_param_conventions: HashMap::new(),
validate_expr_depth: 0,
}
}
pub fn analyze(&mut self, file: &File) -> Result<(), Vec<CompilerError>> {
self.run_passes(file);
if self.errors.is_empty() {
Ok(())
} else {
Err(self.errors.clone())
}
}
pub fn analyze_and_classify(&mut self, file: &mut File) -> Result<(), Vec<CompilerError>> {
self.run_passes(file);
if self.errors.is_empty() {
Ok(())
} else {
Err(self.errors.clone())
}
}
fn run_passes(&mut self, file: &File) {
self.resolve_modules(file);
self.build_symbol_table(file);
self.validate_generic_parameters(file);
self.infer_let_types(file);
self.resolve_types(file);
self.validate_expressions(file);
self.validate_trait_implementations(file);
self.detect_circular_dependencies(file);
}
pub const fn symbols(&self) -> &SymbolTable {
&self.symbols
}
pub const fn module_cache(&self) -> &HashMap<PathBuf, (File, SymbolTable)> {
&self.module_cache
}
pub const fn imported_ir_modules(&self) -> &HashMap<PathBuf, crate::ir::IrModule> {
&self.module_ir_cache
}
}