use std::collections::HashMap;
use std::hash::Hash;
use crate::LocalNamelessTerm;
use crate::Normal;
use crate::ReducedTerm;
use crate::Term;
pub mod statement;
pub use statement::*;
pub mod lexer;
pub mod parser;
#[derive(Clone)]
pub enum Command<T> {
Reduce(Term<T>),
Exec(Vec<Statement<T>>),
GetReduceLimit,
SetReduceLimit(usize),
Exit,
}
pub enum CommandOutcome<T> {
TermReduced(ReducedTerm<T>),
ReduceLimitReached(usize),
BindAdded(T),
BindOverwritten(T),
ReduceLimitGot(usize),
ReduceLimitSet(usize),
Exit,
}
pub struct Repl<T> {
binds: HashMap<T, LocalNamelessTerm<T>>,
reduce_limit: usize,
}
impl<T> Repl<T> {
pub fn new() -> Self {
Self::default()
}
}
impl<T: Clone + Eq + Hash> Repl<T> {
pub fn exec(&mut self, command: Command<T>) -> Vec<CommandOutcome<T>> {
let mut actions = Vec::with_capacity(1);
match command {
Command::Reduce(term) => {
let mut local_nameless = LocalNamelessTerm::from(&term);
local_nameless.rebind(&mut self.binds);
let count = local_nameless.beta_reduce_limit(self.reduce_limit, &Normal);
actions.push(CommandOutcome::TermReduced(ReducedTerm {
count,
term: Term::try_from(&local_nameless).unwrap(),
}));
if count >= self.reduce_limit {
actions.push(CommandOutcome::ReduceLimitReached(count));
}
},
Command::Exec(statements) => actions.extend(statements.into_iter()
.map(|statement| match statement {
Statement::Bind(name, term) => {
let mut local_nameless = LocalNamelessTerm::from(&term);
local_nameless.rebind(&mut self.binds);
match self.binds.insert(name.clone(), local_nameless) {
None => CommandOutcome::BindAdded(name),
Some(_) => CommandOutcome::BindOverwritten(name),
}
},
})),
Command::GetReduceLimit => actions.push(CommandOutcome::ReduceLimitGot(self.reduce_limit)),
Command::SetReduceLimit(limit) => {
self.reduce_limit = limit;
actions.push(CommandOutcome::ReduceLimitSet(limit));
},
Command::Exit => actions.push(CommandOutcome::Exit),
}
actions
}
}
impl<T> Default for Repl<T> {
fn default() -> Self {
Self {
binds: HashMap::default(),
reduce_limit: 1000,
}
}
}