forked from MightyPork/crsn
buffer module, replacing stacks. TODO: docs, fix parsing of "numbers tuple" in mkbfv (consumed by the conditional branch parser)
parent
1f2dbaa81d
commit
ee59096821
@ -1,5 +1,5 @@ |
|||||||
[package] |
[package] |
||||||
name = "crsn_stacks" |
name = "crsn_buf" |
||||||
version = "0.1.0" |
version = "0.1.0" |
||||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
||||||
edition = "2018" |
edition = "2018" |
@ -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 }, |
||||||
|
} |
@ -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(|_| ())) |
||||||
|
} |
@ -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)); |
||||||
|
} |
||||||
|
})) |
||||||
|
} |
@ -1,10 +0,0 @@ |
|||||||
use crsn::asm::data::{Rd, RdObj, Wr}; |
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)] |
|
||||||
pub enum StackOp { |
|
||||||
NewStack { dst: Wr }, |
|
||||||
Push { obj: RdObj, src: Rd }, |
|
||||||
Pop { dst: Wr, obj: RdObj }, |
|
||||||
ReversePush { obj: RdObj, src: Rd }, |
|
||||||
ReversePop { dst: Wr, obj: RdObj }, |
|
||||||
} |
|
@ -1,108 +0,0 @@ |
|||||||
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<Value, VecDeque<Value>>, |
|
||||||
} |
|
||||||
|
|
||||||
impl OpTrait for StackOp { |
|
||||||
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { |
|
||||||
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<Option<()>, 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>, 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<Value>) -> Option<Value>) -> 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(()) |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
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; |
|
||||||
|
|
||||||
use crate::defs::StackOp; |
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> { |
|
||||||
Ok(ParseRes::ext(match keyword { |
|
||||||
"stack" => { |
|
||||||
StackOp::NewStack { |
|
||||||
dst: args.next_wr()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
"push" => { |
|
||||||
StackOp::Push { |
|
||||||
obj: args.next_rdobj()?, |
|
||||||
src: args.next_rd()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
"pop" => { |
|
||||||
StackOp::Pop { |
|
||||||
dst: args.next_wr()?, |
|
||||||
obj: args.next_rdobj()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
"rpush" => { |
|
||||||
StackOp::ReversePush { |
|
||||||
obj: args.next_rdobj()?, |
|
||||||
src: args.next_rd()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
"rpop" => { |
|
||||||
StackOp::ReversePop { |
|
||||||
dst: args.next_wr()?, |
|
||||||
obj: args.next_rdobj()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
_other => { |
|
||||||
return Ok(ParseRes::Unknown(args)); |
|
||||||
} |
|
||||||
})) |
|
||||||
} |
|
@ -1,27 +1,47 @@ |
|||||||
( |
( |
||||||
; we don't have strings yet 👌 |
; Create a table of strings |
||||||
(ld @stdout 'P') (ld @stdout 'r') (ld @stdout 'e') (ld @stdout 's') (ld @stdout 's') (ld @stdout ' ') |
(sym TXT r7) |
||||||
(ld @stdout 'q') (ld @stdout ' ') |
(def T_HELLO 0) |
||||||
(ld @stdout 't') (ld @stdout 'o') (ld @stdout ' ') |
(def T_UNK 1) |
||||||
(ld @stdout 'q') (ld @stdout 'u') (ld @stdout 'i') (ld @stdout 't') |
(mkbf TXT) |
||||||
(ld @stdout '…') (ld @stdout ' ') |
(mkbfv r0 "*** Type ascii to uppercase. Press q to quit. ***\n") |
||||||
|
(bfins @TXT T_HELLO r0) |
||||||
|
(mkbfv r0 "🐈") |
||||||
|
(bfins @TXT T_UNK r0) |
||||||
|
|
||||||
|
; Print string from the table |
||||||
|
(bfrd r0 @TXT T_HELLO) |
||||||
|
(call print r0) |
||||||
|
|
||||||
|
(proc print str |
||||||
|
; Print string from a buffer |
||||||
|
(sym ch r1) (sym pos r2) |
||||||
|
(ld pos 0) |
||||||
|
(:next) |
||||||
|
(bfrd ch @str pos) |
||||||
|
(ret.ov) |
||||||
|
(ld @stdout ch) |
||||||
|
(inc pos) |
||||||
|
(j :next) |
||||||
|
) |
||||||
|
|
||||||
(:loop) |
(:loop) |
||||||
(ld r0 @stdin) |
(ld r0 @stdin) |
||||||
|
|
||||||
; exit by pressing 'q' |
(cmp r0 'q' |
||||||
(cmp r0 'q' |
(eq? (ld @stdout '\n') |
||||||
(=? (ld @stdout '\n') |
(halt))) |
||||||
(halt))) |
|
||||||
|
|
||||||
; uppercase ASCII |
; uppercase ASCII |
||||||
(cmp r0 'a' (<? (j :badchar))) |
(cmp r0 'a' (<? (j :badchar))) |
||||||
(cmp r0 'z' (>? (j :badchar))) |
(cmp r0 'z' (>? (j :badchar))) |
||||||
(sub r0 ' ') |
(sub r0 ' ') |
||||||
(ld @stdout r0) |
(ld @stdout r0) |
||||||
(j :loop) |
(j :loop) |
||||||
|
|
||||||
(:badchar) |
(:badchar) |
||||||
(ld @stdout '🐈') ; show a kitty if not ASCII |
(ld @stdout r0) |
||||||
|
(bfrd r0 @TXT T_UNK) |
||||||
|
(call print r0) |
||||||
(j :loop) |
(j :loop) |
||||||
) |
) |
||||||
|
Loading…
Reference in new issue