use std::{cmp::Eq, collections::HashMap, fmt::Write, hash::Hash}; /// Utility function for printing a comma-delimited list of things pub(crate) fn delim_wrapped(lhs: char, rhs: char, terms: impl Iterator) -> String { let mut buf = String::new(); write!(buf, "{}", lhs).unwrap(); for term in terms.map(Some).intersperse(None) { match term { Some(e) => write!(buf, "{}", e).unwrap(), None => write!(buf, ", ").unwrap(), }; } write!(buf, "{}", rhs).unwrap(); buf } #[derive(Default, Debug)] pub struct ScopeStack<'a, T: 'a, V: 'a, N = String> where T: Hash + Eq { parent: Option<&'a ScopeStack<'a, T, V, N>>, values: HashMap, scope_name: Option, } impl<'a, T, V, N> ScopeStack<'a, T, V, N> where T: Hash + Eq { pub fn new(scope_name: Option) -> Self where T: Hash + Eq { ScopeStack { parent: None, values: HashMap::new(), scope_name } } pub fn insert(&mut self, key: T, value: V) where T: Hash + Eq { self.values.insert(key, value); } pub fn lookup(&self, key: &T) -> Option<&V> where T: Hash + Eq { match (self.values.get(key), self.parent) { (None, None) => None, (None, Some(parent)) => parent.lookup(key), (Some(value), _) => Some(value), } } pub fn new_scope(&'a self, scope_name: Option) -> Self where T: Hash + Eq { ScopeStack { parent: Some(self), values: HashMap::default(), scope_name } } #[allow(dead_code)] pub fn lookup_with_scope(&self, key: &T) -> Option<(&V, Option<&N>)> where T: Hash + Eq { match (self.values.get(key), self.parent) { (None, None) => None, (None, Some(parent)) => parent.lookup_with_scope(key), (Some(value), _) => Some((value, self.scope_name.as_ref())), } } pub fn get_name(&self) -> Option<&N> { self.scope_name.as_ref() } } /// Quickly create an AST from a string, with no error checking. For test use only #[cfg(test)] pub fn quick_ast(input: &str) -> crate::ast::AST { let mut parser = crate::parsing::Parser::new(); let output = parser.parse(input); match output { Ok(output) => output, Err(err) => { println!("Parse error: {}", err.msg); panic!(); } } } #[allow(unused_macros)] macro_rules! rc { ($string:tt) => { Rc::new(stringify!($string).to_string()) }; }