forked from MightyPork/crsn
add new rdwr access type to guard against illegal writes that can be caught at compile time
This commit is contained in:
@@ -6,6 +6,7 @@ pub use rd::Rd;
|
||||
pub use rd::RdObj;
|
||||
pub use reg::Register;
|
||||
pub use wr::Wr;
|
||||
pub use rdwr::RdWr;
|
||||
|
||||
use crate::asm::data::literal::{as_signed, is_negative, Value};
|
||||
|
||||
@@ -15,8 +16,8 @@ pub mod literal;
|
||||
pub mod reg;
|
||||
|
||||
mod rd;
|
||||
|
||||
mod wr;
|
||||
mod rdwr;
|
||||
|
||||
/// Data source disposition
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
@@ -134,6 +135,12 @@ pub enum WrData {
|
||||
Discard,
|
||||
}
|
||||
|
||||
impl WrData {
|
||||
pub fn is_readable(self) -> bool {
|
||||
self != Self::Discard
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for WrData {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -12,9 +12,6 @@ impl Rd {
|
||||
pub const fn new(src: RdData) -> Self {
|
||||
Rd(src)
|
||||
}
|
||||
pub const fn data(self) -> RdData {
|
||||
self.0
|
||||
}
|
||||
pub const fn immediate(val: Value) -> Rd {
|
||||
Rd(RdData::Immediate(val))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::fmt;
|
||||
|
||||
use crate::asm::data::{Rd, WrData, Wr};
|
||||
|
||||
/// Data destination argument (read-write)
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct RdWr(pub WrData);
|
||||
|
||||
impl RdWr {
|
||||
pub fn new(dst: WrData) -> Self {
|
||||
if !dst.is_readable() {
|
||||
panic!("Not readable: {}", dst);
|
||||
}
|
||||
RdWr(dst)
|
||||
}
|
||||
pub fn wr(self) -> Wr {
|
||||
Wr(self.0)
|
||||
}
|
||||
pub fn rd(self) -> Rd {
|
||||
Rd(self.0.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RdWr> for Rd {
|
||||
fn from(rdwr: RdWr) -> Self {
|
||||
rdwr.rd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RdWr> for Wr {
|
||||
fn from(rdwr: RdWr) -> Self {
|
||||
rdwr.wr()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RdWr> for Rd {
|
||||
fn from(rdwr: &RdWr) -> Self {
|
||||
rdwr.rd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RdWr> for Wr {
|
||||
fn from(rdwr: &RdWr) -> Self {
|
||||
rdwr.wr()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RdWr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RdWr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "RdWr({})", self.0)
|
||||
}
|
||||
}
|
||||
@@ -5,21 +5,22 @@ use crate::asm::data::{Rd, WrData};
|
||||
|
||||
/// Data destination argument (read-write)
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct Wr(WrData);
|
||||
pub struct Wr(pub WrData);
|
||||
|
||||
impl Wr {
|
||||
pub fn new(dst: WrData) -> Self {
|
||||
Wr(dst)
|
||||
}
|
||||
pub fn d(self) -> WrData {
|
||||
self.0
|
||||
pub fn discard() -> Wr {
|
||||
Wr(WrData::Discard)
|
||||
}
|
||||
|
||||
pub fn as_rd(self) -> Rd {
|
||||
Rd(self.0.into())
|
||||
}
|
||||
|
||||
pub fn discard() -> Wr {
|
||||
Wr(WrData::Discard)
|
||||
pub fn is_readable(self) -> bool {
|
||||
self.0.is_readable()
|
||||
}
|
||||
|
||||
pub fn is_discard(self) -> bool {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use sexp::{Sexp, SourcePosition};
|
||||
|
||||
use crate::asm::data::{Rd, RdData, RdObj, Wr};
|
||||
use crate::asm::data::{Rd, RdData, RdObj, Wr, RdWr};
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
||||
use crate::asm::parse::ParserContext;
|
||||
@@ -109,4 +109,17 @@ impl<'a> TokenParser<'a> {
|
||||
pub fn next_wr(&mut self) -> Result<Wr, CrsnError> {
|
||||
parse_wr(self.next_or_err()?, self.pcx)
|
||||
}
|
||||
|
||||
/// Get the next entry as write location
|
||||
pub fn next_rdwr(&mut self) -> Result<RdWr, CrsnError> {
|
||||
let next = self.next_or_err()?;
|
||||
let pos = next.pos().clone();
|
||||
let wr = parse_wr(next, self.pcx)?;
|
||||
|
||||
if !wr.is_readable() {
|
||||
return Err(CrsnError::Parse("Argument is not readable!".into(), pos));
|
||||
}
|
||||
|
||||
Ok(RdWr::new(wr.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use sexp::SourcePosition;
|
||||
|
||||
use crate::asm::data::{Rd, RdObj, Wr};
|
||||
use crate::asm::data::{Rd, RdObj, Wr, RdWr};
|
||||
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
|
||||
use crate::asm::instr::Op;
|
||||
use crate::asm::instr::op::OpKind;
|
||||
@@ -73,7 +73,7 @@ pub enum BuiltinOp {
|
||||
/// Copy value
|
||||
MoveValue { dst: Wr, src: Rd },
|
||||
/// Swap two registers
|
||||
SwapValues { a: Wr, b: Wr },
|
||||
SwapValues { a: RdWr, b: RdWr },
|
||||
/// Store runtime status to a register
|
||||
StoreFlags { dst: Wr },
|
||||
/// Load runtime status from a register
|
||||
|
||||
@@ -110,10 +110,10 @@ impl OpTrait for BuiltinOp {
|
||||
state.write(*dst, val)?;
|
||||
}
|
||||
BuiltinOp::SwapValues { a, b } => {
|
||||
let aa = state.read(a.as_rd())?;
|
||||
let bb = state.read(b.as_rd())?;
|
||||
state.write(*a, bb)?;
|
||||
state.write(*b, aa)?;
|
||||
let aa = state.read(a)?;
|
||||
let bb = state.read(b)?;
|
||||
state.write(a, bb)?;
|
||||
state.write(b, aa)?;
|
||||
}
|
||||
BuiltinOp::StoreFlags { dst } => {
|
||||
let packed = state.frame.status.store();
|
||||
|
||||
@@ -185,8 +185,8 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
|
||||
|
||||
"swap" => {
|
||||
BuiltinOp::SwapValues {
|
||||
a: args.next_wr()?,
|
||||
b: args.next_wr()?,
|
||||
a: args.next_rdwr()?,
|
||||
b: args.next_rdwr()?,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,8 +93,9 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Read a `Rd` value
|
||||
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
|
||||
match rd.data() {
|
||||
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
|
||||
let rd = rd.into();
|
||||
match rd.0 {
|
||||
RdData::Register(Register::Gen(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
||||
@@ -161,10 +162,12 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Write a value to a `Wr` location
|
||||
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
|
||||
pub fn write(&mut self, wr: impl Into<Wr>, val: Value) -> Result<(), Fault> {
|
||||
let wr = wr.into();
|
||||
|
||||
trace!("WR {:?} := {}", wr, val);
|
||||
|
||||
match wr.d() {
|
||||
match wr.0 {
|
||||
WrData::Register(Register::Gen(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
self.frame.gen[rn as usize] = val;
|
||||
|
||||
Reference in New Issue
Block a user