use std::collections::{HashMap, VecDeque}; 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, atom_qs}; use crsn::utils::A; use crate::defs::{BufOps, BufValue}; #[derive(Debug, Default)] struct ExtData { store: HashMap>, } // TODO optimize and DRY impl OpTrait for BufOps { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { let eres = EvalRes::default(); match self { BufOps::New { dst, value } => { let id = info.unique_handle(); let que = match value { BufValue::Zeros(len) => { let len = state.read(*len)? as usize; let mut que = VecDeque::with_capacity(len); que.resize(len, 0); que } BufValue::Values(vals) => { let mut que = VecDeque::with_capacity(vals.len()); for val in vals { que.push_back(state.read(*val)?); } que } BufValue::Chars(string) => { let mut que = VecDeque::new(); for val in string.chars() { que.push_back(val as Value); } que } }; let data: &mut ExtData = state.ext_mut(); data.store.insert(id, que); state.write(*dst, id)?; } BufOps::Push { obj, src } => { state.clear_status(); let val = state.read(*src)?; let handle = state.read_obj(*obj)?; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; stack.push_back(val); } BufOps::Pop { dst, obj } => { state.clear_status(); let handle = state.read_obj(*obj)?; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; if let Some(val) = stack.pop_back() { let empty = stack.is_empty(); state.write(*dst, val)?; state.update_status(val); state.set_flag(Cond::Empty, empty); } else { state.set_flag(Cond::Empty, true); state.set_flag(Cond::Overflow, true); } } BufOps::Read { dst, obj, idx } => { state.clear_status(); let handle = state.read_obj(*obj)?; let idx = state.read(*idx)?; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; if let Some(val) = stack.get(idx as usize) { let val = *val; state.update_status(val); state.write(*dst, val)?; } else { state.set_flag(Cond::Overflow, true); } } BufOps::GetLen { dst, obj } => { state.clear_status(); let handle = state.read_obj(*obj)?; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; let val = stack.len() as Value; state.write(*dst, val)?; state.update_status(val); } BufOps::Write { obj, idx, value } => { state.clear_status(); let handle = state.read_obj(*obj)?; let val = state.read(*value)?; let idx = state.read(*idx)? as usize; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; if idx < stack.len() { stack[idx] = val; } else if idx == stack.len() { stack.push_back(val); } else { state.set_flag(Cond::Overflow, true); } } BufOps::Insert { obj, idx, value } => { state.clear_status(); let handle = state.read_obj(*obj)?; let val = state.read(*value)?; let idx = state.read(*idx)? as usize; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; if idx < stack.len() { stack.insert(idx, val); } else if idx == stack.len() { stack.push_back(val); } else { state.set_flag(Cond::Overflow, true); } } BufOps::Remove { dst, obj, idx } => { state.clear_status(); let handle = state.read_obj(*obj)?; let idx = state.read(*idx)? as usize; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; if idx < stack.len() { let val = stack.remove(idx).unwrap(); let empty = stack.is_empty(); state.update_status(val); state.write(*dst, val)?; state.set_flag(Cond::Empty, empty); } else { state.set_flag(Cond::Overflow, true); } } BufOps::Resize { obj, len } => { let handle = state.read_obj(*obj)?; let len = state.read(*len)? as usize; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; stack.resize(len, 0); } BufOps::Reverse { obj } => { let handle = state.read_obj(*obj)?; let stacks: &mut ExtData = state.ext_mut(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; let len = stack.len(); if len > 1 { let mut start = 0; let mut end = len - 1; while start < end { stack.swap(start, end); start += 1; end -= 1; } } } BufOps::AppendBuf { obj, obj2 } => { let handle = state.read_obj(*obj)?; let handle2 = state.read_obj(*obj2)?; let stacks: &mut ExtData = state.ext_mut(); let stack2 = stacks.store.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.clone(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; stack.extend(stack2); } BufOps::PrependBuf { obj, obj2 } => { let handle = state.read_obj(*obj)?; let handle2 = state.read_obj(*obj2)?; let stacks: &mut ExtData = state.ext_mut(); let stack2 = stacks.store.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.clone(); let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; for v in stack2.into_iter().rev() { stack.push_front(v); } } } Ok(eres) } fn to_sexp(&self) -> Sexp { match self { BufOps::Push { obj, src } => sexp::list(&[A("push"), A(obj), A(src)]), BufOps::Pop { dst, obj } => sexp::list(&[A("pop"), A(dst), A(obj)]), BufOps::New { dst, value } => { match value { BufValue::Zeros(n) => { sexp::list(&[A("mkbf"), A(dst), A(n)]) } BufValue::Values(vals) => { let mut vals: Vec<_> = vals.iter().map(A).collect(); vals.insert(0, A(dst)); vals.insert(0, A("mkbfv")); sexp::list(&vals) } BufValue::Chars(str) => { sexp::list(&[A("mkbfv"), A(dst), atom_qs(str)]) } } } BufOps::Read { dst, obj, idx } => { sexp::list(&[A("bfrd"), A(dst), A(obj), A(idx)]) } BufOps::GetLen { dst, obj } => { sexp::list(&[A("bfsz"), A(dst), A(obj)]) } BufOps::Write { obj, idx, value } => { sexp::list(&[A("bfwr"), A(obj), A(idx), A(value)]) } BufOps::Insert { obj, idx, value } => { sexp::list(&[A("bfins"), A(obj), A(idx), A(value)]) } BufOps::Remove { dst, obj, idx } => { sexp::list(&[A("bfrm"), A(dst), A(obj), A(idx)]) } BufOps::Resize { obj, len } => { sexp::list(&[A("bfrsz"), A(obj), A(len)]) } BufOps::Reverse { obj } => { sexp::list(&[A("bfrev"), A(obj)]) } BufOps::AppendBuf { obj, obj2 } => { sexp::list(&[A("bfapp"), A(obj), A(obj2)]) } BufOps::PrependBuf { obj, obj2 } => { sexp::list(&[A("bfprep"), A(obj), A(obj2)]) } } } } pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result, Fault> { let stacks: &mut ExtData = state.ext_mut(); Ok(stacks.store.remove(&handle).map(|_| ())) }