parent
e8d215a65f
commit
b7d6bb0095
@ -0,0 +1,155 @@
|
||||
//! Repl commands
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context<'a>
|
||||
{
|
||||
/// Environment containing variable name mappings.
|
||||
env: &'a mut Lexenv,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value
|
||||
{
|
||||
String(String),
|
||||
Symbol(String),
|
||||
List(Vec<Value>),
|
||||
|
||||
Command(Box<dyn Command>),
|
||||
}
|
||||
|
||||
pub trait Command: fmt::Debug
|
||||
{
|
||||
fn execute(self: Box<Self>, cx: &mut Context<'_>, params: Vec<Value>) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
/// Command structurally parsed.
|
||||
///
|
||||
/// Can be converted into `Command` with the `TryInto` trait.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct IR
|
||||
{
|
||||
op: String,
|
||||
params: Vec<String>,
|
||||
}
|
||||
|
||||
impl FromStr for IR
|
||||
{
|
||||
type Err = CommandParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Error when parsing a command into `IR`.
|
||||
#[derive(Debug)]
|
||||
pub struct CommandParseError(String);
|
||||
|
||||
impl error::Error for CommandParseError{}
|
||||
|
||||
impl fmt::Display for CommandParseError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "failed to parse command from {:?}", self.0)
|
||||
}
|
||||
}
|
Loading…
Reference in new issue