use super::anon_map::AnonMap;
use crate::common::Hygiene;
use crate::common::LocalMacro;
use crate::deterred_map::DeterredMacroMap;
use crate::function_map::FunctionMacroMap;
use crate::runtime_map::{RuntimeMacro, RuntimeMacroMap};
#[cfg(feature = "signature")]
use crate::sigmap::MacroSignature;
use crate::trim;
use crate::utils::Utils;
use crate::MacroType;
use crate::RadResult;
use std::collections::{HashMap, HashSet};
pub(crate) struct MacroMap {
pub pass_through: HashSet<String>,
pub deterred: DeterredMacroMap,
pub function: FunctionMacroMap,
pub runtime: RuntimeMacroMap,
pub anon_map: AnonMap,
pub local: HashMap<String, LocalMacro>,
}
impl MacroMap {
pub fn empty() -> Self {
Self {
pass_through: HashSet::new(),
deterred: DeterredMacroMap::empty(),
function: FunctionMacroMap::empty(),
runtime: RuntimeMacroMap::new(),
anon_map: AnonMap::new(),
local: HashMap::new(),
}
}
pub fn new() -> Self {
Self {
pass_through: HashSet::new(),
deterred: DeterredMacroMap::new(),
function: FunctionMacroMap::new(),
runtime: RuntimeMacroMap::new(),
anon_map: AnonMap::new(),
local: HashMap::new(),
}
}
pub fn add_new_pass_through(&mut self, name: &str) {
self.pass_through.insert(name.to_string());
}
pub fn clear_pass_through(&mut self) {
self.pass_through.clear();
}
pub fn clear_anonymous_macros(&mut self) {
self.anon_map.clear();
}
pub fn clear_runtime_macros(&mut self, volatile: bool) {
self.runtime.clear_runtime_macros(volatile);
}
pub fn add_local_macro(&mut self, level: usize, name: &str, value: &str) {
self.local.insert(
Utils::local_name(level, name),
LocalMacro::new(level, name.to_owned(), value.to_owned()),
);
}
pub fn remove_local_macro(&mut self, level: usize, name: &str) {
self.local.remove(&Utils::local_name(level, name));
}
pub fn clear_local(&mut self) {
self.local.clear();
}
pub fn clear_lower_locals(&mut self, current_level: usize) {
self.local.retain(|_, mac| mac.level <= current_level);
}
pub fn is_deterred_macro(&self, name: &str) -> bool {
self.deterred.contains(name)
}
pub fn contains_local_macro(&self, macro_name: &str) -> bool {
self.local.contains_key(macro_name)
}
pub fn contains_macro(
&self,
macro_name: &str,
macro_type: MacroType,
hygiene_type: Hygiene,
) -> bool {
match macro_type {
MacroType::Deterred => self.deterred.contains(macro_name),
MacroType::Function => self.function.contains(macro_name),
MacroType::Runtime => self.runtime.contains(macro_name, hygiene_type),
MacroType::Any => {
self.function.contains(macro_name)
|| self.runtime.contains(macro_name, hygiene_type)
|| self.deterred.contains(macro_name)
}
}
}
pub fn new_anon_macro(&mut self, body: &str) -> RadResult<()> {
self.anon_map.new_macro(body)
}
pub fn get_anon_macro(&self) -> Option<&RuntimeMacro> {
self.anon_map.get_anon()
}
pub fn register_runtime(
&mut self,
name: &str,
args: &str,
body: &str,
hygiene_type: Hygiene,
) -> RadResult<()> {
let mac = RuntimeMacro::new(&trim!(name), &trim!(args), body, false);
self.runtime.new_macro(name, mac, hygiene_type);
Ok(())
}
pub fn undefine(&mut self, macro_name: &str, macro_type: MacroType, hygiene_type: Hygiene) {
match macro_type {
MacroType::Deterred => {
self.deterred.undefine(macro_name);
}
MacroType::Function => {
self.function.undefine(macro_name);
}
MacroType::Runtime => {
self.runtime.undefine(macro_name, hygiene_type);
}
MacroType::Any => {
self.function.undefine(macro_name);
self.runtime.undefine(macro_name, hygiene_type);
self.deterred.undefine(macro_name);
}
}
}
pub fn rename(
&mut self,
macro_name: &str,
target_name: &str,
macro_type: MacroType,
hygiene_type: Hygiene,
) {
match macro_type {
MacroType::Deterred => {
self.deterred.rename(macro_name, target_name);
}
MacroType::Function => {
self.function.rename(macro_name, target_name);
}
MacroType::Runtime => {
self.runtime.rename(macro_name, target_name, hygiene_type);
}
MacroType::Any => {
if !self.runtime.rename(macro_name, target_name, hygiene_type)
&& !self.deterred.rename(macro_name, target_name)
{
self.function.rename(macro_name, target_name);
}
}
}
}
pub fn append_local(&mut self, name: &str, target: &str) {
if let Some(loc) = self.local.get_mut(name) {
loc.body.push_str(target);
}
}
pub fn append(&mut self, name: &str, target: &str, hygiene_type: Hygiene) {
if self.runtime.contains(name, hygiene_type) {
self.runtime.append_macro(name, target, hygiene_type);
}
}
pub fn replace(&mut self, name: &str, target: &str, hygiene_type: Hygiene) -> bool {
if self.runtime.contains(name, hygiene_type) {
self.runtime.replace_macro(name, target, hygiene_type);
true
} else {
false
}
}
#[cfg(feature = "signature")]
pub fn get_signature(&self, macro_name: &str) -> Option<MacroSignature> {
if let Some(mac) = self.runtime.get(macro_name, Hygiene::None) {
Some(MacroSignature::from(mac))
} else if let Some(mac) = self.deterred.get_signature(macro_name) {
Some(MacroSignature::from(mac))
} else {
self.function
.get_signature(macro_name)
.map(MacroSignature::from)
}
}
#[cfg(feature = "signature")]
pub fn get_signatures(&self) -> Vec<MacroSignature> {
let key_iter = self.deterred.macros.values().map(MacroSignature::from);
let funcm_iter = self.function.macros.values().map(MacroSignature::from);
let runtime_iter = self.runtime.macros.values().map(MacroSignature::from);
key_iter.chain(funcm_iter).chain(runtime_iter).collect()
}
#[cfg(feature = "signature")]
pub fn get_function_signatures(&self) -> Vec<MacroSignature> {
let key_iter = self.deterred.macros.values().map(MacroSignature::from);
let funcm_iter = self.function.macros.values().map(MacroSignature::from);
key_iter.chain(funcm_iter).collect()
}
#[cfg(feature = "signature")]
pub fn get_runtime_signatures(&self) -> Vec<MacroSignature> {
self.runtime
.macros
.values()
.map(MacroSignature::from)
.collect()
}
}