use std::collections::{HashMap, VecDeque}; use crsn::asm::data::{Rd, RdObj, Wr}; use crsn::asm::data::literal::Value; use crsn::asm::instr::Cond; use crsn::module::{EvalRes, OpTrait}; use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crsn::sexp; use crsn::sexp::Sexp; use crsn::utils::A; use crate::defs::StackOp; #[derive(Debug, Default)] struct Stacks { store: HashMap>, } impl OpTrait for StackOp { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { let eres = EvalRes::default(); match self { StackOp::NewStack { dst } => { let id = info.unique_handle(); let stacks: &mut Stacks = state.ext_mut(); stacks.store.insert(id, VecDeque::new()); state.write(*dst, id)?; } StackOp::Push { obj, src } => { prepare_push(state, obj, src, |stack, val| stack.push_back(val))?; } StackOp::ReversePush { obj, src } => { prepare_push(state, obj, src, |stack, val| stack.push_front(val))?; } StackOp::Pop { dst, obj } => { prepare_pop(state, dst, obj, |stack| stack.pop_back())?; } StackOp::ReversePop { dst, obj } => { prepare_pop(state, dst, obj, |stack| stack.pop_front())?; } } Ok(eres) } fn to_sexp(&self) -> Sexp { match self { StackOp::NewStack { dst } => sexp::list(&[A("stack"), A(dst)]), StackOp::Push { obj, src } => sexp::list(&[A("push"), A(obj), A(src)]), StackOp::Pop { dst, obj } => sexp::list(&[A("pop"), A(dst), A(obj)]), StackOp::ReversePush { obj, src } => sexp::list(&[A("rpush"), A(obj), A(src)]), StackOp::ReversePop { dst, obj } => sexp::list(&[A("rpop"), A(dst), A(obj)]), } } } pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result, Fault> { let stacks: &mut Stacks = state.ext_mut(); Ok(stacks.store.remove(&handle).map(|_| ())) } fn prepare_push(state: &mut RunState, obj: &RdObj, src: &Rd, pushfn: impl FnOnce(&mut VecDeque, Value) -> ()) -> Result<(), Fault> { state.clear_status(); let handle = state.read_obj(*obj)?; let val = state.read(*src)?; let stacks: &mut Stacks = state.ext_mut(); let mutable = stacks.store.get_mut(&handle) .ok_or_else(|| Fault::ObjectNotExist(handle))?; pushfn(mutable, val); Ok(()) } fn prepare_pop(state: &mut RunState, dst: &Wr, obj: &RdObj, popfn: impl FnOnce(&mut VecDeque) -> Option) -> Result<(), Fault> { state.clear_status(); let handle = state.read_obj(*obj)?; let stacks: &mut Stacks = state.ext_mut(); let stack = stacks.store.get_mut(&handle) .ok_or_else(|| Fault::ObjectNotExist(handle))?; let val = popfn(stack); if stack.is_empty() { state.set_flag(Cond::Zero, true); } let val = match val { None => { state.set_flag(Cond::Overflow, true); 0 } Some(val) => { val } }; state.write(*dst, val)?; Ok(()) }