use crate::number::Number;
use crate::symbol::{FuncError, Symbol, SymbolError};
use std::borrow::Cow;
#[derive(Debug, Default, Clone)]
pub struct SymTable {
symbols: Vec<Symbol>,
}
impl SymTable {
pub fn new() -> Self {
Self::default()
}
pub(crate) fn from_symbols(symbols: Vec<Symbol>) -> Self {
Self { symbols }
}
pub fn add_const<S: Into<Cow<'static, str>>>(
&mut self,
name: S,
value: Number,
local: bool,
) -> Result<&mut Self, SymbolError> {
let name = name.into();
if self.get_by_name(&name).is_ok() {
return Err(SymbolError::DuplicateSymbol(name.to_string()));
}
self.symbols.push(Symbol::Const {
name,
value,
description: None,
local,
});
Ok(self)
}
pub fn add_func<S: Into<Cow<'static, str>>>(
&mut self,
name: S,
args: usize,
variadic: bool,
callback: fn(&[Number]) -> Result<Number, FuncError>,
local: bool,
) -> Result<&mut Self, SymbolError> {
let name = name.into();
if self.get_by_name(&name).is_ok() {
return Err(SymbolError::DuplicateSymbol(name.to_string()));
}
self.symbols.push(Symbol::Func {
name,
args,
variadic,
callback,
description: None,
local,
});
Ok(self)
}
pub fn get_by_name(&self, name: &str) -> Result<&Symbol, SymbolError> {
self.symbols
.iter()
.find(|sym| sym.name().eq_ignore_ascii_case(name))
.ok_or_else(|| SymbolError::SymbolNotFound(name.to_string()))
}
pub fn get_with_index(&self, name: &str) -> Result<(usize, &Symbol), SymbolError> {
self.symbols
.iter()
.enumerate()
.find(|(_, sym)| sym.name().eq_ignore_ascii_case(name))
.ok_or_else(|| SymbolError::SymbolNotFound(name.to_string()))
}
pub fn get_by_index(&self, index: usize) -> Result<&Symbol, SymbolError> {
self.symbols
.get(index)
.ok_or_else(|| SymbolError::SymbolNotFound(index.to_string()))
}
pub fn get_mut_by_index(&mut self, index: usize) -> Result<&mut Symbol, SymbolError> {
self.symbols
.get_mut(index)
.ok_or_else(|| SymbolError::SymbolNotFound(index.to_string()))
}
pub fn symbols(&self) -> impl Iterator<Item = &Symbol> {
self.symbols.iter()
}
}