add rpush and rpop stack instructions

floats
Ondřej Hruška 4 years ago
parent 7ce51c0cc6
commit f4ced467e4
  1. 2
      crsn_stacks/src/defs.rs
  2. 73
      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 }, NewStack { dst: Wr },
Push { obj: RdObj, src: Rd }, Push { obj: RdObj, src: Rd },
Pop { dst: Wr, obj: RdObj }, 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::Sexp;
use crsn::sexp; use crsn::sexp;
use crsn::utils::A; use crsn::utils::A;
use crsn::asm::data::{RdObj, Rd, Wr};
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct Stacks { struct Stacks {
@ -28,16 +29,57 @@ impl OpTrait for StackOp {
state.write(*dst, id)?; state.write(*dst, id)?;
} }
StackOp::Push { obj, src } => { 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(mut state: &mut RunState, obj: &RdObj, src: &Rd, pushfn : impl FnOnce(&mut VecDeque<Value>, Value) -> ()) -> Result<(), Fault> {
state.clear_status(); state.clear_status();
let handle = state.read_obj(*obj)?; let handle = state.read_obj(*obj)?;
let val = state.read(*src)?; let val = state.read(*src)?;
let stacks: &mut Stacks = state.ext_mut(); let stacks: &mut Stacks = state.ext_mut();
stacks.store.get_mut(&handle) let mutable = stacks.store.get_mut(&handle)
.ok_or_else(|| Fault::ObjectNotExist(handle))? .ok_or_else(|| Fault::ObjectNotExist(handle))?;
.push_back(val);
} pushfn(mutable, val);
StackOp::Pop { dst, obj } => { Ok(())
}
fn prepare_pop(state: &mut RunState, dst: &Wr, obj: &RdObj, popfn : impl FnOnce(&mut VecDeque<Value>) -> Option<Value>) -> Result<(), Fault> {
state.clear_status(); state.clear_status();
let handle = state.read_obj(*obj)?; let handle = state.read_obj(*obj)?;
@ -45,7 +87,7 @@ impl OpTrait for StackOp {
let stack = stacks.store.get_mut(&handle) let stack = stacks.store.get_mut(&handle)
.ok_or_else(|| Fault::ObjectNotExist(handle))?; .ok_or_else(|| Fault::ObjectNotExist(handle))?;
let val = stack.pop_back(); let val = popfn(stack);
if stack.is_empty() { if stack.is_empty() {
state.set_flag(Cond::Zero, true); state.set_flag(Cond::Zero, true);
@ -62,22 +104,5 @@ impl OpTrait for StackOp {
}; };
state.write(*dst, val)?; state.write(*dst, val)?;
} Ok(())
}
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)]),
}
}
}
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(|_| ()))
} }

@ -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 => { _other => {
return Ok(ParseRes::Unknown(args)); return Ok(ParseRes::Unknown(args));
} }

@ -10,5 +10,27 @@
(pop r1 @r0) (pop r1 @r0)
(cmp r1 1 (ne? (fault))) (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) (drop @r0)
) )

Loading…
Cancel
Save