use crate::core::ScriptRef;
use crate::prelude::*;
use core::marker::PhantomData;
pub struct Machine<Op, Val, F, E>
where
Val: core::fmt::Debug + core::cmp::PartialEq,
F: FnMut(&mut Stack<Val>, &Op, &mut ConditionStack) -> Result<(), E>,
{
op_sys: F,
stack: Stack<Val>,
if_stack: ConditionStack,
phantom_op: PhantomData<fn(&Op)>,
}
impl<Op, Val, F, E> Machine<Op, Val, F, E>
where
Op: core::fmt::Debug + core::cmp::Eq,
Val: core::fmt::Debug + core::cmp::PartialEq + core::clone::Clone,
F: FnMut(&mut Stack<Val>, &Op, &mut ConditionStack) -> Result<(), E>,
{
pub fn new(op_sys: F) -> Self {
Self {
op_sys,
stack: Stack::<Val>::default(),
if_stack: ConditionStack::default(),
phantom_op: PhantomData,
}
}
pub fn operate(&mut self, item: &Item<Op, Val>) -> Result<Option<&Val>, E> {
match item {
Item::Operator(operator) => {
(self.op_sys)(&mut self.stack, operator, &mut self.if_stack)
}
Item::Value(value) => {
if self.if_stack.all_true() {
self.stack.push((*value).clone());
}
Ok(())
}
}
.map(|()| self.stack.topmost())
}
pub fn run_script(&mut self, script: ScriptRef<Op, Val>) -> Result<Option<&Val>, E> {
for item in script {
self.operate(item)?;
}
Ok(self.stack.topmost())
}
pub fn stack_length(&self) -> usize {
self.stack.length()
}
}
impl<Op, Val, F, E> core::fmt::Debug for Machine<Op, Val, F, E>
where
Op: core::fmt::Debug + core::cmp::Eq,
Val: core::fmt::Debug + core::cmp::PartialEq + core::clone::Clone,
F: FnMut(&mut Stack<Val>, &Op, &mut ConditionStack) -> Result<(), E>,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
f.debug_struct("Machine")
.field("stack", &self.stack)
.field("if_stack", &self.if_stack)
.finish()
}
}