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