Skip to content

Commit

Permalink
Add a safe "into_data()" method to turn Words into i32s (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmunns authored Sep 16, 2023
1 parent 4b23ef1 commit 3acd0df
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 43 deletions.
4 changes: 2 additions & 2 deletions source/forth3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl<T: 'static> CallContext<T> {

fn get_current_val(&self) -> Result<i32, Error> {
let w = self.get_current_word()?;
Ok(unsafe { w.data })
Ok(w.into_data())
}

fn get_current_word(&self) -> Result<Word, Error> {
Expand Down Expand Up @@ -341,7 +341,7 @@ pub mod test {
// Takes one value off the stack, and stores it in the vec
fn squirrel(forth: &mut Forth<TestContext>) -> Result<(), crate::Error> {
let val = forth.data_stack.try_pop()?;
forth.host_ctxt.contents.push(unsafe { val.data });
forth.host_ctxt.contents.push(val.into_data());
Ok(())
}
forth.add_builtin("squirrel", squirrel).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion source/forth3/src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ pub mod test {
}
assert!(stack.push(Word::data(100)).is_err());
for i in (0..(ITEMS as i32)).rev() {
assert_eq!(unsafe { stack.pop().unwrap().data }, i);
assert_eq!(stack.pop().unwrap().into_data(), i);
}
assert!(stack.pop().is_none());
}
Expand Down
79 changes: 40 additions & 39 deletions source/forth3/src/vm/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl<T: 'static> Forth<T> {
write!(&mut self.output, "<{}> ", depth)?;
for d in (0..depth).rev() {
let val = self.data_stack.try_peek_back_n(d)?;
write!(&mut self.output, "{} ", unsafe { val.data })?;
write!(&mut self.output, "{} ", val.into_data())?;
}
self.output.push_str("\n")?;
Ok(())
Expand Down Expand Up @@ -293,7 +293,10 @@ impl<T: 'static> Forth<T> {
let w_addr = self.data_stack.try_pop()?;
let w_val = self.data_stack.try_pop()?;
unsafe {
w_addr.ptr.cast::<u8>().write((w_val.data & 0xFF) as u8);
w_addr
.ptr
.cast::<u8>()
.write((w_val.into_data() & 0xFF) as u8);
}
Ok(())
}
Expand Down Expand Up @@ -463,7 +466,7 @@ impl<T: 'static> Forth<T> {

pub fn spaces(&mut self) -> Result<(), Error> {
let num = self.data_stack.try_pop()?;
let num = unsafe { num.data };
let num = num.into_data();

if num.is_negative() {
return Err(Error::LoopCountIsNegative);
Expand Down Expand Up @@ -499,7 +502,7 @@ impl<T: 'static> Forth<T> {
pub fn and(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
let val = Word::data(unsafe { a.data & b.data });
let val = Word::data(a.into_data() & b.into_data());
self.data_stack.push(val)?;
Ok(())
}
Expand All @@ -519,15 +522,15 @@ impl<T: 'static> Forth<T> {
pub fn greater(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
let val = if unsafe { b.data > a.data } { -1 } else { 0 };
let val = if b.into_data() > a.into_data() { -1 } else { 0 };
self.data_stack.push(Word::data(val))?;
Ok(())
}

pub fn less(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
let val = if unsafe { b.data < a.data } { -1 } else { 0 };
let val = if b.into_data() < a.into_data() { -1 } else { 0 };
self.data_stack.push(Word::data(val))?;
Ok(())
}
Expand All @@ -550,24 +553,24 @@ impl<T: 'static> Forth<T> {
pub fn div_mod(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
if unsafe { a.data == 0 } {
if a.into_data() == 0 {
return Err(Error::DivideByZero);
}
let rem = unsafe { Word::data(b.data % a.data) };
let rem = Word::data(b.into_data() % a.into_data());
self.data_stack.push(rem)?;
let val = unsafe { Word::data(b.data / a.data) };
let val = Word::data(b.into_data() / a.into_data());
self.data_stack.push(val)?;
Ok(())
}

pub fn div(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
let val = unsafe {
if a.data == 0 {
let val = {
if a.into_data() == 0 {
return Err(Error::DivideByZero);
}
Word::data(b.data / a.data)
Word::data(b.into_data() / a.into_data())
};
self.data_stack.push(val)?;
Ok(())
Expand All @@ -576,11 +579,11 @@ impl<T: 'static> Forth<T> {
pub fn modu(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
let val = unsafe {
if a.data == 0 {
let val = {
if a.into_data() == 0 {
return Err(Error::DivideByZero);
}
Word::data(b.data % a.data)
Word::data(b.into_data() % a.into_data())
};
self.data_stack.push(val)?;
Ok(())
Expand Down Expand Up @@ -610,7 +613,7 @@ impl<T: 'static> Forth<T> {
let _ = self.return_stack.try_pop()?;
// Pop the "end of loop" value
let idx = self.return_stack.try_pop()?;
let idx = unsafe { idx.data };
let idx = idx.into_data();
let idx = u16::try_from(idx).map_err(|_| Error::BadCfaOffset)?;

// Move the parent's interpreter index forward to the end of loop index
Expand All @@ -623,7 +626,7 @@ impl<T: 'static> Forth<T> {
pub fn jump_doloop(&mut self) -> Result<(), Error> {
let a = self.return_stack.try_pop()?;
let b = self.return_stack.try_peek()?;
let ctr = unsafe { Word::data(a.data + 1) };
let ctr = Word::data(a.into_data() + 1);
let do_jmp = ctr != b;
if do_jmp {
self.return_stack.push(ctr)?;
Expand All @@ -638,15 +641,15 @@ impl<T: 'static> Forth<T> {

pub fn emit(&mut self) -> Result<(), Error> {
let val = self.data_stack.try_pop()?;
let val = unsafe { val.data };
let val = val.into_data();
self.output.push_bstr(&[val as u8])?;
Ok(())
}

pub fn jump_if_zero(&mut self) -> Result<(), Error> {
let do_jmp = unsafe {
let do_jmp = {
let val = self.data_stack.try_pop()?;
val.data == 0
val.into_data() == 0
};
if do_jmp {
self.jump()
Expand Down Expand Up @@ -700,13 +703,13 @@ impl<T: 'static> Forth<T> {

pub fn pop_print(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
write!(&mut self.output, "{} ", unsafe { a.data })?;
write!(&mut self.output, "{} ", a.into_data())?;
Ok(())
}

pub fn unsigned_pop_print(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
write!(&mut self.output, "{} ", unsafe { a.data } as u32)?;
write!(&mut self.output, "{} ", a.into_data() as u32)?;
Ok(())
}

Expand Down Expand Up @@ -738,37 +741,37 @@ impl<T: 'static> Forth<T> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
self.data_stack
.push(Word::data(unsafe { a.data.wrapping_mul(b.data) }))?;
.push(Word::data(a.into_data().wrapping_mul(b.into_data())))?;
Ok(())
}

pub fn abs(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
self.data_stack
.push(Word::data(unsafe { a.data.wrapping_abs() }))?;
.push(Word::data(a.into_data().wrapping_abs()))?;
Ok(())
}

pub fn negate(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
self.data_stack
.push(Word::data(unsafe { a.data.wrapping_neg() }))?;
.push(Word::data(a.into_data().wrapping_neg()))?;
Ok(())
}

pub fn min(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
self.data_stack
.push(Word::data(unsafe { a.data.min(b.data) }))?;
.push(Word::data(a.into_data().min(b.into_data())))?;
Ok(())
}

pub fn max(&mut self) -> Result<(), Error> {
let a = self.data_stack.try_pop()?;
let b = self.data_stack.try_pop()?;
self.data_stack
.push(Word::data(unsafe { a.data.max(b.data) }))?;
.push(Word::data(a.into_data().max(b.into_data())))?;
Ok(())
}

Expand All @@ -789,10 +792,10 @@ impl<T: 'static> Forth<T> {
let n3 = self.data_stack.try_pop()?;
let n2 = self.data_stack.try_pop()?;
let n1 = self.data_stack.try_pop()?;
self.data_stack.push(Word::data(unsafe {
(n1.data as i64)
.wrapping_mul(n2.data as i64)
.wrapping_div(n3.data as i64) as i32
self.data_stack.push(Word::data({
(i64::from(n1.into_data()))
.wrapping_mul(i64::from(n2.into_data()))
.wrapping_div(i64::from(n3.into_data())) as i32
}))?;
Ok(())
}
Expand All @@ -801,14 +804,12 @@ impl<T: 'static> Forth<T> {
let n3 = self.data_stack.try_pop()?;
let n2 = self.data_stack.try_pop()?;
let n1 = self.data_stack.try_pop()?;
unsafe {
let top = (n1.data as i64).wrapping_mul(n2.data as i64);
let div = n3.data as i64;
let quo = top / div;
let rem = top % div;
self.data_stack.push(Word::data(rem as i32))?;
self.data_stack.push(Word::data(quo as i32))?;
}
let top = i64::from(n1.into_data()).wrapping_mul(i64::from(n2.into_data()));
let div = i64::from(n3.into_data());
let quo = top / div;
let rem = top % div;
self.data_stack.push(Word::data(rem as i32))?;
self.data_stack.push(Word::data(quo as i32))?;
Ok(())
}

Expand Down
7 changes: 6 additions & 1 deletion source/forth3/src/word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl TryInto<usize> for Word {
type Error = crate::Error;

fn try_into(self) -> Result<usize, Self::Error> {
let val = unsafe { self.data };
let val = self.into_data();
usize::try_from(val).replace_err(crate::Error::WordToUsizeInvalid(val))
}
}
Expand All @@ -55,6 +55,11 @@ impl Word {
}
}

#[inline]
pub fn into_data(self) -> i32 {
unsafe { self.data }
}

#[cfg(feature = "floats")]
#[inline]
pub fn float(f: f32) -> Self {
Expand Down

0 comments on commit 3acd0df

Please sign in to comment.