forked from MightyPork/crsn
buffer module, replacing stacks. TODO: docs, fix parsing of "numbers tuple" in mkbfv (consumed by the conditional branch parser)
This commit is contained in:
Generated
+8
-8
@@ -207,6 +207,13 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crsn_buf"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crsn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crsn_screen"
|
||||
version = "0.1.0"
|
||||
@@ -217,13 +224,6 @@ dependencies = [
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crsn_stacks"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crsn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crsn_stdio"
|
||||
version = "0.1.0"
|
||||
@@ -377,8 +377,8 @@ dependencies = [
|
||||
"clappconfig",
|
||||
"crsn",
|
||||
"crsn_arith",
|
||||
"crsn_buf",
|
||||
"crsn_screen",
|
||||
"crsn_stacks",
|
||||
"crsn_stdio",
|
||||
"log",
|
||||
"serde",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ members = [
|
||||
"launcher",
|
||||
"crsn",
|
||||
"crsn_arith",
|
||||
"crsn_stacks",
|
||||
"crsn_screen",
|
||||
"crsn_stdio",
|
||||
"crsn_buf",
|
||||
]
|
||||
|
||||
@@ -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<Cond, CrsnError> {
|
||||
@@ -59,14 +67,18 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
||||
"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,
|
||||
|
||||
@@ -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<RdObj, CrsnError> {
|
||||
match parse_rd(self.next_or_err()?, self.pcx)? {
|
||||
Rd(RdData::RegObject(reg), Mask::FULL) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(|_| ()))
|
||||
}
|
||||
@@ -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<dyn CrsnExtension> {
|
||||
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<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));
|
||||
}
|
||||
}))
|
||||
}
|
||||
+14
-14
@@ -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)
|
||||
|
||||
+37
-17
@@ -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)))
|
||||
(cmp r0 'z' (>? (j :badchar)))
|
||||
(sub r0 ' ')
|
||||
(ld @stdout r0)
|
||||
; uppercase ASCII
|
||||
(cmp r0 'a' (<? (j :badchar)))
|
||||
(cmp r0 'z' (>? (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)
|
||||
)
|
||||
|
||||
+1
-1
@@ -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" }
|
||||
|
||||
|
||||
@@ -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(),
|
||||
])?;
|
||||
|
||||
Reference in New Issue
Block a user