From ee59096821cbd90a623dd4d98544b7762b2ae9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 10 Oct 2020 01:26:40 +0200 Subject: [PATCH] buffer module, replacing stacks. TODO: docs, fix parsing of "numbers tuple" in mkbfv (consumed by the conditional branch parser) --- Cargo.lock | 12 +- Cargo.toml | 2 +- crsn/src/asm/instr/cond.rs | 32 +++- crsn/src/asm/parse/arg_parser.rs | 2 +- crsn/src/builtin/exec.rs | 4 +- crsn/src/runtime/frame/status.rs | 42 ++++- {crsn_stacks => crsn_buf}/Cargo.toml | 2 +- crsn_buf/src/defs.rs | 31 +++ crsn_buf/src/exec.rs | 269 +++++++++++++++++++++++++++ {crsn_stacks => crsn_buf}/src/lib.rs | 8 +- crsn_buf/src/parse.rs | 147 +++++++++++++++ crsn_stacks/src/defs.rs | 10 - crsn_stacks/src/exec.rs | 108 ----------- crsn_stacks/src/parse.rs | 49 ----- examples/stacks.csn | 28 +-- examples/stdio.csn | 54 ++++-- launcher/Cargo.toml | 2 +- launcher/src/main.rs | 4 +- 18 files changed, 576 insertions(+), 230 deletions(-) rename {crsn_stacks => crsn_buf}/Cargo.toml (91%) create mode 100644 crsn_buf/src/defs.rs create mode 100644 crsn_buf/src/exec.rs rename {crsn_stacks => crsn_buf}/src/lib.rs (90%) create mode 100644 crsn_buf/src/parse.rs delete mode 100644 crsn_stacks/src/defs.rs delete mode 100644 crsn_stacks/src/exec.rs delete mode 100644 crsn_stacks/src/parse.rs diff --git a/Cargo.lock b/Cargo.lock index c285660..79659a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,20 +208,20 @@ dependencies = [ ] [[package]] -name = "crsn_screen" +name = "crsn_buf" version = "0.1.0" dependencies = [ "crsn", - "log", - "minifb", - "parking_lot", ] [[package]] -name = "crsn_stacks" +name = "crsn_screen" version = "0.1.0" dependencies = [ "crsn", + "log", + "minifb", + "parking_lot", ] [[package]] @@ -377,8 +377,8 @@ dependencies = [ "clappconfig", "crsn", "crsn_arith", + "crsn_buf", "crsn_screen", - "crsn_stacks", "crsn_stdio", "log", "serde", diff --git a/Cargo.toml b/Cargo.toml index 44573dd..7691d0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [ "launcher", "crsn", "crsn_arith", - "crsn_stacks", "crsn_screen", "crsn_stdio", + "crsn_buf", ] diff --git a/crsn/src/asm/instr/cond.rs b/crsn/src/asm/instr/cond.rs index 4aa68ab..7be6b31 100644 --- a/crsn/src/asm/instr/cond.rs +++ b/crsn/src/asm/instr/cond.rs @@ -45,6 +45,14 @@ pub enum Cond { Carry, /// Carry not set NotCarry, + // Full + Full, + /// Not full + NotFull, + // Empty + Empty, + /// Not empty + NotEmpty, } pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result { @@ -59,14 +67,18 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result { "ge" | ">=" | "≥" => Cond::GreaterOrEqual, "pos" | "+" | ">0" => Cond::Positive, "neg" | "-" | "<0" => Cond::Negative, - "npos" | "!+" | "0-" | "<=0" | "≥0" => Cond::NonPositive, - "nneg" | "!-" | "0+" | ">=0" | "≤0" => Cond::NonNegative, + "npos" | "0-" | "<=0" | "≥0" => Cond::NonPositive, + "nneg" | "0+" | ">=0" | "≤0" => Cond::NonNegative, "c" => Cond::Carry, - "nc" | "!c" => Cond::NotCarry, + "nc" => Cond::NotCarry, + "em" => Cond::Empty, + "nem" => Cond::NotEmpty, + "f" => Cond::Full, + "nf" => Cond::NotFull, "valid" => Cond::Valid, "inval" => Cond::Invalid, - "ov" | "^" => Cond::Overflow, - "nov" | "!ov" | "!^" => Cond::NotOverflow, + "ov" => Cond::Overflow, + "nov" => Cond::NotOverflow, _ => { return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone())); } @@ -80,6 +92,10 @@ impl Display for Cond { Cond::NotEqual => "ne", Cond::Zero => "z", Cond::NotZero => "nz", + Cond::Empty => "emp", + Cond::NotEmpty => "nemp", + Cond::Full => "full", + Cond::NotFull => "nfull", Cond::Lower => "lt", Cond::LowerOrEqual => "le", Cond::Greater => "gt", @@ -108,6 +124,12 @@ impl Not for Cond { Cond::Overflow => Cond::NotOverflow, Cond::Carry => Cond::NotCarry, + Cond::Empty => Cond::NotEmpty, + Cond::NotEmpty => Cond::Empty, + + Cond::Full => Cond::NotFull, + Cond::NotFull => Cond::Full, + Cond::Positive => Cond::NonPositive, Cond::Negative => Cond::NonNegative, Cond::NonPositive => Cond::Positive, diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index 61a62b4..f040251 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -90,7 +90,7 @@ impl<'a> TokenParser<'a> { parse_rd(next, self.pcx) } - /// Get the next entry as read location + /// Get the next entry as an object location pub fn next_rdobj(&mut self) -> Result { match parse_rd(self.next_or_err()?, self.pcx)? { Rd(RdData::RegObject(reg), Mask::FULL) => { diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index 41c0386..ff2861b 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -123,7 +123,7 @@ impl OpTrait for BuiltinOp { BuiltinOp::Delete(obj) => { let x = state.read(Rd::new(RdData::Register(obj.reg())))?; - trace!("Drop object: {:#x}", x); + trace!("Del object: {:#x}", x); let mut dropped = false; for ex in info.program.extensions.iter() { if ex.drop_obj(info, state, x)?.is_some() { @@ -131,7 +131,7 @@ impl OpTrait for BuiltinOp { } } if !dropped { - warn!("Object {:#x} to drop does not exist!", x); + warn!("Object {:#x} to del does not exist!", x); state.set_flag(Cond::Invalid, true); } } diff --git a/crsn/src/runtime/frame/status.rs b/crsn/src/runtime/frame/status.rs index 0ed5096..7f1d2fa 100644 --- a/crsn/src/runtime/frame/status.rs +++ b/crsn/src/runtime/frame/status.rs @@ -24,6 +24,10 @@ pub struct StatusFlags { pub invalid: bool, /// Arithmetic carry pub carry: bool, + /// Buffer full + pub full: bool, + /// Buffer empty + pub empty: bool, } impl StatusFlags { @@ -43,6 +47,8 @@ impl StatusFlags { if self.overflow { val |= 0x40; } if self.invalid { val |= 0x80; } if self.carry { val |= 0x100; } + if self.full { val |= 0x200; } + if self.empty { val |= 0x400; } val } @@ -56,6 +62,8 @@ impl StatusFlags { if val & 0x40 != 0 { self.overflow = true; } if val & 0x80 != 0 { self.invalid = true; } if val & 0x100 != 0 { self.carry = true; } + if val & 0x200 != 0 { self.full = true; } + if val & 0x400 != 0 { self.empty = true; } } #[inline(always)] @@ -85,7 +93,11 @@ impl StatusFlags { Cond::Invalid => self.invalid, Cond::Valid => !self.invalid, Cond::Carry => self.carry, - Cond::NotCarry => !self.carry + Cond::NotCarry => !self.carry, + Cond::Full => self.full, + Cond::NotFull => !self.full, + Cond::Empty => self.empty, + Cond::NotEmpty => !self.empty, } } @@ -121,6 +133,12 @@ impl StatusFlags { Cond::Carry => { self.carry = true; } + Cond::Empty => { + self.empty = true; + } + Cond::Full => { + self.full = true; + } other => { error!("Cannot set cond by {:?}", other); // ...and do nothing. Don't panic, we don't want to crash the runtime! @@ -133,32 +151,38 @@ impl Display for StatusFlags { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("[")?; if self.equal { - f.write_str(" E")?; + f.write_str(" =")?; } if self.zero { - f.write_str(" Z")?; + f.write_str(" 0")?; } if self.lower { - f.write_str(" L")?; + f.write_str(" Lt")?; } if self.greater { - f.write_str(" G")?; + f.write_str(" Gt")?; } if self.positive { - f.write_str(" P")?; + f.write_str(" +")?; } if self.negative { - f.write_str(" N")?; + f.write_str(" -")?; } if self.overflow { - f.write_str(" V")?; + f.write_str(" Ov")?; } if self.invalid { - f.write_str(" X")?; + f.write_str(" Inv")?; } if self.carry { f.write_str(" C")?; } + if self.full { + f.write_str(" Full")?; + } + if self.empty { + f.write_str(" Emp")?; + } f.write_str(" ]")?; Ok(()) diff --git a/crsn_stacks/Cargo.toml b/crsn_buf/Cargo.toml similarity index 91% rename from crsn_stacks/Cargo.toml rename to crsn_buf/Cargo.toml index dfb3421..3a1ac6c 100644 --- a/crsn_stacks/Cargo.toml +++ b/crsn_buf/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "crsn_stacks" +name = "crsn_buf" version = "0.1.0" authors = ["Ondřej Hruška "] edition = "2018" diff --git a/crsn_buf/src/defs.rs b/crsn_buf/src/defs.rs new file mode 100644 index 0000000..7a72cd1 --- /dev/null +++ b/crsn_buf/src/defs.rs @@ -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), + 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 }, +} diff --git a/crsn_buf/src/exec.rs b/crsn_buf/src/exec.rs new file mode 100644 index 0000000..5c2281f --- /dev/null +++ b/crsn_buf/src/exec.rs @@ -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>, +} + +// TODO optimize and DRY + +impl OpTrait for BufOps { + fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { + 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, Fault> { + let stacks: &mut ExtData = state.ext_mut(); + Ok(stacks.store.remove(&handle).map(|_| ())) +} diff --git a/crsn_stacks/src/lib.rs b/crsn_buf/src/lib.rs similarity index 90% rename from crsn_stacks/src/lib.rs rename to crsn_buf/src/lib.rs index 424a813..0f8f175 100644 --- a/crsn_stacks/src/lib.rs +++ b/crsn_buf/src/lib.rs @@ -12,17 +12,17 @@ mod parse; mod exec; #[derive(Debug, Clone)] -pub struct StackOps; +pub struct BufOps; -impl StackOps { +impl BufOps { pub fn new() -> Box { Box::new(Self) } } -impl CrsnExtension for StackOps { +impl CrsnExtension for BufOps { fn name(&self) -> &'static str { - "stacks" + "bufs" } fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { diff --git a/crsn_buf/src/parse.rs b/crsn_buf/src/parse.rs new file mode 100644 index 0000000..e51dc45 --- /dev/null +++ b/crsn_buf/src/parse.rs @@ -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, 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)); + } + })) +} diff --git a/crsn_stacks/src/defs.rs b/crsn_stacks/src/defs.rs deleted file mode 100644 index ddef1db..0000000 --- a/crsn_stacks/src/defs.rs +++ /dev/null @@ -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 }, -} diff --git a/crsn_stacks/src/exec.rs b/crsn_stacks/src/exec.rs deleted file mode 100644 index e7313f6..0000000 --- a/crsn_stacks/src/exec.rs +++ /dev/null @@ -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>, -} - -impl OpTrait for StackOp { - fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { - 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, 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) -> ()) -> 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) -> Option) -> 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(()) -} diff --git a/crsn_stacks/src/parse.rs b/crsn_stacks/src/parse.rs deleted file mode 100644 index 5fb3199..0000000 --- a/crsn_stacks/src/parse.rs +++ /dev/null @@ -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, 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)); - } - })) -} diff --git a/examples/stacks.csn b/examples/stacks.csn index ca550de..928adb5 100644 --- a/examples/stacks.csn +++ b/examples/stacks.csn @@ -1,35 +1,35 @@ ( - (stack r0) + (mkbf r0) - (push @r0 1) - (push @r0 2) + (bfpush @r0 1) + (bfpush @r0 2) - (pop r1 @r0) + (bfpop r1 @r0) (cmp r1 2 (ne? (fault))) - (pop r1 @r0) + (bfpop r1 @r0) (cmp r1 1 (ne? (fault))) ; test reverse push - (push @r0 '🐈') - (push @r0 7) - (rpush @r0 8) + (bfpush @r0 '🐈') + (bfpush @r0 7) + (bfrpush @r0 8) - (pop r1 @r0) + (bfpop r1 @r0) (cmp r1 7 (ne? (fault))) - (pop r1 @r0) + (bfpop r1 @r0) (cmp r1 '🐈' (ne? (fault))) - (pop r1 @r0) + (bfpop r1 @r0) (cmp r1 8 (ne? (fault))) ; test reverse pop - (push @r0 1000) - (push @r0 2000) + (bfpush @r0 1000) + (bfpush @r0 2000) - (rpop r1 @r0) + (bfrpop r1 @r0) (cmp r1 1000 (ne? (fault))) (del @r0) diff --git a/examples/stdio.csn b/examples/stdio.csn index a533a6b..10808eb 100644 --- a/examples/stdio.csn +++ b/examples/stdio.csn @@ -1,27 +1,47 @@ ( - ; we don't have strings yet 👌 - (ld @stdout 'P') (ld @stdout 'r') (ld @stdout 'e') (ld @stdout 's') (ld @stdout 's') (ld @stdout ' ') - (ld @stdout 'q') (ld @stdout ' ') - (ld @stdout 't') (ld @stdout 'o') (ld @stdout ' ') - (ld @stdout 'q') (ld @stdout 'u') (ld @stdout 'i') (ld @stdout 't') - (ld @stdout '…') (ld @stdout ' ') + ; Create a table of strings + (sym TXT r7) + (def T_HELLO 0) + (def T_UNK 1) + (mkbf TXT) + (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) - (ld r0 @stdin) + (ld r0 @stdin) - ; exit by pressing 'q' - (cmp r0 'q' - (=? (ld @stdout '\n') - (halt))) + (cmp r0 'q' + (eq? (ld @stdout '\n') + (halt))) - ; uppercase ASCII - (cmp r0 'a' (? (j :badchar))) - (sub r0 ' ') - (ld @stdout r0) + ; uppercase ASCII + (cmp r0 'a' (? (j :badchar))) + (sub r0 ' ') + (ld @stdout r0) (j :loop) (:badchar) - (ld @stdout '🐈') ; show a kitty if not ASCII + (ld @stdout r0) + (bfrd r0 @TXT T_UNK) + (call print r0) (j :loop) ) diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml index e61cac8..6c2b7e7 100644 --- a/launcher/Cargo.toml +++ b/launcher/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] crsn = { path = "../crsn" } crsn_arith = { path = "../crsn_arith" } -crsn_stacks = { path = "../crsn_stacks" } +crsn_buf = { path = "../crsn_buf" } crsn_screen = { path = "../crsn_screen" } crsn_stdio = { path = "../crsn_stdio" } diff --git a/launcher/src/main.rs b/launcher/src/main.rs index 7da65cb..956c3f2 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -14,8 +14,8 @@ use crsn::module::{OpTrait, CrsnUniq}; use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams}; use crsn_arith::ArithOps; use crsn_screen::ScreenOps; -use crsn_stacks::StackOps; use crsn_stdio::StdioOps; +use crsn_buf::BufOps; mod read_file; mod serde_duration_millis; @@ -134,7 +134,7 @@ fn main() -> anyhow::Result<()> { let parsed = crsn::asm::assemble(&source, &uniq, vec![ ArithOps::new(), - StackOps::new(), + BufOps::new(), ScreenOps::new(), StdioOps::new(), ])?;