use anyhow::{anyhow, Result};
use std::collections::HashMap;
use crate::{parser::{FipsType, SubstitutionValue}, runtime::{FunctionID, MemberID, ParticleIndexEntry}, utils::FipsValue};
#[derive(Clone)]
pub struct SymbolTable<T> {
symbols: HashMap<String, FipsSymbol<T>>,
subtables: Vec<SymbolTable<T>>
}
macro_rules! insert_or_error {
($map:expr, $key:expr, $val:expr, $err:expr) => {
if $map.contains_key(&$key) { Err($err) }
else {
$map.insert($key, $val); Ok(())
}
}
}
impl<T> SymbolTable<T> {
pub fn new() -> Self {
Self {
symbols: HashMap::new(),
subtables: vec![]
}
}
pub fn from_particle(particle_def: &ParticleIndexEntry) -> Self {
let mut symbol_table = Self::new();
for (member_id, member_def) in particle_def.get_members() {
symbol_table.add_particle_member(member_def.get_name().into(), member_id)
.expect("Inconsistent member names!");
}
symbol_table
}
pub fn add_constant_from_substitution(&mut self, name: String, value: &SubstitutionValue) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::from_substitution(&value),
anyhow!("Cannot redefine constant with name {}", name))
}
pub fn add_constant_f64(&mut self, name: String, value: f64) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::from_f64(value),
anyhow!("Cannot redefine constant with name {}", name))
}
pub fn add_local_symbol(&mut self, name: String, typ: FipsType) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::new_local(typ),
anyhow!("Cannot redefine local variable with name {}", name)
)
}
pub fn add_local_symbol_with_value(&mut self, name: String, typ: FipsType, value: T) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::new_local_with_value(typ, value),
anyhow!("Cannot redefine local variable with name {}", name)
)
}
pub fn add_particle_member(&mut self, name: String, member_id: MemberID) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::new_particle_member(member_id),
anyhow!("Cannot redefine particle member variable with name {}", name)
)
}
pub fn add_function(&mut self, name: String, function_id: FunctionID) -> Result<()> {
insert_or_error!(self.symbols, name,
FipsSymbol::new_function(function_id),
anyhow!("Cannot redefine function with name {}", name)
)
}
pub fn push_table(&mut self, symbols: SymbolTable<T>) {
self.subtables.push(symbols)
}
pub fn pop_table(&mut self) -> Option<SymbolTable<T>> {
self.subtables.pop()
}
pub fn convert<U>(self) -> SymbolTable<U> {
let symbols = self.symbols.into_iter()
.map(|(name, symbol)| (name, symbol.convert()))
.collect::<HashMap<_,_>>();
let subtables = self.subtables.into_iter()
.map(|table| table.convert())
.collect::<Vec<_>>();
SymbolTable {
symbols,
subtables
}
}
pub fn iter_mut(&mut self) -> impl Iterator<Item=(&String, &mut FipsSymbol<T>)> {
let mut total_symbols = vec![];
for symbol_pair in &mut self.symbols {
total_symbols.push(symbol_pair)
}
for subtable in &mut self.subtables {
for symbol_pair in subtable.iter_mut() {
total_symbols.push(symbol_pair);
}
}
total_symbols.into_iter()
}
pub fn iter(&self) -> impl Iterator<Item=(&String, &FipsSymbol<T>)> {
let mut total_symbols = vec![];
for symbol_pair in &self.symbols {
total_symbols.push(symbol_pair)
}
for subtable in &self.subtables {
for symbol_pair in subtable.iter() {
total_symbols.push(symbol_pair);
}
}
total_symbols.into_iter()
}
pub fn resolve_symbol(&self, name: &str) -> Option<&FipsSymbol<T>> {
if let Some(symbol) = self.symbols.get(name) {
return Some(symbol)
};
for subtable in self.subtables.iter().rev() {
if let Some(symbol) = subtable.resolve_symbol(name) {
return Some(symbol)
}
};
None
}
}
#[derive(Clone)]
pub struct FipsSymbol<T> {
pub(crate) kind: FipsSymbolKind,
pub(crate) value: Option<T>
}
impl<T> FipsSymbol<T> {
pub fn from_substitution(value: &SubstitutionValue) -> Self {
Self {
kind: FipsSymbolKind::from_subsitution(value),
value: None
}
}
pub fn from_f64(value: f64) -> Self {
Self {
kind: FipsSymbolKind::from_f64(value),
value: None
}
}
pub fn new_local(typ: FipsType) -> Self {
Self {
kind: FipsSymbolKind::LocalVariable(typ),
value: None
}
}
pub fn new_local_with_value(typ: FipsType, value: T) -> Self {
Self {
kind: FipsSymbolKind::LocalVariable(typ),
value: Some(value)
}
}
pub fn new_particle_member(member_id: MemberID) -> Self {
Self {
kind: FipsSymbolKind::ParticleMember(member_id),
value: None
}
}
pub fn new_function(function_id: FunctionID) -> Self {
Self {
kind: FipsSymbolKind::Function(function_id),
value: None
}
}
pub fn convert<U>(self) -> FipsSymbol<U> {
FipsSymbol {
kind: self.kind,
value: None
}
}
pub fn set_value(&mut self, value: T) {
self.value = Some(value)
}
}
#[derive(Clone)]
pub enum FipsSymbolKind {
Constant(FipsValue),
LocalVariable(FipsType),
ParticleMember(MemberID),
Function(FunctionID)
}
impl FipsSymbolKind {
pub fn from_subsitution(val: &SubstitutionValue) -> Self {
Self::Constant(val.clone().into())
}
pub fn from_f64(val: f64) -> Self {
Self::Constant(val.into())
}
}