use crate::{
util::{ UnwrapUnchecked, },
session::{ SESSION, MessageKind, },
source::{ SourceRegion, },
common::{ Identifier, },
ast::{ Item, },
ctx::{ Context, Module, GlobalItem, GlobalKey, LocalContext, },
};
pub mod passes;
pub struct Analyzer {
pub context: Context,
pub active_modules: Vec<GlobalKey>,
pub local_context: Option<LocalContext>,
}
impl Default for Analyzer {
#[inline] fn default () -> Self { Self::new() }
}
impl Analyzer {
pub fn new () -> Self {
let context = Context::default();
let active_modules = vec![ context.lib_mod ];
Self {
context,
active_modules,
local_context: None,
}
}
pub fn analyze (mut self, mut ast: Vec<Item>) -> (Context, Vec<Item>) {
self.run_passes(&mut ast);
(self.context, ast)
}
pub fn push_active_module (&mut self, key: GlobalKey) {
self.active_modules.push(key);
}
pub fn pop_active_module (&mut self) -> GlobalKey {
assert!(
self.active_modules.len() > 1,
"Internal error, cannot pop lib module"
);
unsafe { self.active_modules.pop().unwrap_unchecked() }
}
pub fn get_active_module_key (&self) -> GlobalKey {
unsafe { *self.active_modules.last().unwrap_unchecked() }
}
pub fn get_active_module (&self) -> &Module {
unsafe { self.context.items.get_unchecked(self.get_active_module_key()).ref_module_unchecked() }
}
pub fn get_active_module_mut (&mut self) -> &mut Module {
unsafe { self.context.items.get_unchecked_mut(self.get_active_module_key()).mut_module_unchecked() }
}
#[track_caller]
pub fn create_local_context (&mut self) -> &mut LocalContext {
self.local_context.replace(LocalContext::default()).expect_none("Internal error, cannot create LocalContext, one already exists");
unsafe { self.local_context.as_mut().unwrap_unchecked() }
}
#[track_caller]
pub fn remove_local_context (&mut self) -> LocalContext {
self.local_context.take().expect("Internal error, cannot remove LocalContext, it does not exist")
}
#[track_caller]
pub fn get_local_context (&self) -> &LocalContext {
self.local_context.as_ref().expect("Internal error, cannot get LocalContext")
}
#[track_caller]
pub fn get_local_context_mut (&mut self) -> &mut LocalContext {
self.local_context.as_mut().expect("Internal error, cannot get LocalContext")
}
pub fn create_item<I: Into<GlobalItem>> (&mut self, identifier: Identifier, new_item: I, origin: SourceRegion) -> GlobalKey {
let new_item = new_item.into();
if let Some(shadowed_key) = self.get_active_module().local_bindings.get_entry(&identifier) {
let shadowed_kind = self.context.items.get(shadowed_key).expect("Internal error, shadowed item does not exist").kind();
let shadowed_location = self.get_active_module().local_bindings.get_bind_location(shadowed_key).expect("Internal error, shadowed item has no bind location");
self.error(origin, format!(
"{} `{}` shadows existing {} in `{}`, defined at [{}]",
new_item.kind(), identifier, shadowed_kind, self.get_active_module().canonical_name, shadowed_location
));
}
let key = (|| {
if let GlobalItem::Type(ty) = &new_item {
if let Some(td) = &ty.data {
if td.is_anon() {
return if let Some(existing_key) = self.context.anon_types.get(td) {
*existing_key
} else {
let td_for_lookup = td.clone();
let new_key = self.context.items.insert(new_item);
self.context.anon_types.insert(td_for_lookup, new_key);
new_key
}
}
}
}
self.context.items.insert(new_item)
})();
self.get_active_module_mut().local_bindings.set_entry_bound(identifier, key, origin);
key
}
pub fn message (&self, origin: SourceRegion, kind: MessageKind, message: String) {
SESSION.message(Some(origin), kind, message)
}
pub fn notice (&self, origin: SourceRegion, message: String) {
self.message(origin, MessageKind::Notice, message)
}
pub fn warning (&self, origin: SourceRegion, message: String) {
self.message(origin, MessageKind::Warning, message)
}
pub fn error (&self, origin: SourceRegion, message: String) {
self.message(origin, MessageKind::Error, message)
}
}