buffer module, replacing stacks. TODO: docs, fix parsing of "numbers tuple" in mkbfv (consumed by the conditional branch parser)

floats
Ondřej Hruška 4 years ago
parent 1f2dbaa81d
commit ee59096821
Signed by untrusted user: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 12
      Cargo.lock
  2. 2
      Cargo.toml
  3. 32
      crsn/src/asm/instr/cond.rs
  4. 2
      crsn/src/asm/parse/arg_parser.rs
  5. 4
      crsn/src/builtin/exec.rs
  6. 42
      crsn/src/runtime/frame/status.rs
  7. 2
      crsn_buf/Cargo.toml
  8. 31
      crsn_buf/src/defs.rs
  9. 269
      crsn_buf/src/exec.rs
  10. 8
      crsn_buf/src/lib.rs
  11. 147
      crsn_buf/src/parse.rs
  12. 10
      crsn_stacks/src/defs.rs
  13. 108
      crsn_stacks/src/exec.rs
  14. 49
      crsn_stacks/src/parse.rs
  15. 28
      examples/stacks.csn
  16. 38
      examples/stdio.csn
  17. 2
      launcher/Cargo.toml
  18. 4
      launcher/src/main.rs

12
Cargo.lock generated

@ -208,20 +208,20 @@ dependencies = [
] ]
[[package]] [[package]]
name = "crsn_screen" name = "crsn_buf"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"crsn", "crsn",
"log",
"minifb",
"parking_lot",
] ]
[[package]] [[package]]
name = "crsn_stacks" name = "crsn_screen"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"crsn", "crsn",
"log",
"minifb",
"parking_lot",
] ]
[[package]] [[package]]
@ -377,8 +377,8 @@ dependencies = [
"clappconfig", "clappconfig",
"crsn", "crsn",
"crsn_arith", "crsn_arith",
"crsn_buf",
"crsn_screen", "crsn_screen",
"crsn_stacks",
"crsn_stdio", "crsn_stdio",
"log", "log",
"serde", "serde",

@ -3,7 +3,7 @@ members = [
"launcher", "launcher",
"crsn", "crsn",
"crsn_arith", "crsn_arith",
"crsn_stacks",
"crsn_screen", "crsn_screen",
"crsn_stdio", "crsn_stdio",
"crsn_buf",
] ]

@ -45,6 +45,14 @@ pub enum Cond {
Carry, Carry,
/// Carry not set /// Carry not set
NotCarry, NotCarry,
// Full
Full,
/// Not full
NotFull,
// Empty
Empty,
/// Not empty
NotEmpty,
} }
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> { pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
@ -59,14 +67,18 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
"ge" | ">=" | "≥" => Cond::GreaterOrEqual, "ge" | ">=" | "≥" => Cond::GreaterOrEqual,
"pos" | "+" | ">0" => Cond::Positive, "pos" | "+" | ">0" => Cond::Positive,
"neg" | "-" | "<0" => Cond::Negative, "neg" | "-" | "<0" => Cond::Negative,
"npos" | "!+" | "0-" | "<=0" | "≥0" => Cond::NonPositive, "npos" | "0-" | "<=0" | "≥0" => Cond::NonPositive,
"nneg" | "!-" | "0+" | ">=0" | "≤0" => Cond::NonNegative, "nneg" | "0+" | ">=0" | "≤0" => Cond::NonNegative,
"c" => Cond::Carry, "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, "valid" => Cond::Valid,
"inval" => Cond::Invalid, "inval" => Cond::Invalid,
"ov" | "^" => Cond::Overflow, "ov" => Cond::Overflow,
"nov" | "!ov" | "!^" => Cond::NotOverflow, "nov" => Cond::NotOverflow,
_ => { _ => {
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone())); return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone()));
} }
@ -80,6 +92,10 @@ impl Display for Cond {
Cond::NotEqual => "ne", Cond::NotEqual => "ne",
Cond::Zero => "z", Cond::Zero => "z",
Cond::NotZero => "nz", Cond::NotZero => "nz",
Cond::Empty => "emp",
Cond::NotEmpty => "nemp",
Cond::Full => "full",
Cond::NotFull => "nfull",
Cond::Lower => "lt", Cond::Lower => "lt",
Cond::LowerOrEqual => "le", Cond::LowerOrEqual => "le",
Cond::Greater => "gt", Cond::Greater => "gt",
@ -108,6 +124,12 @@ impl Not for Cond {
Cond::Overflow => Cond::NotOverflow, Cond::Overflow => Cond::NotOverflow,
Cond::Carry => Cond::NotCarry, 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::Positive => Cond::NonPositive,
Cond::Negative => Cond::NonNegative, Cond::Negative => Cond::NonNegative,
Cond::NonPositive => Cond::Positive, Cond::NonPositive => Cond::Positive,

@ -90,7 +90,7 @@ impl<'a> TokenParser<'a> {
parse_rd(next, self.pcx) 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<RdObj, CrsnError> { pub fn next_rdobj(&mut self) -> Result<RdObj, CrsnError> {
match parse_rd(self.next_or_err()?, self.pcx)? { match parse_rd(self.next_or_err()?, self.pcx)? {
Rd(RdData::RegObject(reg), Mask::FULL) => { Rd(RdData::RegObject(reg), Mask::FULL) => {

@ -123,7 +123,7 @@ impl OpTrait for BuiltinOp {
BuiltinOp::Delete(obj) => { BuiltinOp::Delete(obj) => {
let x = state.read(Rd::new(RdData::Register(obj.reg())))?; let x = state.read(Rd::new(RdData::Register(obj.reg())))?;
trace!("Drop object: {:#x}", x); trace!("Del object: {:#x}", x);
let mut dropped = false; let mut dropped = false;
for ex in info.program.extensions.iter() { for ex in info.program.extensions.iter() {
if ex.drop_obj(info, state, x)?.is_some() { if ex.drop_obj(info, state, x)?.is_some() {
@ -131,7 +131,7 @@ impl OpTrait for BuiltinOp {
} }
} }
if !dropped { 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); state.set_flag(Cond::Invalid, true);
} }
} }

@ -24,6 +24,10 @@ pub struct StatusFlags {
pub invalid: bool, pub invalid: bool,
/// Arithmetic carry /// Arithmetic carry
pub carry: bool, pub carry: bool,
/// Buffer full
pub full: bool,
/// Buffer empty
pub empty: bool,
} }
impl StatusFlags { impl StatusFlags {
@ -43,6 +47,8 @@ impl StatusFlags {
if self.overflow { val |= 0x40; } if self.overflow { val |= 0x40; }
if self.invalid { val |= 0x80; } if self.invalid { val |= 0x80; }
if self.carry { val |= 0x100; } if self.carry { val |= 0x100; }
if self.full { val |= 0x200; }
if self.empty { val |= 0x400; }
val val
} }
@ -56,6 +62,8 @@ impl StatusFlags {
if val & 0x40 != 0 { self.overflow = true; } if val & 0x40 != 0 { self.overflow = true; }
if val & 0x80 != 0 { self.invalid = true; } if val & 0x80 != 0 { self.invalid = true; }
if val & 0x100 != 0 { self.carry = true; } if val & 0x100 != 0 { self.carry = true; }
if val & 0x200 != 0 { self.full = true; }
if val & 0x400 != 0 { self.empty = true; }
} }
#[inline(always)] #[inline(always)]
@ -85,7 +93,11 @@ impl StatusFlags {
Cond::Invalid => self.invalid, Cond::Invalid => self.invalid,
Cond::Valid => !self.invalid, Cond::Valid => !self.invalid,
Cond::Carry => self.carry, 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 => { Cond::Carry => {
self.carry = true; self.carry = true;
} }
Cond::Empty => {
self.empty = true;
}
Cond::Full => {
self.full = true;
}
other => { other => {
error!("Cannot set cond by {:?}", other); error!("Cannot set cond by {:?}", other);
// ...and do nothing. Don't panic, we don't want to crash the runtime! // ...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 { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("[")?; f.write_str("[")?;
if self.equal { if self.equal {
f.write_str(" E")?; f.write_str(" =")?;
} }
if self.zero { if self.zero {
f.write_str(" Z")?; f.write_str(" 0")?;
} }
if self.lower { if self.lower {
f.write_str(" L")?; f.write_str(" Lt")?;
} }
if self.greater { if self.greater {
f.write_str(" G")?; f.write_str(" Gt")?;
} }
if self.positive { if self.positive {
f.write_str(" P")?; f.write_str(" +")?;
} }
if self.negative { if self.negative {
f.write_str(" N")?; f.write_str(" -")?;
} }
if self.overflow { if self.overflow {
f.write_str(" V")?; f.write_str(" Ov")?;
} }
if self.invalid { if self.invalid {
f.write_str(" X")?; f.write_str(" Inv")?;
} }
if self.carry { if self.carry {
f.write_str(" C")?; f.write_str(" C")?;
} }
if self.full {
f.write_str(" Full")?;
}
if self.empty {
f.write_str(" Emp")?;
}
f.write_str(" ]")?; f.write_str(" ]")?;
Ok(()) Ok(())

@ -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(|_| ()))
}

@ -12,17 +12,17 @@ mod parse;
mod exec; mod exec;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StackOps; pub struct BufOps;
impl StackOps { impl BufOps {
pub fn new() -> Box<dyn CrsnExtension> { pub fn new() -> Box<dyn CrsnExtension> {
Box::new(Self) Box::new(Self)
} }
} }
impl CrsnExtension for StackOps { impl CrsnExtension for BufOps {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"stacks" "bufs"
} }
fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> { fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {

@ -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,35 +1,35 @@
( (
(stack r0) (mkbf r0)
(push @r0 1) (bfpush @r0 1)
(push @r0 2) (bfpush @r0 2)
(pop r1 @r0) (bfpop r1 @r0)
(cmp r1 2 (ne? (fault))) (cmp r1 2 (ne? (fault)))
(pop r1 @r0) (bfpop r1 @r0)
(cmp r1 1 (ne? (fault))) (cmp r1 1 (ne? (fault)))
; test reverse push ; test reverse push
(push @r0 '🐈') (bfpush @r0 '🐈')
(push @r0 7) (bfpush @r0 7)
(rpush @r0 8) (bfrpush @r0 8)
(pop r1 @r0) (bfpop r1 @r0)
(cmp r1 7 (ne? (fault))) (cmp r1 7 (ne? (fault)))
(pop r1 @r0) (bfpop r1 @r0)
(cmp r1 '🐈' (ne? (fault))) (cmp r1 '🐈' (ne? (fault)))
(pop r1 @r0) (bfpop r1 @r0)
(cmp r1 8 (ne? (fault))) (cmp r1 8 (ne? (fault)))
; test reverse pop ; test reverse pop
(push @r0 1000) (bfpush @r0 1000)
(push @r0 2000) (bfpush @r0 2000)
(rpop r1 @r0) (bfrpop r1 @r0)
(cmp r1 1000 (ne? (fault))) (cmp r1 1000 (ne? (fault)))
(del @r0) (del @r0)

@ -1,17 +1,35 @@
( (
; 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'
(=? (ld @stdout '\n') (eq? (ld @stdout '\n')
(halt))) (halt)))
; uppercase ASCII ; uppercase ASCII
@ -22,6 +40,8 @@
(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)
) )

@ -9,7 +9,7 @@ edition = "2018"
[dependencies] [dependencies]
crsn = { path = "../crsn" } crsn = { path = "../crsn" }
crsn_arith = { path = "../crsn_arith" } crsn_arith = { path = "../crsn_arith" }
crsn_stacks = { path = "../crsn_stacks" } crsn_buf = { path = "../crsn_buf" }
crsn_screen = { path = "../crsn_screen" } crsn_screen = { path = "../crsn_screen" }
crsn_stdio = { path = "../crsn_stdio" } crsn_stdio = { path = "../crsn_stdio" }

@ -14,8 +14,8 @@ use crsn::module::{OpTrait, CrsnUniq};
use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams}; use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams};
use crsn_arith::ArithOps; use crsn_arith::ArithOps;
use crsn_screen::ScreenOps; use crsn_screen::ScreenOps;
use crsn_stacks::StackOps;
use crsn_stdio::StdioOps; use crsn_stdio::StdioOps;
use crsn_buf::BufOps;
mod read_file; mod read_file;
mod serde_duration_millis; mod serde_duration_millis;
@ -134,7 +134,7 @@ fn main() -> anyhow::Result<()> {
let parsed = crsn::asm::assemble(&source, &uniq, vec![ let parsed = crsn::asm::assemble(&source, &uniq, vec![
ArithOps::new(), ArithOps::new(),
StackOps::new(), BufOps::new(),
ScreenOps::new(), ScreenOps::new(),
StdioOps::new(), StdioOps::new(),
])?; ])?;

Loading…
Cancel
Save