//! Execution environment for repl use super::*; use std::str::FromStr; use std::collections::{BTreeMap, HashMap}; #[derive(Debug)] pub struct Lexenv { /// Maps symbol name to value in generations. kvstack: BTreeMap>, /// Current generation of the satck current_generation: usize, } impl Lexenv { /// The generation number of the current level. pub fn depth(&self) -> usize { self.current_generation } /// Create a new empty lexenv pub fn new() -> Self { Self { kvstack: BTreeMap::new(), current_generation: 0, } } /// All valid symbols at this level. /// /// # Ordering /// Each symbol's level will appear in the order from level 0 to the current level, however the order of intra-level symbols is undefined. pub fn symbols(&self) -> impl Iterator + '_ { self.kvstack.range(0..=self.current_generation).flat_map(|(_, v)| v.values()) } /// All valid symbols **in** this level. pub fn symbols_local(&self) -> impl Iterator + '_ { OptionIterator::from(self.kvstack.get(&self.current_generation).map(|x| x.values())) } /// Remove the current level, but leave its memory allocated for further use. pub fn pop(&mut self) { self.kvstack.entry(self.current_generation).or_insert_with(|| HashMap::new()).clear(); if self.current_generation > 0 { self.current_generation-=1; } } /// Remove a symbol from the **current** level. pub fn remove(&mut self, name: &str) -> Option { self.kvstack.entry(self.current_generation).or_insert_with(|| HashMap::new()).remove(name) } /// Insert a new value mapping into the current level. pub fn insert(&mut self, name: String, value: Value) { self.kvstack.entry(self.current_generation).or_insert_with(|| HashMap::new()).insert(name, value); } /// Look up a symbol in this or any of the above levels. pub fn lookup(&self, name: &str) -> Option<&Value> { for (_, lvmap) in self.kvstack.range(0..=self.current_generation).rev() { let m = lvmap.get(name); if m.is_some() { return m; } } None } /// Look up a symbol in this level. pub fn lookup_local(&self, name: &str) -> Option<&Value> { self.kvstack.get(&self.current_generation).map(|map| map.get(name)).flatten() } /// Create a new, empty level. pub fn push(&mut self) { self.current_generation+=1; } /// Remove the current level, deallocating any memory it was using. pub fn pop_clear(&mut self) { if self.current_generation > 0 { self.kvstack.remove(&self.current_generation); self.current_generation -=1; } else { self.kvstack.entry(0).or_insert_with(|| HashMap::new()).clear(); } } } /// The value type #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Value { String(String), Symbol(String), List(Vec), } impl Value { /// Parse from an iterator of `char`s. pub fn parse_chars(ch: &mut T) -> Result where T: Iterator { match ch.next() { Some('(') => { todo!("list"); }, Some('"') => { todo!("string"); }, Some(first_chr) => { todo!("symbol"); }, _ => Err(ValueParseError(String::default())), } } /// Parse a `Value` from this string and then return the rest of the string. #[deprecated] pub fn parse_running(s: &str) -> Result<(Self, &'_ str), ValueParseError> { match s.trim().as_bytes() { & [b'(', ..] => { todo!("list"); }, & [b'"', ..] => { todo!("string"); }, _ => { todo!("shmbol"); } } } } impl FromStr for Value { type Err = ValueParseError; fn from_str(s: &str) -> Result { Self::parse_running(s).map(|(x, _)| x) } } impl Value { pub fn try_as_symbol(&self) -> Result<&str, ValueTypeError> { match self { Self::Symbol(s) => Ok(&s[..]), _ => Err(ValueTypeError::Symbol), } } pub fn try_as_string(&self) -> Result<&str, ValueTypeError> { match self { Self::Symbol(s) | Self::String(s) => Ok(&s[..]), _ => Err(ValueTypeError::String), } } pub fn try_as_list(&self) -> Result<&[Value], ValueTypeError> { match self { Self::List(l) => Ok(&l[..]), _ => Err(ValueTypeError::List), } } pub fn as_symbol(&self) -> Option<&str> { match self { Self::Symbol(s) => Some(&s[..]), _ => None, } } pub fn as_string(&self) -> Option<&str> { match self { Self::Symbol(s) | Self::String(s) => Some(&s[..]), _ => None, } } pub fn as_list(&self) -> Option<&[Value]> { match self { Self::List(l) => Some(&l[..]), _ => None, } } } /// Error when using `try_as_*` functions on `Value`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub enum ValueTypeError { Symbol, String, List, } /// Error when parsing a `Value` from a stirng. #[derive(Debug)] pub struct ValueParseError(String); impl error::Error for ValueParseError{} impl fmt::Display for ValueParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "cannot parse {:?}", self.0) } } impl error::Error for ValueTypeError{} impl fmt::Display for ValueTypeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "type error: expected ")?; match self { Self::Symbol => write!(f, "symbol"), Self::String => write!(f, "string"), Self::List => write!(f, "list"), } } }