use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
Var,
Function,
Type,
Enum,
Import,
}
impl SymbolKind {
pub fn noun(self) -> &'static str {
match self {
SymbolKind::Var => "variable",
SymbolKind::Function => "function",
SymbolKind::Type => "type",
SymbolKind::Enum => "enum",
SymbolKind::Import => "import",
}
}
}
pub struct ScopeStack {
scopes: Vec<HashMap<String, SymbolKind>>,
}
impl ScopeStack {
pub fn new() -> Self {
Self {
scopes: vec![HashMap::new()],
}
}
pub fn push(&mut self) {
self.scopes.push(HashMap::new());
}
pub fn pop(&mut self) {
debug_assert!(self.scopes.len() > 1, "attempted to pop the global scope");
self.scopes.pop();
}
pub fn at_global(&self) -> bool {
self.scopes.len() == 1
}
pub fn declare(&mut self, name: &str, kind: SymbolKind) -> Option<SymbolKind> {
let scope = self
.scopes
.last_mut()
.expect("scope stack always has the global scope");
scope.insert(name.to_string(), kind)
}
pub fn resolve(&self, name: &str) -> Option<SymbolKind> {
self.scopes
.iter()
.rev()
.find_map(|scope| scope.get(name).copied())
}
}
impl Default for ScopeStack {
fn default() -> Self {
Self::new()
}
}
const GLOBAL_ONLY_FUNCTIONS: &[&str] = &[
"plot",
"plotshape",
"plotchar",
"plotcandle",
"plotbar",
"plotarrow",
"fill",
];
pub fn is_global_only(name: &str) -> bool {
GLOBAL_ONLY_FUNCTIONS.contains(&name)
}