add rpush and rpop stack instructions

pull/21/head
Ondřej Hruška 4 years ago
parent 7ce51c0cc6
commit f4ced467e4
  1. 2
      crsn_stacks/src/defs.rs
  2. 89
      crsn_stacks/src/exec.rs
  3. 14
      crsn_stacks/src/parse.rs
  4. 22
      examples/stacks.csn

@ -5,4 +5,6 @@ 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 },
}

@ -10,6 +10,7 @@ use crate::defs::StackOp;
use crsn::sexp::Sexp;
use crsn::sexp;
use crsn::utils::A;
use crsn::asm::data::{RdObj, Rd, Wr};
#[derive(Debug, Default)]
struct Stacks {
@ -28,40 +29,20 @@ impl OpTrait for StackOp {
state.write(*dst, id)?;
}
StackOp::Push { obj, src } => {
state.clear_status();
let handle = state.read_obj(*obj)?;
let val = state.read(*src)?;
let stacks: &mut Stacks = state.ext_mut();
stacks.store.get_mut(&handle)
.ok_or_else(|| Fault::ObjectNotExist(handle))?
.push_back(val);
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 } => {
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 = stack.pop_back();
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)?;
prepare_pop(state, dst, obj,
|stack| stack.pop_back())?;
}
StackOp::ReversePop { dst, obj } => {
prepare_pop(state, dst, obj,
|stack| stack.pop_front())?;
}
}
@ -73,11 +54,55 @@ impl OpTrait for StackOp {
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(mut 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(())
}

@ -27,6 +27,20 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
}
}
"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));
}

@ -10,5 +10,27 @@
(pop r1 @r0)
(cmp r1 1 (ne? (fault)))
; test reverse push
(push @r0 1)
(push @r0 7)
(rpush @r0 8)
(pop r1 @r0)
(cmp r1 7 (ne? (fault)))
(pop r1 @r0)
(cmp r1 1 (ne? (fault)))
(pop r1 @r0)
(cmp r1 8 (ne? (fault)))
; test reverse pop
(push @r0 1000)
(push @r0 2000)
(rpop r1 @r0)
(cmp r1 1000 (ne? (fault)))
(drop @r0)
)

Loading…
Cancel
Save