|
|
|
@ -1,19 +1,25 @@ |
|
|
|
|
use std::collections::{HashMap, VecDeque}; |
|
|
|
|
|
|
|
|
|
use crsn::asm::data::literal::Value; |
|
|
|
|
use crsn::asm::instr::cond::Flag; |
|
|
|
|
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::sexp::{atom_qs, Sexp}; |
|
|
|
|
use crsn::utils::A; |
|
|
|
|
|
|
|
|
|
use crate::defs::{BufOps, BufValue}; |
|
|
|
|
use crsn::asm::instr::cond::Flag; |
|
|
|
|
use crate::defs::{BufIoMode, BufOps, BufValue}; |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Clone)] |
|
|
|
|
struct Buffer { |
|
|
|
|
data: VecDeque<Value>, |
|
|
|
|
iomode: BufIoMode, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default)] |
|
|
|
|
struct ExtData { |
|
|
|
|
store: HashMap<Value, VecDeque<Value>>, |
|
|
|
|
buffers: HashMap<Value, Buffer>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO optimize and DRY
|
|
|
|
@ -49,26 +55,38 @@ impl OpTrait for BufOps { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let data: &mut ExtData = state.ext_mut(); |
|
|
|
|
data.store.insert(id, que); |
|
|
|
|
data.buffers.insert(id, Buffer { |
|
|
|
|
data: que, |
|
|
|
|
iomode: Default::default() |
|
|
|
|
}); |
|
|
|
|
state.write(dst, id)?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BufOps::SetIoMode { obj, mode } => { |
|
|
|
|
state.clear_status(); |
|
|
|
|
let handle = state.read_obj(obj)?; |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
|
|
|
|
|
buf.iomode = *mode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
buf.data.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(); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
if let Some(val) = buf.data.pop_back() { |
|
|
|
|
let empty = buf.data.is_empty(); |
|
|
|
|
state.write(dst, val)?; |
|
|
|
|
state.update_status(val); |
|
|
|
|
state.set_flag(Flag::Empty, empty); |
|
|
|
@ -82,9 +100,9 @@ impl OpTrait for BufOps { |
|
|
|
|
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 store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
if let Some(val) = buf.data.get(idx as usize) { |
|
|
|
|
let val = *val; |
|
|
|
|
state.update_status(val); |
|
|
|
|
state.write(dst, val)?; |
|
|
|
@ -96,9 +114,9 @@ impl OpTrait for BufOps { |
|
|
|
|
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; |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
let val = buf.data.len() as Value; |
|
|
|
|
state.write(dst, val)?; |
|
|
|
|
state.update_status(val); |
|
|
|
|
} |
|
|
|
@ -108,12 +126,12 @@ impl OpTrait for BufOps { |
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
if idx < buf.data.len() { |
|
|
|
|
buf.data[idx] = val; |
|
|
|
|
} else if idx == buf.data.len() { |
|
|
|
|
buf.data.push_back(val); |
|
|
|
|
} else { |
|
|
|
|
state.set_flag(Flag::Overflow, true); |
|
|
|
|
} |
|
|
|
@ -124,12 +142,12 @@ impl OpTrait for BufOps { |
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
if idx < buf.data.len() { |
|
|
|
|
buf.data.insert(idx, val); |
|
|
|
|
} else if idx == buf.data.len() { |
|
|
|
|
buf.data.push_back(val); |
|
|
|
|
} else { |
|
|
|
|
state.set_flag(Flag::Overflow, true); |
|
|
|
|
} |
|
|
|
@ -139,11 +157,11 @@ impl OpTrait for BufOps { |
|
|
|
|
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(); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
if idx < buf.data.len() { |
|
|
|
|
let val = buf.data.remove(idx).unwrap(); |
|
|
|
|
let empty = buf.data.is_empty(); |
|
|
|
|
state.update_status(val); |
|
|
|
|
state.write(dst, val)?; |
|
|
|
|
state.set_flag(Flag::Empty, empty); |
|
|
|
@ -155,21 +173,21 @@ impl OpTrait for BufOps { |
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
buf.data.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(); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
let len = buf.data.len(); |
|
|
|
|
if len > 1 { |
|
|
|
|
let mut start = 0; |
|
|
|
|
let mut end = len - 1; |
|
|
|
|
while start < end { |
|
|
|
|
stack.swap(start, end); |
|
|
|
|
buf.data.swap(start, end); |
|
|
|
|
start += 1; |
|
|
|
|
end -= 1; |
|
|
|
|
} |
|
|
|
@ -179,20 +197,22 @@ impl OpTrait for BufOps { |
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
// TODO figure out how to avoid cloning
|
|
|
|
|
let buf2 = store.buffers.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.data.clone(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
buf.data.extend(buf2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
// TODO figure out how to avoid cloning
|
|
|
|
|
let buf2 = store.buffers.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.data.clone(); |
|
|
|
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?; |
|
|
|
|
for v in buf2.into_iter().rev() { |
|
|
|
|
buf.data.push_front(v); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -257,12 +277,61 @@ impl OpTrait for BufOps { |
|
|
|
|
BufOps::PrependBuf { obj, obj2 } => { |
|
|
|
|
sexp::list(&[A("bfprep"), A(obj), A(obj2)]) |
|
|
|
|
} |
|
|
|
|
BufOps::SetIoMode { obj, mode } => { |
|
|
|
|
sexp::list(&[A("bfio"), A(obj), A(mode.to_value())]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> { |
|
|
|
|
let stacks: &mut ExtData = state.ext_mut(); |
|
|
|
|
Ok(stacks.store.remove(&handle).map(|_| ())) |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
Ok(store.buffers.remove(&handle).map(|_| ())) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Run-time method called to read an object (using the object handle syntax)
|
|
|
|
|
pub(crate) fn read_obj(state: &mut RunState, handle: Value) |
|
|
|
|
-> Result<Option<Value>, Fault> |
|
|
|
|
{ |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
if let Some(buf) = store.buffers.get_mut(&handle) { |
|
|
|
|
match match buf.iomode { |
|
|
|
|
BufIoMode::Queue => buf.data.pop_front(), |
|
|
|
|
BufIoMode::ReverseQueue => buf.data.pop_back(), |
|
|
|
|
BufIoMode::Stack => buf.data.pop_back(), |
|
|
|
|
BufIoMode::ReverseStack => buf.data.pop_front() |
|
|
|
|
} { |
|
|
|
|
None => { |
|
|
|
|
state.set_flag(Flag::Overflow, true); |
|
|
|
|
state.set_flag(Flag::Empty, true); |
|
|
|
|
Ok(Some(0)) |
|
|
|
|
} |
|
|
|
|
Some(val) => { |
|
|
|
|
let em = buf.data.is_empty(); |
|
|
|
|
state.set_flag(Flag::Empty, em); |
|
|
|
|
Ok(Some(val)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
Ok(None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Run-time method called to write an object (using the object handle syntax)
|
|
|
|
|
pub(crate) fn write_obj(state: &mut RunState, handle: Value, value: Value) -> Result<Option<()>, Fault> |
|
|
|
|
{ |
|
|
|
|
let store: &mut ExtData = state.ext_mut(); |
|
|
|
|
if let Some(buf) = store.buffers.get_mut(&handle) { |
|
|
|
|
match buf.iomode { |
|
|
|
|
BufIoMode::Queue => buf.data.push_back(value), |
|
|
|
|
BufIoMode::ReverseQueue => buf.data.push_front(value), |
|
|
|
|
BufIoMode::Stack => buf.data.push_back(value), |
|
|
|
|
BufIoMode::ReverseStack => buf.data.push_front(value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(Some(())) |
|
|
|
|
} else { |
|
|
|
|
Ok(None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|