parent
5169227499
commit
784f3f2c10
@ -0,0 +1,242 @@
|
|||||||
|
//! 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<usize, HashMap<String, Value>>,
|
||||||
|
/// 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<Item = &'_ Value> + '_
|
||||||
|
{
|
||||||
|
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<Item = &'_ Value> + '_
|
||||||
|
{
|
||||||
|
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<Value>
|
||||||
|
{
|
||||||
|
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<Value>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value
|
||||||
|
{
|
||||||
|
/// Parse from an iterator of `char`s.
|
||||||
|
pub fn parse_chars<T>(ch: &mut T) -> Result<Self, ValueParseError>
|
||||||
|
where T: Iterator<Item = char>
|
||||||
|
{
|
||||||
|
|
||||||
|
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, Self::Err> {
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
//! Defined commands
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use env::*;
|
||||||
|
use command::*;
|
||||||
|
|
||||||
|
/// Contains all operations
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Operations
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue