use crate::type_checker::{EnumSchemaId, Name, StructSchemaId, TypeId};
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::ops::Range;
#[derive(Debug, Clone)]
pub enum SymbolTableEntry {
Variable {
ty: TypeId,
definition_span: Range<usize>,
},
TypeVariable {
idx: usize,
},
AbstractTypeVariable,
Struct { schema_id: StructSchemaId },
Enum { schema_id: EnumSchemaId },
}
pub struct SymbolTable {
scopes: Vec<HashMap<Name, SymbolTableEntry>>,
current_scope: usize,
}
impl SymbolTable {
pub fn new() -> Self {
Self {
scopes: vec![HashMap::new()],
current_scope: 0,
}
}
pub fn assert_single_scope(&self) {
debug_assert_eq!(self.scopes.len(), 1)
}
pub fn enter_scope(&mut self) {
self.current_scope += 1;
self.scopes.push(HashMap::new());
}
pub fn exit_scope(&mut self) {
self.current_scope -= 1;
self.scopes.pop();
}
pub(crate) fn insert(&mut self, name: Name, value: SymbolTableEntry) {
self.scopes[self.current_scope].insert(name, value);
}
pub fn lookup(&self, name: impl AsRef<str>) -> Option<&SymbolTableEntry> {
for scope in self.scopes.iter().rev() {
if let Some(ty) = scope.get(name.as_ref()) {
return Some(ty);
}
}
None
}
#[allow(dead_code)]
pub fn lookup_mut(&mut self, name: &Name) -> Option<&mut SymbolTableEntry> {
for scope in self.scopes.iter_mut().rev() {
if let Some(ty) = scope.get_mut(name) {
return Some(ty);
}
}
None
}
}
impl Debug for SymbolTable {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for scope in &self.scopes {
writeln!(f, "---------------------")?;
for (name, entry) in scope {
writeln!(f, "{}: {:?}", name, entry)?;
}
writeln!(f, "---------------------")?;
}
Ok(())
}
}