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