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] | ||||
| name = "crsn_stacks" | ||||
| name = "crsn_buf" | ||||
| version = "0.1.0" | ||||
| authors = ["Ondřej Hruška <ondra@ondrovo.com>"] | ||||
| 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)); | ||||
|         } | ||||
|     })) | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue