From 2d4f6b4af1ca27cdc75fbd577dca7e02719b6e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 15 Oct 2020 20:38:43 +0200 Subject: [PATCH] implement "lds" for objects (buffers, cin) --- README.md | 4 +++ crsn/src/asm/data/rd.rs | 33 +++++++++++++++---- crsn/src/asm/parse/arg_parser.rs | 2 +- crsn/src/builtin/defs.rs | 13 ++++---- crsn/src/builtin/exec.rs | 36 +++++++++++++------- crsn/src/builtin/parse.rs | 48 +++++++++++++++++++-------- crsn/src/module/mod.rs | 11 ++++++- crsn/src/runtime/run_thread/state.rs | 2 +- crsn_buf/src/exec.rs | 16 +++++++++ crsn_buf/src/lib.rs | 8 +++++ crsn_stdio/src/lib.rs | 49 ++++++++++++++++++++++++++++ examples/lds_buf.csn | 7 ++++ examples/lds_cin.csn | 8 +++++ 13 files changed, 197 insertions(+), 40 deletions(-) create mode 100644 examples/lds_buf.csn create mode 100644 examples/lds_cin.csn diff --git a/README.md b/README.md index 25c17aa..c14b010 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,10 @@ Jumping to a label is always safer than a manual skip. ; Functionally, this instruction is equivalent to a sequence of "ld" (lds Wr (Rd...)) ; example - (lds @cout (65 66 67)) (lds Wr "string") +; Some objects can be used as the source for "lds": +; - @cin = read all to EOF or the first fault (invalid utf8) +; - @buffer = read all items in a buffer, first to last, without consuming it +(lds Wr @Obj) ; Exchange two register's values (xch RW RW) diff --git a/crsn/src/asm/data/rd.rs b/crsn/src/asm/data/rd.rs index 5631f2e..27a86ee 100644 --- a/crsn/src/asm/data/rd.rs +++ b/crsn/src/asm/data/rd.rs @@ -3,6 +3,8 @@ use std::fmt; use crate::asm::data::{RdData, Register}; use crate::asm::data::literal::Value; +use crate::runtime::run_thread::RunState; +use crate::runtime::fault::Fault; /// Data source argument (read-only) #[derive(Clone, Copy, Eq, PartialEq)] @@ -47,14 +49,25 @@ impl Debug for Rd { /// Reference an object through a handle #[derive(Clone, Copy, Eq, PartialEq)] -pub struct RdObj(Register); +pub enum RdObj { + Reg(Register), + Imm(Value), +} impl RdObj { - pub const fn new(reg: Register) -> Self { - RdObj(reg) + pub const fn from_reg(reg: Register) -> Self { + RdObj::Reg(reg) + } + + pub const fn from_value(value: Value) -> Self { + RdObj::Imm(value) } - pub const fn reg(self) -> Register { - self.0 + + pub fn read(self, state: &mut RunState) -> Result { + Ok(match self { + RdObj::Reg(r) => state.read(Rd::new(RdData::Register(r)))?, + RdObj::Imm(v) => v, + }) } } @@ -66,12 +79,18 @@ impl From<&RdObj> for RdObj { impl Display for RdObj { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "@{}", self.0) + match self { + RdObj::Reg(r) => write!(f, "@{}", r), + RdObj::Imm(v) => write!(f, "@{:#x}", v) + } } } impl Debug for RdObj { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "Obj({})", self.reg()) + match self { + RdObj::Reg(r) => write!(f, "Obj({})", r), + RdObj::Imm(v) => write!(f, "Obj({:#x})", v) + } } } diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index 0ec8dff..0efeca4 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -102,7 +102,7 @@ impl<'a> TokenParser<'a> { pub fn next_rdobj(&mut self) -> Result { match parse_rd(self.next_or_err()?, self.pcx)? { Rd(RdData::RegObject(reg)) => { - Ok(RdObj::new(reg)) + Ok(RdObj::from_reg(reg)) } other => { Err(CrsnError::Parse( diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index 173d710..c76d0d3 100644 --- a/crsn/src/builtin/defs.rs +++ b/crsn/src/builtin/defs.rs @@ -33,6 +33,7 @@ impl SleepUnit { #[derive(Clone, Debug, PartialEq)] pub enum LdsValue { Values(Vec), + Handle(RdObj), Chars(String), } @@ -77,17 +78,17 @@ pub enum BuiltinOp { /// The object is released and the handle becomes invalid. Delete(RdObj), /// Move a value - Move { dst: Wr, src: Rd }, + Load { dst: Wr, src: Rd }, /// Move lower 32 bits - Move32 { dst: RdWr, src: Rd }, + Load32 { dst: RdWr, src: Rd }, /// Move lower 16 bits - Move16 { dst: RdWr, src: Rd }, + Load16 { dst: RdWr, src: Rd }, /// Move lower 8 bits - Move8 { dst: RdWr, src: Rd }, + Load8 { dst: RdWr, src: Rd }, /// Move N values - MoveMultiple { dst: Wr, src: Rd, count: Rd }, + LoadMultiple { dst: Wr, src: Rd, count: Rd }, /// Move values from a string or integer list - MoveSequence { dst: Wr, value: LdsValue }, + LoadSequence { dst: Wr, value: LdsValue }, /// Swap two registers Exchange { a: RdWr, b: RdWr }, /// Store runtime status to a register diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index 02c798c..462c89b 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -2,7 +2,6 @@ use std::time::Duration; use sexp::Sexp; -use crate::asm::data::{Rd, RdData}; use crate::asm::data::literal::{Addr, Value}; use crate::builtin::defs::{Barrier, BuiltinOp, LdsValue}; use crate::module::{EvalRes, OpTrait}; @@ -103,13 +102,13 @@ impl OpTrait for BuiltinOp { let pc = state.get_pc(); program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?; } - BuiltinOp::Move { dst, src } => { + BuiltinOp::Load { dst, src } => { state.clear_status(); let val = state.read(src)?; state.update_status(val); state.write(dst, val)?; } - BuiltinOp::MoveMultiple { dst, src, count } => { + BuiltinOp::LoadMultiple { dst, src, count } => { state.clear_status(); let mut count = state.read(count)?; let mut last = 0; @@ -120,7 +119,7 @@ impl OpTrait for BuiltinOp { } state.update_status(last); } - BuiltinOp::Move32 { dst, src } => { + BuiltinOp::Load32 { dst, src } => { state.clear_status(); let new = state.read(src)?; let old = state.read(dst)?; @@ -128,7 +127,7 @@ impl OpTrait for BuiltinOp { state.update_status(val); state.write(dst, val)?; } - BuiltinOp::Move16 { dst, src } => { + BuiltinOp::Load16 { dst, src } => { state.clear_status(); let new = state.read(src)?; let old = state.read(dst)?; @@ -136,7 +135,7 @@ impl OpTrait for BuiltinOp { state.update_status(val); state.write(dst, val)?; } - BuiltinOp::Move8 { dst, src } => { + BuiltinOp::Load8 { dst, src } => { state.clear_status(); let new = state.read(src)?; let old = state.read(dst)?; @@ -144,7 +143,7 @@ impl OpTrait for BuiltinOp { state.update_status(val); state.write(dst, val)?; } - BuiltinOp::MoveSequence { dst, value } => { + BuiltinOp::LoadSequence { dst, value } => { match value { LdsValue::Values(vals) => { for val in vals { @@ -157,6 +156,21 @@ impl OpTrait for BuiltinOp { state.write(dst, val as Value)?; } } + LdsValue::Handle(h) => { + let hv = h.read(state)?; + + let mut found = false; + for ex in info.program.extensions.iter() { + if ex.read_obj_all(state, *dst, hv)?.is_some() { + found = true; + } + } + + if !found { + warn!("Object {:#x} to read does not exist!", hv); + state.set_flag(Flag::Invalid, true); + } + } } } BuiltinOp::Exchange { a, b } => { @@ -177,17 +191,17 @@ impl OpTrait for BuiltinOp { std::thread::sleep(Duration::from_micros(state.read(micros)? * unit_us.micros())) } BuiltinOp::Delete(obj) => { - let x = state.read(Rd::new(RdData::Register(obj.reg())))?; + let hv = obj.read(state)?; - trace!("Del object: {:#x}", x); + trace!("Del object: {:#x}", hv); let mut dropped = false; for ex in info.program.extensions.iter() { - if ex.drop_obj(info, state, x)?.is_some() { + if ex.drop_obj(info, state, hv)?.is_some() { dropped = true; } } if !dropped { - warn!("Object {:#x} to del does not exist!", x); + warn!("Object {:#x} to del does not exist!", hv); state.set_flag(Flag::Invalid, true); } } diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs index 719c1d8..ba71a57 100644 --- a/crsn/src/builtin/parse.rs +++ b/crsn/src/builtin/parse.rs @@ -11,6 +11,7 @@ use crate::asm::patches::ErrWithPos; use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit, LdsValue}; use crate::module::ParseRes; use crate::utils::A; +use crate::asm::data::{Rd, RdData, RdObj}; pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { let pcx = args.pcx; @@ -183,35 +184,35 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok } "ld" => { - BuiltinOp::Move { + BuiltinOp::Load { dst: args.next_wr()?, src: args.next_rd()?, } } "ld32" => { - BuiltinOp::Move32 { + BuiltinOp::Load32 { dst: args.next_rdwr()?, src: args.next_rd()?, } } "ld16" => { - BuiltinOp::Move16 { + BuiltinOp::Load16 { dst: args.next_rdwr()?, src: args.next_rd()?, } } "ld8" => { - BuiltinOp::Move8 { + BuiltinOp::Load8 { dst: args.next_rdwr()?, src: args.next_rd()?, } } "ldn" => { - BuiltinOp::MoveMultiple { + BuiltinOp::LoadMultiple { dst: args.next_wr()?, src: args.next_rd()?, count: args.next_rd()?, @@ -225,6 +226,22 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok Sexp::Atom(Atom::QS(s), _) => { LdsValue::Chars(s) } + tok @ Sexp::Atom(Atom::S(_), _) => { + let pos = tok.pos().clone(); + match parse_rd(tok, args.pcx)? { + Rd(RdData::ImmObject(v)) => { + LdsValue::Handle(RdObj::Imm(v)) + } + Rd(RdData::RegObject(r)) => { + LdsValue::Handle(RdObj::Reg(r)) + } + _ => { + return Err(CrsnError::Parse( + "Expected a handle, quoted string, or a tuple of values".into(), + pos)); + } + } + } Sexp::List(list, _) => { let mut vals = vec![]; for v in list { @@ -233,11 +250,13 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok LdsValue::Values(vals) } other => { - return Err(CrsnError::Parse("Expected quoted string or a tuple of values".into(), other.pos().clone())); + return Err(CrsnError::Parse( + "Expected a handle, quoted string, or a tuple of values".into(), + other.pos().clone())); } }; - BuiltinOp::MoveSequence { dst, value } + BuiltinOp::LoadSequence { dst, value } } "xch" => { @@ -359,15 +378,15 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { } } BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]), - BuiltinOp::Move { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]), - BuiltinOp::Move32 { dst, src } => sexp::list(&[A("ld32"), A(dst), A(src)]), - BuiltinOp::Move16 { dst, src } => sexp::list(&[A("ld16"), A(dst), A(src)]), - BuiltinOp::Move8 { dst, src } => sexp::list(&[A("ld8"), A(dst), A(src)]), - BuiltinOp::MoveMultiple { dst, src, count } => sexp::list(&[A("ldn"), A(dst), A(src), A(count)]), + BuiltinOp::Load { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]), + BuiltinOp::Load32 { dst, src } => sexp::list(&[A("ld32"), A(dst), A(src)]), + BuiltinOp::Load16 { dst, src } => sexp::list(&[A("ld16"), A(dst), A(src)]), + BuiltinOp::Load8 { dst, src } => sexp::list(&[A("ld8"), A(dst), A(src)]), + BuiltinOp::LoadMultiple { dst, src, count } => sexp::list(&[A("ldn"), A(dst), A(src), A(count)]), BuiltinOp::Exchange { a, b } => sexp::list(&[A("xch"), A(a), A(b)]), BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]), BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]), - BuiltinOp::MoveSequence { dst, value } => { + BuiltinOp::LoadSequence { dst, value } => { match value { LdsValue::Values(vals) => { let mut vals: Vec<_> = vals.iter().map(A).collect(); @@ -378,6 +397,9 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { LdsValue::Chars(str) => { sexp::list(&[A("lds"), A(dst), atom_qs(str)]) } + LdsValue::Handle(h) => { + sexp::list(&[A("lds"), A(dst), A(h)]) + } } } } diff --git a/crsn/src/module/mod.rs b/crsn/src/module/mod.rs index 941ffc6..2c0572c 100644 --- a/crsn/src/module/mod.rs +++ b/crsn/src/module/mod.rs @@ -15,6 +15,7 @@ use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::ThreadInfo; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; +use crate::asm::data::Wr; mod eval_res; @@ -105,7 +106,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static { Ok(None) } - /// Run-time method called to read an object (using the object handle syntax) + /// Run-time method called to read an object ("ld" and its variants, using the object handle syntax) fn read_obj(&self, state: &mut RunState, handle: Value) -> Result, Fault> { @@ -113,6 +114,14 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static { Ok(None) } + /// Run-time method called to read all values from an object ("lds" using the object handle syntax) + fn read_obj_all(&self, state: &mut RunState, whandle: Wr, rhandle: Value) + -> Result, Fault> + { + // Default impl - we do not support reading this object + Ok(None) + } + /// Run-time method called to write an object (using the object handle syntax) fn write_obj(&self, state: &mut RunState, handle: Value, value: Value) -> Result, Fault> { diff --git a/crsn/src/runtime/run_thread/state.rs b/crsn/src/runtime/run_thread/state.rs index 53be796..7e286f0 100644 --- a/crsn/src/runtime/run_thread/state.rs +++ b/crsn/src/runtime/run_thread/state.rs @@ -91,7 +91,7 @@ impl RunState { /// Read object handle value pub fn read_obj(&mut self, rdo: impl Into) -> Result { - self.read(Rd::new(RdData::Register(rdo.into().reg()))) + rdo.into().read(self) } /// Read a `Rd` value diff --git a/crsn_buf/src/exec.rs b/crsn_buf/src/exec.rs index fae582e..a22e1bc 100644 --- a/crsn_buf/src/exec.rs +++ b/crsn_buf/src/exec.rs @@ -10,6 +10,7 @@ use crsn::sexp::{atom_qs, Sexp}; use crsn::utils::A; use crate::defs::{BufIoMode, BufOps, BufValue}; +use crsn::asm::data::Wr; #[derive(Debug, Default, Clone)] struct Buffer { @@ -318,6 +319,21 @@ pub(crate) fn read_obj(state: &mut RunState, handle: Value) } } +/// Run-time method called to read all from an object (using the object handle syntax) +pub(crate) fn read_obj_all(state: &mut RunState, whandle: Wr, rhandle: Value) + -> Result, Fault> +{ + let store: &mut ExtData = state.ext_mut(); + if let Some(buf) = store.buffers.get_mut(&rhandle) { + for v in buf.data.clone() { // FIXME potentially needless clone (but allows "aliasing") + state.write(whandle, v)?; + } + Ok(Some(())) + } else { + Ok(None) + } +} + /// Run-time method called to write an object (using the object handle syntax) pub(crate) fn write_obj(state: &mut RunState, handle: Value, value: Value) -> Result, Fault> { diff --git a/crsn_buf/src/lib.rs b/crsn_buf/src/lib.rs index 9f02233..d87a497 100644 --- a/crsn_buf/src/lib.rs +++ b/crsn_buf/src/lib.rs @@ -7,6 +7,7 @@ use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{RunState, ThreadInfo}; use crsn::sexp::SourcePosition; use crate::parse::{BUF_IOMODE_STACK, BUF_IOMODE_REVERSE_STACK, BUF_IOMODE_QUEUE, BUF_IOMODE_REVERSE_QUEUE}; +use crsn::asm::data::Wr; mod defs; mod parse; @@ -59,4 +60,11 @@ impl CrsnExtension for BufOps { _ => None } } + + /// Run-time method called to read all values from an object ("lds" using the object handle syntax) + fn read_obj_all(&self, state: &mut RunState, whandle: Wr, rhandle: Value) + -> Result, Fault> + { + exec::read_obj_all(state, whandle, rhandle) + } } diff --git a/crsn_stdio/src/lib.rs b/crsn_stdio/src/lib.rs index c570ce6..5088df4 100644 --- a/crsn_stdio/src/lib.rs +++ b/crsn_stdio/src/lib.rs @@ -10,6 +10,7 @@ use std::convert::TryFrom; use std::io; use crsn::asm::instr::cond::Flag; use std::fmt; +use crsn::asm::data::Wr; mod console { use std::{io}; @@ -244,4 +245,52 @@ impl CrsnExtension for StdioOps { Ok(None) } + + /// Run-time method called to read all values from an object ("lds" using the object handle syntax) + fn read_obj_all(&self, state: &mut RunState, whandle: Wr, rhandle: Value) + -> Result, Fault> + { + if rhandle == self.hdl_stdin { + loop { + match console::read_char() { + Ok(c) => { + state.write(whandle, c as Value)?; + } + Err(e) => { + if e.kind() != io::ErrorKind::InvalidData { + state.set_flag(Flag::Eof, true); + } else { + state.set_flag(Flag::Invalid, true); + } + return Ok(Some(())); + } + } + } + } + + if rhandle == self.hdl_stdin_raw { + loop { + match console::read_byte() { + Ok(c) => { + state.write(whandle, c as Value)?; + } + Err(e) => { + if e.kind() != io::ErrorKind::InvalidData { + state.set_flag(Flag::Eof, true); + } else { + state.set_flag(Flag::Invalid, true); + } + return Ok(Some(())); + } + } + } + } + + if rhandle == self.hdl_stdout || rhandle == self.hdl_stdout_raw { + state.set_flag(Flag::Invalid, true); + return Ok(Some(())); + } + + Ok(None) + } } diff --git a/examples/lds_buf.csn b/examples/lds_buf.csn new file mode 100644 index 0000000..02c99bf --- /dev/null +++ b/examples/lds_buf.csn @@ -0,0 +1,7 @@ +( + (mkbf r0 "Lazy fox\n") + (lds @cout @r0) ; buffers implement lds as a non-consuming read from start to end + (lds @cout @r0) + (lds @cout @r0) + (halt) +) diff --git a/examples/lds_cin.csn b/examples/lds_cin.csn new file mode 100644 index 0000000..139ec1a --- /dev/null +++ b/examples/lds_cin.csn @@ -0,0 +1,8 @@ +( + ; Read all stdin and print it reversed + (mkbf r0) + (lds @r0 @cin) ; cin implements the "lds" operation + (bfrev @r0) + (lds @cout @r0) + (del @r0) +)