implement "lds" for objects (buffers, cin)
This commit is contained in:
@@ -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"
|
; Functionally, this instruction is equivalent to a sequence of "ld"
|
||||||
(lds Wr (Rd...)) ; example - (lds @cout (65 66 67))
|
(lds Wr (Rd...)) ; example - (lds @cout (65 66 67))
|
||||||
(lds Wr "string")
|
(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
|
; Exchange two register's values
|
||||||
(xch RW RW)
|
(xch RW RW)
|
||||||
|
|||||||
+26
-7
@@ -3,6 +3,8 @@ use std::fmt;
|
|||||||
|
|
||||||
use crate::asm::data::{RdData, Register};
|
use crate::asm::data::{RdData, Register};
|
||||||
use crate::asm::data::literal::Value;
|
use crate::asm::data::literal::Value;
|
||||||
|
use crate::runtime::run_thread::RunState;
|
||||||
|
use crate::runtime::fault::Fault;
|
||||||
|
|
||||||
/// Data source argument (read-only)
|
/// Data source argument (read-only)
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -47,14 +49,25 @@ impl Debug for Rd {
|
|||||||
|
|
||||||
/// Reference an object through a handle
|
/// Reference an object through a handle
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct RdObj(Register);
|
pub enum RdObj {
|
||||||
|
Reg(Register),
|
||||||
|
Imm(Value),
|
||||||
|
}
|
||||||
|
|
||||||
impl RdObj {
|
impl RdObj {
|
||||||
pub const fn new(reg: Register) -> Self {
|
pub const fn from_reg(reg: Register) -> Self {
|
||||||
RdObj(reg)
|
RdObj::Reg(reg)
|
||||||
}
|
}
|
||||||
pub const fn reg(self) -> Register {
|
|
||||||
self.0
|
pub const fn from_value(value: Value) -> Self {
|
||||||
|
RdObj::Imm(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(self, state: &mut RunState) -> Result<Value, Fault> {
|
||||||
|
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 {
|
impl Display for RdObj {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
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 {
|
impl Debug for RdObj {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ impl<'a> TokenParser<'a> {
|
|||||||
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)) => {
|
Rd(RdData::RegObject(reg)) => {
|
||||||
Ok(RdObj::new(reg))
|
Ok(RdObj::from_reg(reg))
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
Err(CrsnError::Parse(
|
Err(CrsnError::Parse(
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ impl SleepUnit {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum LdsValue {
|
pub enum LdsValue {
|
||||||
Values(Vec<Rd>),
|
Values(Vec<Rd>),
|
||||||
|
Handle(RdObj),
|
||||||
Chars(String),
|
Chars(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,17 +78,17 @@ pub enum BuiltinOp {
|
|||||||
/// The object is released and the handle becomes invalid.
|
/// The object is released and the handle becomes invalid.
|
||||||
Delete(RdObj),
|
Delete(RdObj),
|
||||||
/// Move a value
|
/// Move a value
|
||||||
Move { dst: Wr, src: Rd },
|
Load { dst: Wr, src: Rd },
|
||||||
/// Move lower 32 bits
|
/// Move lower 32 bits
|
||||||
Move32 { dst: RdWr, src: Rd },
|
Load32 { dst: RdWr, src: Rd },
|
||||||
/// Move lower 16 bits
|
/// Move lower 16 bits
|
||||||
Move16 { dst: RdWr, src: Rd },
|
Load16 { dst: RdWr, src: Rd },
|
||||||
/// Move lower 8 bits
|
/// Move lower 8 bits
|
||||||
Move8 { dst: RdWr, src: Rd },
|
Load8 { dst: RdWr, src: Rd },
|
||||||
/// Move N values
|
/// 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
|
/// Move values from a string or integer list
|
||||||
MoveSequence { dst: Wr, value: LdsValue },
|
LoadSequence { dst: Wr, value: LdsValue },
|
||||||
/// Swap two registers
|
/// Swap two registers
|
||||||
Exchange { a: RdWr, b: RdWr },
|
Exchange { a: RdWr, b: RdWr },
|
||||||
/// Store runtime status to a register
|
/// Store runtime status to a register
|
||||||
|
|||||||
+25
-11
@@ -2,7 +2,6 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::asm::data::{Rd, RdData};
|
|
||||||
use crate::asm::data::literal::{Addr, Value};
|
use crate::asm::data::literal::{Addr, Value};
|
||||||
use crate::builtin::defs::{Barrier, BuiltinOp, LdsValue};
|
use crate::builtin::defs::{Barrier, BuiltinOp, LdsValue};
|
||||||
use crate::module::{EvalRes, OpTrait};
|
use crate::module::{EvalRes, OpTrait};
|
||||||
@@ -103,13 +102,13 @@ impl OpTrait for BuiltinOp {
|
|||||||
let pc = state.get_pc();
|
let pc = state.get_pc();
|
||||||
program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
|
program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
|
||||||
}
|
}
|
||||||
BuiltinOp::Move { dst, src } => {
|
BuiltinOp::Load { dst, src } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let val = state.read(src)?;
|
let val = state.read(src)?;
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
}
|
}
|
||||||
BuiltinOp::MoveMultiple { dst, src, count } => {
|
BuiltinOp::LoadMultiple { dst, src, count } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let mut count = state.read(count)?;
|
let mut count = state.read(count)?;
|
||||||
let mut last = 0;
|
let mut last = 0;
|
||||||
@@ -120,7 +119,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
}
|
}
|
||||||
state.update_status(last);
|
state.update_status(last);
|
||||||
}
|
}
|
||||||
BuiltinOp::Move32 { dst, src } => {
|
BuiltinOp::Load32 { dst, src } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let new = state.read(src)?;
|
let new = state.read(src)?;
|
||||||
let old = state.read(dst)?;
|
let old = state.read(dst)?;
|
||||||
@@ -128,7 +127,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
}
|
}
|
||||||
BuiltinOp::Move16 { dst, src } => {
|
BuiltinOp::Load16 { dst, src } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let new = state.read(src)?;
|
let new = state.read(src)?;
|
||||||
let old = state.read(dst)?;
|
let old = state.read(dst)?;
|
||||||
@@ -136,7 +135,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
}
|
}
|
||||||
BuiltinOp::Move8 { dst, src } => {
|
BuiltinOp::Load8 { dst, src } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let new = state.read(src)?;
|
let new = state.read(src)?;
|
||||||
let old = state.read(dst)?;
|
let old = state.read(dst)?;
|
||||||
@@ -144,7 +143,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
}
|
}
|
||||||
BuiltinOp::MoveSequence { dst, value } => {
|
BuiltinOp::LoadSequence { dst, value } => {
|
||||||
match value {
|
match value {
|
||||||
LdsValue::Values(vals) => {
|
LdsValue::Values(vals) => {
|
||||||
for val in vals {
|
for val in vals {
|
||||||
@@ -157,6 +156,21 @@ impl OpTrait for BuiltinOp {
|
|||||||
state.write(dst, val as Value)?;
|
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 } => {
|
BuiltinOp::Exchange { a, b } => {
|
||||||
@@ -177,17 +191,17 @@ impl OpTrait for BuiltinOp {
|
|||||||
std::thread::sleep(Duration::from_micros(state.read(micros)? * unit_us.micros()))
|
std::thread::sleep(Duration::from_micros(state.read(micros)? * unit_us.micros()))
|
||||||
}
|
}
|
||||||
BuiltinOp::Delete(obj) => {
|
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;
|
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, hv)?.is_some() {
|
||||||
dropped = true;
|
dropped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !dropped {
|
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);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-13
@@ -11,6 +11,7 @@ use crate::asm::patches::ErrWithPos;
|
|||||||
use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit, LdsValue};
|
use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit, LdsValue};
|
||||||
use crate::module::ParseRes;
|
use crate::module::ParseRes;
|
||||||
use crate::utils::A;
|
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<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
let pcx = args.pcx;
|
let pcx = args.pcx;
|
||||||
@@ -183,35 +184,35 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
|
|||||||
}
|
}
|
||||||
|
|
||||||
"ld" => {
|
"ld" => {
|
||||||
BuiltinOp::Move {
|
BuiltinOp::Load {
|
||||||
dst: args.next_wr()?,
|
dst: args.next_wr()?,
|
||||||
src: args.next_rd()?,
|
src: args.next_rd()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"ld32" => {
|
"ld32" => {
|
||||||
BuiltinOp::Move32 {
|
BuiltinOp::Load32 {
|
||||||
dst: args.next_rdwr()?,
|
dst: args.next_rdwr()?,
|
||||||
src: args.next_rd()?,
|
src: args.next_rd()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"ld16" => {
|
"ld16" => {
|
||||||
BuiltinOp::Move16 {
|
BuiltinOp::Load16 {
|
||||||
dst: args.next_rdwr()?,
|
dst: args.next_rdwr()?,
|
||||||
src: args.next_rd()?,
|
src: args.next_rd()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"ld8" => {
|
"ld8" => {
|
||||||
BuiltinOp::Move8 {
|
BuiltinOp::Load8 {
|
||||||
dst: args.next_rdwr()?,
|
dst: args.next_rdwr()?,
|
||||||
src: args.next_rd()?,
|
src: args.next_rd()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"ldn" => {
|
"ldn" => {
|
||||||
BuiltinOp::MoveMultiple {
|
BuiltinOp::LoadMultiple {
|
||||||
dst: args.next_wr()?,
|
dst: args.next_wr()?,
|
||||||
src: args.next_rd()?,
|
src: args.next_rd()?,
|
||||||
count: 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), _) => {
|
Sexp::Atom(Atom::QS(s), _) => {
|
||||||
LdsValue::Chars(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, _) => {
|
Sexp::List(list, _) => {
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
for v in list {
|
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)
|
LdsValue::Values(vals)
|
||||||
}
|
}
|
||||||
other => {
|
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" => {
|
"xch" => {
|
||||||
@@ -359,15 +378,15 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]),
|
BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]),
|
||||||
BuiltinOp::Move { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]),
|
BuiltinOp::Load { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]),
|
||||||
BuiltinOp::Move32 { dst, src } => sexp::list(&[A("ld32"), A(dst), A(src)]),
|
BuiltinOp::Load32 { dst, src } => sexp::list(&[A("ld32"), A(dst), A(src)]),
|
||||||
BuiltinOp::Move16 { dst, src } => sexp::list(&[A("ld16"), A(dst), A(src)]),
|
BuiltinOp::Load16 { dst, src } => sexp::list(&[A("ld16"), A(dst), A(src)]),
|
||||||
BuiltinOp::Move8 { dst, src } => sexp::list(&[A("ld8"), A(dst), A(src)]),
|
BuiltinOp::Load8 { 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::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::Exchange { a, b } => sexp::list(&[A("xch"), A(a), A(b)]),
|
||||||
BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]),
|
BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]),
|
||||||
BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]),
|
BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]),
|
||||||
BuiltinOp::MoveSequence { dst, value } => {
|
BuiltinOp::LoadSequence { dst, value } => {
|
||||||
match value {
|
match value {
|
||||||
LdsValue::Values(vals) => {
|
LdsValue::Values(vals) => {
|
||||||
let mut vals: Vec<_> = vals.iter().map(A).collect();
|
let mut vals: Vec<_> = vals.iter().map(A).collect();
|
||||||
@@ -378,6 +397,9 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp {
|
|||||||
LdsValue::Chars(str) => {
|
LdsValue::Chars(str) => {
|
||||||
sexp::list(&[A("lds"), A(dst), atom_qs(str)])
|
sexp::list(&[A("lds"), A(dst), atom_qs(str)])
|
||||||
}
|
}
|
||||||
|
LdsValue::Handle(h) => {
|
||||||
|
sexp::list(&[A("lds"), A(dst), A(h)])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -15,6 +15,7 @@ use crate::runtime::run_thread::state::RunState;
|
|||||||
use crate::runtime::run_thread::ThreadInfo;
|
use crate::runtime::run_thread::ThreadInfo;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use crate::asm::data::Wr;
|
||||||
|
|
||||||
mod eval_res;
|
mod eval_res;
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
|||||||
Ok(None)
|
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)
|
fn read_obj(&self, state: &mut RunState, handle: Value)
|
||||||
-> Result<Option<Value>, Fault>
|
-> Result<Option<Value>, Fault>
|
||||||
{
|
{
|
||||||
@@ -113,6 +114,14 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
|||||||
Ok(None)
|
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<Option<()>, 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)
|
/// 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<Option<()>, Fault>
|
fn write_obj(&self, state: &mut RunState, handle: Value, value: Value) -> Result<Option<()>, Fault>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ impl RunState {
|
|||||||
|
|
||||||
/// Read object handle value
|
/// Read object handle value
|
||||||
pub fn read_obj(&mut self, rdo: impl Into<RdObj>) -> Result<Value, Fault> {
|
pub fn read_obj(&mut self, rdo: impl Into<RdObj>) -> Result<Value, Fault> {
|
||||||
self.read(Rd::new(RdData::Register(rdo.into().reg())))
|
rdo.into().read(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a `Rd` value
|
/// Read a `Rd` value
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crsn::sexp::{atom_qs, Sexp};
|
|||||||
use crsn::utils::A;
|
use crsn::utils::A;
|
||||||
|
|
||||||
use crate::defs::{BufIoMode, BufOps, BufValue};
|
use crate::defs::{BufIoMode, BufOps, BufValue};
|
||||||
|
use crsn::asm::data::Wr;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
struct Buffer {
|
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<Option<()>, 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)
|
/// 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<Option<()>, Fault>
|
pub(crate) fn write_obj(state: &mut RunState, handle: Value, value: Value) -> Result<Option<()>, Fault>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crsn::runtime::fault::Fault;
|
|||||||
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
||||||
use crsn::sexp::SourcePosition;
|
use crsn::sexp::SourcePosition;
|
||||||
use crate::parse::{BUF_IOMODE_STACK, BUF_IOMODE_REVERSE_STACK, BUF_IOMODE_QUEUE, BUF_IOMODE_REVERSE_QUEUE};
|
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 defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -59,4 +60,11 @@ impl CrsnExtension for BufOps {
|
|||||||
_ => None
|
_ => 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<Option<()>, Fault>
|
||||||
|
{
|
||||||
|
exec::read_obj_all(state, whandle, rhandle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use std::convert::TryFrom;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use crsn::asm::instr::cond::Flag;
|
use crsn::asm::instr::cond::Flag;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use crsn::asm::data::Wr;
|
||||||
|
|
||||||
mod console {
|
mod console {
|
||||||
use std::{io};
|
use std::{io};
|
||||||
@@ -244,4 +245,52 @@ impl CrsnExtension for StdioOps {
|
|||||||
|
|
||||||
Ok(None)
|
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<Option<()>, 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
)
|
||||||
@@ -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)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user