buffer module, replacing stacks. TODO: docs, fix parsing of "numbers tuple" in mkbfv (consumed by the conditional branch parser)

This commit is contained in:
2020-10-10 01:26:40 +02:00
parent 1f2dbaa81d
commit ee59096821
18 changed files with 578 additions and 232 deletions
+31
View File
@@ -0,0 +1,31 @@
use crsn::asm::data::{Rd, RdObj, Wr};
use crsn::asm::data::literal::Value;
#[derive(Clone, Debug, PartialEq)]
pub enum BufValue {
Zeros(Rd),
Values(Vec<Rd>),
Chars(String),
}
#[derive(Clone, Debug, PartialEq)]
pub enum BufOps {
New { dst: Wr, value: BufValue },
// Elementary ops
Read { dst: Wr, obj: RdObj, idx: Rd },
GetLen { dst: Wr, obj: RdObj },
Write { obj: RdObj, idx: Rd, value: Rd },
Insert { obj: RdObj, idx: Rd, value: Rd },
Remove { dst: Wr, obj: RdObj, idx: Rd },
// Whole buffer ops
Resize { obj: RdObj, len: Rd },
Reverse { obj: RdObj },
AppendBuf { obj: RdObj, obj2: RdObj },
PrependBuf { obj: RdObj, obj2: RdObj },
// Stack-style ops
Push { obj: RdObj, src: Rd },
Pop { dst: Wr, obj: RdObj },
}
+269
View File
@@ -0,0 +1,269 @@
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, atom_qs};
use crsn::utils::A;
use crate::defs::{BufOps, BufValue};
#[derive(Debug, Default)]
struct ExtData {
store: HashMap<Value, VecDeque<Value>>,
}
// TODO optimize and DRY
impl OpTrait for BufOps {
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
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<Option<()>, Fault> {
let stacks: &mut ExtData = state.ext_mut();
Ok(stacks.store.remove(&handle).map(|_| ()))
}
+35
View File
@@ -0,0 +1,35 @@
use crsn::asm::data::literal::Value;
use crsn::asm::error::CrsnError;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes};
use crsn::runtime::fault::Fault;
use crsn::runtime::run_thread::{RunState, ThreadInfo};
use crsn::sexp::SourcePosition;
mod defs;
mod parse;
mod exec;
#[derive(Debug, Clone)]
pub struct BufOps;
impl BufOps {
pub fn new() -> Box<dyn CrsnExtension> {
Box::new(Self)
}
}
impl CrsnExtension for BufOps {
fn name(&self) -> &'static str {
"bufs"
}
fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
parse::parse(pos, keyword, args)
}
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
exec::drop_obj(state, handle)
}
}
+147
View File
@@ -0,0 +1,147 @@
use crsn::asm::error::CrsnError;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes;
use crsn::sexp::{SourcePosition, Sexp, Atom};
use crate::defs::{BufOps, BufValue};
use crsn::asm::data::Rd;
use crsn::sexp;
use crsn::asm::parse::parse_data::parse_rd;
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
Ok(ParseRes::ext(match keyword {
"mkbf" => {
let dst = args.next_wr()?;
let len = if args.have_more() {
args.next_rd()?
} else {
Rd::immediate(0)
};
BufOps::New { dst, value: BufValue::Zeros(len) }
}
"mkbfv" => {
let dst = args.next_wr()?;
let next = args.next_or_err()?;
match next {
Sexp::Atom(Atom::QS(s), _) => {
BufOps::New {
dst,
value: BufValue::Chars(s),
}
}
Sexp::List(list, _) => {
let mut vals = vec![];
for v in list {
vals.push(parse_rd(v, args.pcx)?);
}
BufOps::New {
dst,
value: BufValue::Values(vals),
}
}
other => {
return Err(CrsnError::Parse("Expected quoted string or a tuple of values".into(), other.pos().clone()));
}
}
}
"bfrd" => {
let dst = args.next_wr()?;
let obj = args.next_rdobj()?;
let idx = args.next_rd()?;
BufOps::Read { dst, obj, idx }
}
"bfwr" => {
let obj = args.next_rdobj()?;
let idx = args.next_rd()?;
let value = args.next_rd()?;
BufOps::Write { obj, idx, value }
}
"bfsz" => {
let dst = args.next_wr()?;
let obj = args.next_rdobj()?;
BufOps::GetLen { dst, obj }
}
"bfins" => {
let obj = args.next_rdobj()?;
let idx = args.next_rd()?;
let value = args.next_rd()?;
BufOps::Insert { obj, idx, value }
}
"bfrm" => {
let dst = args.next_wr()?;
let obj = args.next_rdobj()?;
let idx = args.next_rd()?;
BufOps::Remove { dst, obj, idx }
}
"bfpush" => {
BufOps::Push {
obj: args.next_rdobj()?,
src: args.next_rd()?,
}
}
"bfpop" => {
BufOps::Pop {
dst: args.next_wr()?,
obj: args.next_rdobj()?,
}
}
"bfrpush" => {
BufOps::Insert {
obj: args.next_rdobj()?,
idx: Rd::immediate(0),
value: args.next_rd()?,
}
}
"bfrpop" => {
BufOps::Remove {
dst: args.next_wr()?,
obj: args.next_rdobj()?,
idx: Rd::immediate(0),
}
}
"bfrsz" => {
BufOps::Resize {
obj: args.next_rdobj()?,
len: args.next_rd()?,
}
}
"bfrev" => {
BufOps::Reverse {
obj: args.next_rdobj()?,
}
}
"bfapp" => {
BufOps::AppendBuf {
obj: args.next_rdobj()?,
obj2: args.next_rdobj()?,
}
}
"bfprep" => {
BufOps::PrependBuf {
obj: args.next_rdobj()?,
obj2: args.next_rdobj()?,
}
}
_other => {
return Ok(ParseRes::Unknown(args));
}
}))
}