mod insert;
mod kinds;
mod normalization;
pub use kinds::{
EnumInfo, FieldInfo, FunctionInfo, ImplInfo, ImportError, LetInfo, ModuleInfo, ParamInfo,
StructInfo, SymbolKind, TraitImplInfo, TraitInfo,
};
use crate::ast::{GenericParam, Type, Visibility};
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct SymbolTable {
pub traits: HashMap<String, TraitInfo>,
pub structs: HashMap<String, StructInfo>,
pub impls: HashMap<String, ImplInfo>,
pub trait_impls: HashMap<String, Vec<TraitImplInfo>>,
pub enums: HashMap<String, EnumInfo>,
pub lets: HashMap<String, LetInfo>,
pub functions: HashMap<String, Vec<FunctionInfo>>,
pub modules: HashMap<String, ModuleInfo>,
module_origins: HashMap<String, Option<PathBuf>>,
module_logical_paths: HashMap<String, Vec<String>>,
}
impl SymbolTable {
#[must_use]
pub fn new() -> Self {
Self {
traits: HashMap::new(),
structs: HashMap::new(),
impls: HashMap::new(),
trait_impls: HashMap::new(),
enums: HashMap::new(),
lets: HashMap::new(),
functions: HashMap::new(),
modules: HashMap::new(),
module_origins: HashMap::new(),
module_logical_paths: HashMap::new(),
}
}
#[must_use]
pub fn get_all_traits_for_struct(&self, struct_name: &str) -> Vec<String> {
let mut traits = Vec::new();
if let Some(impls) = self.trait_impls.get(struct_name) {
for impl_info in impls {
if !traits.contains(&impl_info.trait_name) {
traits.push(impl_info.trait_name.clone());
}
}
}
traits
}
#[must_use]
pub fn get_all_traits_for_enum(&self, enum_name: &str) -> Vec<String> {
let mut all_traits = Vec::new();
if let Some(enum_info) = self.enums.get(enum_name) {
all_traits.extend(enum_info.traits.clone());
}
if let Some(impls) = self.trait_impls.get(enum_name) {
for impl_info in impls {
if !all_traits.contains(&impl_info.trait_name) {
all_traits.push(impl_info.trait_name.clone());
}
}
}
all_traits
}
#[must_use]
pub fn get_enum_variants(
&self,
name: &str,
) -> Option<&HashMap<String, (usize, crate::location::Span)>> {
self.enums.get(name).map(|info| &info.variants)
}
#[must_use]
pub fn get_function(&self, name: &str) -> Option<&FunctionInfo> {
self.functions.get(name).and_then(|v| v.first())
}
#[must_use]
pub fn get_function_overloads(&self, name: &str) -> &[FunctionInfo] {
self.functions.get(name).map_or(&[], |v| v.as_slice())
}
#[must_use]
pub fn get_let_type(&self, name: &str) -> Option<&str> {
self.lets
.get(name)
.and_then(|info| info.inferred_type.as_deref())
}
pub(super) fn find_any(&self, name: &str) -> Option<(SymbolKind, crate::location::Span)> {
if let Some(info) = self.traits.get(name) {
return Some((SymbolKind::Trait, info.span));
}
if let Some(info) = self.structs.get(name) {
return Some((SymbolKind::Struct, info.span));
}
if let Some(info) = self.impls.get(name) {
return Some((SymbolKind::Impl, info.span));
}
if let Some(info) = self.enums.get(name) {
return Some((SymbolKind::Enum, info.span));
}
if let Some(info) = self.lets.get(name) {
return Some((SymbolKind::Let, info.span));
}
if let Some(info) = self.modules.get(name) {
return Some((SymbolKind::Module, info.span));
}
None
}
#[must_use]
pub fn get_trait(&self, name: &str) -> Option<&TraitInfo> {
self.traits.get(name)
}
#[must_use]
pub fn get_struct(&self, name: &str) -> Option<&StructInfo> {
self.structs.get(name)
}
#[must_use]
pub fn get_struct_qualified(&self, name: &str) -> Option<&StructInfo> {
if let Some(info) = self.structs.get(name) {
return Some(info);
}
if let Some((module_name, struct_name)) = name.split_once("::") {
if let Some(module_info) = self.modules.get(module_name) {
return module_info.symbols.get_struct_qualified(struct_name);
}
}
None
}
#[must_use]
pub fn get_enum_qualified(&self, name: &str) -> Option<&EnumInfo> {
if let Some(info) = self.enums.get(name) {
return Some(info);
}
if let Some((module_name, enum_name)) = name.split_once("::") {
if let Some(module_info) = self.modules.get(module_name) {
return module_info.symbols.get_enum_qualified(enum_name);
}
}
None
}
#[must_use]
pub fn is_struct(&self, name: &str) -> bool {
self.structs.contains_key(name)
}
#[must_use]
pub fn is_enum(&self, name: &str) -> bool {
self.enums.contains_key(name)
}
#[must_use]
pub fn is_let(&self, name: &str) -> bool {
self.lets.contains_key(name)
}
#[must_use]
pub fn is_type(&self, name: &str) -> bool {
self.structs.contains_key(name) || self.enums.contains_key(name)
}
#[must_use]
pub fn get_all_trait_fields(&self, name: &str) -> HashMap<String, Type> {
let mut all_fields = HashMap::new();
if let Some(trait_info) = self.get_trait(name) {
for composed_trait in &trait_info.composed_traits {
let composed_fields = self.get_all_trait_fields(composed_trait);
all_fields.extend(composed_fields);
}
for f in &trait_info.fields {
all_fields.insert(f.name.clone(), f.ty.clone());
}
}
all_fields
}
#[must_use]
pub fn get_generics(&self, type_name: &str) -> Option<Vec<GenericParam>> {
if let Some(info) = self.traits.get(type_name) {
return Some(info.generics.clone());
}
if let Some(info) = self.structs.get(type_name) {
return Some(info.generics.clone());
}
if let Some(info) = self.enums.get(type_name) {
return Some(info.generics.clone());
}
None
}
#[must_use]
pub fn is_trait(&self, name: &str) -> bool {
self.traits.contains_key(name)
}
#[must_use]
pub fn all_public_symbols(&self) -> Vec<String> {
let mut symbols = Vec::new();
for (name, info) in &self.traits {
if info.visibility == Visibility::Public {
symbols.push(name.clone());
}
}
for (name, info) in &self.structs {
if info.visibility == Visibility::Public {
symbols.push(name.clone());
}
}
for (name, info) in &self.enums {
if info.visibility == Visibility::Public {
symbols.push(name.clone());
}
}
for (name, info) in &self.lets {
if info.visibility == Visibility::Public {
symbols.push(name.clone());
}
}
for (name, info) in &self.modules {
if info.visibility == Visibility::Public {
symbols.push(name.clone());
}
}
for (name, overloads) in &self.functions {
if overloads.iter().any(|f| f.visibility == Visibility::Public) {
symbols.push(name.clone());
}
}
symbols.sort();
symbols
}
#[must_use]
pub fn get_module_origin(&self, name: &str) -> Option<&PathBuf> {
self.module_origins.get(name).and_then(|opt| opt.as_ref())
}
#[must_use]
pub fn get_module_logical_path(&self, name: &str) -> Option<&Vec<String>> {
self.module_logical_paths.get(name)
}
#[must_use]
pub fn get_symbol_kind(&self, name: &str) -> Option<SymbolKind> {
if self.structs.contains_key(name) {
Some(SymbolKind::Struct)
} else if self.traits.contains_key(name) {
Some(SymbolKind::Trait)
} else if self.enums.contains_key(name) {
Some(SymbolKind::Enum)
} else if self.lets.contains_key(name) {
Some(SymbolKind::Let)
} else if self.modules.contains_key(name) {
Some(SymbolKind::Module)
} else if self.impls.contains_key(name) {
Some(SymbolKind::Impl)
} else if self.functions.contains_key(name) {
Some(SymbolKind::Function)
} else {
None
}
}
}
impl Default for SymbolTable {
fn default() -> Self {
Self::new()
}
}