Sword OOM round 2: PANIC! in alloc_would_oom_ (#286)

* Revert "fix build error in assert_no_alloc (#284)"

This reverts commit 14124d804e.

* Revert "NockStack: explicitly catch OOM (#283)"

This reverts commit bd27200ef3.

* Panic instead of Result for OOM

* panic_any, don't use expect

* Buh-bye to PMA + guard

* fix tests

---------

Co-authored-by: Chris Allen <cma@bitemyapp.com>
This commit is contained in:
Edward Amsden 2024-11-26 19:18:39 -06:00 committed by GitHub
parent 14124d804e
commit f9915a75ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 2350 additions and 3014 deletions

View File

@ -173,7 +173,6 @@ pub struct AllocDisabler;
#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled #[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled
impl AllocDisabler { impl AllocDisabler {
#[allow(unused_variables)]
fn check(&self, layout: Layout) { fn check(&self, layout: Layout) {
let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get()); let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get());
let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get()); let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get());

View File

@ -1,20 +1,16 @@
//! Addition and subtraction operators. //! Addition and subtraction operators.
use crate::{ use crate::arch::word::Word;
add, use crate::buffer::Buffer;
arch::word::Word, use crate::ibig::IBig;
buffer::Buffer, use crate::memory::Stack;
helper_macros, use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
ibig::IBig, use crate::sign::Sign::*;
memory::Stack, use crate::ubig::Repr::*;
primitive::{PrimitiveSigned, PrimitiveUnsigned}, use crate::ubig::UBig;
sign::Sign::*, use crate::{add, helper_macros};
ubig::{Repr::*, UBig}, use core::mem;
}; use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::{
mem,
ops::{Add, AddAssign, Sub, SubAssign},
};
impl Add<UBig> for UBig { impl Add<UBig> for UBig {
type Output = UBig; type Output = UBig;
@ -531,58 +527,58 @@ impl UBig {
// given at least 2 words of extra capacity. However, this supports UBigs which have already // given at least 2 words of extra capacity. However, this supports UBigs which have already
// been expanded through other operations. // been expanded through other operations.
#[inline] #[inline]
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> { pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig = match (lhs.into_repr(), rhs.into_repr()) { let ubig = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1)?, (Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1),
(Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0)?, (Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0),
(Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1)?, (Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1),
(Large(buffer0), Large(buffer1)) => { (Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() { if buffer0.len() >= buffer1.len() {
UBig::add_large_stack(stack, buffer0, &buffer1)? UBig::add_large_stack(stack, buffer0, &buffer1)
} else { } else {
UBig::add_large_stack(stack, buffer1, &buffer0)? UBig::add_large_stack(stack, buffer1, &buffer0)
} }
} }
}; };
Ok(ubig) ubig
} }
/// Add two `Word`s. /// Add two `Word`s.
#[inline] #[inline]
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> { fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
let (res, overflow) = a.overflowing_add(b); let (res, overflow) = a.overflowing_add(b);
let ubig = if overflow { let ubig = if overflow {
let mut buffer = Buffer::allocate_stack(stack, 2)?; let mut buffer = Buffer::allocate_stack(stack, 2);
buffer.push(res); buffer.push(res);
buffer.push(1); buffer.push(1);
buffer.into() buffer.into()
} else { } else {
UBig::from_word(res) UBig::from_word(res)
}; };
Ok(ubig) ubig
} }
/// Add a large number to a `Word`. /// Add a large number to a `Word`.
fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> Result<UBig, S::AllocError> { fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> UBig {
debug_assert!(buffer.len() >= 2); debug_assert!(buffer.len() >= 2);
if add::add_word_in_place(&mut buffer, rhs) { if add::add_word_in_place(&mut buffer, rhs) {
buffer.push_may_reallocate_stack(stack, 1)?; buffer.push_may_reallocate_stack(stack, 1);
} }
Ok(buffer.into()) buffer.into()
} }
/// Add two large numbers. /// Add two large numbers.
fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> Result<UBig, S::AllocError> { fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> UBig {
let n = buffer.len().min(rhs.len()); let n = buffer.len().min(rhs.len());
let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]); let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
if rhs.len() > n { if rhs.len() > n {
buffer.ensure_capacity_stack(stack, rhs.len())?; buffer.ensure_capacity_stack(stack, rhs.len());
buffer.extend(&rhs[n..]); buffer.extend(&rhs[n..]);
} }
if overflow && add::add_one_in_place(&mut buffer[n..]) { if overflow && add::add_one_in_place(&mut buffer[n..]) {
buffer.push_may_reallocate_stack(stack, 1)?; buffer.push_may_reallocate_stack(stack, 1);
} }
Ok(buffer.into()) buffer.into()
} }
/// Add two `Word`s. /// Add two `Word`s.

View File

@ -1,13 +1,14 @@
//! Word buffer. //! Word buffer.
use crate::{arch::word::Word, memory, memory::Stack, ubig::UBig}; use crate::arch::word::Word;
use crate::memory;
use crate::memory::Stack;
use crate::ubig::UBig;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{ use core::iter;
iter, use core::mem::ManuallyDrop;
mem::ManuallyDrop, use core::ops::{Deref, DerefMut};
ops::{Deref, DerefMut},
};
/// Buffer for Words. /// Buffer for Words.
/// ///
@ -21,14 +22,14 @@ use core::{
pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>); pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>);
impl Buffer { impl Buffer {
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Result<Buffer, S::AllocError> { pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Buffer {
if num_words > Buffer::MAX_CAPACITY { if num_words > Buffer::MAX_CAPACITY {
UBig::panic_number_too_large(); UBig::panic_number_too_large();
} }
let capacity = Buffer::default_capacity(num_words); let capacity = Buffer::default_capacity(num_words);
unsafe { unsafe {
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity))?; let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity));
Ok(Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))) Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))
} }
} }
@ -44,11 +45,9 @@ impl Buffer {
))) )))
} }
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> { pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
if num_words > self.capacity() { if num_words > self.capacity() {
self.reallocate_stack(stack, num_words) self.reallocate_stack(stack, num_words)
} else {
Ok(())
} }
} }
@ -71,12 +70,11 @@ impl Buffer {
// } // }
} }
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> { fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
assert!(num_words >= self.len()); assert!(num_words >= self.len());
let mut new_buffer = Buffer::allocate_stack(stack, num_words)?; let mut new_buffer = Buffer::allocate_stack(stack, num_words);
new_buffer.clone_from(self); new_buffer.clone_from(self);
*self = new_buffer; *self = new_buffer;
Ok(())
} }
/// Change capacity to store `num_words` plus some extra space for future growth. /// Change capacity to store `num_words` plus some extra space for future growth.
@ -109,10 +107,9 @@ impl Buffer {
} }
#[inline] #[inline]
pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) -> Result<(), S::AllocError> { pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) {
self.ensure_capacity_stack(stack, self.len() + 1)?; self.ensure_capacity_stack(stack, self.len() + 1);
self.push(word); self.push(word);
Ok(())
} }
/// Append a Word and reallocate if necessary. /// Append a Word and reallocate if necessary.

View File

@ -1,15 +1,14 @@
//! Conversions between types. //! Conversions between types.
use crate::{ use crate::arch::word::Word;
arch::word::Word, use crate::buffer::Buffer;
buffer::Buffer, use crate::error::OutOfBoundsError;
error::OutOfBoundsError, use crate::ibig::IBig;
ibig::IBig, use crate::memory::Stack;
memory::Stack, use crate::primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES};
primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES}, use crate::sign::Sign::*;
sign::Sign::*, use crate::ubig::Repr::*;
ubig::{Repr::*, UBig}, use crate::ubig::UBig;
};
use alloc::vec::Vec; use alloc::vec::Vec;
use core::convert::{TryFrom, TryInto}; use core::convert::{TryFrom, TryInto};
@ -31,19 +30,19 @@ impl Default for IBig {
impl UBig { impl UBig {
#[inline] #[inline]
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> { pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
let ubig = if bytes.len() <= WORD_BYTES { let ubig = if bytes.len() <= WORD_BYTES {
// fast path // fast path
UBig::from_word(primitive::word_from_le_bytes_partial(bytes)) UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
} else { } else {
UBig::from_le_bytes_large_stack(stack, bytes)? UBig::from_le_bytes_large_stack(stack, bytes)
}; };
Ok(ubig) ubig
} }
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> { fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
debug_assert!(bytes.len() > WORD_BYTES); debug_assert!(bytes.len() > WORD_BYTES);
let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1)?; let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1);
let mut chunks = bytes.chunks_exact(WORD_BYTES); let mut chunks = bytes.chunks_exact(WORD_BYTES);
for chunk in &mut chunks { for chunk in &mut chunks {
buffer.push(Word::from_le_bytes(chunk.try_into().unwrap())); buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
@ -51,7 +50,7 @@ impl UBig {
if !chunks.remainder().is_empty() { if !chunks.remainder().is_empty() {
buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder())); buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
} }
Ok(buffer.into()) buffer.into()
} }
/// Construct from little-endian bytes. /// Construct from little-endian bytes.
@ -553,7 +552,7 @@ impl TryFrom<&IBig> for UBig {
impl UBig { impl UBig {
#[inline] #[inline]
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> Result<UBig, S::AllocError> pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> UBig
where where
T: PrimitiveUnsigned, T: PrimitiveUnsigned,
{ {
@ -561,10 +560,10 @@ impl UBig {
Ok(w) => UBig::from_word(w), Ok(w) => UBig::from_word(w),
Err(_) => { Err(_) => {
let repr = x.to_le_bytes(); let repr = x.to_le_bytes();
UBig::from_le_bytes_stack(stack, repr.as_ref())? UBig::from_le_bytes_stack(stack, repr.as_ref())
} }
}; };
Ok(ubig) ubig
} }
/// Convert an unsigned primitive to [UBig]. /// Convert an unsigned primitive to [UBig].

View File

@ -1,23 +1,19 @@
//! Division operators. //! Division operators.
use crate::{ use crate::arch::word::Word;
arch::word::Word, use crate::buffer::Buffer;
buffer::Buffer, use crate::ibig::IBig;
div, helper_macros, use crate::memory::{MemoryAllocation, Stack};
ibig::IBig, use crate::ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid};
memory::{MemoryAllocation, Stack}, use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid}, use crate::sign::Sign::*;
primitive::{PrimitiveSigned, PrimitiveUnsigned}, use crate::ubig::Repr::*;
shift, use crate::ubig::UBig;
sign::Sign::*, use crate::{div, helper_macros, shift};
ubig::{Repr::*, UBig}, use core::convert::TryFrom;
}; use core::fmt::Debug;
use core::{ use core::mem;
convert::TryFrom, use core::ops::{Div, DivAssign, Rem, RemAssign};
fmt::Debug,
mem,
ops::{Div, DivAssign, Rem, RemAssign},
};
impl Div<UBig> for UBig { impl Div<UBig> for UBig {
type Output = UBig; type Output = UBig;
@ -1279,71 +1275,71 @@ impl_div_ibig_signed!(isize);
impl UBig { impl UBig {
#[inline] #[inline]
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> { pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_word(word0, word1), (Small(word0), Small(word1)) => UBig::div_word(word0, word1),
(Small(_), Large(_)) => UBig::from_word(0), (Small(_), Large(_)) => UBig::from_word(0),
(Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1), (Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => { (Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() { if buffer0.len() >= buffer1.len() {
UBig::div_large_stack(stack, buffer0, buffer1)? UBig::div_large_stack(stack, buffer0, buffer1)
} else { } else {
UBig::from_word(0) UBig::from_word(0)
} }
} }
}; };
Ok(ubig_tuple) ubig_tuple
} }
#[inline] #[inline]
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> { pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::rem_word(word0, word1), (Small(word0), Small(word1)) => UBig::rem_word(word0, word1),
(Small(word0), Large(_)) => UBig::from_word(word0), (Small(word0), Large(_)) => UBig::from_word(word0),
(Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1), (Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1),
(Large(buffer0), Large(buffer1)) => { (Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() { if buffer0.len() >= buffer1.len() {
UBig::rem_large_stack(stack, buffer0, buffer1)? UBig::rem_large_stack(stack, buffer0, buffer1)
} else { } else {
buffer0.into() buffer0.into()
} }
} }
}; };
Ok(ubig_tuple) ubig_tuple
} }
#[inline] #[inline]
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<(UBig, UBig), S::AllocError> { pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> (UBig, UBig) {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) { let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1), (Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1),
(Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)), (Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)),
(Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1), (Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => { (Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() { if buffer0.len() >= buffer1.len() {
UBig::div_rem_large_stack(stack, buffer0, buffer1)? UBig::div_rem_large_stack(stack, buffer0, buffer1)
} else { } else {
(UBig::from_word(0), buffer0.into()) (UBig::from_word(0), buffer0.into())
} }
} }
}; };
Ok(ubig_tuple) ubig_tuple
} }
/// `lhs / rhs` /// `lhs / rhs`
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> { fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
lhs.erase_front(rhs.len()); lhs.erase_front(rhs.len());
Ok(lhs.into()) lhs.into()
} }
/// `lhs % rhs` /// `lhs % rhs`
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> { fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
let n = rhs.len(); let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]); rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift); let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0); debug_assert!(low_bits == 0);
Ok(rhs.into()) rhs.into()
} }
/// `(lhs / rhs, lhs % rhs)` /// `(lhs / rhs, lhs % rhs)`
@ -1351,33 +1347,33 @@ impl UBig {
stack: &mut S, stack: &mut S,
mut lhs: Buffer, mut lhs: Buffer,
mut rhs: Buffer, mut rhs: Buffer,
) -> Result<(UBig, UBig), S::AllocError> { ) -> (UBig, UBig) {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?; let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
let n = rhs.len(); let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]); rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift); let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0); debug_assert!(low_bits == 0);
lhs.erase_front(n); lhs.erase_front(n);
Ok((lhs.into(), rhs.into())) (lhs.into(), rhs.into())
} }
/// lhs = (lhs / rhs, lhs % rhs) /// lhs = (lhs / rhs, lhs % rhs)
/// ///
/// Returns shift. /// Returns shift.
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> Result<u32, S::AllocError> { fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> u32 {
let (shift, fast_div_rhs_top) = div::normalize_large(rhs); let (shift, fast_div_rhs_top) = div::normalize_large(rhs);
let lhs_carry = shift::shl_in_place(lhs, shift); let lhs_carry = shift::shl_in_place(lhs, shift);
if lhs_carry != 0 { if lhs_carry != 0 {
lhs.push_may_reallocate_stack(stack, lhs_carry)?; lhs.push_may_reallocate_stack(stack, lhs_carry);
} }
let mut allocation = let mut allocation =
MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()))?; MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()));
let mut memory = allocation.memory(); let mut memory = allocation.memory();
let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory); let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory);
if overflow { if overflow {
lhs.push_may_reallocate(1); lhs.push_may_reallocate(1);
} }
Ok(shift) shift
} }
/// `lhs / rhs` /// `lhs / rhs`

View File

@ -1,7 +1,8 @@
//! Memory allocation. //! Memory allocation.
use alloc::alloc::Layout; use alloc::alloc::Layout;
use core::{marker::PhantomData, mem, slice}; use core::marker::PhantomData;
use core::{mem, slice};
/// Chunk of memory directly allocated from the global allocator. /// Chunk of memory directly allocated from the global allocator.
pub(crate) struct MemoryAllocation { pub(crate) struct MemoryAllocation {
@ -10,10 +11,8 @@ pub(crate) struct MemoryAllocation {
} }
pub trait Stack: Sized { pub trait Stack: Sized {
// type AllocError: Debug;
// no-std bites me in the keister again // no-std bites me in the keister again
type AllocError; unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64;
unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<*mut u64, Self::AllocError>;
} }
/// Chunk of memory. /// Chunk of memory.
@ -27,7 +26,7 @@ pub(crate) struct Memory<'a> {
} }
impl MemoryAllocation { impl MemoryAllocation {
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> Result<MemoryAllocation, S::AllocError> { pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> MemoryAllocation {
let start = if layout.size() == 0 { let start = if layout.size() == 0 {
// We should use layout.dangling(), but that is unstable. // We should use layout.dangling(), but that is unstable.
layout.align() as *mut u8 layout.align() as *mut u8
@ -36,7 +35,7 @@ impl MemoryAllocation {
} else { } else {
// Safe because size is non-zero. // Safe because size is non-zero.
let ptr = unsafe { let ptr = unsafe {
let ep = stack.alloc_layout(layout)?; let ep = stack.alloc_layout(layout);
ep as *mut u8 ep as *mut u8
}; };
if ptr.is_null() { if ptr.is_null() {
@ -45,7 +44,7 @@ impl MemoryAllocation {
ptr ptr
}; };
Ok(MemoryAllocation { layout, start }) MemoryAllocation { layout, start }
} }
/// Allocate memory. /// Allocate memory.

View File

@ -1,20 +1,16 @@
//! Multiplication operators. //! Multiplication operators.
use crate::{ use crate::arch::word::Word;
arch::word::Word, use crate::buffer::Buffer;
buffer::Buffer, use crate::ibig::IBig;
helper_macros, use crate::memory::{MemoryAllocation, Stack};
ibig::IBig, use crate::primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned};
memory::{MemoryAllocation, Stack}, use crate::sign::Sign::{self, *};
mul, use crate::ubig::Repr::*;
primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned}, use crate::ubig::UBig;
sign::Sign::{self, *}, use crate::{helper_macros, mul};
ubig::{Repr::*, UBig}, use core::mem;
}; use core::ops::{Mul, MulAssign};
use core::{
mem,
ops::{Mul, MulAssign},
};
use static_assertions::const_assert; use static_assertions::const_assert;
impl Mul<UBig> for UBig { impl Mul<UBig> for UBig {
@ -300,52 +296,52 @@ impl_mul_ibig_primitive!(isize);
impl UBig { impl UBig {
#[inline] #[inline]
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> { pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let res = match (lhs.into_repr(), rhs.into_repr()) { let res = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1)?, (Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1),
(Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0)?, (Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0),
(Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1)?, (Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1),
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1)?, (Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1),
}; };
Ok(res) res
} }
#[inline] #[inline]
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> { fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b)) UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b))
} }
fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> Result<UBig, S::AllocError> { fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> UBig {
match a { match a {
0 => Ok(UBig::from_word(0)), 0 => UBig::from_word(0),
1 => Ok(buffer.into()), 1 => buffer.into(),
_ => { _ => {
let carry = mul::mul_word_in_place(&mut buffer, a); let carry = mul::mul_word_in_place(&mut buffer, a);
if carry != 0 { if carry != 0 {
buffer.push_may_reallocate_stack(stack, carry)?; buffer.push_may_reallocate_stack(stack, carry);
} }
Ok(buffer.into()) buffer.into()
} }
} }
} }
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> Result<UBig, S::AllocError> { pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> UBig {
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2); debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
// This may be 1 too large. // This may be 1 too large.
const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1); const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1);
let res_len = lhs.len() + rhs.len(); let res_len = lhs.len() + rhs.len();
let mut buffer = Buffer::allocate_stack(stack, res_len)?; let mut buffer = Buffer::allocate_stack(stack, res_len);
buffer.push_zeros(res_len); buffer.push_zeros(res_len);
let mut allocation = MemoryAllocation::new_stack( let mut allocation = MemoryAllocation::new_stack(
stack, stack,
mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())), mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())),
)?; );
let mut memory = allocation.memory(); let mut memory = allocation.memory();
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory); let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
assert!(overflow == 0); assert!(overflow == 0);
Ok(buffer.into()) buffer.into()
} }
/// Multiply two `Word`s. /// Multiply two `Word`s.

View File

@ -17,7 +17,7 @@ fn main() -> io::Result<()> {
let jammed_input = unsafe { let jammed_input = unsafe {
let in_map = memmap::Mmap::map(&f)?; let in_map = memmap::Mmap::map(&f)?;
let word_len = (in_len + 7) >> 3; let word_len = (in_len + 7) >> 3;
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize).expect("Out of memory condition on IndirectAtom allocation in main()"); let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize);
write_bytes(dest.add(word_len as usize - 1), 0, 8); write_bytes(dest.add(word_len as usize - 1), 0, 8);
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize); copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
mem::drop(in_map); mem::drop(in_map);
@ -45,7 +45,7 @@ fn main() -> io::Result<()> {
let nuw = SystemTime::now(); let nuw = SystemTime::now();
let jammed_output = jam(&mut stack, input).expect("Out of memory condition on jam in main()"); let jammed_output = jam(&mut stack, input);
match nuw.elapsed() { match nuw.elapsed() {
Ok(elapse) => { Ok(elapse) => {

View File

@ -1,5 +1,5 @@
use crate::interpreter::Context; use crate::interpreter::Context;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Atom, IndirectAtom}; use crate::noun::{Atom, IndirectAtom};
use std::fmt::Arguments; use std::fmt::Arguments;
use std::io::{Result, Write}; use std::io::{Result, Write};
@ -14,27 +14,26 @@ struct NockWriter<'s, 'b> {
const INITIAL_CAPACITY_BYTES: usize = 256; const INITIAL_CAPACITY_BYTES: usize = 256;
impl<'s, 'b> NockWriter<'s, 'b> { impl<'s, 'b> NockWriter<'s, 'b> {
unsafe fn new(stack: &'s mut NockStack) -> AllocResult<Self> { unsafe fn new(stack: &'s mut NockStack) -> Self {
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES)?; let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES);
Ok(NockWriter { NockWriter {
stack, stack,
buffer, buffer,
indirect, indirect,
cursor: 0, cursor: 0,
}) }
} }
unsafe fn finalize(mut self) -> Atom { unsafe fn finalize(mut self) -> Atom {
self.indirect.normalize_as_atom() self.indirect.normalize_as_atom()
} }
unsafe fn expand(&mut self) -> AllocResult<()> { unsafe fn expand(&mut self) {
let sz = self.buffer.len(); let sz = self.buffer.len();
let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2)?; let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2);
new_buffer[0..sz].copy_from_slice(self.buffer); new_buffer[0..sz].copy_from_slice(self.buffer);
self.buffer = new_buffer; self.buffer = new_buffer;
self.indirect = new_indirect; self.indirect = new_indirect;
Ok(())
} }
} }
@ -42,7 +41,7 @@ impl Write for NockWriter<'_, '_> {
fn write(&mut self, buf: &[u8]) -> Result<usize> { fn write(&mut self, buf: &[u8]) -> Result<usize> {
let sz = buf.len(); let sz = buf.len();
while (self.buffer.len() - self.cursor) < sz { while (self.buffer.len() - self.cursor) < sz {
unsafe { self.expand()? }; unsafe { self.expand() };
} }
self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf); self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf);
self.cursor += sz; self.cursor += sz;
@ -55,14 +54,14 @@ impl Write for NockWriter<'_, '_> {
} }
pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<Atom> { pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<Atom> {
let mut nw = unsafe { NockWriter::new(&mut context.stack)? }; let mut nw = unsafe { NockWriter::new(&mut context.stack) };
nw.write_fmt(fmt)?; nw.write_fmt(fmt)?;
Ok(unsafe { nw.finalize() }) Ok(unsafe { nw.finalize() })
} }
pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> { pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> {
let cord = nock_fmt(context, fmt)?; let cord = nock_fmt(context, fmt)?;
context.slogger.flog(&mut context.stack, cord.as_noun())?; context.slogger.flog(&mut context.stack, cord.as_noun());
Ok(()) Ok(())
} }

View File

@ -1,4 +1,4 @@
use crate::mem::{AllocResult, NockStack, Preserve}; use crate::mem::{NockStack, Preserve};
use crate::mug::mug_u32; use crate::mug::mug_u32;
use crate::noun::Noun; use crate::noun::Noun;
use crate::unifying_equality::unifying_equality; use crate::unifying_equality::unifying_equality;
@ -59,45 +59,45 @@ impl<T: Copy> MutStem<T> {
pub struct MutHamt<T: Copy>(*mut MutStem<T>); pub struct MutHamt<T: Copy>(*mut MutStem<T>);
impl<T: Copy> MutHamt<T> { impl<T: Copy> MutHamt<T> {
pub fn new(stack: &mut NockStack) -> AllocResult<MutHamt<T>> { pub fn new(stack: &mut NockStack) -> MutHamt<T> {
unsafe { unsafe {
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?; let new_stem = stack.struct_alloc::<MutStem<T>>(1);
(*new_stem).bitmap = 0; (*new_stem).bitmap = 0;
(*new_stem).typemap = 0; (*new_stem).typemap = 0;
Ok(MutHamt(new_stem)) MutHamt(new_stem)
} }
} }
pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> { pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
let mut stem = self.0; let mut stem = self.0;
let mut mug = mug_u32(stack, *n)?; let mut mug = mug_u32(stack, *n);
unsafe { unsafe {
'lookup: loop { 'lookup: loop {
let chunk = mug & 0x1f; let chunk = mug & 0x1f;
mug >>= 5; mug >>= 5;
match (*stem).entry(chunk) { match (*stem).entry(chunk) {
None => { None => {
break Ok(None); break None;
} }
Some(Left(next_stem)) => { Some(Left(next_stem)) => {
stem = next_stem; stem = next_stem;
} }
Some(Right(leaf)) => { Some(Right(leaf)) => {
for pair in leaf.to_mut_slice().iter_mut() { for pair in leaf.to_mut_slice().iter_mut() {
if unifying_equality(stack, n, &mut pair.0)? { if unifying_equality(stack, n, &mut pair.0) {
break 'lookup Ok(Some(pair.1)); break 'lookup Some(pair.1);
} }
} }
break Ok(None); break None;
} }
} }
} }
} }
} }
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> { pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) {
let mut stem = self.0; let mut stem = self.0;
let mut mug = mug_u32(stack, *n)?; let mut mug = mug_u32(stack, *n);
let mut depth = 0u8; let mut depth = 0u8;
unsafe { unsafe {
'insert: loop { 'insert: loop {
@ -105,7 +105,7 @@ impl<T: Copy> MutHamt<T> {
mug >>= 5; mug >>= 5;
match (*stem).entry(chunk) { match (*stem).entry(chunk) {
None => { None => {
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1)?; let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1);
*new_leaf_buffer = (*n, t); *new_leaf_buffer = (*n, t);
(*stem).bitmap |= chunk_to_bit(chunk); (*stem).bitmap |= chunk_to_bit(chunk);
(*stem).typemap &= !chunk_to_bit(chunk); (*stem).typemap &= !chunk_to_bit(chunk);
@ -124,13 +124,13 @@ impl<T: Copy> MutHamt<T> {
} }
Some(Right(leaf)) => { Some(Right(leaf)) => {
for pair in leaf.to_mut_slice().iter_mut() { for pair in leaf.to_mut_slice().iter_mut() {
if unifying_equality(stack, n, &mut pair.0)? { if unifying_equality(stack, n, &mut pair.0) {
pair.1 = t; pair.1 = t;
break 'insert; break 'insert;
} }
} }
if depth >= 5 { if depth >= 5 {
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1)?; let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
*new_leaf_buffer.add(leaf.len) = (*n, t); *new_leaf_buffer.add(leaf.len) = (*n, t);
(*stem).buffer[chunk as usize] = MutEntry { (*stem).buffer[chunk as usize] = MutEntry {
@ -142,8 +142,8 @@ impl<T: Copy> MutHamt<T> {
break; break;
} else { } else {
assert!(leaf.len == 1); assert!(leaf.len == 1);
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?; let new_stem = stack.struct_alloc::<MutStem<T>>(1);
let leaf_mug = mug_u32(stack, (*leaf.buffer).0)?; let leaf_mug = mug_u32(stack, (*leaf.buffer).0);
let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f; let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f;
(*new_stem).bitmap = chunk_to_bit(leaf_chunk); (*new_stem).bitmap = chunk_to_bit(leaf_chunk);
(*new_stem).typemap = 0; (*new_stem).typemap = 0;
@ -158,7 +158,6 @@ impl<T: Copy> MutHamt<T> {
} }
} }
} }
Ok(())
} }
} }
@ -283,15 +282,15 @@ impl<T: Copy + Preserve> Hamt<T> {
unsafe { (*self.0).bitmap == 0 } unsafe { (*self.0).bitmap == 0 }
} }
// Make a new, empty HAMT // Make a new, empty HAMT
pub fn new(stack: &mut NockStack) -> AllocResult<Self> { pub fn new(stack: &mut NockStack) -> Self {
unsafe { unsafe {
let stem_ptr = stack.struct_alloc::<Stem<T>>(1)?; let stem_ptr = stack.struct_alloc::<Stem<T>>(1);
*stem_ptr = Stem { *stem_ptr = Stem {
bitmap: 0, bitmap: 0,
typemap: 0, typemap: 0,
buffer: null_mut(), buffer: null_mut(),
}; };
Ok(Hamt(stem_ptr)) Hamt(stem_ptr)
} }
} }
@ -306,15 +305,15 @@ impl<T: Copy + Preserve> Hamt<T> {
* A mutable reference is required so that unifying equality can unify the key with a key entry * A mutable reference is required so that unifying equality can unify the key with a key entry
* in the HAMT * in the HAMT
*/ */
pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> { pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
let mut stem = unsafe { *self.0 }; let mut stem = unsafe { *self.0 };
let mut mug = mug_u32(stack, *n)?; let mut mug = mug_u32(stack, *n);
'lookup: loop { 'lookup: loop {
let chunk = mug & 0x1F; // 5 bits let chunk = mug & 0x1F; // 5 bits
mug >>= 5; mug >>= 5;
match stem.entry(chunk) { match stem.entry(chunk) {
None => { None => {
break Ok(None); break None;
} }
Some((Left(next_stem), _idx)) => { Some((Left(next_stem), _idx)) => {
stem = next_stem; stem = next_stem;
@ -322,11 +321,11 @@ impl<T: Copy + Preserve> Hamt<T> {
} }
Some((Right(leaf), _idx)) => { Some((Right(leaf), _idx)) => {
for pair in unsafe { leaf.to_mut_slice().iter_mut() } { for pair in unsafe { leaf.to_mut_slice().iter_mut() } {
if unsafe { unifying_equality(stack, n, &mut pair.0)? } { if unsafe { unifying_equality(stack, n, &mut pair.0) } {
break 'lookup Ok(Some(pair.1)); break 'lookup Some(pair.1);
} }
} }
break Ok(None); break None;
} }
} }
} }
@ -335,11 +334,11 @@ impl<T: Copy + Preserve> Hamt<T> {
// XX a delete function requires a stack, do we need one? // XX a delete function requires a stack, do we need one?
/// Make a new HAMT with the value inserted or replaced at the key. /// Make a new HAMT with the value inserted or replaced at the key.
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<Hamt<T>> { pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> Hamt<T> {
let mut mug = mug_u32(stack, *n)?; let mut mug = mug_u32(stack, *n);
let mut depth = 0u8; let mut depth = 0u8;
let mut stem = unsafe { *self.0 }; let mut stem = unsafe { *self.0 };
let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) }?; let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) };
let mut dest = stem_ret; let mut dest = stem_ret;
unsafe { unsafe {
'insert: loop { 'insert: loop {
@ -348,10 +347,10 @@ impl<T: Copy + Preserve> Hamt<T> {
match stem.entry(chunk) { match stem.entry(chunk) {
// No entry found at mug chunk index; add Leaf to current Stem // No entry found at mug chunk index; add Leaf to current Stem
None => { None => {
let new_leaf_buffer = stack.struct_alloc(1)?; let new_leaf_buffer = stack.struct_alloc(1);
*new_leaf_buffer = (*n, t); *new_leaf_buffer = (*n, t);
let split = stem.hypothetical_index(chunk); let split = stem.hypothetical_index(chunk);
let new_buffer = stack.struct_alloc(stem.size() + 1)?; let new_buffer = stack.struct_alloc(stem.size() + 1);
if split > 0 { if split > 0 {
copy_nonoverlapping(stem.buffer, new_buffer, split); copy_nonoverlapping(stem.buffer, new_buffer, split);
} }
@ -373,11 +372,11 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap & !chunk_to_bit(chunk), typemap: stem.typemap & !chunk_to_bit(chunk),
buffer: new_buffer, buffer: new_buffer,
}; };
break Ok(Hamt(stem_ret)); break Hamt(stem_ret);
} }
// Stem found at mug chunk index; insert into found Stem // Stem found at mug chunk index; insert into found Stem
Some((Left(next_stem), idx)) => { Some((Left(next_stem), idx)) => {
let new_buffer = stack.struct_alloc(stem.size())?; let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*dest = Stem { *dest = Stem {
bitmap: stem.bitmap, bitmap: stem.bitmap,
@ -393,11 +392,11 @@ impl<T: Copy + Preserve> Hamt<T> {
Some((Right(leaf), idx)) => { Some((Right(leaf), idx)) => {
// Override existing value for key, if one exists // Override existing value for key, if one exists
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() { for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
if unifying_equality(stack, n, &mut pair.0)? { if unifying_equality(stack, n, &mut pair.0) {
let new_leaf_buffer = stack.struct_alloc(leaf.len)?; let new_leaf_buffer = stack.struct_alloc(leaf.len);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
(*new_leaf_buffer.add(ldx)).1 = t; (*new_leaf_buffer.add(ldx)).1 = t;
let new_buffer = stack.struct_alloc(stem.size())?; let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*new_buffer.add(idx) = Entry { *new_buffer.add(idx) = Entry {
leaf: Leaf { leaf: Leaf {
@ -410,16 +409,16 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap, typemap: stem.typemap,
buffer: new_buffer, buffer: new_buffer,
}; };
break 'insert Ok(Hamt(stem_ret)); break 'insert Hamt(stem_ret);
} }
} }
// No existing pair in this Leaf matches the key, and we've maxxed out the // No existing pair in this Leaf matches the key, and we've maxxed out the
// Hamt depth; add the the key-value pair to the list of pairs for this Leaf // Hamt depth; add the the key-value pair to the list of pairs for this Leaf
if depth >= 5 { if depth >= 5 {
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1)?; let new_leaf_buffer = stack.struct_alloc(leaf.len + 1);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len); copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
*new_leaf_buffer.add(leaf.len) = (*n, t); *new_leaf_buffer.add(leaf.len) = (*n, t);
let new_buffer = stack.struct_alloc(stem.size())?; let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*new_buffer.add(idx) = Entry { *new_buffer.add(idx) = Entry {
leaf: Leaf { leaf: Leaf {
@ -432,7 +431,7 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap, typemap: stem.typemap,
buffer: new_buffer, buffer: new_buffer,
}; };
break 'insert Ok(Hamt(stem_ret)); break 'insert Hamt(stem_ret);
// No existing pair in this Leaf matches the key, but we haven't maxxed out // No existing pair in this Leaf matches the key, but we haven't maxxed out
// the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't // the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't
// be making a linked list of pairs. Turn the Leaf into a Stem and insert // be making a linked list of pairs. Turn the Leaf into a Stem and insert
@ -442,18 +441,18 @@ impl<T: Copy + Preserve> Hamt<T> {
// Make a fake node pointing to the old leaf and "insert into it" the // Make a fake node pointing to the old leaf and "insert into it" the
// next time around // next time around
assert!(leaf.len == 1); assert!(leaf.len == 1);
let fake_buffer = stack.struct_alloc(1)?; let fake_buffer = stack.struct_alloc(1);
*fake_buffer = Entry { leaf }; *fake_buffer = Entry { leaf };
// Get the mug chunk for the Noun at the *next* level so that we can // Get the mug chunk for the Noun at the *next* level so that we can
// build a fake stem for it // build a fake stem for it
let fake_mug = mug_u32(stack, (*leaf.buffer).0)?; let fake_mug = mug_u32(stack, (*leaf.buffer).0);
let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F; let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F;
let next_stem = Stem { let next_stem = Stem {
bitmap: chunk_to_bit(fake_chunk), bitmap: chunk_to_bit(fake_chunk),
typemap: 0, typemap: 0,
buffer: fake_buffer, buffer: fake_buffer,
}; };
let new_buffer = stack.struct_alloc(stem.size())?; let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size()); copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*dest = Stem { *dest = Stem {
bitmap: stem.bitmap, bitmap: stem.bitmap,
@ -518,13 +517,13 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
} }
} }
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
let res = if stack.is_in_frame(self.0) { if stack.is_in_frame(self.0) {
let dest_stem = stack.struct_alloc_in_previous_frame(1)?; let dest_stem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(self.0, dest_stem, 1); copy_nonoverlapping(self.0, dest_stem, 1);
self.0 = dest_stem; self.0 = dest_stem;
if stack.is_in_frame((*dest_stem).buffer) { if stack.is_in_frame((*dest_stem).buffer) {
let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size())?; let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size());
copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size()); copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size());
(*dest_stem).buffer = dest_buffer; (*dest_stem).buffer = dest_buffer;
// Here we're using the Rust stack since the array is a fixed // Here we're using the Rust stack since the array is a fixed
@ -557,7 +556,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
Some((Left(next_stem), idx)) => { Some((Left(next_stem), idx)) => {
if stack.is_in_frame(next_stem.buffer) { if stack.is_in_frame(next_stem.buffer) {
let dest_buffer = let dest_buffer =
stack.struct_alloc_in_previous_frame(next_stem.size())?; stack.struct_alloc_in_previous_frame(next_stem.size());
copy_nonoverlapping( copy_nonoverlapping(
next_stem.buffer, next_stem.buffer,
dest_buffer, dest_buffer,
@ -583,15 +582,15 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
Some((Right(leaf), idx)) => { Some((Right(leaf), idx)) => {
if stack.is_in_frame(leaf.buffer) { if stack.is_in_frame(leaf.buffer) {
let dest_buffer = let dest_buffer =
stack.struct_alloc_in_previous_frame(leaf.len)?; stack.struct_alloc_in_previous_frame(leaf.len);
copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len); copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len);
let new_leaf = Leaf { let new_leaf = Leaf {
len: leaf.len, len: leaf.len,
buffer: dest_buffer, buffer: dest_buffer,
}; };
for pair in new_leaf.to_mut_slice().iter_mut() { for pair in new_leaf.to_mut_slice().iter_mut() {
pair.0.preserve(stack)?; pair.0.preserve(stack);
pair.1.preserve(stack)?; pair.1.preserve(stack);
} }
*stem.buffer.add(idx) = Entry { leaf: new_leaf }; *stem.buffer.add(idx) = Entry { leaf: new_leaf };
} }
@ -602,8 +601,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
} }
} }
} }
}; }
Ok(res)
} }
} }
@ -709,10 +707,10 @@ mod test {
let size = 1 << 27; let size = 1 << 27;
let top_slots = 100; let top_slots = 100;
let mut stack = NockStack::new(size, top_slots); let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap(); let mut hamt = Hamt::<Noun>::new(&mut stack);
hamt = hamt.insert(&mut stack, &mut D(0), D(1)).unwrap(); hamt = hamt.insert(&mut stack, &mut D(0), D(1));
hamt = hamt.insert(&mut stack, &mut D(2), D(3)).unwrap(); hamt = hamt.insert(&mut stack, &mut D(2), D(3));
hamt = hamt.insert(&mut stack, &mut D(4), D(5)).unwrap(); hamt = hamt.insert(&mut stack, &mut D(4), D(5));
let mut iter = hamt.iter(); let mut iter = hamt.iter();
let three = cdr(&mut iter); let three = cdr(&mut iter);
let one = cdr(&mut iter); let one = cdr(&mut iter);
@ -730,10 +728,10 @@ mod test {
let size = 1 << 27; let size = 1 << 27;
let top_slots = 100; let top_slots = 100;
let mut stack = NockStack::new(size, top_slots); let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap(); let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hs = HashSet::new(); let mut hs = HashSet::new();
for n in 0..100 { for n in 0..100 {
hamt = hamt.insert(&mut stack, &mut D(n), D(n)).unwrap(); hamt = hamt.insert(&mut stack, &mut D(n), D(n));
hs.insert((n, n)); hs.insert((n, n));
} }
let mut iter = hamt.iter(); let mut iter = hamt.iter();
@ -748,21 +746,17 @@ mod test {
let size = 1 << 27; let size = 1 << 27;
let top_slots = 100; let top_slots = 100;
let mut stack = NockStack::new(size, top_slots); let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap(); let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut n = D(0); let mut n = D(0);
let t = D(1); let t = D(1);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt let lu = hamt.lookup(&mut stack, &mut n);
.lookup(&mut stack, &mut n)
.expect("lookup failed due to OOM");
let lu_value = unsafe { lu.expect("lookup failed").as_raw() }; let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 1); assert_eq!(lu_value, 1);
let mut n = D(2); let mut n = D(2);
let t = D(3); let t = D(3);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt let lu = hamt.lookup(&mut stack, &mut D(2));
.lookup(&mut stack, &mut D(2))
.expect("lookup failed due to OOM");
let lu_value = unsafe { lu.expect("lookup failed").as_raw() }; let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 3); assert_eq!(lu_value, 3);
} }
@ -772,38 +766,32 @@ mod test {
let size = 1 << 27; let size = 1 << 27;
let top_slots = 100; let top_slots = 100;
let mut stack = NockStack::new(size, top_slots); let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap(); let mut hamt = Hamt::<Noun>::new(&mut stack);
// 3-way collision // 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072 // x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072 // x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut n = D(0); let mut n = D(0);
let t = D(0); let t = D(0);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); hamt = hamt.insert(&mut stack, &mut n, t);
let mut n = D(87699370); let mut n = D(87699370);
let t = D(87699370); let t = D(87699370);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); hamt = hamt.insert(&mut stack, &mut n, t);
let mut n = D(317365951); let mut n = D(317365951);
let t = D(317365951); let t = D(317365951);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap(); hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt let lu = hamt.lookup(&mut stack, &mut D(0));
.lookup(&mut stack, &mut D(0))
.expect("lookup failed due to OOM");
let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() }; let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() };
assert_eq!(lu_value, 0); assert_eq!(lu_value, 0);
let lu = hamt let lu = hamt.lookup(&mut stack, &mut D(87699370));
.lookup(&mut stack, &mut D(87699370))
.expect("lookup failed due to OOM");
let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() }; let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() };
assert_eq!(lu_value, 87699370); assert_eq!(lu_value, 87699370);
let lu = hamt let lu = hamt.lookup(&mut stack, &mut D(317365951));
.lookup(&mut stack, &mut D(317365951))
.expect("lookup failed due to OOM");
let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() }; let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() };
assert_eq!(lu_value, 317365951); assert_eq!(lu_value, 317365951);
} }
@ -813,13 +801,13 @@ mod test {
let size = 1 << 27; let size = 1 << 27;
let top_slots = 100; let top_slots = 100;
let mut stack = NockStack::new(size, top_slots); let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap(); let mut hamt = Hamt::<Noun>::new(&mut stack);
// 3-way collision // 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072 // x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072 // x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut hs = HashSet::new(); let mut hs = HashSet::new();
for x in &[0, 87699370, 317365951] { for x in &[0, 87699370, 317365951] {
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)).unwrap(); hamt = hamt.insert(&mut stack, &mut D(*x), D(*x));
hs.insert((*x, *x)); hs.insert((*x, *x));
} }
for x in hamt.iter() { for x in hamt.iter() {

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,10 @@ pub mod tree;
use crate::flog; use crate::flog;
use crate::interpreter::{Context, Error, Mote}; use crate::interpreter::{Context, Error, Mote};
use crate::jets::bits::*; use crate::jets::bits::*;
use crate::jets::cold::Cold;
use crate::jets::form::*; use crate::jets::form::*;
use crate::jets::hash::*; use crate::jets::hash::*;
use crate::jets::hot::{Hot, URBIT_HOT_STATE};
use crate::jets::list::*; use crate::jets::list::*;
use crate::jets::lock::aes::*; use crate::jets::lock::aes::*;
use crate::jets::lock::ed::*; use crate::jets::lock::ed::*;
@ -32,36 +34,31 @@ use crate::jets::serial::*;
use crate::jets::sort::*; use crate::jets::sort::*;
use crate::jets::tree::*; use crate::jets::tree::*;
use crate::mem::{AllocResult, NockStack, Preserve}; use crate::jets::warm::Warm;
use crate::mem::{NockStack, Preserve};
use crate::noun::{self, Noun, Slots, D}; use crate::noun::{self, Noun, Slots, D};
use sword_macros::tas; use sword_macros::tas;
crate::gdb!(); crate::gdb!();
/// Return Err if the computation crashed or should punt to Nock /// Return Err if the computation crashed or should punt to Nock
pub type Result<T> = std::result::Result<T, JetErr>; pub type Result = std::result::Result<Noun, JetErr>;
pub type Jet = fn(&mut Context, Noun) -> Result<Noun>; pub type Jet = fn(&mut Context, Noun) -> Result;
/** /**
* Only return a deterministic error if the Nock would have deterministically * Only return a deterministic error if the Nock would have deterministically
* crashed. * crashed.
*/ */
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug)]
pub enum JetErr { pub enum JetErr {
Punt, // Retry with the raw nock Punt, // Retry with the raw nock
Fail(Error), // Error; do not retry Fail(Error), // Error; do not retry
} }
impl From<crate::mem::AllocationError> for JetErr {
fn from(_err: crate::mem::AllocationError) -> Self {
JetErr::Fail(Error::NonDeterministic(Mote::Meme, D(0)))
}
}
impl Preserve for JetErr { impl Preserve for JetErr {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self { match self {
JetErr::Punt => Ok(()), JetErr::Punt => {}
JetErr::Fail(ref mut err) => err.preserve(stack), JetErr::Fail(ref mut err) => err.preserve(stack),
} }
} }
@ -235,7 +232,7 @@ pub mod util {
bits_to_word(checked_left_shift(bloq, step)?) bits_to_word(checked_left_shift(bloq, step)?)
} }
pub fn slot(noun: Noun, axis: u64) -> Result<Noun> { pub fn slot(noun: Noun, axis: u64) -> Result {
noun.slot(axis).map_err(|_e| BAIL_EXIT) noun.slot(axis).map_err(|_e| BAIL_EXIT)
} }
@ -291,7 +288,7 @@ pub mod util {
} }
pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> { pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> {
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)])?; let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)]);
interpret(context, core, formula).map_err(JetErr::Fail) interpret(context, core, formula).map_err(JetErr::Fail)
} }
@ -299,44 +296,41 @@ pub mod util {
let core: Noun = T( let core: Noun = T(
&mut context.stack, &mut context.stack,
&[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()], &[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()],
)?; );
kick(context, core, D(2)) kick(context, core, D(2))
} }
#[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;
use crate::hamt::Hamt; use crate::hamt::Hamt;
use crate::interpreter::Slogger; use crate::interpreter::Slogger;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Atom, Noun, D, T}; use crate::noun::{Atom, Noun, D, T};
use crate::unifying_equality::test::unifying_equality; use crate::unifying_equality::unifying_equality;
use assert_no_alloc::assert_no_alloc; use assert_no_alloc::assert_no_alloc;
use ibig::UBig; use ibig::UBig;
struct TestSlogger {} struct TestSlogger {}
impl Slogger for TestSlogger { impl Slogger for TestSlogger {
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) -> AllocResult<()> { fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) {
eprintln!("Jet slogged."); eprintln!("Jet slogged.");
Ok(())
} }
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) -> AllocResult<()> { fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) {
eprintln!("Jet flogged."); eprintln!("Jet flogged.");
Ok(())
} }
} }
pub fn init_context() -> Result<Context> { pub fn init_context() -> Context {
let mut stack = NockStack::new(8 << 10 << 10, 0); let mut stack = NockStack::new(8 << 10 << 10, 0);
let cold = cold::Cold::new(&mut stack)?; let cold = Cold::new(&mut stack);
let warm = warm::Warm::new(&mut stack)?; let warm = Warm::new(&mut stack);
let hot = hot::Hot::init(&mut stack, hot::URBIT_HOT_STATE)?; let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
let cache = Hamt::<Noun>::new(&mut stack)?; let cache = Hamt::<Noun>::new(&mut stack);
let slogger = std::boxed::Box::pin(TestSlogger {}); let slogger = std::boxed::Box::pin(TestSlogger {});
Ok(Context { Context {
stack, stack,
slogger, slogger,
cold, cold,
@ -345,12 +339,12 @@ pub mod util {
cache, cache,
scry_stack: D(0), scry_stack: D(0),
trace_info: None, trace_info: None,
}) }
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn A(stack: &mut NockStack, ubig: &UBig) -> AllocResult<Noun> { pub fn A(stack: &mut NockStack, ubig: &UBig) -> Noun {
Ok(Atom::from_ubig(stack, ubig)?.as_noun()) Atom::from_ubig(stack, ubig).as_noun()
} }
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) { pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
@ -358,92 +352,28 @@ pub mod util {
assert!(eq, "got: {}, need: {}", a, b); assert!(eq, "got: {}, need: {}", a, b);
} }
pub fn assert_jet( pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
context: &mut Context,
jet: Jet,
sam: Noun,
res: Noun,
) -> AllocResult<()> {
assert_jet_door(context, jet, sam, D(0), res) assert_jet_door(context, jet, sam, D(0), res)
} }
pub type AssertJetFn = fn( pub fn assert_jet_door(context: &mut Context, jet: Jet, sam: Noun, pay: Noun, res: Noun) {
&mut Context, let sam = T(&mut context.stack, &[D(0), sam, pay]);
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
Noun,
);
pub fn assert_jet_panicky(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
assert_jet(context, jet, sam, res).expect("assert_jet failed");
}
pub fn assert_jet_door(
context: &mut Context,
jet: Jet,
sam: Noun,
pay: Noun,
res: Noun,
) -> AllocResult<()> {
let sam = T(&mut context.stack, &[D(0), sam, pay])?;
let jet_res = assert_no_alloc(|| jet(context, sam).unwrap()); let jet_res = assert_no_alloc(|| jet(context, sam).unwrap());
assert_noun_eq(&mut context.stack, jet_res, res); assert_noun_eq(&mut context.stack, jet_res, res);
Ok(())
} }
pub type AssertJetDoorFn = fn( pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
&mut Context, let res = A(&mut context.stack, &res);
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>, assert_jet(context, jet, sam, res);
Noun,
Noun,
Noun,
);
pub fn assert_jet_door_panicky(
context: &mut Context,
jet: Jet,
sam: Noun,
pay: Noun,
res: Noun,
) {
assert_jet_door(context, jet, sam, pay, res).expect("assert_jet_door failed");
} }
pub fn assert_jet_ubig( pub fn assert_nary_jet_ubig(context: &mut Context, jet: Jet, sam: &[Noun], res: UBig) {
context: &mut Context, let sam = T(&mut context.stack, sam);
jet: Jet, assert_jet_ubig(context, jet, sam, res);
sam: Noun,
res: UBig,
) -> AllocResult<()> {
let res = A(&mut context.stack, &res)?;
assert_jet(context, jet, sam, res)
} }
pub type AssertJetUBigFn = fn( pub fn assert_jet_err(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
&mut Context, let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
UBig,
);
pub fn assert_jet_ubig_panicky(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
assert_jet_ubig(context, jet, sam, res).expect("assert_jet_ubig failed");
}
pub fn assert_nary_jet_ubig(
context: &mut Context,
jet: Jet,
sam: &[Noun],
res: UBig,
) -> AllocResult<()> {
let sam = T(&mut context.stack, sam)?;
assert_jet_ubig(context, jet, sam, res)
}
pub fn assert_jet_err(
context: &mut Context,
jet: Jet,
sam: Noun,
err: JetErr,
) -> AllocResult<()> {
let sam = T(&mut context.stack, &[D(0), sam, D(0)])?;
let jet_res = jet(context, sam); let jet_res = jet(context, sam);
assert!( assert!(
jet_res.is_err(), jet_res.is_err(),
@ -453,10 +383,10 @@ pub mod util {
&jet_res &jet_res
); );
let jet_err = jet_res.unwrap_err(); let jet_err = jet_res.unwrap_err();
match (jet_err.clone(), err.clone()) { match (jet_err, err) {
(JetErr::Punt, JetErr::Punt) => {} (JetErr::Punt, JetErr::Punt) => {}
(JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => { (JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => {
match (actual_err.clone(), expected_err.clone()) { match (actual_err, expected_err) {
(Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected)) (Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected))
| (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected)) | (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected))
| ( | (
@ -485,22 +415,11 @@ pub mod util {
sam, err, jet_err sam, err, jet_err
); );
} }
}; }
Ok(())
}
pub type AssertJetErrFn = fn(
&mut Context,
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
JetErr,
);
pub fn assert_jet_err_panicky(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
assert_jet_err(context, jet, sam, err).expect("assert_jet failed");
} }
pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) { pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]).unwrap(); let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
let res = assert_no_alloc(|| jet(context, sam).unwrap()); let res = assert_no_alloc(|| jet(context, sam).unwrap());
assert!(res.is_atom(), "jet result not atom"); assert!(res.is_atom(), "jet result not atom");
let res_siz = res.atom().unwrap().size(); let res_siz = res.atom().unwrap().size();
@ -514,7 +433,7 @@ pub mod util {
res: UBig, res: UBig,
) { ) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect(); let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
assert_nary_jet_ubig(context, jet, &sam, res).unwrap(); assert_nary_jet_ubig(context, jet, &sam, res);
} }
pub fn assert_common_jet_noun( pub fn assert_common_jet_noun(
@ -524,8 +443,8 @@ pub mod util {
res: Noun, res: Noun,
) { ) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect(); let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap(); let sam = T(&mut context.stack, &sam);
assert_jet(context, jet, sam, res).unwrap(); assert_jet(context, jet, sam, res);
} }
pub fn assert_common_jet_err( pub fn assert_common_jet_err(
@ -535,8 +454,8 @@ pub mod util {
err: JetErr, err: JetErr,
) { ) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect(); let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap(); let sam = T(&mut context.stack, &sam);
assert_jet_err(context, jet, sam, err).unwrap(); assert_jet_err(context, jet, sam, err);
} }
pub fn assert_common_jet_size( pub fn assert_common_jet_size(
@ -546,7 +465,7 @@ pub mod util {
siz: usize, siz: usize,
) { ) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect(); let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap(); let sam = T(&mut context.stack, &sam);
assert_jet_size(context, jet, sam, siz) assert_jet_size(context, jet, sam, siz)
} }
} }

View File

@ -14,12 +14,12 @@ crate::gdb!();
* Bit arithmetic * Bit arithmetic
*/ */
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_bex(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?.as_direct()?.data() as usize; let arg = slot(subject, 6)?.as_direct()?.data() as usize;
Ok(util::bex(&mut context.stack, arg)?.as_noun()) Ok(util::bex(&mut context.stack, arg).as_noun())
} }
pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_can(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?; let bloq = bloq(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?; let original_list = slot(arg, 3)?;
@ -27,7 +27,7 @@ pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> {
util::can(&mut context.stack, bloq, original_list) util::can(&mut context.stack, bloq, original_list)
} }
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cat(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?; let bloq = bloq(slot(arg, 2)?)?;
let a = slot(arg, 6)?.as_atom()?; let a = slot(arg, 6)?.as_atom()?;
@ -41,7 +41,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
} else { } else {
unsafe { unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len);
chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?; chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?;
chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?; chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?;
Ok(new_indirect.normalize_as_atom().as_noun()) Ok(new_indirect.normalize_as_atom().as_noun())
@ -49,7 +49,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cut(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?; let bloq = bloq(slot(arg, 2)?)?;
let start = slot(arg, 12)?.as_direct()?.data() as usize; let start = slot(arg, 12)?.as_direct()?.data() as usize;
@ -62,14 +62,14 @@ pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_indirect = unsafe { let new_indirect = unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?);
chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?; chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?;
new_indirect.normalize_as_atom() new_indirect.normalize_as_atom()
}; };
Ok(new_indirect.as_noun()) Ok(new_indirect.as_noun())
} }
pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sew(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let bloq = bloq(slot(sam, 2)?)?; let bloq = bloq(slot(sam, 2)?)?;
let e = slot(sam, 7)?.as_atom()?; let e = slot(sam, 7)?.as_atom()?;
@ -90,12 +90,12 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
unsafe { unsafe {
let (mut dest_indirect, dest) = let (mut dest_indirect, dest) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?);
chop(bloq, 0, len_e, 0, dest, e.as_bitslice())?; chop(bloq, 0, len_e, 0, dest, e.as_bitslice())?;
let (_, lead) = let (_, lead) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
chop(bloq, 0, min(step, len_d), 0, lead, donor.as_bitslice())?; chop(bloq, 0, min(step, len_d), 0, lead, donor.as_bitslice())?;
@ -104,7 +104,7 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_end(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?; let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?; let a = slot(arg, 3)?.as_atom()?;
@ -116,14 +116,14 @@ pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> {
} else { } else {
unsafe { unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?; chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?;
Ok(new_indirect.normalize_as_atom().as_noun()) Ok(new_indirect.normalize_as_atom().as_noun())
} }
} }
} }
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?; let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?; let a = slot(arg, 3)?.as_atom()?;
@ -131,7 +131,7 @@ pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> {
util::lsh(&mut context.stack, bloq, step, a) util::lsh(&mut context.stack, bloq, step, a)
} }
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_met(_context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?; let bloq = bloq(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?; let a = slot(arg, 3)?.as_atom()?;
@ -139,14 +139,14 @@ pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(D(util::met(bloq, a) as u64)) Ok(D(util::met(bloq, a) as u64))
} }
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_rap(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?; let bloq = bloq(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?; let original_list = slot(arg, 3)?;
Ok(util::rap(&mut context.stack, bloq, original_list)?.as_noun()) Ok(util::rap(&mut context.stack, bloq, original_list)?.as_noun())
} }
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_rep(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?; let (bloq, step) = bite(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?; let original_list = slot(arg, 3)?;
@ -169,7 +169,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
} else { } else {
unsafe { unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?)?; IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?);
let mut pos = 0; let mut pos = 0;
let mut list = original_list; let mut list = original_list;
loop { loop {
@ -189,7 +189,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_rev(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data(); let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data();
@ -207,7 +207,7 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
let src = dat.as_bitslice(); let src = dat.as_bitslice();
let (mut output, dest) = let (mut output, dest) =
unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize)? }; unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize) };
let len = len as usize; let len = len as usize;
let total_len = len << boz; let total_len = len << boz;
@ -219,14 +219,14 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(unsafe { output.normalize_as_atom() }.as_noun()) Ok(unsafe { output.normalize_as_atom() }.as_noun())
} }
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_rip(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?; let (bloq, step) = bite(slot(arg, 2)?)?;
let atom = slot(arg, 3)?.as_atom()?; let atom = slot(arg, 3)?.as_atom()?;
util::rip(&mut context.stack, bloq, step, atom) util::rip(&mut context.stack, bloq, step, atom)
} }
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?; let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?; let a = slot(arg, 3)?.as_atom()?;
@ -238,13 +238,13 @@ pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?; let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe { unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
chop(bloq, step, len - step, 0, dest, a.as_bitslice())?; chop(bloq, step, len - step, 0, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun()) Ok(atom.normalize_as_atom().as_noun())
} }
} }
pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let a = slot(sam, 1)?.as_atom()?; let a = slot(sam, 1)?.as_atom()?;
Ok(D(util::met(0, a) as u64)) Ok(D(util::met(0, a) as u64))
@ -254,15 +254,15 @@ pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> {
* Bit logic * Bit logic
*/ */
pub fn jet_con(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_con(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::con(&mut context.stack, a, b)?.as_noun()) Ok(util::con(&mut context.stack, a, b).as_noun())
} }
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_dis(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
@ -270,7 +270,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = cmp::max(a.size(), b.size()); let new_size = cmp::max(a.size(), b.size());
unsafe { unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
let a_bit = a.as_bitslice(); let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit); dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest &= b.as_bitslice(); *dest &= b.as_bitslice();
@ -278,7 +278,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mix(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
@ -286,7 +286,7 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = cmp::max(a.size(), b.size()); let new_size = cmp::max(a.size(), b.size());
unsafe { unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
let a_bit = a.as_bitslice(); let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit); dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest ^= b.as_bitslice(); *dest ^= b.as_bitslice();
@ -297,26 +297,25 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
pub mod util { pub mod util {
use crate::jets::util::*; use crate::jets::util::*;
use crate::jets::{JetErr, Result}; use crate::jets::{JetErr, Result};
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D}; use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
use std::cmp; use std::cmp;
use std::result; use std::result;
/// Binary exponent /// Binary exponent
pub fn bex(stack: &mut NockStack, arg: usize) -> AllocResult<Atom> { pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
unsafe { unsafe {
let res = if arg < 63 { if arg < 63 {
DirectAtom::new_unchecked(1 << arg).as_atom() DirectAtom::new_unchecked(1 << arg).as_atom()
} else { } else {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
dest.set(arg, true); dest.set(arg, true);
atom.normalize_as_atom() atom.normalize_as_atom()
}; }
Ok(res)
} }
} }
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result<Noun> { pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result {
let len = met(bloq, a); let len = met(bloq, a);
if len == 0 { if len == 0 {
return Ok(D(0)); return Ok(D(0));
@ -324,13 +323,13 @@ pub mod util {
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?; let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe { unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
chop(bloq, 0, len, step, dest, a.as_bitslice())?; chop(bloq, 0, len, step, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun()) Ok(atom.normalize_as_atom().as_noun())
} }
} }
pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result<Noun> { pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result {
let mut len = 0usize; let mut len = 0usize;
let mut list = original_list; let mut list = original_list;
loop { loop {
@ -351,7 +350,7 @@ pub mod util {
} else { } else {
unsafe { unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?; IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
let mut pos = 0; let mut pos = 0;
let mut list = original_list; let mut list = original_list;
loop { loop {
@ -385,32 +384,32 @@ pub mod util {
} }
} }
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result<Noun> { pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result {
let len = (met(bloq, atom) + step - 1) / step; let len = (met(bloq, atom) + step - 1) / step;
let mut list = D(0); let mut list = D(0);
for i in (0..len).rev() { for i in (0..len).rev() {
let new_atom = unsafe { let new_atom = unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq)?; IndirectAtom::new_raw_mut_bitslice(stack, step << bloq);
chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?; chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?;
new_indirect.normalize_as_atom() new_indirect.normalize_as_atom()
}; };
list = Cell::new(stack, new_atom.as_noun(), list)?.as_noun(); list = Cell::new(stack, new_atom.as_noun(), list).as_noun();
} }
Ok(list) Ok(list)
} }
/// Binary OR /// Binary OR
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> { pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
let new_size = cmp::max(a.size(), b.size()); let new_size = cmp::max(a.size(), b.size());
unsafe { unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size)?; let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
let a_bit = a.as_bitslice(); let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit); dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest |= b.as_bitslice(); *dest |= b.as_bitslice();
Ok(atom.normalize_as_atom()) atom.normalize_as_atom()
} }
} }
@ -433,11 +432,11 @@ pub mod util {
} }
if len == 0 { if len == 0 {
Ok(Atom::new(stack, 0)?) Ok(Atom::new(stack, 0))
} else { } else {
unsafe { unsafe {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?; IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
let mut pos = 0; let mut pos = 0;
let mut list = original_list; let mut list = original_list;
@ -476,7 +475,6 @@ pub mod util {
let s = &mut init_stack(); let s = &mut init_stack();
let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210)) let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210))
.unwrap()
.as_atom() .as_atom()
.unwrap(); .unwrap();
assert_eq!(met(0, a), 128); assert_eq!(met(0, a), 128);
@ -507,15 +505,8 @@ mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::*;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Noun, D}; use crate::noun::{Noun, D, T};
use ibig::ubig; use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) { fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s)) (atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -547,7 +538,7 @@ mod tests {
#[test] #[test]
fn test_bex() { fn test_bex() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet(c, jet_bex, D(0), D(1)); assert_jet(c, jet_bex, D(0), D(1));
assert_jet(c, jet_bex, D(5), D(32)); assert_jet(c, jet_bex, D(5), D(32));
@ -562,7 +553,7 @@ mod tests {
#[test] #[test]
fn test_can() { fn test_can() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack); let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
let bloq0 = D(0); let bloq0 = D(0);
@ -607,7 +598,7 @@ mod tests {
#[test] #[test]
fn test_cat() { fn test_cat() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack); let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
let bloq0 = D(0); let bloq0 = D(0);
@ -639,7 +630,7 @@ mod tests {
#[test] #[test]
fn test_cut() { fn test_cut() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack); let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let run = T(&mut c.stack, &[D(0), D(0)]); let run = T(&mut c.stack, &[D(0), D(0)]);
@ -662,7 +653,7 @@ mod tests {
#[test] #[test]
fn test_end() { fn test_end() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a24]); let sam = T(&mut c.stack, &[a0, a24]);
@ -685,7 +676,7 @@ mod tests {
#[test] #[test]
fn test_lsh() { fn test_lsh() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (_, a24, _a63, a96, a128) = atoms(&mut c.stack); let (_, a24, _a63, a96, a128) = atoms(&mut c.stack);
assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86)); assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86));
@ -718,7 +709,7 @@ mod tests {
#[test] #[test]
fn test_met() { fn test_met() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack); let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]); let sam = T(&mut c.stack, &[a0, a0]);
@ -733,7 +724,7 @@ mod tests {
#[test] #[test]
fn test_rap() { fn test_rap() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let bloq0 = D(0); let bloq0 = D(0);
let bloq2 = D(2); let bloq2 = D(2);
@ -763,7 +754,7 @@ mod tests {
#[test] #[test]
fn test_rep() { fn test_rep() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(0)]); let sam = T(&mut c.stack, &[D(0), D(0)]);
@ -776,7 +767,7 @@ mod tests {
#[test] #[test]
fn test_rev() { fn test_rev() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (_a0, a24, _a63, a96, _a128) = atoms(&mut c.stack); let (_a0, a24, _a63, a96, _a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(60), a24]); let sam = T(&mut c.stack, &[D(0), D(60), a24]);
@ -791,7 +782,7 @@ mod tests {
#[test] #[test]
fn test_rip() { fn test_rip() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack); let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(0)]); let sam = T(&mut c.stack, &[D(0), D(0)]);
@ -814,7 +805,7 @@ mod tests {
#[test] #[test]
fn test_rsh() { fn test_rsh() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a24]); let sam = T(&mut c.stack, &[a0, a24]);
@ -840,7 +831,7 @@ mod tests {
#[test] #[test]
fn test_sew() { fn test_sew() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
// 0xfaceb00c15deadbeef123456 // 0xfaceb00c15deadbeef123456
@ -885,7 +876,7 @@ mod tests {
#[test] #[test]
fn test_con() { fn test_con() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]); let sam = T(&mut c.stack, &[a0, a0]);
@ -906,7 +897,7 @@ mod tests {
#[test] #[test]
fn test_dis() { fn test_dis() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]); let sam = T(&mut c.stack, &[a0, a0]);
@ -926,7 +917,7 @@ mod tests {
#[test] #[test]
fn test_mix() { fn test_mix() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]); let sam = T(&mut c.stack, &[a0, a0]);
@ -948,7 +939,7 @@ mod tests {
#[test] #[test]
fn test_xeb() { fn test_xeb() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
assert_jet(c, jet_xeb, a0, D(0)); assert_jet(c, jet_xeb, a0, D(0));

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ use crate::noun::Noun;
crate::gdb!(); crate::gdb!();
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_scow(context: &mut Context, subject: Noun) -> Result {
let aura = slot(subject, 12)?.as_direct()?; let aura = slot(subject, 12)?.as_direct()?;
let atom = slot(subject, 13)?.as_atom()?; let atom = slot(subject, 13)?.as_atom()?;
util::scow(&mut context.stack, aura, atom) util::scow(&mut context.stack, aura, atom)
@ -17,7 +17,7 @@ pub mod util {
use crate::jets; use crate::jets;
use crate::jets::JetErr; use crate::jets::JetErr;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, Noun, D, T}; use crate::noun::{Atom, Cell, DirectAtom, D, T};
use num_traits::identities::Zero; use num_traits::identities::Zero;
use sword_macros::tas; use sword_macros::tas;
@ -25,11 +25,11 @@ pub mod util {
stack: &mut NockStack, stack: &mut NockStack,
aura: DirectAtom, // XX: technically this should be Atom? aura: DirectAtom, // XX: technically this should be Atom?
atom: Atom, atom: Atom,
) -> jets::Result<Noun> { ) -> jets::Result {
match aura.data() { match aura.data() {
tas!(b"ud") => { tas!(b"ud") => {
if atom.as_bitslice().first_one().is_none() { if atom.as_bitslice().first_one().is_none() {
return Ok(T(stack, &[D(b'0' as u64), D(0)])?); return Ok(T(stack, &[D(b'0' as u64), D(0)]));
} }
let mut root = D(0); let mut root = D(0);
@ -38,15 +38,15 @@ pub mod util {
let mut n = atom.as_direct()?.data(); let mut n = atom.as_direct()?.data();
while n != 0 { while n != 0 {
root = T(stack, &[D(b'0' as u64 + (n % 10)), root])?; root = T(stack, &[D(b'0' as u64 + (n % 10)), root]);
n /= 10; n /= 10;
lent += 1; lent += 1;
} }
} else { } else {
let mut n = atom.as_indirect()?.as_ubig(stack)?; let mut n = atom.as_indirect()?.as_ubig(stack);
while !n.is_zero() { while !n.is_zero() {
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root])?; root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root]);
n /= 10u64; n /= 10u64;
lent += 1; lent += 1;
} }
@ -58,7 +58,7 @@ pub mod util {
while lent > 2 { while lent > 2 {
if lent % 3 == 0 { if lent % 3 == 0 {
let (cell, memory) = Cell::new_raw_mut(stack)?; let (cell, memory) = Cell::new_raw_mut(stack);
(*memory).head = D(b'.' as u64); (*memory).head = D(b'.' as u64);
(*memory).tail = list.tail(); (*memory).tail = list.tail();
(*(list.to_raw_pointer_mut())).tail = cell.as_noun(); (*(list.to_raw_pointer_mut())).tail = cell.as_noun();
@ -79,18 +79,11 @@ pub mod util {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
use crate::jets::JetErr; use crate::jets::JetErr;
use crate::noun::{Noun, D}; use crate::noun::{Noun, D, T};
use ibig::ubig; use ibig::ubig;
use sword_macros::tas; use sword_macros::tas;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
// Rust can't handle implicit conversions from u8 to u64 // Rust can't handle implicit conversions from u8 to u64
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -100,7 +93,7 @@ mod tests {
#[test] #[test]
fn test_scow() { fn test_scow() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let aura = D(tas!(b"ud")); let aura = D(tas!(b"ud"));
let sam = T(&mut c.stack, &[aura, D(0)]); let sam = T(&mut c.stack, &[aura, D(0)]);

View File

@ -8,22 +8,18 @@ use crate::noun::Noun;
crate::gdb!(); crate::gdb!();
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
Ok(mug(&mut context.stack, arg)?.as_noun()) Ok(mug(&mut context.stack, arg).as_noun())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, init_context, A};
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Noun, D}; use crate::noun::{Noun, D, T};
use ibig::ubig; use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) { fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s)) (atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -51,7 +47,7 @@ mod tests {
#[test] #[test]
fn test_mug() { fn test_mug() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
assert_jet(c, jet_mug, a0, D(0x79ff04e8)); assert_jet(c, jet_mug, a0, D(0x79ff04e8));

View File

@ -1,5 +1,4 @@
use crate::jets::*; use crate::jets::*;
use crate::mem::AllocResult;
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T}; use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T};
use either::Either::{self, Left, Right}; use either::Either::{self, Left, Right};
use std::ptr::{copy_nonoverlapping, null_mut}; use std::ptr::{copy_nonoverlapping, null_mut};
@ -1505,7 +1504,7 @@ pub const URBIT_HOT_STATE: &[HotEntry] = &[
pub struct Hot(*mut HotMem); pub struct Hot(*mut HotMem);
impl Hot { impl Hot {
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> AllocResult<Self> { pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> Self {
unsafe { unsafe {
let mut next = Hot(null_mut()); let mut next = Hot(null_mut());
for (htap, axe, jet) in constant_hot_state { for (htap, axe, jet) in constant_hot_state {
@ -1513,10 +1512,10 @@ impl Hot {
for i in *htap { for i in *htap {
match i { match i {
Left(tas) => { Left(tas) => {
let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)? let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)
.normalize_as_atom() .normalize_as_atom()
.as_noun(); .as_noun();
a_path = T(stack, &[chum, a_path])?; a_path = T(stack, &[chum, a_path]);
} }
Right((tas, ver)) => { Right((tas, ver)) => {
let chum = T( let chum = T(
@ -1525,13 +1524,13 @@ impl Hot {
DirectAtom::new_panic(*tas).as_atom().as_noun(), DirectAtom::new_panic(*tas).as_atom().as_noun(),
DirectAtom::new_panic(*ver).as_atom().as_noun(), DirectAtom::new_panic(*ver).as_atom().as_noun(),
], ],
)?; );
a_path = T(stack, &[chum, a_path])?; a_path = T(stack, &[chum, a_path]);
} }
}; };
} }
let axis = DirectAtom::new_panic(*axe).as_atom(); let axis = DirectAtom::new_panic(*axe).as_atom();
let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1)?; let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1);
*hot_mem_ptr = HotMem { *hot_mem_ptr = HotMem {
a_path, a_path,
axis, axis,
@ -1540,7 +1539,7 @@ impl Hot {
}; };
next = Hot(hot_mem_ptr); next = Hot(hot_mem_ptr);
} }
Ok(next) next
} }
} }
} }
@ -1567,17 +1566,16 @@ struct HotMem {
} }
impl Preserve for Hot { impl Preserve for Hot {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
let mut it = self; let mut it = self;
while !it.0.is_null() && stack.is_in_frame(it.0) { while !it.0.is_null() && stack.is_in_frame(it.0) {
let dest_mem = stack.struct_alloc_in_previous_frame(1)?; let dest_mem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(it.0, dest_mem, 1); copy_nonoverlapping(it.0, dest_mem, 1);
it.0 = dest_mem; it.0 = dest_mem;
(*it.0).a_path.preserve(stack)?; (*it.0).a_path.preserve(stack);
(*it.0).axis.preserve(stack)?; (*it.0).axis.preserve(stack);
it = &mut (*it.0).next; it = &mut (*it.0).next;
} }
Ok(())
} }
unsafe fn assert_in_stack(&self, stack: &NockStack) { unsafe fn assert_in_stack(&self, stack: &NockStack) {

View File

@ -8,27 +8,27 @@ use crate::site::{site_slam, Site};
crate::gdb!(); crate::gdb!();
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_flop(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
util::flop(&mut context.stack, sam) util::flop(&mut context.stack, sam)
} }
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?; let list = slot(subject, 6)?;
util::lent(list).map(|x| D(x as u64)) util::lent(list).map(|x| D(x as u64))
} }
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
let sample = slot(subject, 6)?; let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?; let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?; let mut gate = slot(sample, 3)?;
let mut prod = slot(gate, 13)?; let mut prod = slot(gate, 13)?;
let site = Site::new(context, &mut gate)?; let site = Site::new(context, &mut gate);
loop { loop {
if let Ok(list_cell) = list.as_cell() { if let Ok(list_cell) = list.as_cell() {
list = list_cell.tail(); list = list_cell.tail();
let sam = T(&mut context.stack, &[list_cell.head(), prod])?; let sam = T(&mut context.stack, &[list_cell.head(), prod]);
prod = site_slam(context, &site, sam)?; prod = site_slam(context, &site, sam)?;
} else { } else {
if unsafe { !list.raw_equals(D(0)) } { if unsafe { !list.raw_equals(D(0)) } {
@ -39,7 +39,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let index = slot(sam, 2)?; let index = slot(sam, 2)?;
let list = slot(sam, 3)?; let list = slot(sam, 3)?;
@ -47,12 +47,12 @@ pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
util::snag(list, index) util::snag(list, index)
} }
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_snip(context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?; let list = slot(subject, 6)?;
util::snip(&mut context.stack, list) util::snip(&mut context.stack, list)
} }
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
let sample = slot(subject, 6)?; let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?; let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?; let mut gate = slot(sample, 3)?;
@ -61,12 +61,12 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
// Since the gate doesn't change, we can do a single jet check and use that through the whole // Since the gate doesn't change, we can do a single jet check and use that through the whole
// loop // loop
let site = Site::new(context, &mut gate)?; let site = Site::new(context, &mut gate);
loop { loop {
if let Ok(list_cell) = list.as_cell() { if let Ok(list_cell) = list.as_cell() {
list = list_cell.tail(); list = list_cell.tail();
unsafe { unsafe {
let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack)?; let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack);
(*new_mem).head = site_slam(context, &site, list_cell.head())?; (*new_mem).head = site_slam(context, &site, list_cell.head())?;
*dest = new_cell.as_noun(); *dest = new_cell.as_noun();
dest = &mut (*new_mem).tail; dest = &mut (*new_mem).tail;
@ -83,7 +83,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_zing(context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?; let list = slot(subject, 6)?;
let stack = &mut context.stack; let stack = &mut context.stack;
@ -98,7 +98,7 @@ pub mod util {
use std::result; use std::result;
/// Reverse order of list /// Reverse order of list
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result<Noun> { pub fn flop(stack: &mut NockStack, noun: Noun) -> Result {
let mut list = noun; let mut list = noun;
let mut tsil = D(0); let mut tsil = D(0);
loop { loop {
@ -107,7 +107,7 @@ pub mod util {
} }
let cell = list.as_cell()?; let cell = list.as_cell()?;
tsil = T(stack, &[cell.head(), tsil])?; tsil = T(stack, &[cell.head(), tsil]);
list = cell.tail(); list = cell.tail();
} }
@ -133,7 +133,7 @@ pub mod util {
Ok(len) Ok(len)
} }
pub fn snag(tape: Noun, index: Noun) -> Result<Noun> { pub fn snag(tape: Noun, index: Noun) -> Result {
let mut list = tape; let mut list = tape;
let mut idx = index.as_atom()?.as_u64()? as usize; let mut idx = index.as_atom()?.as_u64()? as usize;
loop { loop {
@ -149,7 +149,7 @@ pub mod util {
} }
} }
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result<Noun> { pub fn snip(stack: &mut NockStack, tape: Noun) -> Result {
let mut ret = D(0); let mut ret = D(0);
let mut dest = &mut ret as *mut Noun; let mut dest = &mut ret as *mut Noun;
let mut list = tape; let mut list = tape;
@ -170,7 +170,7 @@ pub mod util {
} }
} }
unsafe { unsafe {
let (new_cell, new_mem) = Cell::new_raw_mut(stack)?; let (new_cell, new_mem) = Cell::new_raw_mut(stack);
(*new_mem).head = cell.head(); (*new_mem).head = cell.head();
*dest = new_cell.as_noun(); *dest = new_cell.as_noun();
dest = &mut (*new_mem).tail; dest = &mut (*new_mem).tail;
@ -181,7 +181,7 @@ pub mod util {
Ok(ret) Ok(ret)
} }
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result<Noun> { pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result {
unsafe { unsafe {
let mut res: Noun = D(0); let mut res: Noun = D(0);
let mut dest = &mut res as *mut Noun; let mut dest = &mut res as *mut Noun;
@ -196,7 +196,7 @@ pub mod util {
let i = it.head(); let i = it.head();
sublist = it.tail(); sublist = it.tail();
let (new_cell, new_memory) = Cell::new_raw_mut(stack)?; let (new_cell, new_memory) = Cell::new_raw_mut(stack);
(*new_memory).head = i; (*new_memory).head = i;
*dest = new_cell.as_noun(); *dest = new_cell.as_noun();
dest = &mut (*new_memory).tail; dest = &mut (*new_memory).tail;
@ -212,19 +212,13 @@ pub mod util {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, assert_jet_err, init_context};
use crate::jets::util::BAIL_EXIT; use crate::jets::util::BAIL_EXIT;
use crate::noun::D; use crate::noun::{D, T};
// Override T with the panicky variants
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
#[test] #[test]
fn test_flop() { fn test_flop() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]); let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
let res = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]); let res = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]);
@ -261,7 +255,7 @@ mod tests {
#[test] #[test]
fn test_lent() { fn test_lent() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet(c, jet_lent, D(0), D(0)); assert_jet(c, jet_lent, D(0), D(0));
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]); let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
@ -275,7 +269,7 @@ mod tests {
#[test] #[test]
fn test_snag() { fn test_snag() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]); let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
let sam = T(&mut c.stack, &[D(1), list1]); let sam = T(&mut c.stack, &[D(1), list1]);
assert_jet(c, jet_snag, sam, D(2)); assert_jet(c, jet_snag, sam, D(2));
@ -293,7 +287,7 @@ mod tests {
#[test] #[test]
fn test_snip() { fn test_snip() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(0)]); let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet(c, jet_snip, sam, D(0)); assert_jet(c, jet_snip, sam, D(0));
@ -319,7 +313,7 @@ mod tests {
#[test] #[test]
fn test_zing() { fn test_zing() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let list_0 = T(&mut c.stack, &[D(0), D(0), D(0), D(0)]); let list_0 = T(&mut c.stack, &[D(0), D(0), D(0), D(0)]);
let list_1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]); let list_1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);

View File

@ -11,7 +11,7 @@ crate::gdb!();
// have fixed maximum key sizes, therefore we must punt if the key is // have fixed maximum key sizes, therefore we must punt if the key is
// too large. // too large.
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?; let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?; let key = slot(subject, 60)?.as_atom()?;
@ -27,7 +27,7 @@ pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?; let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?; let len = slot(subject, 26)?.as_atom()?;
@ -45,7 +45,7 @@ pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?; let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?; let key = slot(subject, 60)?.as_atom()?;
@ -61,7 +61,7 @@ pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?; let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?; let len = slot(subject, 26)?.as_atom()?;
@ -79,7 +79,7 @@ pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?; let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?; let key = slot(subject, 60)?.as_atom()?;
@ -95,7 +95,7 @@ pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?; let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?; let len = slot(subject, 26)?.as_atom()?;
@ -142,7 +142,7 @@ mod util {
let length = list::util::lent(ads)?; let length = list::util::lent(ads)?;
let siv_data: &mut [AcAesSivData] = unsafe { let siv_data: &mut [AcAesSivData] = unsafe {
let ptr = stack.struct_alloc::<AcAesSivData>(length)?; let ptr = stack.struct_alloc::<AcAesSivData>(length);
std::slice::from_raw_parts_mut(ptr, length) std::slice::from_raw_parts_mut(ptr, length)
}; };
@ -153,7 +153,7 @@ mod util {
let bytes = head.as_bytes(); let bytes = head.as_bytes();
let len = met(3, head); let len = met(3, head);
let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len())?; let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len());
buffer[0..len].copy_from_slice(&(bytes[0..len])); buffer[0..len].copy_from_slice(&(bytes[0..len]));
item.length = bytes.len(); item.length = bytes.len();
@ -171,7 +171,7 @@ mod util {
key: &mut [u8; N], key: &mut [u8; N],
ads: Noun, ads: Noun,
txt: Atom, txt: Atom,
) -> Result<Noun> { ) -> Result {
unsafe { unsafe {
let ac_siv_data = _allocate_ads(stack, ads)?; let ac_siv_data = _allocate_ads(stack, ads)?;
let siv_data: &mut [&mut [u8]] = std::slice::from_raw_parts_mut( let siv_data: &mut [&mut [u8]] = std::slice::from_raw_parts_mut(
@ -181,19 +181,19 @@ mod util {
let txt_len = met(3, txt); let txt_len = met(3, txt);
let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack)?; let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack);
// We match on length here and elsewhere where a similar pattern is followed // We match on length here and elsewhere where a similar pattern is followed
// to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes. // to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes.
match txt_len { match txt_len {
0 => { 0 => {
ac_aes_siv_en::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap(); ac_aes_siv_en::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)])?) Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)]))
} }
_ => { _ => {
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?; let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]); txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?; let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
ac_aes_siv_en::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap(); ac_aes_siv_en::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
Ok(T( Ok(T(
stack, stack,
@ -202,7 +202,7 @@ mod util {
D(txt_len as u64), D(txt_len as u64),
out_atom.normalize_as_atom().as_noun(), out_atom.normalize_as_atom().as_noun(),
], ],
)?) ))
} }
} }
} }
@ -215,7 +215,7 @@ mod util {
iv: Atom, iv: Atom,
len: Atom, len: Atom,
txt: Atom, txt: Atom,
) -> Result<Noun> { ) -> Result {
unsafe { unsafe {
let txt_len = match len.as_direct() { let txt_len = match len.as_direct() {
Ok(direct) => direct.data() as usize, Ok(direct) => direct.data() as usize,
@ -231,20 +231,20 @@ mod util {
ac_siv_data.len(), ac_siv_data.len(),
); );
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?; let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
match txt_len { match txt_len {
0 => { 0 => {
ac_aes_siv_de::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap(); ac_aes_siv_de::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
} }
_ => { _ => {
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?; let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]); txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
ac_aes_siv_de::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap(); ac_aes_siv_de::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
} }
} }
Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()])?) Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()]))
} }
} }
} }
@ -252,34 +252,33 @@ mod util {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_noun_eq, init_context, A};
use crate::jets::Jet; use crate::jets::Jet;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Cell, D, T}; use crate::noun::{Cell, D, T};
use ibig::ubig; use ibig::ubig;
pub fn assert_jet_in_door( pub fn assert_jet_in_door(
c: &mut Context, c: &mut Context,
jet: Jet, jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> AllocResult<Noun>], // door sample as context ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun, res: Noun,
) { ) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect(); let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect();
let ctx: Vec<Noun> = ctx.iter().flat_map(|f| f(&mut c.stack)).collect(); let ctx: Vec<Noun> = ctx.iter().map(|f| f(&mut c.stack)).collect();
let sam = if sam.len() > 1 { let sam = if sam.len() > 1 {
T(&mut c.stack, &sam).expect("T alloc failed in assert_jet_in_door") T(&mut c.stack, &sam)
} else { } else {
sam[0] sam[0]
}; };
let ctx = if ctx.len() > 1 { let ctx = if ctx.len() > 1 {
T(&mut c.stack, &ctx).expect("2nd T alloc failed in assert_jet_in_door") T(&mut c.stack, &ctx)
} else { } else {
ctx[0] ctx[0]
}; };
let pay = Cell::new(&mut c.stack, sam, ctx).expect("Cell alloc failed in assert_jet_in_door").as_noun(); let pay = Cell::new(&mut c.stack, sam, ctx).as_noun();
let sbj = Cell::new(&mut c.stack, D(0), pay).expect("2nd Cell alloc failed").as_noun(); let sbj = Cell::new(&mut c.stack, D(0), pay).as_noun();
// std::io::stderr().flush().unwrap(); // std::io::stderr().flush().unwrap();
let jet_res = jet(c, sbj).unwrap(); let jet_res = jet(c, sbj).unwrap();
// std::io::stderr().flush().unwrap(); // std::io::stderr().flush().unwrap();
@ -288,7 +287,7 @@ mod tests {
#[test] #[test]
pub fn test_siva_en() { pub fn test_siva_en() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* /*
> (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0) > (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0)
[p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0] [p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0]
@ -296,44 +295,44 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun { fn sample(_s: &mut NockStack) -> Noun {
D(0) D(0)
} }
fn context(s: &mut NockStack) -> AllocResult<Noun> { fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)])?; let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77)).unwrap(); let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap(); let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res); assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res);
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap() A(s, &ubig!(0x112233445566778899aabbccddee))
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A( let key = A(
s, s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff), &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
)?; );
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap(); let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let len = D(14); let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap(); let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap(); let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res);
} }
#[test] #[test]
pub fn test_sivb_en() { pub fn test_sivb_en() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* /*
> (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0) > (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -342,41 +341,41 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun { fn sample(_s: &mut NockStack) -> Noun {
D(0) D(0)
} }
fn context(s: &mut NockStack) -> AllocResult<Noun> { fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)])?; let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd)).unwrap(); let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap(); let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res); assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res);
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap() A(s, &ubig!(0x112233445566778899aabbccddee))
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?; let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap(); let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740));
let len = D(14); let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap(); let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c));
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap(); let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res);
} }
#[test] #[test]
pub fn test_sivc_en() { pub fn test_sivc_en() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* /*
> (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0) > (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -385,122 +384,122 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun { fn sample(_s: &mut NockStack) -> Noun {
D(0) D(0)
} }
fn context(s: &mut NockStack) -> AllocResult<Noun> { fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)])?; let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519)).unwrap(); let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap(); let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res); assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res);
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap() A(s, &ubig!(0x112233445566778899aabbccddee))
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?; let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap(); let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let len = D(14); let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap(); let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0));
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap(); let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res);
} }
#[test] #[test]
pub fn test_siva_de() { pub fn test_siva_de() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap(); let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let len = D(14); let len = D(14);
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap(); let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
T(s, &[iv, len, cyp]).unwrap() T(s, &[iv, len, cyp])
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A( let key = A(
s, s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff), &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
)?; );
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap(); let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]).unwrap(); let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res);
} }
#[test] #[test]
pub fn test_sivb_de() { pub fn test_sivb_de() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap(); let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740));
let len = D(14); let len = D(14);
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap(); let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c));
T(s, &[iv, len, cyp]).unwrap() T(s, &[iv, len, cyp])
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?; let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap(); let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]).unwrap(); let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res);
} }
#[test] #[test]
pub fn test_sivc_de() { pub fn test_sivc_de() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
/* RFC 5297 /* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A * https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/ */
fn gate_sample(s: &mut NockStack) -> Noun { fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap(); let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let len = D(14); let len = D(14);
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap(); let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0));
T(s, &[iv, len, cyp]).unwrap() T(s, &[iv, len, cyp])
} }
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> { fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?; let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
let a = A( let a = A(
s, s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627), &ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?; );
let vec = T(s, &[a, D(0)])?; let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec])?; let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)]) T(s, &[D(0), sample, D(0)])
} }
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap(); let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]).unwrap(); let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_sivc_de, &[gate_sample], &[gate_context], res); assert_jet_in_door(c, jet_sivc_de, &[gate_sample], &[gate_context], res);
} }
} }

View File

@ -8,7 +8,7 @@ use sword_crypto::ed25519::{ac_ed_puck, ac_ed_shar, ac_ed_sign, ac_ed_veri};
crate::gdb!(); crate::gdb!();
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_puck(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sed = slot(subject, 6)?.as_atom()?; let sed = slot(subject, 6)?.as_atom()?;
@ -21,14 +21,14 @@ pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
let sed_bytes = &mut [0u8; 32]; let sed_bytes = &mut [0u8; 32];
sed_bytes[0..sed_len].copy_from_slice(&(sed.as_bytes())[0..sed_len]); sed_bytes[0..sed_len].copy_from_slice(&(sed.as_bytes())[0..sed_len]);
let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?; let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
ac_ed_puck(sed_bytes, pub_key); ac_ed_puck(sed_bytes, pub_key);
Ok(pub_ida.normalize_as_atom().as_noun()) Ok(pub_ida.normalize_as_atom().as_noun())
} }
} }
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shar(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let pub_key = slot(subject, 12)?.as_atom()?; let pub_key = slot(subject, 12)?.as_atom()?;
let sec_key = slot(subject, 13)?.as_atom()?; let sec_key = slot(subject, 13)?.as_atom()?;
@ -53,14 +53,14 @@ pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
public[0..pub_bytes.len()].copy_from_slice(pub_bytes); public[0..pub_bytes.len()].copy_from_slice(pub_bytes);
secret[0..sec_bytes.len()].copy_from_slice(sec_bytes); secret[0..sec_bytes.len()].copy_from_slice(sec_bytes);
let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?; let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
ac_ed_shar(public, secret, shar); ac_ed_shar(public, secret, shar);
Ok(shar_ida.normalize_as_atom().as_noun()) Ok(shar_ida.normalize_as_atom().as_noun())
} }
} }
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let msg = slot(subject, 12)?.as_atom()?; let msg = slot(subject, 12)?.as_atom()?;
let sed = slot(subject, 13)?.as_atom()?; let sed = slot(subject, 13)?.as_atom()?;
@ -74,11 +74,11 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
let seed = &mut [0u8; 32]; let seed = &mut [0u8; 32];
seed[0..sed_len].copy_from_slice(sed_bytes); seed[0..sed_len].copy_from_slice(sed_bytes);
let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack)?; let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack);
let msg_len = met(3, msg); let msg_len = met(3, msg);
if msg_len > 0 { if msg_len > 0 {
let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len)?; let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len);
message.copy_from_slice(&msg.as_bytes()[0..msg_len]); message.copy_from_slice(&msg.as_bytes()[0..msg_len]);
ac_ed_sign(message, seed, sig); ac_ed_sign(message, seed, sig);
} else { } else {
@ -90,7 +90,7 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result {
let sig = slot(subject, 12)?.as_atom()?; let sig = slot(subject, 12)?.as_atom()?;
let msg = slot(subject, 26)?.as_atom()?; let msg = slot(subject, 26)?.as_atom()?;
let puk = slot(subject, 27)?.as_atom()?; let puk = slot(subject, 27)?.as_atom()?;
@ -120,68 +120,64 @@ pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
use crate::noun::{D, T}; use crate::noun::{D, T};
use ibig::ubig; use ibig::ubig;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
// XX: Should use the test vectors from Section 7.1 of RFC 8032: // XX: Should use the test vectors from Section 7.1 of RFC 8032:
// https://tools.ietf.org/html/rfc8032#section-7.1 // https://tools.ietf.org/html/rfc8032#section-7.1
#[test] #[test]
fn test_puck() { fn test_puck() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = A(&mut c.stack, &ubig!(_0x0)).unwrap(); let sam = A(&mut c.stack, &ubig!(_0x0));
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b), &ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b),
).unwrap(); );
assert_jet(c, jet_puck, sam, ret); assert_jet(c, jet_puck, sam, ret);
let sam = A( let sam = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d), &ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d),
).unwrap(); );
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7), &ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7),
).unwrap(); );
assert_jet(c, jet_puck, sam, ret); assert_jet(c, jet_puck, sam, ret);
} }
#[test] #[test]
fn test_shar() { fn test_shar() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x0)).unwrap(); let ret = A(&mut c.stack, &ubig!(_0x0));
assert_jet(c, jet_shar, sam, ret); assert_jet(c, jet_shar, sam, ret);
let sam = T(&mut c.stack, &[D(234), D(234)]).unwrap(); let sam = T(&mut c.stack, &[D(234), D(234)]);
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5), &ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5),
).unwrap(); );
assert_jet(c, jet_shar, sam, ret); assert_jet(c, jet_shar, sam, ret);
let sam = A( let sam = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b), &ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b),
).unwrap(); );
assert_jet_err(c, jet_shar, sam, BAIL_EXIT); assert_jet_err(c, jet_shar, sam, BAIL_EXIT);
} }
#[test] #[test]
fn test_sign() { fn test_sign() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
unsafe { unsafe {
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803)).unwrap(); let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803));
assert_jet(c, jet_sign, sam, ret); assert_jet(c, jet_sign, sam, ret);
let message = D(0x72); let message = D(0x72);
@ -191,18 +187,16 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes(); let sed_bytes = sed_ubig.to_be_bytes();
let seed = let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let sam = T(&mut c.stack, &[message, seed]).unwrap(); let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00)).unwrap(); let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00));
assert_jet(c, jet_sign, sam, ret); assert_jet(c, jet_sign, sam, ret);
let msg_ubig = ubig!(_0xaf82); let msg_ubig = ubig!(_0xaf82);
let msg_bytes = msg_ubig.to_be_bytes(); let msg_bytes = msg_ubig.to_be_bytes();
let message = let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let sed_ubig = let sed_ubig =
@ -210,28 +204,26 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes(); let sed_bytes = sed_ubig.to_be_bytes();
let seed = let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let sam = T(&mut c.stack, &[message, seed]).unwrap(); let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a)).unwrap(); let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a));
assert_jet(c, jet_sign, sam, ret); assert_jet(c, jet_sign, sam, ret);
} }
} }
#[test] #[test]
fn test_veri() { fn test_veri() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
unsafe { unsafe {
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0), D(0)]);
assert_jet(c, jet_veri, sam, NO); assert_jet(c, jet_veri, sam, NO);
let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00); let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00);
let sig_bytes = sig_ubig.to_be_bytes(); let sig_bytes = sig_ubig.to_be_bytes();
let signature = let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let message = D(0x72); let message = D(0x72);
@ -241,24 +233,21 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes(); let pub_bytes = pub_ubig.to_be_bytes();
let public_key = let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap(); let sam = T(&mut c.stack, &[signature, message, public_key]);
assert_jet(c, jet_veri, sam, YES); assert_jet(c, jet_veri, sam, YES);
let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a); let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a);
let sig_bytes = sig_ubig.to_be_bytes(); let sig_bytes = sig_ubig.to_be_bytes();
let signature = let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let msg_ubig = ubig!(0xaf82); let msg_ubig = ubig!(0xaf82);
let msg_bytes = msg_ubig.to_be_bytes(); let msg_bytes = msg_ubig.to_be_bytes();
let message = let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let pub_ubig = let pub_ubig =
@ -266,10 +255,9 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes(); let pub_bytes = pub_ubig.to_be_bytes();
let public_key = let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr()) IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun(); .as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap(); let sam = T(&mut c.stack, &[signature, message, public_key]);
assert_jet(c, jet_veri, sam, YES); assert_jet(c, jet_veri, sam, YES);
} }
} }

View File

@ -7,23 +7,23 @@ use sword_crypto::sha::{ac_sha1, ac_shal, ac_shas, ac_shay};
crate::gdb!(); crate::gdb!();
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shas(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let sal = slot(sam, 2)?.as_atom()?; let sal = slot(sam, 2)?.as_atom()?;
let ruz = slot(sam, 3)?.as_atom()?; let ruz = slot(sam, 3)?.as_atom()?;
unsafe { unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?; let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
let sal_bytes = &(sal.as_bytes())[0..met(3, sal)]; // drop trailing zeros let sal_bytes = &(sal.as_bytes())[0..met(3, sal)]; // drop trailing zeros
let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len())?; let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len());
salt.copy_from_slice(sal_bytes); salt.copy_from_slice(sal_bytes);
let msg_len = met(3, ruz); let msg_len = met(3, ruz);
if msg_len > 0 { if msg_len > 0 {
let msg_bytes = &(ruz.as_bytes())[0..msg_len]; let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?; let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
msg.copy_from_slice(msg_bytes); msg.copy_from_slice(msg_bytes);
ac_shas(msg, salt, out); ac_shas(msg, salt, out);
} else { } else {
@ -34,18 +34,18 @@ pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shax(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let ruz = sam.as_atom()?; let ruz = sam.as_atom()?;
let msg_len = met(3, ruz); let msg_len = met(3, ruz);
unsafe { unsafe {
let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?; let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
if msg_len > 0 { if msg_len > 0 {
let msg_bytes = &(ruz.as_bytes())[0..msg_len]; let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?; let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
msg.copy_from_slice(msg_bytes); msg.copy_from_slice(msg_bytes);
ac_shay(msg, out); ac_shay(msg, out);
} else { } else {
@ -56,7 +56,7 @@ pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?; let len = slot(sam, 2)?.as_atom()?;
@ -69,16 +69,16 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz); let msg_len = met(3, ruz);
unsafe { unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?; let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
if length == 0 { if length == 0 {
ac_shay(&mut [], out); ac_shay(&mut [], out);
} else if msg_len >= length { } else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]); msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_shay(msg, out); ac_shay(msg, out);
} else { } else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len]; let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes); msg[0..msg_len].copy_from_slice(msg_bytes);
ac_shay(msg, out); ac_shay(msg, out);
} }
@ -87,7 +87,7 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?; let len = slot(sam, 2)?.as_atom()?;
@ -100,16 +100,16 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz); let msg_len = met(3, ruz);
unsafe { unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64)?; let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64);
if length == 0 { if length == 0 {
ac_shal(&mut [], out); ac_shal(&mut [], out);
} else if msg_len >= length { } else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]); msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_shal(msg, out); ac_shal(msg, out);
} else { } else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len]; let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes); msg[0..msg_len].copy_from_slice(msg_bytes);
ac_shal(msg, out); ac_shal(msg, out);
} }
@ -118,7 +118,7 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?; let len = slot(sam, 2)?.as_atom()?;
@ -131,16 +131,16 @@ pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz); let msg_len = met(3, ruz);
unsafe { unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20)?; let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20);
if length == 0 { if length == 0 {
ac_sha1(&mut [], out); ac_sha1(&mut [], out);
} else if msg_len >= length { } else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]); msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_sha1(msg, out); ac_sha1(msg, out);
} else { } else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len]; let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?; let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes); msg[0..msg_len].copy_from_slice(msg_bytes);
ac_sha1(msg, out); ac_sha1(msg, out);
} }
@ -158,242 +158,242 @@ mod tests {
#[test] #[test]
fn test_shas() { fn test_shas() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shas, jet_shas,
sam, sam,
ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60), ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60),
).unwrap(); );
let sam = T(&mut c.stack, &[D(1), D(1)]).unwrap(); let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shas, jet_shas,
sam, sam,
ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc), ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc),
).unwrap(); );
let sam = T(&mut c.stack, &[D(2), D(2)]).unwrap(); let sam = T(&mut c.stack, &[D(2), D(2)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shas, jet_shas,
sam, sam,
ubig!(_0x4cf01fe7cc56ef70d17735322488de0d31857afcfe451e199abe6295f78f5328), ubig!(_0x4cf01fe7cc56ef70d17735322488de0d31857afcfe451e199abe6295f78f5328),
).unwrap(); );
let a = A( let a = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let b = A( let b = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap(); );
let sam = T(&mut c.stack, &[a, b]).unwrap(); let sam = T(&mut c.stack, &[a, b]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shas, jet_shas,
sam, sam,
ubig!(_0xf7569a89650553ef13f9a8f0bb751fd42b70a4821be6bc1cbe197af33ce4843c), ubig!(_0xf7569a89650553ef13f9a8f0bb751fd42b70a4821be6bc1cbe197af33ce4843c),
).unwrap(); );
} }
#[test] #[test]
fn test_shax() { fn test_shax() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shax, jet_shax,
D(0), // '' D(0), // ''
ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3), ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap(); );
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shax, jet_shax,
D(7303014), // 'foo' D(7303014), // 'foo'
ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c), ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
).unwrap(); );
let a = A( let a = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c), &ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
).unwrap(); );
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shax, jet_shax,
a, a,
ubig!(_0x9ee26e46c2028aa4a9c463aa722b82ed8bf6e185c3e5a5a69814a2c78fe8adc7), ubig!(_0x9ee26e46c2028aa4a9c463aa722b82ed8bf6e185c3e5a5a69814a2c78fe8adc7),
).unwrap(); );
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shax, jet_shax,
D(123456789), D(123456789),
ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let a = A( let a = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shax, jet_shax,
a, a,
ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9), ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9),
).unwrap(); )
} }
#[test] #[test]
fn test_shay() { fn test_shay() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3), &ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap(); );
assert_jet(c, jet_shay, sam, ret).unwrap(); assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(1), D(0)]);
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e), &ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e),
).unwrap(); );
assert_jet(c, jet_shay, sam, ret).unwrap(); assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(1)]);
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3), &ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap(); );
assert_jet(c, jet_shay, sam, ret).unwrap(); assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(478560413032)]).unwrap(); // [1 'hello'] let sam = T(&mut c.stack, &[D(1), D(478560413032)]); // [1 'hello']
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa), &ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa),
).unwrap(); );
assert_jet(c, jet_shay, sam, ret).unwrap(); assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(2), D(478560413032)]).unwrap(); // [2 'hello'] let sam = T(&mut c.stack, &[D(2), D(478560413032)]); // [2 'hello']
let ret = A( let ret = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37), &ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37),
).unwrap(); );
assert_jet(c, jet_shay, sam, ret).unwrap(); assert_jet(c, jet_shay, sam, ret);
let big = DIRECT_MAX + 1; let big = DIRECT_MAX + 1;
let ida = unsafe { let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8).unwrap() IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8)
}; };
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap(); let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
let big: u128 = (DIRECT_MAX as u128) << 64; let big: u128 = (DIRECT_MAX as u128) << 64;
let ida = unsafe { let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8).unwrap() IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8)
}; };
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap(); let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
} }
#[test] #[test]
fn test_shal() { fn test_shal() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shal, jet_shal,
sam, sam,
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf) ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
).unwrap(); );
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shal, jet_shal,
sam, sam,
ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8) ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8)
).unwrap(); );
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(1)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_shal, jet_shal,
sam, sam,
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf) ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
).unwrap(); );
let wid = A( let wid = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let dat = A( let dat = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap(); );
let sam = T(&mut c.stack, &[wid, dat]).unwrap(); let sam = T(&mut c.stack, &[wid, dat]);
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
let wid = A( let wid = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap(); let sam = T(&mut c.stack, &[wid, D(1)]);
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
} }
#[test] #[test]
fn test_sha1() { fn test_sha1() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(0)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_sha1, jet_sha1,
sam, sam,
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709), ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
).unwrap(); );
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap(); let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_sha1, jet_sha1,
sam, sam,
ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f), ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f),
).unwrap(); );
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap(); let sam = T(&mut c.stack, &[D(0), D(1)]);
assert_jet_ubig( assert_jet_ubig(
c, c,
jet_sha1, jet_sha1,
sam, sam,
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709), ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
).unwrap(); );
let wid = A( let wid = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let dat = A( let dat = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap(); );
let sam = T(&mut c.stack, &[wid, dat]).unwrap(); let sam = T(&mut c.stack, &[wid, dat]);
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
let wid = A( let wid = A(
&mut c.stack, &mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72), &ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap(); );
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap(); let sam = T(&mut c.stack, &[wid, D(1)]);
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap(); assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
} }
} }

View File

@ -8,7 +8,7 @@ use sword_macros::tas;
crate::gdb!(); crate::gdb!();
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?; let rff = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
@ -25,19 +25,19 @@ pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = 141 + tas!(b"crop") + (flag << 8); let fun = 141 + tas!(b"crop") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result {
// axe must be Atom, though we use it as Noun // axe must be Atom, though we use it as Noun
let axe = slot(subject, 6)?.as_atom()?; let axe = slot(subject, 6)?.as_atom()?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
@ -55,19 +55,19 @@ pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = 141 + tas!(b"fish") + (flag << 8); let fun = 141 + tas!(b"fish") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?; let rff = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
@ -84,19 +84,19 @@ pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = 141 + tas!(b"fuse") + (flag << 8); let fun = 141 + tas!(b"fuse") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?; let gol = slot(subject, 12)?;
let gen = slot(subject, 13)?; let gen = slot(subject, 13)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
@ -106,19 +106,19 @@ pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
let fun = 141 + tas!(b"mint"); let fun = 141 + tas!(b"mint");
let vet = slot(van, 59).map_or(NONE, |x| x); let vet = slot(van, 59).map_or(NONE, |x| x);
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat])?; let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?; let gol = slot(subject, 12)?;
let dox = slot(subject, 26)?; let dox = slot(subject, 26)?;
let gen = slot(subject, 27)?; let gen = slot(subject, 27)?;
@ -137,19 +137,19 @@ pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = 141 + tas!(b"mull") + (flag << 8); let fun = 141 + tas!(b"mull") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
let nest_in_core = slot(subject, 3)?; let nest_in_core = slot(subject, 3)?;
let seg = slot(nest_in_core, 12)?; let seg = slot(nest_in_core, 12)?;
@ -172,23 +172,23 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = (141 + tas!(b"dext")) + (flag << 8); let fun = (141 + tas!(b"dext")) + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) } if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) }
|| unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) } || unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) }
{ {
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
} }
Ok(pro) Ok(pro)
} }
} }
} }
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
let leg = slot(subject, 6)?; let leg = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
@ -205,13 +205,13 @@ pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
1 1
}; };
let fun = 141 + tas!(b"rest") + (flag << 8); let fun = 141 + tas!(b"rest") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat])?; let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? { match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro), Some(pro) => Ok(pro),
None => { None => {
let pro = interpret(context, subject, slot(subject, 2)?)?; let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?; context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro) Ok(pro)
} }
} }

View File

@ -22,14 +22,14 @@ use ibig::UBig;
crate::gdb!(); crate::gdb!();
pub fn jet_add(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_add(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::add(&mut context.stack, a, b)?.as_noun()) Ok(util::add(&mut context.stack, a, b).as_noun())
} }
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_dec(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
if let Ok(atom) = arg.as_atom() { if let Ok(atom) = arg.as_atom() {
match atom.as_either() { match atom.as_either() {
@ -48,7 +48,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
Some(first_one) => { Some(first_one) => {
let (mut new_indirect, new_slice) = unsafe { let (mut new_indirect, new_slice) = unsafe {
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())? IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())
}; };
if first_one > 0 { if first_one > 0 {
new_slice[..first_one].fill(true); new_slice[..first_one].fill(true);
@ -67,7 +67,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_div(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -78,14 +78,14 @@ pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> {
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { } else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun()) Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun())
} else { } else {
let a_big = a.as_ubig(stack)?; let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack)?; let b_big = b.as_ubig(stack);
let res = UBig::div_stack(stack, a_big, b_big)?; let res = UBig::div_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res)?.as_noun()) Ok(Atom::from_ubig(stack, &res).as_noun())
} }
} }
pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -103,54 +103,54 @@ pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> {
) )
} }
} else { } else {
let (div, rem) = a.as_ubig(stack)?.div_rem(b.as_ubig(stack)?); let (div, rem) = a.as_ubig(stack).div_rem(b.as_ubig(stack));
( (
Atom::from_ubig(stack, &div)?.as_noun(), Atom::from_ubig(stack, &div).as_noun(),
Atom::from_ubig(stack, &rem)?.as_noun(), Atom::from_ubig(stack, &rem).as_noun(),
) )
}; };
Ok(T(stack, &[div, rem])?) Ok(T(stack, &[div, rem]))
} }
} }
pub fn jet_gte(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_gte(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::gte(stack, a, b)?) Ok(util::gte(stack, a, b))
} }
pub fn jet_gth(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_gth(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::gth(stack, a, b)?) Ok(util::gth(stack, a, b))
} }
pub fn jet_lte(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_lte(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::lte(stack, a, b)?) Ok(util::lte(stack, a, b))
} }
pub fn jet_lth(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_lth(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
Ok(util::lth(stack, a, b)?) Ok(util::lth(stack, a, b))
} }
pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_max(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -166,14 +166,14 @@ pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> {
a.as_noun() a.as_noun()
} else if a.bit_size() < b.bit_size() { } else if a.bit_size() < b.bit_size() {
b.as_noun() b.as_noun()
} else if a.as_ubig(stack)? >= b.as_ubig(stack)? { } else if a.as_ubig(stack) >= b.as_ubig(stack) {
a.as_noun() a.as_noun()
} else { } else {
b.as_noun() b.as_noun()
}) })
} }
pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_min(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -189,14 +189,14 @@ pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> {
a.as_noun() a.as_noun()
} else if a.bit_size() > b.bit_size() { } else if a.bit_size() > b.bit_size() {
b.as_noun() b.as_noun()
} else if a.as_ubig(stack)? <= b.as_ubig(stack)? { } else if a.as_ubig(stack) <= b.as_ubig(stack) {
a.as_noun() a.as_noun()
} else { } else {
b.as_noun() b.as_noun()
}) })
} }
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mod(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -207,12 +207,12 @@ pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> {
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { } else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun()) Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun())
} else { } else {
let res = a.as_ubig(stack)? % b.as_ubig(stack)?; let res = a.as_ubig(stack) % b.as_ubig(stack);
Ok(Atom::from_ubig(stack, &res)?.as_noun()) Ok(Atom::from_ubig(stack, &res).as_noun())
} }
} }
pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mul(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -221,26 +221,26 @@ pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
let res = a.data() as u128 * b.data() as u128; let res = a.data() as u128 * b.data() as u128;
if res < DIRECT_MAX as u128 { if res < DIRECT_MAX as u128 {
Ok(Atom::new(stack, res as u64)?.as_noun()) Ok(Atom::new(stack, res as u64).as_noun())
} else { } else {
Ok(unsafe { Ok(unsafe {
IndirectAtom::new_raw_bytes( IndirectAtom::new_raw_bytes(
stack, stack,
if res < u64::MAX as u128 { 8 } else { 16 }, if res < u64::MAX as u128 { 8 } else { 16 },
&res as *const u128 as *const u8, &res as *const u128 as *const u8,
)? )
} }
.as_noun()) .as_noun())
} }
} else { } else {
let a_big = a.as_ubig(stack)?; let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack)?; let b_big = b.as_ubig(stack);
let res = UBig::mul_stack(stack, a_big, b_big)?; let res = UBig::mul_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res)?.as_noun()) Ok(Atom::from_ubig(stack, &res).as_noun())
} }
} }
pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sub(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?;
@ -249,115 +249,108 @@ pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
pub mod util { pub mod util {
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Atom, Error, Noun, Result, NO, YES}; use crate::noun::{Atom, Error, Noun, Result, NO, YES};
use ibig::UBig; use ibig::UBig;
/// Addition /// Addition
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> { pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Atom::new(stack, a.data() + b.data()) Atom::new(stack, a.data() + b.data())
} else { } else {
let a_big = a.as_ubig(stack)?; let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack)?; let b_big = b.as_ubig(stack);
let res = UBig::add_stack(stack, a_big, b_big)?; let res = UBig::add_stack(stack, a_big, b_big);
Atom::from_ubig(stack, &res) Atom::from_ubig(stack, &res)
} }
} }
/// Greater than or equal to (boolean) /// Greater than or equal to (boolean)
pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> { pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() >= b.data() a.data() >= b.data()
} else if a.bit_size() > b.bit_size() { } else if a.bit_size() > b.bit_size() {
true true
} else if a.bit_size() < b.bit_size() { } else if a.bit_size() < b.bit_size() {
false false
} else { } else {
a.as_ubig(stack)? >= b.as_ubig(stack)? a.as_ubig(stack) >= b.as_ubig(stack)
}; }
Ok(res)
} }
/// Greater than or equal to /// Greater than or equal to
pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> { pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if gte_b(stack, a, b)? { if gte_b(stack, a, b) {
Ok(YES) YES
} else { } else {
Ok(NO) NO
} }
} }
/// Greater than (boolean) /// Greater than (boolean)
pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> { pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() > b.data() a.data() > b.data()
} else if a.bit_size() > b.bit_size() { } else if a.bit_size() > b.bit_size() {
true true
} else if a.bit_size() < b.bit_size() { } else if a.bit_size() < b.bit_size() {
false false
} else { } else {
a.as_ubig(stack)? > b.as_ubig(stack)? a.as_ubig(stack) > b.as_ubig(stack)
}; }
Ok(res)
} }
/// Greater than /// Greater than
pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> { pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
let res = if gth_b(stack, a, b)? { if gth_b(stack, a, b) {
YES YES
} else { } else {
NO NO
}; }
Ok(res)
} }
/// Less than or equal to (boolean) /// Less than or equal to (boolean)
pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> { pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() <= b.data() a.data() <= b.data()
} else if a.bit_size() < b.bit_size() { } else if a.bit_size() < b.bit_size() {
true true
} else if a.bit_size() > b.bit_size() { } else if a.bit_size() > b.bit_size() {
false false
} else { } else {
a.as_ubig(stack)? <= b.as_ubig(stack)? a.as_ubig(stack) <= b.as_ubig(stack)
}; }
Ok(res)
} }
/// Less than or equal to /// Less than or equal to
pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> { pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
let res = if lte_b(stack, a, b)? { if lte_b(stack, a, b) {
YES YES
} else { } else {
NO NO
}; }
Ok(res)
} }
/// Less than (boolean) /// Less than (boolean)
pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> { pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() < b.data() a.data() < b.data()
} else if a.bit_size() > b.bit_size() { } else if a.bit_size() > b.bit_size() {
false false
} else if a.bit_size() < b.bit_size() { } else if a.bit_size() < b.bit_size() {
true true
} else { } else {
a.as_ubig(stack)? < b.as_ubig(stack)? a.as_ubig(stack) < b.as_ubig(stack)
}; }
Ok(res)
} }
/// Less than /// Less than
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> { pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
let res = if lth_b(stack, a, b)? { if lth_b(stack, a, b) {
YES YES
} else { } else {
NO NO
}; }
Ok(res)
} }
/// Subtraction /// Subtraction
@ -369,19 +362,19 @@ pub mod util {
if a_small < b_small { if a_small < b_small {
Err(Error::NotRepresentable) Err(Error::NotRepresentable)
} else { } else {
Ok(Atom::new(stack, a_small - b_small)?) Ok(Atom::new(stack, a_small - b_small))
} }
} else { } else {
let a_big = a.as_ubig(stack)?; let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack)?; let b_big = b.as_ubig(stack);
if a_big < b_big { if a_big < b_big {
Err(Error::NotRepresentable) Err(Error::NotRepresentable)
} else { } else {
let a_big = a.as_ubig(stack)?; let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack)?; let b_big = b.as_ubig(stack);
let res = UBig::sub_stack(stack, a_big, b_big); let res = UBig::sub_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res)?) Ok(Atom::from_ubig(stack, &res))
} }
} }
} }
@ -392,17 +385,8 @@ mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::*;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Noun, D, NO, YES}; use crate::noun::{Noun, D, NO, T, YES};
use ibig::ubig; use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) { fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s)) (atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -445,7 +429,7 @@ mod tests {
#[test] #[test]
fn test_add() { fn test_add() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,
@ -464,7 +448,7 @@ mod tests {
#[test] #[test]
fn test_dec() { fn test_dec() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let s = &mut c.stack; let s = &mut c.stack;
let (a0, _a24, a63, _a96, a128) = atoms(s); let (a0, _a24, a63, _a96, a128) = atoms(s);
@ -475,7 +459,7 @@ mod tests {
#[test] #[test]
fn test_div() { fn test_div() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0)); assert_common_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0));
assert_common_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018)); assert_common_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018));
@ -498,7 +482,7 @@ mod tests {
#[test] #[test]
fn test_dvr() { fn test_dvr() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let a264 = atom_264(&mut c.stack); let a264 = atom_264(&mut c.stack);
@ -544,7 +528,7 @@ mod tests {
#[test] #[test]
fn test_gte() { fn test_gte() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_96], YES); assert_common_jet_noun(c, jet_gte, &[atom_128, atom_96], YES);
assert_common_jet_noun(c, jet_gte, &[atom_96, atom_63], YES); assert_common_jet_noun(c, jet_gte, &[atom_96, atom_63], YES);
@ -558,7 +542,7 @@ mod tests {
#[test] #[test]
fn test_gth() { fn test_gth() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_96], YES); assert_common_jet_noun(c, jet_gth, &[atom_128, atom_96], YES);
assert_common_jet_noun(c, jet_gth, &[atom_96, atom_63], YES); assert_common_jet_noun(c, jet_gth, &[atom_96, atom_63], YES);
@ -572,7 +556,7 @@ mod tests {
#[test] #[test]
fn test_lte() { fn test_lte() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_96], NO); assert_common_jet_noun(c, jet_lte, &[atom_128, atom_96], NO);
assert_common_jet_noun(c, jet_lte, &[atom_96, atom_63], NO); assert_common_jet_noun(c, jet_lte, &[atom_96, atom_63], NO);
@ -586,7 +570,7 @@ mod tests {
#[test] #[test]
fn test_lth() { fn test_lth() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_96], NO); assert_common_jet_noun(c, jet_lth, &[atom_128, atom_96], NO);
assert_common_jet_noun(c, jet_lth, &[atom_96, atom_63], NO); assert_common_jet_noun(c, jet_lth, &[atom_96, atom_63], NO);
@ -600,7 +584,7 @@ mod tests {
#[test] #[test]
fn test_max() { fn test_max() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,
@ -646,7 +630,7 @@ mod tests {
#[test] #[test]
fn test_min() { fn test_min() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,
@ -687,7 +671,7 @@ mod tests {
#[test] #[test]
fn test_mod() { fn test_mod() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,
@ -707,7 +691,7 @@ mod tests {
#[test] #[test]
fn test_mul() { fn test_mul() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,
@ -732,7 +716,7 @@ mod tests {
#[test] #[test]
fn test_sub() { fn test_sub() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet( assert_common_jet(
c, c,

View File

@ -7,7 +7,7 @@ use crate::noun::{Noun, D, NO, T};
crate::gdb!(); crate::gdb!();
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
// mink sample = [nock scry_namespace] // mink sample = [nock scry_namespace]
// = [[subject formula] scry_namespace] // = [[subject formula] scry_namespace]
@ -19,18 +19,18 @@ pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(util::mink(context, v_subject, v_formula, scry_handler)?) Ok(util::mink(context, v_subject, v_formula, scry_handler)?)
} }
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mole(context: &mut Context, subject: Noun) -> Result {
jet_mure(context, subject) jet_mure(context, subject)
} }
pub fn jet_mule(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mule(context: &mut Context, subject: Noun) -> Result {
jet_mute(context, subject) jet_mute(context, subject)
} }
pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mure(context: &mut Context, subject: Noun) -> Result {
let tap = slot(subject, 6)?; let tap = slot(subject, 6)?;
let fol = util::slam_gate_fol(&mut context.stack)?; let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack)?; let scry = util::pass_thru_scry(&mut context.stack);
match util::mink(context, tap, fol, scry) { match util::mink(context, tap, fol, scry) {
Ok(tone) => { Ok(tone) => {
@ -44,10 +44,10 @@ pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mute(context: &mut Context, subject: Noun) -> Result {
let tap = slot(subject, 6)?; let tap = slot(subject, 6)?;
let fol = util::slam_gate_fol(&mut context.stack)?; let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack)?; let scry = util::pass_thru_scry(&mut context.stack);
let tone = util::mink(context, tap, fol, scry); let tone = util::mink(context, tap, fol, scry);
@ -59,11 +59,9 @@ pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> {
// XX: Need to check that result is actually of type path // XX: Need to check that result is actually of type path
// return [[%leaf "mute.hunk"] ~] if not // return [[%leaf "mute.hunk"] ~] if not
let bon = util::smyt(&mut context.stack, toon.tail())?; let bon = util::smyt(&mut context.stack, toon.tail())?;
Ok(T(&mut context.stack, &[NO, bon, D(0)])?) Ok(T(&mut context.stack, &[NO, bon, D(0)]))
}
x if unsafe { x.raw_equals(D(2)) } => {
Ok(T(&mut context.stack, &[NO, toon.tail()])?)
} }
x if unsafe { x.raw_equals(D(2)) } => Ok(T(&mut context.stack, &[NO, toon.tail()])),
_ => panic!("serf: mook: invalid toon"), _ => panic!("serf: mook: invalid toon"),
} }
} }
@ -77,7 +75,7 @@ pub mod util {
use crate::jets; use crate::jets;
use crate::jets::bits::util::rip; use crate::jets::bits::util::rip;
use crate::jets::form::util::scow; use crate::jets::form::util::scow;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{tape, Cell, Noun, D, T}; use crate::noun::{tape, Cell, Noun, D, T};
use either::{Left, Right}; use either::{Left, Right};
use std::result; use std::result;
@ -87,37 +85,37 @@ pub mod util {
pub const ROSE: Noun = D(tas!(b"rose")); pub const ROSE: Noun = D(tas!(b"rose"));
/// The classic "slam gate" formula. /// The classic "slam gate" formula.
pub fn slam_gate_fol(stack: &mut NockStack) -> AllocResult<Noun> { pub fn slam_gate_fol(stack: &mut NockStack) -> Noun {
T(stack, &[D(9), D(2), D(0), D(1)]) T(stack, &[D(9), D(2), D(0), D(1)])
} }
/// The classic "pass-through" scry handler. /// The classic "pass-through" scry handler.
pub fn pass_thru_scry(stack: &mut NockStack) -> AllocResult<Noun> { pub fn pass_thru_scry(stack: &mut NockStack) -> Noun {
// .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3])) // .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
// [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0] // [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0]
let sig = T(stack, &[D(1), D(0)])?; let sig = T(stack, &[D(1), D(0)]);
let sam = T(stack, &[D(0), D(6)])?; let sam = T(stack, &[D(0), D(6)]);
let hed = T(stack, &[D(0), D(2)])?; let hed = T(stack, &[D(0), D(2)]);
let tel = T(stack, &[D(0), D(3)])?; let tel = T(stack, &[D(0), D(3)]);
let zap = T(stack, &[D(0), D(0)])?; let zap = T(stack, &[D(0), D(0)]);
let cry = T(stack, &[D(12), hed, tel])?; let cry = T(stack, &[D(12), hed, tel]);
let fol = T(stack, &[D(1), cry])?; let fol = T(stack, &[D(1), cry]);
let res = T(stack, &[D(2), sam, fol])?; let res = T(stack, &[D(2), sam, fol]);
let uno = T(stack, &[sig, res])?; let uno = T(stack, &[sig, res]);
let dos = T(stack, &[sig, uno])?; let dos = T(stack, &[sig, uno]);
let gat = T(stack, &[zap, D(0)])?; let gat = T(stack, &[zap, D(0)]);
T(stack, &[dos, gat]) T(stack, &[dos, gat])
} }
/// The "always-fail" scry /// The "always-fail" scry
pub fn null_scry(stack: &mut NockStack) -> AllocResult<Noun> { pub fn null_scry(stack: &mut NockStack) -> Noun {
// .* 0 != => ~ |=(^ ~) // .* 0 != => ~ |=(^ ~)
// [[1 0] [0 0] 0] // [[1 0] [0 0] 0]
let sig = T(stack, &[D(1), D(0)])?; let sig = T(stack, &[D(1), D(0)]);
let zap = T(stack, &[D(0), D(0)])?; let zap = T(stack, &[D(0), D(0)]);
T(stack, &[sig, zap, D(0)]) T(stack, &[sig, zap, D(0)])
} }
@ -151,25 +149,25 @@ pub mod util {
let cache_snapshot = context.cache; let cache_snapshot = context.cache;
let scry_snapshot = context.scry_stack; let scry_snapshot = context.scry_stack;
context.cache = Hamt::<Noun>::new(&mut context.stack)?; context.cache = Hamt::<Noun>::new(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack])?; context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
match interpret(context, subject, formula) { match interpret(context, subject, formula) {
Ok(res) => { Ok(res) => {
context.cache = cache_snapshot; context.cache = cache_snapshot;
context.scry_stack = scry_snapshot; context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(0), res])?) Ok(T(&mut context.stack, &[D(0), res]))
} }
Err(err) => match err { Err(err) => match err {
Error::ScryBlocked(path) => { Error::ScryBlocked(path) => {
context.cache = cache_snapshot; context.cache = cache_snapshot;
context.scry_stack = scry_snapshot; context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(1), path])?) Ok(T(&mut context.stack, &[D(1), path]))
} }
Error::Deterministic(_, trace) => { Error::Deterministic(_, trace) => {
context.cache = cache_snapshot; context.cache = cache_snapshot;
context.scry_stack = scry_snapshot; context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(2), trace])?) Ok(T(&mut context.stack, &[D(2), trace]))
} }
Error::ScryCrashed(trace) => { Error::ScryCrashed(trace) => {
context.cache = cache_snapshot; context.cache = cache_snapshot;
@ -199,7 +197,7 @@ pub mod util {
context.cache = cache_snapshot; context.cache = cache_snapshot;
context.scry_stack = scry_snapshot; context.scry_stack = scry_snapshot;
Err(err) Err(err)
} // TODO: Implement the rest of the error handling }
}, },
} }
} }
@ -234,8 +232,8 @@ pub mod util {
tas!(b"hunk") => match dat.as_either_atom_cell() { tas!(b"hunk") => match dat.as_either_atom_cell() {
Left(_) => { Left(_) => {
let stack = &mut context.stack; let stack = &mut context.stack;
let tape = tape(stack, "mook.hunk")?; let tape = tape(stack, "mook.hunk");
T(stack, &[LEAF, tape])? T(stack, &[LEAF, tape])
} }
Right(cell) => { Right(cell) => {
// XX: need to check that this is actually a path // XX: need to check that this is actually a path
@ -248,11 +246,11 @@ pub mod util {
Left(atom) => { Left(atom) => {
let stack = &mut context.stack; let stack = &mut context.stack;
let tape = rip(stack, 3, 1, atom)?; let tape = rip(stack, 3, 1, atom)?;
T(stack, &[LEAF, tape])? T(stack, &[LEAF, tape])
} }
Right(cell) => { Right(cell) => {
'tank: { 'tank: {
let scry = null_scry(&mut context.stack)?; let scry = null_scry(&mut context.stack);
// if +mink didn't crash... // if +mink didn't crash...
if let Ok(tone) = mink(context, dat, cell.head(), scry) { if let Ok(tone) = mink(context, dat, cell.head(), scry) {
if let Some(tonc) = tone.cell() { if let Some(tonc) = tone.cell() {
@ -272,8 +270,8 @@ pub mod util {
// This code only called when the break statement // This code only called when the break statement
// above doesn't trigger // above doesn't trigger
let stack = &mut context.stack; let stack = &mut context.stack;
let tape = tape(stack, "####")?; let tape = tape(stack, "####");
T(stack, &[LEAF, tape])? T(stack, &[LEAF, tape])
} }
} }
}, },
@ -285,8 +283,8 @@ pub mod util {
let pstr = pint.head().as_cell()?; let pstr = pint.head().as_cell()?;
let pend = pint.tail().as_cell()?; let pend = pint.tail().as_cell()?;
let colo = T(stack, &[D(b':' as u64), D(0)])?; let colo = T(stack, &[D(b':' as u64), D(0)]);
let trel = T(stack, &[colo, D(0), D(0)])?; let trel = T(stack, &[colo, D(0), D(0)]);
let smyt = smyt(stack, spot.head())?; let smyt = smyt(stack, spot.head())?;
@ -304,7 +302,7 @@ pub mod util {
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
} }
// "{end_col}]>" // "{end_col}]>"
let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)])?; let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)]);
(*list.tail_as_mut()) = p4; (*list.tail_as_mut()) = p4;
list = end_lin.as_cell()?; list = end_lin.as_cell()?;
@ -315,7 +313,7 @@ pub mod util {
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
} }
// "{end_lin} {end_col}]>" // "{end_lin} {end_col}]>"
let p3 = T(stack, &[D(b' ' as u64), end_col])?; let p3 = T(stack, &[D(b' ' as u64), end_col]);
(*list.tail_as_mut()) = p3; (*list.tail_as_mut()) = p3;
list = str_col.as_cell()?; list = str_col.as_cell()?;
@ -329,7 +327,7 @@ pub mod util {
let p2 = T( let p2 = T(
stack, stack,
&[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin], &[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin],
)?; );
(*list.tail_as_mut()) = p2; (*list.tail_as_mut()) = p2;
list = str_lin.as_cell()?; list = str_lin.as_cell()?;
@ -340,14 +338,14 @@ pub mod util {
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
} }
// "{str_lin} {str_col}].[{end_lin} {end_col}]>" // "{str_lin} {str_col}].[{end_lin} {end_col}]>"
let p1 = T(stack, &[D(b' ' as u64), str_col])?; let p1 = T(stack, &[D(b' ' as u64), str_col]);
(*list.tail_as_mut()) = p1; (*list.tail_as_mut()) = p1;
// "<[{str_lin} {str_col}].[{end_lin} {end_col}]>" // "<[{str_lin} {str_col}].[{end_lin} {end_col}]>"
let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin])?; let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]);
let finn = T(stack, &[LEAF, tape])?; let finn = T(stack, &[LEAF, tape]);
T(stack, &[ROSE, trel, smyt, finn, D(0)])? T(stack, &[ROSE, trel, smyt, finn, D(0)])
} }
_ => { _ => {
let stack = &mut context.stack; let stack = &mut context.stack;
@ -362,16 +360,16 @@ pub mod util {
D(tas!(b".")), D(tas!(b".")),
tape, tape,
], ],
)? )
} // XX: TODO } // XX: TODO
// %hand // %hand
// %lose // %lose
}; };
if flop { if flop {
res = T(&mut context.stack, &[tank, res])?; res = T(&mut context.stack, &[tank, res]);
} else { } else {
let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack)?; let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack);
(*new_memory).head = tank; (*new_memory).head = tank;
*dest = new_cell.as_noun(); *dest = new_cell.as_noun();
dest = &mut (*new_memory).tail; dest = &mut (*new_memory).tail;
@ -381,23 +379,23 @@ pub mod util {
} }
*dest = D(0); *dest = D(0);
let toon = Cell::new(&mut context.stack, D(2), res)?; let toon = Cell::new(&mut context.stack, D(2), res);
Ok(toon) Ok(toon)
} }
} }
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> { pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result {
let lash = D(tas!(b"/")); let lash = D(tas!(b"/"));
let zero = D(0); let zero = D(0);
let sep = T(stack, &[lash, zero])?; let sep = T(stack, &[lash, zero]);
let trel = T(stack, &[sep, sep, zero])?; let trel = T(stack, &[sep, sep, zero]);
let tank = smyt_help(stack, path)?; let tank = smyt_help(stack, path)?;
Ok(T(stack, &[ROSE, trel, tank])?) Ok(T(stack, &[ROSE, trel, tank]))
} }
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> { fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result {
// XX: switch to using Cell:new_raw_mut // XX: switch to using Cell:new_raw_mut
if unsafe { path.raw_equals(D(0)) } { if unsafe { path.raw_equals(D(0)) } {
return Ok(D(0)); return Ok(D(0));
@ -406,23 +404,18 @@ pub mod util {
let cell = path.as_cell()?; let cell = path.as_cell()?;
let tail = smyt_help(stack, cell.tail())?; let tail = smyt_help(stack, cell.tail())?;
let trip = rip(stack, 3, 1, cell.head().as_atom()?)?; let trip = rip(stack, 3, 1, cell.head().as_atom()?)?;
let head = T(stack, &[LEAF, trip])?; let head = T(stack, &[LEAF, trip]);
Ok(T(stack, &[head, tail])?) Ok(T(stack, &[head, tail]))
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, init_context};
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::D; use crate::noun::{D, T};
// Override T and A with the panicky variants
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[test] #[test]
fn init() { fn init() {
@ -438,7 +431,7 @@ mod tests {
#[test] #[test]
fn test_mink_success() { fn test_mink_success() {
let context = &mut init_context().unwrap(); let context = &mut init_context();
let stack = &mut context.stack; let stack = &mut context.stack;
let subj = D(0); let subj = D(0);
@ -452,7 +445,7 @@ mod tests {
#[test] #[test]
fn test_mink_zapzap() { fn test_mink_zapzap() {
let context = &mut init_context().unwrap(); let context = &mut init_context();
let stack = &mut context.stack; let stack = &mut context.stack;
let subj = D(0); let subj = D(0);
@ -466,7 +459,7 @@ mod tests {
#[test] #[test]
fn test_mink_trace() { fn test_mink_trace() {
let context = &mut init_context().unwrap(); let context = &mut init_context();
let stack = &mut context.stack; let stack = &mut context.stack;
let subj = D(0); let subj = D(0);
let scry = D(0); let scry = D(0);

View File

@ -13,7 +13,7 @@ crate::gdb!();
// //
// Text conversion // Text conversion
// //
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?.as_atom()?; let sam = slot(subject, 6)?.as_atom()?;
let chars = met(3, sam); let chars = met(3, sam);
if chars == 0 { if chars == 0 {
@ -27,7 +27,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
for byte in bytes { for byte in bytes {
unsafe { unsafe {
let (it, it_mem) = Cell::new_raw_mut(&mut context.stack)?; let (it, it_mem) = Cell::new_raw_mut(&mut context.stack);
// safe because a byte can't overflow a direct atom // safe because a byte can't overflow a direct atom
(*it_mem).head = D((*byte) as u64); (*it_mem).head = D((*byte) as u64);
@ -44,7 +44,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
// Tracing // Tracing
// //
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let zyc = slot(sam, 2)?; let zyc = slot(sam, 2)?;
let naz = slot(sam, 3)?; let naz = slot(sam, 3)?;
@ -56,7 +56,7 @@ pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
// Combinators // Combinators
// //
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?; let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?; let sab = slot(sam, 3)?;
@ -81,25 +81,25 @@ pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?; let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } { if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex])?) Ok(T(&mut context.stack, &[yur, q_vex]))
} else { } else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?; let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head(); let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail(); let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?; let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?; let vux = slam(context, raq, arg)?;
if unsafe { vux.raw_equals(D(0)) } { if unsafe { vux.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex])?) Ok(T(&mut context.stack, &[yur, q_vex]))
} else { } else {
let q_vux = vux.as_cell()?.tail(); let q_vux = vux.as_cell()?.tail();
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit])?) Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit]))
} }
} }
} }
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_comp(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?; let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?; let sab = slot(sam, 3)?;
@ -124,19 +124,19 @@ pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?; let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } { if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?) Ok(T(&mut context.stack, &[yur, D(0)]))
} else { } else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?; let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head(); let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail(); let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?; let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?; let vux = slam(context, raq, arg)?;
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit])?) Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit]))
} }
} }
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?; let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?; let sab = slot(sam, 3)?;
@ -161,7 +161,7 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?; let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } { if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?) Ok(T(&mut context.stack, &[yur, D(0)]))
} else { } else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?; let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail(); let quq_yit = uq_yit.tail();
@ -173,19 +173,19 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
let goy = util::last(yur, p_wam)?; let goy = util::last(yur, p_wam)?;
if unsafe { q_wam.raw_equals(D(0)) } { if unsafe { q_wam.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[goy, D(0)])?) Ok(T(&mut context.stack, &[goy, D(0)]))
} else { } else {
let uq_wam = q_wam.as_cell()?.tail().as_cell()?; let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
let puq_wam = uq_wam.head(); let puq_wam = uq_wam.head();
let quq_wam = uq_wam.tail(); let quq_wam = uq_wam.tail();
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam])?; let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam]);
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam])?) Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam]))
} }
} }
} }
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?; let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?; let sab = slot(sam, 3)?;
@ -207,10 +207,10 @@ pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
// XX: Why don't we just return yit? When would p_vex ever be the later of the two? // XX: Why don't we just return yit? When would p_vex ever be the later of the two?
let arg = util::last(p_vex, p_yit)?; let arg = util::last(p_vex, p_yit)?;
Ok(T(&mut context.stack, &[arg, q_yit])?) Ok(T(&mut context.stack, &[arg, q_yit]))
} }
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_plug(context: &mut Context, subject: Noun) -> Result {
let vex = slot(subject, 12)?.as_cell()?; let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?; let sab = slot(subject, 13)?;
let p_vex = vex.head(); let p_vex = vex.head();
@ -230,19 +230,19 @@ pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?; let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } { if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?) Ok(T(&mut context.stack, &[yur, D(0)]))
} else { } else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?; let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head(); let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail(); let quq_yit = uq_yit.tail();
let inner = T(&mut context.stack, &[puq_vex, puq_yit])?; let inner = T(&mut context.stack, &[puq_vex, puq_yit]);
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit])?) Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit]))
} }
} }
} }
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
let vex = slot(subject, 12)?.as_cell()?; let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?; let sab = slot(subject, 13)?;
@ -255,10 +255,10 @@ pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
let roq = kick(context, sab, D(2))?.as_cell()?; let roq = kick(context, sab, D(2))?.as_cell()?;
let yur = util::last(p_vex, roq.head())?; let yur = util::last(p_vex, roq.head())?;
Ok(T(&mut context.stack, &[yur, roq.tail()])?) Ok(T(&mut context.stack, &[yur, roq.tail()]))
} }
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?; let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?; let sab = slot(sam, 3)?;
@ -281,12 +281,12 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?; let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } { if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?) Ok(T(&mut context.stack, &[yur, D(0)]))
} else { } else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?; let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail(); let quq_yit = uq_yit.tail();
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit])?) Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit]))
} }
} }
@ -294,7 +294,7 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
// Rule Builders // Rule Builders
// //
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cold(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let cus = slot(van, 12)?; let cus = slot(van, 12)?;
@ -309,11 +309,11 @@ pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
} else { } else {
let quq_vex = q_vex.as_cell()?.tail().as_cell()?.tail(); let quq_vex = q_vex.as_cell()?.tail().as_cell()?.tail();
Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex])?) Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex]))
} }
} }
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cook(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let poq = slot(van, 12)?; let poq = slot(van, 12)?;
@ -331,11 +331,11 @@ pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
let quq_vex = uq_vex.tail(); let quq_vex = uq_vex.tail();
let wag = slam(context, poq, puq_vex)?; let wag = slam(context, poq, puq_vex)?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?) Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
} }
} }
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_easy(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let huf = slot(van, 6)?; let huf = slot(van, 6)?;
@ -343,10 +343,10 @@ pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(T( Ok(T(
&mut context.stack, &mut context.stack,
&[tub.as_cell()?.head(), D(0), huf, tub], &[tub.as_cell()?.head(), D(0), huf, tub],
)?) ))
} }
pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let hez = slot(van, 12)?; let hez = slot(van, 12)?;
@ -368,14 +368,14 @@ pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
let quq_vex = uq_vex.tail(); let quq_vex = uq_vex.tail();
let pquq_vex = quq_vex.as_cell()?.head(); let pquq_vex = quq_vex.as_cell()?.head();
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex])?; let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex]);
let gud = T(&mut context.stack, &[inner_gud, puq_vex])?; let gud = T(&mut context.stack, &[inner_gud, puq_vex]);
let wag = slam(context, hez, gud)?; let wag = slam(context, hez, gud)?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?) Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
} }
pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_just(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let daf = slot(van, 6)?; let daf = slot(van, 6)?;
@ -390,7 +390,7 @@ pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let mut bud = slot(van, 6)?; let mut bud = slot(van, 6)?;
@ -413,7 +413,7 @@ pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
util::fail(context, p_tub) util::fail(context, p_tub)
} }
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_shim(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?.as_cell()?; let tub = slot(subject, 6)?.as_cell()?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let zep = slot(van, 6)?.as_cell()?; let zep = slot(van, 6)?.as_cell()?;
@ -442,7 +442,7 @@ pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?; let tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let gob = slot(van, 12)?; let gob = slot(van, 12)?;
@ -459,12 +459,12 @@ pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
let puq_vex = uq_vex.head(); let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail(); let quq_vex = uq_vex.tail();
let wag = T(&mut context.stack, &[gob, puq_vex])?; let wag = T(&mut context.stack, &[gob, puq_vex]);
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?) Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
} }
} }
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?.as_cell()?; let tub = slot(subject, 6)?.as_cell()?;
let con = slot(subject, 7)?; let con = slot(subject, 7)?;
let mut hel = slot(con, 2)?; let mut hel = slot(con, 2)?;
@ -505,8 +505,8 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
match (hpn_hel.as_either(), tpn_hel.as_either()) { match (hpn_hel.as_either(), tpn_hel.as_either()) {
(Left(_), Left(_)) => { (Left(_), Left(_)) => {
gte_b(&mut context.stack, iq_tub, hpn_hel)? gte_b(&mut context.stack, iq_tub, hpn_hel)
&& lte_b(&mut context.stack, iq_tub, tpn_hel)? && lte_b(&mut context.stack, iq_tub, tpn_hel)
} }
_ => { _ => {
// XX: Fixes jet mismatch in Vere // XX: Fixes jet mismatch in Vere
@ -525,7 +525,7 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
Right(cell) => cell.head().as_atom()?, Right(cell) => cell.head().as_atom()?,
}; };
if lth_b(&mut context.stack, iq_tub, wor)? { if lth_b(&mut context.stack, iq_tub, wor) {
hel = l_hel; hel = l_hel;
} else { } else {
hel = r_hel; hel = r_hel;
@ -542,9 +542,9 @@ struct StirPair {
pub res: Noun, // p.u.q.edge pub res: Noun, // p.u.q.edge
} }
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_stir(context: &mut Context, subject: Noun) -> Result {
unsafe { unsafe {
let res = context.with_stack_frame(0, |context| { context.with_stack_frame(0, |context| {
let mut tub = slot(subject, 6)?; let mut tub = slot(subject, 6)?;
let van = slot(subject, 7)?; let van = slot(subject, 7)?;
let rud = slot(van, 12)?; let rud = slot(van, 12)?;
@ -565,7 +565,7 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
let puq_vex = slot(q_vex, 6)?; let puq_vex = slot(q_vex, 6)?;
let quq_vex = slot(q_vex, 7)?; let quq_vex = slot(q_vex, 7)?;
*(context.stack.push::<StirPair>()?) = StirPair { *(context.stack.push::<StirPair>()) = StirPair {
har: p_vex, har: p_vex,
res: puq_vex, res: puq_vex,
}; };
@ -586,15 +586,14 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
while !context.stack.stack_is_empty() { while !context.stack.stack_is_empty() {
let par_u = *(context.stack.top::<StirPair>()); let par_u = *(context.stack.top::<StirPair>());
p_wag = util::last(par_u.har, p_wag)?; p_wag = util::last(par_u.har, p_wag)?;
let sam = T(&mut context.stack, &[par_u.res, puq_wag])?; let sam = T(&mut context.stack, &[par_u.res, puq_wag]);
puq_wag = slam(context, raq, sam)?; puq_wag = slam(context, raq, sam)?;
context.stack.pop::<StirPair>(); context.stack.pop::<StirPair>();
} }
let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag])?; let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag]);
Ok(res) Ok(res)
})?; })
res
} }
} }
@ -604,7 +603,7 @@ pub mod util {
use crate::noun::{Noun, D, T}; use crate::noun::{Noun, D, T};
use std::cmp::Ordering; use std::cmp::Ordering;
pub fn last(zyc: Noun, naz: Noun) -> Result<Noun> { pub fn last(zyc: Noun, naz: Noun) -> Result {
let zyl = zyc.as_cell()?; let zyl = zyc.as_cell()?;
let nal = naz.as_cell()?; let nal = naz.as_cell()?;
@ -627,7 +626,7 @@ pub mod util {
} }
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon. // Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn next(context: &mut Context, tub: Noun) -> Result<Noun> { pub fn next(context: &mut Context, tub: Noun) -> Result {
let p_tub = tub.as_cell()?.head(); let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail(); let q_tub = tub.as_cell()?.tail();
@ -639,25 +638,25 @@ pub mod util {
let tq_tub = q_tub.as_cell()?.tail(); let tq_tub = q_tub.as_cell()?.tail();
let zac = lust(context, iq_tub, p_tub)?; let zac = lust(context, iq_tub, p_tub)?;
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub])?) Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub]))
} }
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon. // Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result<Noun> { pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result {
let p_naz = naz.as_cell()?.head().as_atom()?; let p_naz = naz.as_cell()?.head().as_atom()?;
let q_naz = naz.as_cell()?.tail().as_atom()?; let q_naz = naz.as_cell()?.tail().as_atom()?;
if unsafe { weq.raw_equals(D(10)) } { if unsafe { weq.raw_equals(D(10)) } {
let arg = inc(&mut context.stack, p_naz)?.as_noun(); let arg = inc(&mut context.stack, p_naz).as_noun();
Ok(T(&mut context.stack, &[arg, D(1)])?) Ok(T(&mut context.stack, &[arg, D(1)]))
} else { } else {
let arg = inc(&mut context.stack, q_naz)?.as_noun(); let arg = inc(&mut context.stack, q_naz).as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg])?) Ok(T(&mut context.stack, &[p_naz.as_noun(), arg]))
} }
} }
pub fn fail(context: &mut Context, hair: Noun) -> Result<Noun> { pub fn fail(context: &mut Context, hair: Noun) -> Result {
Ok(T(&mut context.stack, &[hair, D(0)])?) Ok(T(&mut context.stack, &[hair, D(0)]))
} }
} }
@ -665,13 +664,9 @@ pub mod util {
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::*;
use crate::noun::D; use crate::noun::{D, T};
use crate::serialization::cue; use crate::serialization::cue;
use ibig::ubig; use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet_door: AssertJetDoorFn = assert_jet_door_panicky;
// XX: need unit tests for: // XX: need unit tests for:
// +last // +last
@ -688,7 +683,7 @@ mod tests {
#[test] #[test]
fn test_easy() { fn test_easy() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
// ((easy 'a') [[1 1] "abc"]) // ((easy 'a') [[1 1] "abc"])
// [[1 1] "abc"] // [[1 1] "abc"]

View File

@ -6,27 +6,23 @@ use crate::serialization::{cue, jam};
crate::gdb!(); crate::gdb!();
pub fn jet_cue(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cue(context: &mut Context, subject: Noun) -> Result {
Ok(cue(&mut context.stack, slot(subject, 6)?.as_atom()?)?) Ok(cue(&mut context.stack, slot(subject, 6)?.as_atom()?)?)
} }
pub fn jet_jam(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_jam(context: &mut Context, subject: Noun) -> Result {
Ok(jam(&mut context.stack, slot(subject, 6)?)?.as_noun()) Ok(jam(&mut context.stack, slot(subject, 6)?).as_noun())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::*;
use crate::noun::D; use crate::noun::{D, T};
// Override T with the panicky variant
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[test] #[test]
fn test_jam() { fn test_jam() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet(c, jet_jam, D(0x0), D(0x2)); assert_jet(c, jet_jam, D(0x0), D(0x2));
assert_jet(c, jet_jam, D(0x1), D(0xc)); assert_jet(c, jet_jam, D(0x1), D(0xc));
@ -38,7 +34,7 @@ mod tests {
#[test] #[test]
fn test_cue() { fn test_cue() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet(c, jet_cue, D(0x2), D(0x0)); assert_jet(c, jet_cue, D(0x2), D(0x0));
assert_jet(c, jet_cue, D(0xc), D(0x1)); assert_jet(c, jet_cue, D(0xc), D(0x1));

View File

@ -9,100 +9,95 @@ use std::cmp::Ordering;
crate::gdb!(); crate::gdb!();
pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result<Noun> { pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result {
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let a = slot(sam, 2)?; let a = slot(sam, 2)?;
let b = slot(sam, 3)?; let b = slot(sam, 3)?;
Ok(util::dor(&mut context.stack, a, b)?) Ok(util::dor(&mut context.stack, a, b))
} }
pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result<Noun> { pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let a = slot(sam, 2)?; let a = slot(sam, 2)?;
let b = slot(sam, 3)?; let b = slot(sam, 3)?;
let c = mug(stack, a)?; let c = mug(stack, a);
let d = mug(stack, b)?; let d = mug(stack, b);
match c.data().cmp(&d.data()) { match c.data().cmp(&d.data()) {
Ordering::Greater => Ok(NO), Ordering::Greater => Ok(NO),
Ordering::Less => Ok(YES), Ordering::Less => Ok(YES),
Ordering::Equal => Ok(util::dor(stack, a, b)?), Ordering::Equal => Ok(util::dor(stack, a, b)),
} }
} }
pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result<Noun> { pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let sam = slot(subject, 6)?; let sam = slot(subject, 6)?;
let a = slot(sam, 2)?; let a = slot(sam, 2)?;
let b = slot(sam, 3)?; let b = slot(sam, 3)?;
let c = mug(stack, a)?; let c = mug(stack, a);
let d = mug(stack, b)?; let d = mug(stack, b);
let e = mug(stack, c.as_noun())?; let e = mug(stack, c.as_noun());
let f = mug(stack, d.as_noun())?; let f = mug(stack, d.as_noun());
match e.data().cmp(&f.data()) { match e.data().cmp(&f.data()) {
Ordering::Greater => Ok(NO), Ordering::Greater => Ok(NO),
Ordering::Less => Ok(YES), Ordering::Less => Ok(YES),
Ordering::Equal => Ok(util::dor(stack, a, b)?), Ordering::Equal => Ok(util::dor(stack, a, b)),
} }
} }
pub mod util { pub mod util {
use crate::jets::math::util::lth; use crate::jets::math::util::lth;
use crate::jets::util::slot; use crate::jets::util::slot;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Noun, NO, YES}; use crate::noun::{Noun, NO, YES};
use either::{Left, Right}; use either::{Left, Right};
pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> AllocResult<Noun> { pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> Noun {
let res = if unsafe { a.raw_equals(b) } { if unsafe { a.raw_equals(b) } {
YES YES
} else { } else {
match (a.as_either_atom_cell(), b.as_either_atom_cell()) { match (a.as_either_atom_cell(), b.as_either_atom_cell()) {
(Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b)?, (Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b),
(Left(_), Right(_)) => YES, (Left(_), Right(_)) => YES,
(Right(_), Left(_)) => NO, (Right(_), Left(_)) => NO,
(Right(cell_a), Right(cell_b)) => { (Right(cell_a), Right(cell_b)) => {
let a_head = match slot(cell_a.as_noun(), 2) { let a_head = match slot(cell_a.as_noun(), 2) {
Ok(n) => n, Ok(n) => n,
Err(_) => return Ok(NO), Err(_) => return NO,
}; };
let b_head = slot(cell_b.as_noun(), 2).unwrap(); let b_head = slot(cell_b.as_noun(), 2).unwrap();
let a_tail = slot(cell_a.as_noun(), 3).unwrap(); let a_tail = slot(cell_a.as_noun(), 3).unwrap();
let b_tail = slot(cell_b.as_noun(), 3).unwrap(); let b_tail = slot(cell_b.as_noun(), 3).unwrap();
if unsafe { a_head.raw_equals(b_head) } { if unsafe { a_head.raw_equals(b_head) } {
dor(stack, a_tail, b_tail)? dor(stack, a_tail, b_tail)
} else { } else {
dor(stack, a_head, b_head)? dor(stack, a_head, b_head)
} }
} }
} }
}; }
Ok(res)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::jets::util::test::*; use crate::jets::util::test::{assert_jet, init_context, A};
use crate::noun::D; use crate::noun::{D, T};
use ibig::ubig; use ibig::ubig;
// Override with the panicky variant
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[test] #[test]
fn test_dor() { fn test_dor() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]); let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_dor, sam, YES); assert_jet(c, jet_dor, sam, YES);
@ -118,7 +113,7 @@ mod tests {
#[test] #[test]
fn test_gor() { fn test_gor() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]); let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_gor, sam, YES); assert_jet(c, jet_gor, sam, YES);
@ -130,7 +125,7 @@ mod tests {
#[test] #[test]
fn test_mor() { fn test_mor() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]); let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_mor, sam, YES); assert_jet(c, jet_mor, sam, YES);

View File

@ -8,7 +8,7 @@ use crate::noun::{IndirectAtom, Noun, D};
crate::gdb!(); crate::gdb!();
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let tom = arg.as_atom()?; let tom = arg.as_atom()?;
let met = met(0, tom); let met = met(0, tom);
@ -24,7 +24,7 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let tom = slot(subject, 6)?.as_atom()?; let tom = slot(subject, 6)?.as_atom()?;
let met = met(0, tom); let met = met(0, tom);
@ -35,7 +35,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
let out_bits = met - 1; let out_bits = met - 1;
let out_words = (out_bits + 63) >> 6; let out_words = (out_bits + 63) >> 6;
let (mut indirect_out, out_bs) = let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? }; unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
out_bs.set(met - 2, true); // Set MSB out_bs.set(met - 2, true); // Set MSB
if met > 2 { if met > 2 {
out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]); out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]);
@ -44,7 +44,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
} }
} }
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> { pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack; let stack = &mut context.stack;
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?; let a = slot(arg, 2)?.as_atom()?;
@ -67,7 +67,7 @@ pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
let (mut indirect_out, out_bs) = let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? }; unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
out_bs[0..b_bits - 1].copy_from_bitslice(&b.as_bitslice()[0..b_bits - 1]); out_bs[0..b_bits - 1].copy_from_bitslice(&b.as_bitslice()[0..b_bits - 1]);
out_bs[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]); out_bs[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]);
@ -82,13 +82,6 @@ mod tests {
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Noun, D, DIRECT_MAX}; use crate::noun::{Noun, D, DIRECT_MAX};
use ibig::ubig; use ibig::ubig;
// Override with the panicky variant
use crate::test_fns::A;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
fn atom_0(_stack: &mut NockStack) -> Noun { fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x0) D(0x0)
@ -132,7 +125,7 @@ mod tests {
#[test] #[test]
fn test_cap() { fn test_cap() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_jet_err(c, jet_cap, D(0), BAIL_EXIT); assert_jet_err(c, jet_cap, D(0), BAIL_EXIT);
assert_jet_err(c, jet_cap, D(1), BAIL_EXIT); assert_jet_err(c, jet_cap, D(1), BAIL_EXIT);
@ -148,7 +141,7 @@ mod tests {
#[test] #[test]
fn test_mas() { fn test_mas() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
let a63 = atom_63(&mut c.stack); let a63 = atom_63(&mut c.stack);
let a64 = atom_64(&mut c.stack); let a64 = atom_64(&mut c.stack);
let a65 = atom_65(&mut c.stack); let a65 = atom_65(&mut c.stack);
@ -180,7 +173,7 @@ mod tests {
#[test] #[test]
fn test_peg() { fn test_peg() {
let c = &mut init_context().unwrap(); let c = &mut init_context();
assert_common_jet_err(c, jet_peg, &[atom_0, atom_1], BAIL_EXIT); assert_common_jet_err(c, jet_peg, &[atom_0, atom_1], BAIL_EXIT);
assert_common_jet_err(c, jet_peg, &[atom_1, atom_0], BAIL_EXIT); assert_common_jet_err(c, jet_peg, &[atom_1, atom_0], BAIL_EXIT);

View File

@ -2,7 +2,7 @@ use crate::hamt::Hamt;
use crate::jets::cold::{Batteries, Cold}; use crate::jets::cold::{Batteries, Cold};
use crate::jets::hot::Hot; use crate::jets::hot::Hot;
use crate::jets::Jet; use crate::jets::Jet;
use crate::mem::{AllocResult, NockStack, Preserve}; use crate::mem::{NockStack, Preserve};
use crate::noun::{Noun, Slots}; use crate::noun::{Noun, Slots};
use std::ptr::{copy_nonoverlapping, null_mut}; use std::ptr::{copy_nonoverlapping, null_mut};
@ -14,8 +14,8 @@ impl Preserve for Warm {
unsafe fn assert_in_stack(&self, stack: &NockStack) { unsafe fn assert_in_stack(&self, stack: &NockStack) {
self.0.assert_in_stack(stack); self.0.assert_in_stack(stack);
} }
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
self.0.preserve(stack) self.0.preserve(stack);
} }
} }
@ -47,17 +47,16 @@ impl Preserve for WarmEntry {
cursor = (*cursor.0).next; cursor = (*cursor.0).next;
} }
} }
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
// TODO: Should this panic? What is this?
if self.0.is_null() { if self.0.is_null() {
return Ok(()); return;
} }
let mut ptr: *mut *mut WarmEntryMem = &mut self.0; let mut ptr: *mut *mut WarmEntryMem = &mut self.0;
loop { loop {
if stack.is_in_frame(*ptr) { if stack.is_in_frame(*ptr) {
(**ptr).batteries.preserve(stack)?; (**ptr).batteries.preserve(stack);
(**ptr).path.preserve(stack)?; (**ptr).path.preserve(stack);
let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1)?; let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(*ptr, dest_mem, 1); copy_nonoverlapping(*ptr, dest_mem, 1);
*ptr = dest_mem; *ptr = dest_mem;
ptr = &mut ((*dest_mem).next.0); ptr = &mut ((*dest_mem).next.0);
@ -68,7 +67,6 @@ impl Preserve for WarmEntry {
break; break;
} }
} }
Ok(())
} }
} }
@ -88,8 +86,8 @@ impl Iterator for WarmEntry {
impl Warm { impl Warm {
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub fn new(stack: &mut NockStack) -> AllocResult<Self> { pub fn new(stack: &mut NockStack) -> Self {
Ok(Warm(Hamt::new(stack)?)) Warm(Hamt::new(stack))
} }
fn insert( fn insert(
@ -99,32 +97,31 @@ impl Warm {
path: Noun, path: Noun,
batteries: Batteries, batteries: Batteries,
jet: Jet, jet: Jet,
) -> AllocResult<()> { ) {
let current_warm_entry = self.0.lookup(stack, formula)?.unwrap_or(WARM_ENTRY_NIL); let current_warm_entry = self.0.lookup(stack, formula).unwrap_or(WARM_ENTRY_NIL);
unsafe { unsafe {
let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1)?; let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1);
*warm_entry_mem_ptr = WarmEntryMem { *warm_entry_mem_ptr = WarmEntryMem {
batteries, batteries,
jet, jet,
path, path,
next: current_warm_entry, next: current_warm_entry,
}; };
self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr))?; self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr));
} }
Ok(())
} }
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> AllocResult<Self> { pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> Self {
let mut warm = Self::new(stack)?; let mut warm = Self::new(stack);
for (mut path, axis, jet) in *hot { for (mut path, axis, jet) in *hot {
let batteries_list = cold.find(stack, &mut path)?; let batteries_list = cold.find(stack, &mut path);
for batteries in batteries_list { for batteries in batteries_list {
let mut batteries_tmp = batteries; let mut batteries_tmp = batteries;
let (battery, _parent_axis) = batteries_tmp let (battery, _parent_axis) = batteries_tmp
.next() .next()
.expect("IMPOSSIBLE: empty battery entry in cold state"); .expect("IMPOSSIBLE: empty battery entry in cold state");
if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } { if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } {
warm.insert(stack, &mut formula, path, batteries, jet)?; warm.insert(stack, &mut formula, path, batteries, jet);
} else { } else {
// XX: need NockStack allocated string interpolation // XX: need NockStack allocated string interpolation
// eprintln!("Bad axis {} into formula {:?}", axis, battery); // eprintln!("Bad axis {} into formula {:?}", axis, battery);
@ -132,7 +129,7 @@ impl Warm {
} }
} }
} }
Ok(warm) warm
} }
/// Walk through the linked list of WarmEntry objects and do a partial check /// Walk through the linked list of WarmEntry objects and do a partial check
@ -143,17 +140,13 @@ impl Warm {
stack: &mut NockStack, stack: &mut NockStack,
s: &mut Noun, s: &mut Noun,
f: &mut Noun, f: &mut Noun,
) -> AllocResult<Option<(Jet, Noun)>> { ) -> Option<(Jet, Noun)> {
let warm_it = self.0.lookup(stack, f)?; let warm_it = self.0.lookup(stack, f)?;
if let Some(warm_entry) = warm_it { for (path, batteries, jet) in warm_it {
unsafe { if batteries.matches(stack, *s) {
let jet = (*warm_entry.0).jet; return Some((jet, path));
let path = (*warm_entry.0).path;
if (*warm_entry.0).batteries.matches(stack, *s)? {
return Ok(Some((jet, path)));
}
} }
} }
Ok(None) None
} }
} }

View File

@ -2,22 +2,15 @@ extern crate lazy_static;
extern crate num_derive; extern crate num_derive;
#[macro_use] #[macro_use]
extern crate static_assertions; extern crate static_assertions;
//pub mod bytecode;
pub mod flog; pub mod flog;
pub mod hamt; pub mod hamt;
pub mod interpreter; pub mod interpreter;
pub mod jets; pub mod jets;
pub mod mem; pub mod mem;
pub mod mug; pub mod mug;
pub mod newt;
pub mod noun; pub mod noun;
pub mod serialization; pub mod serialization;
pub mod site; pub mod site;
#[cfg(test)]
pub mod test_fns;
pub mod trace; pub mod trace;
pub mod unifying_equality; pub mod unifying_equality;
@ -78,10 +71,10 @@ mod tests {
use crate::noun::*; use crate::noun::*;
use crate::serialization::jam; use crate::serialization::jam;
let mut stack = NockStack::new(8 << 10 << 10, 0); let mut stack = NockStack::new(8 << 10 << 10, 0);
let head = Atom::new(&mut stack, 0).unwrap().as_noun(); let head = Atom::new(&mut stack, 0).as_noun();
let tail = Atom::new(&mut stack, 1).unwrap().as_noun(); let tail = Atom::new(&mut stack, 1).as_noun();
let cell = Cell::new(&mut stack, head, tail).unwrap().as_noun(); let cell = Cell::new(&mut stack, head, tail).as_noun();
let res = jam(&mut stack, cell).unwrap().as_direct().unwrap().data(); let res = jam(&mut stack, cell).as_direct().unwrap().data();
assert_eq!(res, 201); assert_eq!(res, 201);
} }
} }

View File

@ -6,6 +6,7 @@ use either::Either::{self, Left, Right};
use ibig::Stack; use ibig::Stack;
use memmap::MmapMut; use memmap::MmapMut;
use std::alloc::Layout; use std::alloc::Layout;
use std::panic::panic_any;
use std::ptr::copy_nonoverlapping; use std::ptr::copy_nonoverlapping;
use std::{mem, ptr}; use std::{mem, ptr};
use thiserror::Error; use thiserror::Error;
@ -65,8 +66,6 @@ impl From<AllocationError> for std::io::Error {
} }
} }
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum NewStackError { pub enum NewStackError {
#[error("stack too small")] #[error("stack too small")]
@ -185,9 +184,11 @@ impl NockStack {
* top_slots is how many slots to allocate to the top stack frame. * top_slots is how many slots to allocate to the top stack frame.
*/ */
pub fn new(size: usize, top_slots: usize) -> NockStack { pub fn new(size: usize, top_slots: usize) -> NockStack {
Self::new_(size, top_slots) let result = Self::new_(size, top_slots);
.expect("Error making new NockStack") match result {
.0 Ok((stack, _)) => stack,
Err(e) => std::panic::panic_any(e),
}
} }
pub fn new_(size: usize, top_slots: usize) -> Result<(NockStack, usize), NewStackError> { pub fn new_(size: usize, top_slots: usize) -> Result<(NockStack, usize), NewStackError> {
@ -294,10 +295,10 @@ impl NockStack {
// Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false) // Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false)
// Types of size: word (words: usize) // Types of size: word (words: usize)
/// Check if an allocation or pointer retrieval indicates an invalid request or an invalid state /// Check if an allocation or pointer retrieval indicates an invalid request or an invalid state
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> AllocResult<()> { pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) {
let _memory_state = self.memory_state(Some(words)); let _memory_state = self.memory_state(Some(words));
if self.pc && !alloc.alloc_type.allowed_when_pc() { if self.pc && !alloc.alloc_type.allowed_when_pc() {
return Err(self.cannot_alloc_in_pc(Some(words))); panic_any(self.cannot_alloc_in_pc(Some(words)));
} }
// When self.pc is true // When self.pc is true
// west: // west:
@ -409,30 +410,24 @@ impl NockStack {
}; };
match direction { match direction {
Direction::Increasing => { Direction::Increasing => {
if target_point <= limit_point { if !(target_point <= limit_point) {
Ok(()) panic_any(self.out_of_memory(alloc, Some(words)))
} else {
Err(self.out_of_memory(alloc, Some(words)))
} }
} }
Direction::Decreasing => { Direction::Decreasing => {
if target_point >= limit_point { if !(target_point >= limit_point) {
Ok(()) panic_any(self.out_of_memory(alloc, Some(words)))
} else {
Err(self.out_of_memory(alloc, Some(words)))
} }
} }
// TODO this check is imprecise and should take into account the size of the pointer! // TODO this check is imprecise and should take into account the size of the pointer!
Direction::IncreasingDeref => { Direction::IncreasingDeref => {
if target_point < limit_point { if !(target_point < limit_point) {
Ok(()) panic_any(self.out_of_memory(alloc, Some(words)))
} else {
Err(self.out_of_memory(alloc, Some(words)))
} }
} }
} }
} }
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) -> AllocResult<()> { pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) {
let alloc = self.get_alloc_config(alloc_type); let alloc = self.get_alloc_config(alloc_type);
self.alloc_would_oom_(alloc, words) self.alloc_would_oom_(alloc, words)
} }
@ -443,7 +438,7 @@ impl NockStack {
* "popping" the top frame. * "popping" the top frame.
*/ */
// Pop analogue, doesn't need OOM check. // Pop analogue, doesn't need OOM check.
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) -> AllocResult<()> { pub unsafe fn flip_top_frame(&mut self, top_slots: usize) {
// Assert that we are at the top // Assert that we are at the top
assert!((*self.prev_frame_pointer_pointer()).is_null()); assert!((*self.prev_frame_pointer_pointer()).is_null());
assert!((*self.prev_stack_pointer_pointer()).is_null()); assert!((*self.prev_stack_pointer_pointer()).is_null());
@ -459,7 +454,7 @@ impl NockStack {
pc: self.pc, pc: self.pc,
}, },
byte_size, byte_size,
)?; );
// new top frame will be east // new top frame will be east
let new_frame_pointer = self.start.add(self.size).sub(size) as *mut u64; let new_frame_pointer = self.start.add(self.size).sub(size) as *mut u64;
*new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64; *new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64;
@ -481,7 +476,7 @@ impl NockStack {
pc: self.pc, pc: self.pc,
}, },
byte_size, byte_size,
)?; );
let new_frame_pointer = self.start.add(size) as *mut u64; let new_frame_pointer = self.start.add(size) as *mut u64;
*new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64; *new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64;
*new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64; *new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64;
@ -492,7 +487,6 @@ impl NockStack {
self.pc = false; self.pc = false;
assert!(self.is_west()); assert!(self.is_west());
}; };
Ok(())
} }
/// Resets the NockStack. The top frame is west as in the initial creation of the NockStack. /// Resets the NockStack. The top frame is west as in the initial creation of the NockStack.
@ -615,32 +609,32 @@ impl NockStack {
/** Mutable pointer to a slot in a stack frame: east stack */ /** Mutable pointer to a slot in a stack frame: east stack */
// TODO: slot_pointer_east_: Needs a simple bounds check // TODO: slot_pointer_east_: Needs a simple bounds check
#[cfg(test)] #[cfg(test)]
unsafe fn slot_pointer_east_(&self, slot: usize) -> AllocResult<*mut u64> { unsafe fn slot_pointer_east_(&self, slot: usize) -> *mut u64 {
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::East, orientation: ArenaOrientation::East,
alloc_type: AllocationType::SlotPointer, alloc_type: AllocationType::SlotPointer,
pc: self.pc, pc: self.pc,
}, },
slot, slot,
)?; );
Ok(self.frame_pointer.add(slot)) self.frame_pointer.add(slot)
} }
/** Mutable pointer to a slot in a stack frame: west stack */ /** Mutable pointer to a slot in a stack frame: west stack */
// TODO: slot_pointer_west_: Needs a simple bounds check // TODO: slot_pointer_west_: Needs a simple bounds check
#[cfg(test)] #[cfg(test)]
unsafe fn slot_pointer_west_(&self, slot: usize) -> AllocResult<*mut u64> { unsafe fn slot_pointer_west_(&self, slot: usize) -> *mut u64 {
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::West, orientation: ArenaOrientation::West,
alloc_type: AllocationType::SlotPointer, alloc_type: AllocationType::SlotPointer,
pc: self.pc, pc: self.pc,
}, },
slot, slot,
)?; );
Ok(self.frame_pointer.sub(slot + 1)) self.frame_pointer.sub(slot + 1)
} }
/** Mutable pointer to a slot in a stack frame: east stack */ /** Mutable pointer to a slot in a stack frame: east stack */
@ -659,7 +653,7 @@ impl NockStack {
/// Mutable pointer to a slot in a stack frame /// Mutable pointer to a slot in a stack frame
/// Panics on out-of-bounds conditions /// Panics on out-of-bounds conditions
#[cfg(test)] #[cfg(test)]
unsafe fn slot_pointer_(&self, slot: usize) -> AllocResult<*mut u64> { unsafe fn slot_pointer_(&self, slot: usize) -> *mut u64 {
if self.is_west() { if self.is_west() {
self.slot_pointer_west_(slot) self.slot_pointer_west_(slot)
} else { } else {
@ -742,38 +736,38 @@ impl NockStack {
* allocation pointer is returned as the pointer to the newly allocated memory. */ * allocation pointer is returned as the pointer to the newly allocated memory. */
/** Bump the alloc pointer for a west frame to make space for an allocation */ /** Bump the alloc pointer for a west frame to make space for an allocation */
unsafe fn raw_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn raw_alloc_west(&mut self, words: usize) -> *mut u64 {
let () = self.alloc_would_oom(AllocationType::Alloc, words)?; self.alloc_would_oom(AllocationType::Alloc, words);
if self.pc { if self.pc {
panic!("Allocation during cleanup phase is prohibited."); panic!("Allocation during cleanup phase is prohibited.");
} }
self.alloc_pointer = self.alloc_pointer.sub(words); self.alloc_pointer = self.alloc_pointer.sub(words);
Ok(self.alloc_pointer) self.alloc_pointer
} }
/** Bump the alloc pointer for an east frame to make space for an allocation */ /** Bump the alloc pointer for an east frame to make space for an allocation */
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn raw_alloc_east(&mut self, words: usize) -> *mut u64 {
let () = self.alloc_would_oom(AllocationType::Alloc, words)?; self.alloc_would_oom(AllocationType::Alloc, words);
if self.pc { if self.pc {
panic!("Allocation during cleanup phase is prohibited."); panic!("Allocation during cleanup phase is prohibited.");
} }
let alloc = self.alloc_pointer; let alloc = self.alloc_pointer;
self.alloc_pointer = self.alloc_pointer.add(words); self.alloc_pointer = self.alloc_pointer.add(words);
Ok(alloc) alloc
} }
/** Allocate space for an indirect pointer in a west frame */ /** Allocate space for an indirect pointer in a west frame */
unsafe fn indirect_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn indirect_alloc_west(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_west(words + 2) self.raw_alloc_west(words + 2)
} }
/** Allocate space for an indirect pointer in an east frame */ /** Allocate space for an indirect pointer in an east frame */
unsafe fn indirect_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn indirect_alloc_east(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_east(words + 2) self.raw_alloc_east(words + 2)
} }
/** Allocate space for an indirect pointer in a stack frame */ /** Allocate space for an indirect pointer in a stack frame */
unsafe fn indirect_alloc(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn indirect_alloc(&mut self, words: usize) -> *mut u64 {
if self.is_west() { if self.is_west() {
self.indirect_alloc_west(words) self.indirect_alloc_west(words)
} else { } else {
@ -782,19 +776,19 @@ impl NockStack {
} }
/** Allocate space for a struct in a west frame */ /** Allocate space for a struct in a west frame */
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> AllocResult<*mut T> { unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> *mut T {
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count)?; let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count);
Ok(eigen_pointer as *mut T) eigen_pointer as *mut T
} }
/** Allocate space for a struct in an east frame */ /** Allocate space for a struct in an east frame */
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> AllocResult<*mut T> { unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> *mut T {
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count)?; let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count);
Ok(eigen_pointer as *mut T) eigen_pointer as *mut T
} }
/** Allocate space for a struct in a stack frame */ /** Allocate space for a struct in a stack frame */
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> AllocResult<*mut T> { pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> *mut T {
if self.is_west() { if self.is_west() {
self.struct_alloc_west::<T>(count) self.struct_alloc_west::<T>(count)
} else { } else {
@ -802,40 +796,40 @@ impl NockStack {
} }
} }
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> *mut u64 {
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::West, orientation: ArenaOrientation::West,
alloc_type: AllocationType::AllocPreviousFrame, alloc_type: AllocationType::AllocPreviousFrame,
pc: self.pc, pc: self.pc,
}, },
words, words,
)?; );
// note that the allocation is on the east frame, and thus resembles raw_alloc_east // note that the allocation is on the east frame, and thus resembles raw_alloc_east
let alloc = *self.prev_alloc_pointer_pointer(); let alloc = *self.prev_alloc_pointer_pointer();
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words); *(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words);
Ok(alloc) alloc
} }
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> *mut u64 {
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::East, orientation: ArenaOrientation::East,
alloc_type: AllocationType::AllocPreviousFrame, alloc_type: AllocationType::AllocPreviousFrame,
pc: self.pc, pc: self.pc,
}, },
words, words,
)?; );
// note that the allocation is on the west frame, and thus resembles raw_alloc_west // note that the allocation is on the west frame, and thus resembles raw_alloc_west
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words); *(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words);
Ok(*(self.prev_alloc_pointer_pointer())) *(self.prev_alloc_pointer_pointer())
} }
/** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the /** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the
* stack frame is in cleanup phase, which is the only time we should be allocating in a previous * stack frame is in cleanup phase, which is the only time we should be allocating in a previous
* frame. */ * frame. */
unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
self.pre_copy()?; self.pre_copy();
if self.is_west() { if self.is_west() {
self.raw_alloc_in_previous_frame_west(words) self.raw_alloc_in_previous_frame_west(words)
} else { } else {
@ -844,21 +838,18 @@ impl NockStack {
} }
/** Allocates space in the previous frame for some number of T's. */ /** Allocates space in the previous frame for some number of T's. */
pub unsafe fn struct_alloc_in_previous_frame<T>( pub unsafe fn struct_alloc_in_previous_frame<T>(&mut self, count: usize) -> *mut T {
&mut self, let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count);
count: usize, res as *mut T
) -> AllocResult<*mut T> {
let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count)?;
Ok(res as *mut T)
} }
/** Allocate space for an indirect atom in the previous stack frame. */ /** Allocate space for an indirect atom in the previous stack frame. */
unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_in_previous_frame(words + 2) self.raw_alloc_in_previous_frame(words + 2)
} }
/** Allocate space for an alloc::Layout in a stack frame */ /** Allocate space for an alloc::Layout in a stack frame */
unsafe fn layout_alloc(&mut self, layout: Layout) -> AllocResult<*mut u64> { unsafe fn layout_alloc(&mut self, layout: Layout) -> *mut u64 {
assert!(layout.align() <= 64, "layout alignment must be <= 64"); assert!(layout.align() <= 64, "layout alignment must be <= 64");
if self.is_west() { if self.is_west() {
self.raw_alloc_west((layout.size() + 7) >> 3) self.raw_alloc_west((layout.size() + 7) >> 3)
@ -896,15 +887,14 @@ impl NockStack {
* lightweight stack (push(), pop(), top()) are the same regardless of whether * lightweight stack (push(), pop(), top()) are the same regardless of whether
* or not pre_copy() has been called. * or not pre_copy() has been called.
* */ * */
unsafe fn pre_copy(&mut self) -> AllocResult<()> { unsafe fn pre_copy(&mut self) {
// pre_copy is intended to be idempotent, so we don't need to do anything if it's already been called // pre_copy is intended to be idempotent, so we don't need to do anything if it's already been called
if !self.pc { if !self.pc {
let is_west = self.is_west(); let is_west = self.is_west();
let words = if is_west { RESERVED + 1 } else { RESERVED }; let words = if is_west { RESERVED + 1 } else { RESERVED };
// TODO: pre_copy: Treating pre_copy like a FramePush for OOM checking purposes // TODO: pre_copy: Treating pre_copy like a FramePush for OOM checking purposes
// Is this correct? // Is this correct?
let () = let () = self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words);
self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words)?;
*(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME)); *(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME));
*(self.free_slot(STACK)) = *(self.slot_pointer(STACK)); *(self.free_slot(STACK)) = *(self.slot_pointer(STACK));
*(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC)); *(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC));
@ -916,22 +906,21 @@ impl NockStack {
self.stack_pointer = self.alloc_pointer.add(words); self.stack_pointer = self.alloc_pointer.add(words);
} }
} }
Ok(())
} }
unsafe fn copy(&mut self, noun: &mut Noun) -> AllocResult<()> { unsafe fn copy(&mut self, noun: &mut Noun) {
assert_acyclic!(*noun); assert_acyclic!(*noun);
assert_no_forwarding_pointers!(*noun); assert_no_forwarding_pointers!(*noun);
assert_no_junior_pointers!(self, *noun); assert_no_junior_pointers!(self, *noun);
self.pre_copy()?; self.pre_copy();
assert!(self.stack_is_empty()); assert!(self.stack_is_empty());
let noun_ptr = noun as *mut Noun; let noun_ptr = noun as *mut Noun;
// Add two slots to the lightweight stack // Add two slots to the lightweight stack
// Set the first new slot to the noun to be copied // Set the first new slot to the noun to be copied
*(self.push::<Noun>()?) = *noun; *(self.push::<Noun>()) = *noun;
// Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change // Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change
*(self.push::<*mut Noun>()?) = noun_ptr; *(self.push::<*mut Noun>()) = noun_ptr;
loop { loop {
if self.stack_is_empty() { if self.stack_is_empty() {
break; break;
@ -965,7 +954,7 @@ impl NockStack {
Either::Left(mut indirect) => { Either::Left(mut indirect) => {
// Make space for the atom // Make space for the atom
let alloc = let alloc =
self.indirect_alloc_in_previous_frame(indirect.size())?; self.indirect_alloc_in_previous_frame(indirect.size());
// Indirect atoms can be copied directly // Indirect atoms can be copied directly
copy_nonoverlapping( copy_nonoverlapping(
@ -984,16 +973,16 @@ impl NockStack {
Either::Right(mut cell) => { Either::Right(mut cell) => {
// Make space for the cell // Make space for the cell
let alloc = let alloc =
self.struct_alloc_in_previous_frame::<CellMemory>(1)?; self.struct_alloc_in_previous_frame::<CellMemory>(1);
// Copy the cell metadata // Copy the cell metadata
(*alloc).metadata = (*cell.to_raw_pointer()).metadata; (*alloc).metadata = (*cell.to_raw_pointer()).metadata;
// Push the tail and the head to the work stack // Push the tail and the head to the work stack
*(self.push::<Noun>()?) = cell.tail(); *(self.push::<Noun>()) = cell.tail();
*(self.push::<*mut Noun>()?) = &mut (*alloc).tail; *(self.push::<*mut Noun>()) = &mut (*alloc).tail;
*(self.push::<Noun>()?) = cell.head(); *(self.push::<Noun>()) = cell.head();
*(self.push::<*mut Noun>()?) = &mut (*alloc).head; *(self.push::<*mut Noun>()) = &mut (*alloc).head;
// Set the forwarding pointer // Set the forwarding pointer
cell.set_forwarding_pointer(alloc); cell.set_forwarding_pointer(alloc);
@ -1015,7 +1004,6 @@ impl NockStack {
assert_acyclic!(*noun); assert_acyclic!(*noun);
assert_no_forwarding_pointers!(*noun); assert_no_forwarding_pointers!(*noun);
assert_no_junior_pointers!(self, *noun); assert_no_junior_pointers!(self, *noun);
Ok(())
} }
// Doesn't need an OOM check, just an assertion. We expect it to panic. // Doesn't need an OOM check, just an assertion. We expect it to panic.
@ -1103,7 +1091,7 @@ impl NockStack {
self.pc = false; self.pc = false;
} }
pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) -> AllocResult<()> { pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) {
x.preserve(self) x.preserve(self)
} }
@ -1116,12 +1104,12 @@ impl NockStack {
/** Push a frame onto the stack with 0 or more local variable slots. */ /** Push a frame onto the stack with 0 or more local variable slots. */
/// This computation for num_locals is done in the east/west variants, but roughly speaking it's the input n words + 3 for prev frame alloc/stack/frame pointers /// This computation for num_locals is done in the east/west variants, but roughly speaking it's the input n words + 3 for prev frame alloc/stack/frame pointers
pub fn frame_push(&mut self, num_locals: usize) -> AllocResult<()> { pub fn frame_push(&mut self, num_locals: usize) {
if self.pc { if self.pc {
panic!("frame_push during cleanup phase is prohibited."); panic!("frame_push during cleanup phase is prohibited.");
} }
let words = num_locals + RESERVED; let words = num_locals + RESERVED;
let () = self.alloc_would_oom(AllocationType::FramePush, words)?; self.alloc_would_oom(AllocationType::FramePush, words);
let current_frame_pointer = self.frame_pointer; let current_frame_pointer = self.frame_pointer;
let current_stack_pointer = self.stack_pointer; let current_stack_pointer = self.stack_pointer;
@ -1138,7 +1126,6 @@ impl NockStack {
*(self.slot_pointer(STACK)) = current_stack_pointer as u64; *(self.slot_pointer(STACK)) = current_stack_pointer as u64;
*(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64; *(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64;
} }
Ok(())
} }
/** Run a closure inside a frame, popping regardless of the value returned by the closure. /** Run a closure inside a frame, popping regardless of the value returned by the closure.
@ -1146,16 +1133,16 @@ impl NockStack {
* *
* Note that results allocated on the stack *must* be `preserve()`d by the closure. * Note that results allocated on the stack *must* be `preserve()`d by the closure.
*/ */
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> AllocResult<O> pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> O
where where
F: FnOnce(&mut NockStack) -> O, F: FnOnce(&mut NockStack) -> O,
O: Preserve, O: Preserve,
{ {
self.frame_push(num_locals)?; self.frame_push(num_locals);
let mut ret = f(self); let mut ret = f(self);
ret.preserve(self)?; ret.preserve(self);
self.frame_pop(); self.frame_pop();
Ok(ret) ret
} }
/** Lightweight stack. /** Lightweight stack.
@ -1182,7 +1169,7 @@ impl NockStack {
* this violates the _east/_west naming convention somewhat, since e.g. * this violates the _east/_west naming convention somewhat, since e.g.
* a west frame when pc == false has a west-oriented lightweight stack, * a west frame when pc == false has a west-oriented lightweight stack,
* but when pc == true it becomes east-oriented.*/ * but when pc == true it becomes east-oriented.*/
pub unsafe fn push<T>(&mut self) -> AllocResult<*mut T> { pub unsafe fn push<T>(&mut self) -> *mut T {
if self.is_west() && !self.pc || !self.is_west() && self.pc { if self.is_west() && !self.pc || !self.is_west() && self.pc {
self.push_west::<T>() self.push_west::<T>()
} else { } else {
@ -1191,16 +1178,16 @@ impl NockStack {
} }
/// Push onto a west-oriented lightweight stack, moving the stack_pointer. /// Push onto a west-oriented lightweight stack, moving the stack_pointer.
unsafe fn push_west<T>(&mut self) -> AllocResult<*mut T> { unsafe fn push_west<T>(&mut self) -> *mut T {
let words = word_size_of::<T>(); let words = word_size_of::<T>();
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::West, orientation: ArenaOrientation::West,
alloc_type: AllocationType::Push, alloc_type: AllocationType::Push,
pc: self.pc, pc: self.pc,
}, },
words, words,
)?; );
let ap = if self.pc { let ap = if self.pc {
*(self.prev_alloc_pointer_pointer()) *(self.prev_alloc_pointer_pointer())
} else { } else {
@ -1219,21 +1206,21 @@ impl NockStack {
); );
} else { } else {
self.stack_pointer = new_sp; self.stack_pointer = new_sp;
Ok(alloc as *mut T) alloc as *mut T
} }
} }
/// Push onto an east-oriented ligthweight stack, moving the stack_pointer /// Push onto an east-oriented ligthweight stack, moving the stack_pointer
unsafe fn push_east<T>(&mut self) -> AllocResult<*mut T> { unsafe fn push_east<T>(&mut self) -> *mut T {
let words = word_size_of::<T>(); let words = word_size_of::<T>();
let () = self.alloc_would_oom_( self.alloc_would_oom_(
Allocation { Allocation {
orientation: ArenaOrientation::East, orientation: ArenaOrientation::East,
alloc_type: AllocationType::Push, alloc_type: AllocationType::Push,
pc: self.pc, pc: self.pc,
}, },
words, words,
)?; );
let ap = if self.pc { let ap = if self.pc {
*(self.prev_alloc_pointer_pointer()) *(self.prev_alloc_pointer_pointer())
} else { } else {
@ -1251,7 +1238,7 @@ impl NockStack {
); );
} else { } else {
self.stack_pointer = alloc; self.stack_pointer = alloc;
Ok(alloc as *mut T) alloc as *mut T
} }
} }
@ -1485,15 +1472,15 @@ impl NockStack {
} }
impl NounAllocator for NockStack { impl NounAllocator for NockStack {
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64> { unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
self.indirect_alloc(words) self.indirect_alloc(words)
} }
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory> { unsafe fn alloc_cell(&mut self) -> *mut CellMemory {
self.struct_alloc::<CellMemory>(1) self.struct_alloc::<CellMemory>(1)
} }
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T> { unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T {
self.struct_alloc::<T>(count) self.struct_alloc::<T>(count)
} }
} }
@ -1501,17 +1488,16 @@ impl NounAllocator for NockStack {
/// Immutable, acyclic objects which may be copied up the stack /// Immutable, acyclic objects which may be copied up the stack
pub trait Preserve { pub trait Preserve {
/// Ensure an object will not be invalidated by popping the NockStack /// Ensure an object will not be invalidated by popping the NockStack
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()>; unsafe fn preserve(&mut self, stack: &mut NockStack);
unsafe fn assert_in_stack(&self, stack: &NockStack); unsafe fn assert_in_stack(&self, stack: &NockStack);
} }
impl Preserve for IndirectAtom { impl Preserve for IndirectAtom {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
let size = indirect_raw_size(*self); let size = indirect_raw_size(*self);
let buf = stack.struct_alloc_in_previous_frame::<u64>(size)?; let buf = stack.struct_alloc_in_previous_frame::<u64>(size);
copy_nonoverlapping(self.to_raw_pointer(), buf, size); copy_nonoverlapping(self.to_raw_pointer(), buf, size);
*self = IndirectAtom::from_raw_pointer(buf); *self = IndirectAtom::from_raw_pointer(buf);
Ok(())
} }
unsafe fn assert_in_stack(&self, stack: &NockStack) { unsafe fn assert_in_stack(&self, stack: &NockStack) {
stack.assert_noun_in(self.as_atom().as_noun()); stack.assert_noun_in(self.as_atom().as_noun());
@ -1519,15 +1505,14 @@ impl Preserve for IndirectAtom {
} }
impl Preserve for Atom { impl Preserve for Atom {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self.as_either() { match self.as_either() {
Left(_direct) => {} Left(_direct) => {}
Right(mut indirect) => { Right(mut indirect) => {
indirect.preserve(stack)?; indirect.preserve(stack);
*self = indirect.as_atom(); *self = indirect.as_atom();
} }
} }
Ok(())
} }
unsafe fn assert_in_stack(&self, stack: &NockStack) { unsafe fn assert_in_stack(&self, stack: &NockStack) {
stack.assert_noun_in(self.as_noun()); stack.assert_noun_in(self.as_noun());
@ -1535,7 +1520,7 @@ impl Preserve for Atom {
} }
impl Preserve for Noun { impl Preserve for Noun {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
stack.copy(self) stack.copy(self)
} }
unsafe fn assert_in_stack(&self, stack: &NockStack) { unsafe fn assert_in_stack(&self, stack: &NockStack) {
@ -1544,14 +1529,13 @@ impl Preserve for Noun {
} }
impl Stack for NockStack { impl Stack for NockStack {
type AllocError = AllocationError; unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64 {
unsafe fn alloc_layout(&mut self, layout: Layout) -> AllocResult<*mut u64> {
self.layout_alloc(layout) self.layout_alloc(layout)
} }
} }
impl<T: Preserve, E: Preserve> Preserve for Result<T, E> { impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self.as_mut() { match self.as_mut() {
Ok(t_ref) => t_ref.preserve(stack), Ok(t_ref) => t_ref.preserve(stack),
Err(e_ref) => e_ref.preserve(stack), Err(e_ref) => e_ref.preserve(stack),
@ -1567,25 +1551,25 @@ impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
} }
impl Preserve for bool { impl Preserve for bool {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, _: &mut NockStack) {}
Ok(())
}
unsafe fn assert_in_stack(&self, _: &NockStack) {} unsafe fn assert_in_stack(&self, _: &NockStack) {}
} }
impl Preserve for u32 { impl Preserve for u32 {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, _: &mut NockStack) {}
Ok(())
} unsafe fn assert_in_stack(&self, _: &NockStack) {}
}
impl Preserve for usize {
unsafe fn preserve(&mut self, _: &mut NockStack) {}
unsafe fn assert_in_stack(&self, _: &NockStack) {} unsafe fn assert_in_stack(&self, _: &NockStack) {}
} }
impl Preserve for AllocationError { impl Preserve for AllocationError {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> { unsafe fn preserve(&mut self, _: &mut NockStack) {}
Ok(())
}
unsafe fn assert_in_stack(&self, _: &NockStack) {} unsafe fn assert_in_stack(&self, _: &NockStack) {}
} }
@ -1593,6 +1577,7 @@ impl Preserve for AllocationError {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::iter::FromIterator; use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
use super::*; use super::*;
use crate::jets::cold::test::{make_noun_list, make_test_stack}; use crate::jets::cold::test::{make_noun_list, make_test_stack};
@ -1613,9 +1598,9 @@ mod test {
let vec = Vec::from_iter(0..item_count); let vec = Vec::from_iter(0..item_count);
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>(); let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
let slice = vec.as_slice(); let slice = vec.as_slice();
let noun_list = make_noun_list(&mut stack, slice)?; let noun_list = make_noun_list(&mut stack, slice);
assert!(!noun_list.0.is_null()); assert!(!noun_list.0.is_null());
let noun = noun_list.into_noun(&mut stack)?; let noun = noun_list.into_noun(&mut stack);
let new_noun_list: NounList = let new_noun_list: NounList =
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?; <NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?;
let mut tracking_item_count = 0; let mut tracking_item_count = 0;
@ -1642,9 +1627,9 @@ mod test {
const FAILS: u64 = 73; const FAILS: u64 = 73;
const STACK_SIZE: usize = 512; const STACK_SIZE: usize = 512;
let should_fail_to_alloc = test_noun_list_alloc_fn(STACK_SIZE, FAILS); let should_fail_to_alloc = catch_unwind(|| test_noun_list_alloc_fn(STACK_SIZE, FAILS));
assert!(should_fail_to_alloc assert!(should_fail_to_alloc
.map_err(|err| err.is_alloc_error()) .map_err(|err| err.is::<AllocationError>())
.unwrap_err()); .unwrap_err());
let should_succeed = test_noun_list_alloc_fn(STACK_SIZE, PASSES); let should_succeed = test_noun_list_alloc_fn(STACK_SIZE, PASSES);
assert!(should_succeed.is_ok()); assert!(should_succeed.is_ok());
@ -1654,32 +1639,36 @@ mod test {
#[test] #[test]
fn test_frame_push() { fn test_frame_push() {
// fails at 100, passes at 99, top_slots default to 100? // fails at 100, passes at 99, top_slots default to 100?
const PASSES: usize = 502; const PASSES: usize = 503;
const FAILS: usize = 503; const FAILS: usize = 504;
const STACK_SIZE: usize = 512; const STACK_SIZE: usize = 512;
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
let frame_push_res = stack.frame_push(FAILS); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(FAILS)));
assert!(frame_push_res.is_err()); assert!(frame_push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
let frame_push_res = stack.frame_push(PASSES); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(PASSES)));
assert!(frame_push_res.is_ok()); assert!(frame_push_res.is_ok());
} }
// cargo test -p sword test_stack_push -- --nocapture // cargo test -p sword test_stack_push -- --nocapture
#[test] #[test]
fn test_stack_push() { fn test_stack_push() {
const PASSES: usize = 505; const PASSES: usize = 506;
const STACK_SIZE: usize = 512; const STACK_SIZE: usize = 512;
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
let mut counter = 0; let mut counter = 0;
// Fails at 102, probably because top_slots is 100? // Fails at 102, probably because top_slots is 100?
while counter < PASSES { while counter < PASSES {
let push_res = unsafe { stack.push::<u64>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter); assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
counter += 1; counter += 1;
} }
let push_res = unsafe { stack.push::<u64>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_err()); assert!(push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
} }
// cargo test -p sword test_frame_and_stack_push -- --nocapture // cargo test -p sword test_frame_and_stack_push -- --nocapture
@ -1690,27 +1679,31 @@ mod test {
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
let mut counter = 0; let mut counter = 0;
while counter < SUCCESS_PUSHES { while counter < SUCCESS_PUSHES {
let frame_push_res = stack.frame_push(1); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
assert!( assert!(
frame_push_res.is_ok(), frame_push_res.is_ok(),
"Failed to frame_push, counter: {}", "Failed to frame_push, counter: {}",
counter counter
); );
let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter); assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
counter += 1; counter += 1;
} }
let frame_push_res = stack.frame_push(1); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
assert!(frame_push_res.is_err()); assert!(frame_push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
// a single stack u64 push won't cause an error but a frame push will // a single stack u64 push won't cause an error but a frame push will
let push_res = unsafe { stack.push::<u64>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok()); assert!(push_res.is_ok());
// pushing an array of 1 u64 will NOT cause an error // pushing an array of 1 u64 will NOT cause an error
let push_res = unsafe { stack.push::<[u64; 1]>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 1]>() }));
assert!(push_res.is_ok()); assert!(push_res.is_ok());
// pushing an array of 2 u64s WILL cause an error // pushing an array of 2 u64s WILL cause an error
let push_res = unsafe { stack.push::<[u64; 2]>() }; let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 2]>() }));
assert!(push_res.is_err()); assert!(push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
} }
// cargo test -p sword test_slot_pointer -- --nocapture // cargo test -p sword test_slot_pointer -- --nocapture
@ -1721,12 +1714,13 @@ mod test {
const SLOT_POINTERS: usize = 32; const SLOT_POINTERS: usize = 32;
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
// let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() }; // let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
let frame_push_res = stack.frame_push(SLOT_POINTERS); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(SLOT_POINTERS)));
assert!(frame_push_res.is_ok()); assert!(frame_push_res.is_ok());
let mut counter = 0; let mut counter = 0;
while counter < SLOT_POINTERS + RESERVED { while counter < SLOT_POINTERS + RESERVED {
println!("counter: {counter}"); println!("counter: {counter}");
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) }; let slot_pointer_res =
catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
assert!( assert!(
slot_pointer_res.is_ok(), slot_pointer_res.is_ok(),
"Failed to slot_pointer, counter: {}", "Failed to slot_pointer, counter: {}",
@ -1734,8 +1728,11 @@ mod test {
); );
counter += 1; counter += 1;
} }
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) }; let slot_pointer_res =
assert!(slot_pointer_res.is_err()) catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
assert!(slot_pointer_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err())
} }
// cargo test -p sword test_prev_alloc -- --nocapture // cargo test -p sword test_prev_alloc -- --nocapture
@ -1743,18 +1740,20 @@ mod test {
#[test] #[test]
fn test_prev_alloc() { fn test_prev_alloc() {
const STACK_SIZE: usize = 512; const STACK_SIZE: usize = 512;
const SUCCESS_ALLOCS: usize = 502; const SUCCESS_ALLOCS: usize = 503;
let mut stack = make_test_stack(STACK_SIZE); let mut stack = make_test_stack(STACK_SIZE);
println!("\n############## frame push \n"); println!("\n############## frame push \n");
let frame_push_res = stack.frame_push(0); let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(0)));
assert!(frame_push_res.is_ok()); assert!(frame_push_res.is_ok());
let pre_copy_res = unsafe { stack.pre_copy() }; let pre_copy_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.pre_copy() }));
assert!(pre_copy_res.is_ok()); assert!(pre_copy_res.is_ok());
let mut counter = 0; let mut counter = 0;
while counter < SUCCESS_ALLOCS { while counter < SUCCESS_ALLOCS {
println!("counter: {counter}"); println!("counter: {counter}");
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) }; let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
stack.raw_alloc_in_previous_frame(1)
}));
assert!( assert!(
prev_alloc_res.is_ok(), prev_alloc_res.is_ok(),
"Failed to prev_alloc, counter: {}", "Failed to prev_alloc, counter: {}",
@ -1763,11 +1762,14 @@ mod test {
counter += 1; counter += 1;
} }
println!("### This next raw_alloc_in_previous_frame should fail ###\n"); println!("### This next raw_alloc_in_previous_frame should fail ###\n");
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) }; let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
stack.raw_alloc_in_previous_frame(1)
}));
assert!( assert!(
prev_alloc_res.is_err(),
"Didn't get expected alloc error, res: {:#?}",
prev_alloc_res prev_alloc_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err(),
"Didn't get expected alloc error",
); );
} }
} }

View File

@ -1,6 +1,8 @@
use crate::assert_acyclic;
use crate::assert_no_forwarding_pointers;
use crate::assert_no_junior_pointers;
use crate::mem::*; use crate::mem::*;
use crate::noun::{Allocated, Atom, DirectAtom, Noun}; use crate::noun::{Allocated, Atom, DirectAtom, Noun};
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
use either::Either::*; use either::Either::*;
use murmur3::murmur3_32_of_slice; use murmur3::murmur3_32_of_slice;
@ -126,67 +128,74 @@ pub fn mug_u32_one(noun: Noun) -> Option<u32> {
} }
} }
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> AllocResult<u32> { pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
if let Some(mug) = get_mug(noun) { if let Some(mug) = get_mug(noun) {
return Ok(mug); return mug;
} }
assert_acyclic!(noun); assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun); assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun); assert_no_junior_pointers!(stack, noun);
stack.frame_push(0);
unsafe { unsafe {
stack.with_frame(0, |stack| { *(stack.push()) = noun;
*(stack.push()?) = noun; }
loop { loop {
if stack.stack_is_empty() { if stack.stack_is_empty() {
break; break;
} else { } else {
let noun: Noun = *(stack.top()); let noun: Noun = unsafe { *(stack.top()) };
match noun.as_either_direct_allocated() { match noun.as_either_direct_allocated() {
Left(_direct) => { Left(_direct) => {
unsafe {
stack.pop::<Noun>();
}
continue;
} // no point in calculating a direct mug here as we wont cache it
Right(allocated) => match allocated.get_cached_mug() {
Some(_mug) => {
unsafe {
stack.pop::<Noun>();
}
continue;
}
None => match allocated.as_either() {
Left(indirect) => unsafe {
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
stack.pop::<Noun>(); stack.pop::<Noun>();
continue; continue;
} // no point in calculating a direct mug here as we wont cache it },
Right(allocated) => match allocated.get_cached_mug() { Right(cell) => unsafe {
Some(_mug) => { match (get_mug(cell.head()), get_mug(cell.tail())) {
stack.pop::<Noun>(); (Some(head_mug), Some(tail_mug)) => {
continue; set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug));
}
None => match allocated.as_either() {
Left(indirect) => {
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
stack.pop::<Noun>(); stack.pop::<Noun>();
continue; continue;
} }
Right(cell) => match (get_mug(cell.head()), get_mug(cell.tail())) { _ => {
(Some(head_mug), Some(tail_mug)) => { *(stack.push()) = cell.tail();
set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug)); *(stack.push()) = cell.head();
stack.pop::<Noun>(); continue;
continue; }
} }
_ => {
*(stack.push()?) = cell.tail();
*(stack.push()?) = cell.head();
continue;
}
},
},
}, },
} },
} },
} }
}
assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun);
// TODO: Purge this expect.
Ok(get_mug(noun).expect("Noun should have a mug once it is mugged."))
})?
} }
unsafe {
stack.frame_pop();
}
assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun);
get_mug(noun).expect("Noun should have a mug once it is mugged.")
} }
pub fn mug(stack: &mut NockStack, noun: Noun) -> AllocResult<DirectAtom> { pub fn mug(stack: &mut NockStack, noun: Noun) -> DirectAtom {
Ok(unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun)? as u64) }) unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun) as u64) }
} }

View File

@ -1,307 +0,0 @@
use crate::interpreter::Slogger;
/** Newt: IPC to the king
*
* This manages an IPC connection to the king over stdin and stdout. The protocol is jammed nouns,
* with the following schema:
*
* |%
* :: +writ: from king to serf
* ::
* +$ writ
* $% $: %live
* $% [%cram eve=@]
* [%exit cod=@]
* [%save eve=@]
* [%meld ~]
* [%pack ~]
* == ==
* [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [%beam @tas beam]))
* [%play eve=@ lit=(list ?((pair @da ovum) *))]
* [%work mil=@ job=(pair @da ovum)]
* ==
* :: +plea: from serf to king
* ::
* +$ plea
* $% [%live ~]
* [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@]
* [%slog pri=@ tank]
* [%flog cord]
* $: %peek
* $% [%done dat=(unit (cask))]
* [%bail dud=goof]
* == ==
* $: %play
* $% [%done mug=@]
* [%bail eve=@ mug=@ dud=goof]
* == ==
* $: %work
* $% [%done eve=@ mug=@ fec=(list ovum)]
* [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)]
* [%bail lud=(list goof)]
* == ==
* ==
* --
*
* NB: stdin and stdout are generally buffered, and there's no officially supported way to work
* around that: https://github.com/rust-lang/rust/issues/58326.
*
* We use stdin and stdout with File::from_raw_fd(0) and File::from_raw_fd(1), which seems to get
* around this. We tested that using io::Stdout requires flushing while this doesn't, but we
* haven't tested the same for stdin.
*
* It's important to not use io::Stdin and io::Stdout directly. All printfs should use stderr.
*/
use crate::mem::{AllocResult, NockStack};
use crate::noun::{IndirectAtom, Noun, D, T};
use crate::serialization::{cue, jam};
use either::Either;
use std::io::{Read, Write};
use std::os::unix::prelude::FromRawFd;
use std::pin::Pin;
use std::ptr::copy_nonoverlapping;
use std::slice::from_raw_parts_mut;
use sword_macros::tas;
crate::gdb!();
pub struct Newt {
input: std::fs::File,
output: std::fs::File,
}
impl Newt {
pub fn new_from_files(input: std::fs::File, output: std::fs::File) -> Newt {
Newt { input, output }
}
pub fn new() -> Newt {
Newt {
input: unsafe { std::fs::File::from_raw_fd(0) },
output: unsafe { std::fs::File::from_raw_fd(1) },
}
}
pub fn new_mock() -> Newt {
Newt {
input: std::fs::File::open("/dev/null").expect("newt: could not open /dev/null"),
output: std::fs::File::options()
.read(true)
.write(true)
.open("/dev/null")
.expect("newt: could not open /dev/null"),
}
}
/** Write a noun to the newt.
*
* NB: we write 64-bit words, while vere writes bytes. The extra zero bytes shouldn't be a
* problem.
*/
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) -> AllocResult<()> {
let atom = jam(stack, noun)?;
let size = atom.size() << 3;
// XX: checked add?
let buf = unsafe { from_raw_parts_mut(stack.struct_alloc::<u8>(size + 5)?, size + 5) };
buf[0] = 0u8;
buf[1] = size as u8;
buf[2] = (size >> 8) as u8;
buf[3] = (size >> 16) as u8;
buf[4] = (size >> 24) as u8;
match atom.as_either() {
Either::Left(direct) => unsafe {
copy_nonoverlapping(
&direct.data() as *const u64 as *const u8,
buf.as_mut_ptr().add(5),
size,
);
},
Either::Right(indirect) => unsafe {
// REVIEW: is this safe/the right way to do this?
copy_nonoverlapping(
indirect.data_pointer() as *const u8,
buf.as_mut_ptr().add(5),
size,
);
},
};
self.output.write_all(buf).unwrap();
Ok(())
}
/** Send %ripe, the first event.
*
* eve = event number
* mug = mug of Arvo after above event
*/
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) -> AllocResult<()> {
let version = T(
stack,
&[
D(1), // newt protocol
D(139), // hoon kelvin
D(4), // nock kelvin
],
)?;
let ripe = T(stack, &[D(tas!(b"ripe")), version, D(eve), D(mug)])?;
self.write_noun(stack, ripe)?;
Ok(())
}
/** Send %live, acknowledging. */
pub fn live(&mut self, stack: &mut NockStack) -> AllocResult<()> {
let live = T(stack, &[D(tas!(b"live")), D(0)])?;
self.write_noun(stack, live)?;
Ok(())
}
/** Send %peek %done, successfully scried. */
pub fn peek_done(&mut self, stack: &mut NockStack, dat: Noun) -> AllocResult<()> {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"done")), dat])?;
self.write_noun(stack, peek)?;
Ok(())
}
/** Send %peek %bail, unsuccessfully scried.
*
* dud = goof
*/
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) -> AllocResult<()> {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud])?;
self.write_noun(stack, peek)?;
Ok(())
}
/** Send %play %done, successfully replayed events.
*
* mug = mug of Arvo after full replay
*/
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) -> AllocResult<()> {
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)])?;
self.write_noun(stack, play)?;
Ok(())
}
/** Send %play %bail, failed to replay events.
*
* eve = last good event number
* mug = mug of Arvo after above event
* dud = goof when trying next event
*/
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) -> AllocResult<()> {
let play = T(
stack,
&[D(tas!(b"play")), D(tas!(b"bail")), D(eve), D(mug), dud],
)?;
self.write_noun(stack, play)?;
Ok(())
}
/** Send %work %done, successfully ran event.
*
* eve = new event number
* mug = mug of Arvo after above event
* fec = list of effects
*/
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) -> AllocResult<()> {
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"done")), D(eve), D(mug), fec],
)?;
self.write_noun(stack, work)?;
Ok(())
}
/** Send %work %swap, successfully replaced failed event.
*
* eve = new event number
* mug = mug of Arvo after above event
* job = event performed instead of the one given to serf by king
* fec = list of effects
*/
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) -> AllocResult<()> {
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"swap")), D(eve), D(mug), job, fec],
)?;
self.write_noun(stack, work)?;
Ok(())
}
pub fn slogger(&self) -> Result<Pin<Box<dyn Slogger + Unpin>>, std::io::Error> {
let input = self.input.try_clone()?;
let output = self.output.try_clone()?;
Ok(std::boxed::Box::pin(NewtSlogger(Newt { input, output })))
}
/** Send %work %bail, failed to run event.
*
* lud = list of goof
*/
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) -> AllocResult<()> {
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud])?;
self.write_noun(stack, work)?;
Ok(())
}
/** Fetch next message. */
pub fn next(&mut self, stack: &mut NockStack) -> AllocResult<Option<Noun>> {
let mut header: Vec<u8> = vec![0; 5];
if let Err(err) = self.input.read_exact(&mut header) {
if err.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(None);
} else {
panic!("Newt::next: Error reading header: {}", err);
}
}
let byte_len = u32::from_le_bytes([header[1], header[2], header[3], header[4]]) as usize;
let atom = unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bytes(stack, byte_len)?;
if let Err(err) = self.input.read_exact(dest) {
if err.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(None);
} else {
panic!("Newt::next: Error reading body: {}", err);
}
}
atom.normalize_as_atom()
};
Ok(Some(cue(stack, atom).expect("Newt::next: bad jammed noun")))
}
}
impl Slogger for Newt {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank])?;
self.write_noun(stack, slog)?;
Ok(())
}
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
let flog = T(stack, &[D(tas!(b"flog")), cord])?;
self.write_noun(stack, flog)?;
Ok(())
}
}
impl Default for Newt {
fn default() -> Self {
Self::new()
}
}
struct NewtSlogger(Newt);
impl Slogger for NewtSlogger {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
self.0.slog(stack, pri, tank)?;
Ok(())
}
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
self.0.flog(stack, cord)?;
Ok(())
}
}

View File

@ -1,4 +1,4 @@
use crate::mem::{word_size_of, AllocResult, NockStack}; use crate::mem::{word_size_of, NockStack};
use bitvec::prelude::{BitSlice, Lsb0}; use bitvec::prelude::{BitSlice, Lsb0};
use either::{Either, Left, Right}; use either::{Either, Left, Right};
use ibig::{Stack, UBig}; use ibig::{Stack, UBig};
@ -155,7 +155,7 @@ fn is_cell(noun: u64) -> bool {
} }
/** A noun-related error. */ /** A noun-related error. */
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
/** Expected type [`Allocated`]. */ /** Expected type [`Allocated`]. */
NotAllocated, NotAllocated,
@ -169,7 +169,6 @@ pub enum Error {
NotIndirectAtom, NotIndirectAtom,
/** The value can't be represented by the given type. */ /** The value can't be represented by the given type. */
NotRepresentable, NotRepresentable,
AllocationError(crate::mem::AllocationError),
} }
impl error::Error for Error {} impl error::Error for Error {}
@ -183,17 +182,10 @@ impl std::fmt::Display for Error {
Error::NotDirectAtom => f.write_str("not a direct atom"), Error::NotDirectAtom => f.write_str("not a direct atom"),
Error::NotIndirectAtom => f.write_str("not an indirect atom"), Error::NotIndirectAtom => f.write_str("not an indirect atom"),
Error::NotRepresentable => f.write_str("unrepresentable value"), Error::NotRepresentable => f.write_str("unrepresentable value"),
Error::AllocationError(_) => f.write_str("allocation error"),
} }
} }
} }
impl From<crate::mem::AllocationError> for Error {
fn from(allocation_error: crate::mem::AllocationError) -> Self {
Error::AllocationError(allocation_error)
}
}
impl From<Error> for () { impl From<Error> for () {
fn from(_: Error) -> Self {} fn from(_: Error) -> Self {}
} }
@ -308,18 +300,18 @@ pub const fn D(n: u64) -> Noun {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Noun> { pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
Ok(Cell::new_tuple(allocator, tup)?.as_noun()) Cell::new_tuple(allocator, tup).as_noun()
} }
/// Create $tape Noun from ASCII string /// Create $tape Noun from ASCII string
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> AllocResult<Noun> { pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> Noun {
// XX: Needs unit tests // XX: Needs unit tests
let mut res = D(0); let mut res = D(0);
for c in text.bytes().rev() { for c in text.bytes().rev() {
res = T(allocator, &[D(c as u64), res])? res = T(allocator, &[D(c as u64), res])
} }
Ok(res) res
} }
/** An indirect atom. /** An indirect atom.
@ -380,10 +372,10 @@ impl IndirectAtom {
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
data: *const u64, data: *const u64,
) -> AllocResult<Self> { ) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size)?; let (mut indirect, buffer) = Self::new_raw_mut(allocator, size);
ptr::copy_nonoverlapping(data, buffer, size); ptr::copy_nonoverlapping(data, buffer, size);
Ok(*(indirect.normalize())) *(indirect.normalize())
} }
/** Make an indirect atom by copying from other memory. /** Make an indirect atom by copying from other memory.
@ -394,16 +386,13 @@ impl IndirectAtom {
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
data: *const u8, data: *const u8,
) -> AllocResult<Self> { ) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size)?; let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size);
ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size); ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size);
Ok(*(indirect.normalize())) *(indirect.normalize())
} }
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>( pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(allocator: &mut A, data: &[u8]) -> Self {
allocator: &mut A,
data: &[u8],
) -> AllocResult<Self> {
IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr()) IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr())
} }
@ -414,12 +403,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut<A: NounAllocator>( pub unsafe fn new_raw_mut<A: NounAllocator>(
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
) -> AllocResult<(Self, *mut u64)> { ) -> (Self, *mut u64) {
debug_assert!(size > 0); debug_assert!(size > 0);
let buffer = allocator.alloc_indirect(size)?; let buffer = allocator.alloc_indirect(size);
*buffer = 0; *buffer = 0;
*buffer.add(1) = size as u64; *buffer.add(1) = size as u64;
Ok((Self::from_raw_pointer(buffer), buffer.add(2))) (Self::from_raw_pointer(buffer), buffer.add(2))
} }
/** Make an indirect atom that can be written into, and zero the whole data buffer. /** Make an indirect atom that can be written into, and zero the whole data buffer.
@ -429,10 +418,10 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>( pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>(
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
) -> AllocResult<(Self, *mut u64)> { ) -> (Self, *mut u64) {
let allocation = Self::new_raw_mut(allocator, size)?; let allocation = Self::new_raw_mut(allocator, size);
ptr::write_bytes(allocation.1, 0, size); ptr::write_bytes(allocation.1, 0, size);
Ok(allocation) allocation
} }
/** Make an indirect atom that can be written into as a bitslice. The constraints of /** Make an indirect atom that can be written into as a bitslice. The constraints of
@ -441,12 +430,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>( pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>(
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
) -> AllocResult<(Self, &'a mut BitSlice<u64, Lsb0>)> { ) -> (Self, &'a mut BitSlice<u64, Lsb0>) {
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size)?; let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size);
Ok(( (
noun, noun,
BitSlice::from_slice_mut(from_raw_parts_mut(ptr, size)), BitSlice::from_slice_mut(from_raw_parts_mut(ptr, size)),
)) )
} }
/** Make an indirect atom that can be written into as a slice of bytes. The constraints of /** Make an indirect atom that can be written into as a slice of bytes. The constraints of
@ -457,19 +446,19 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>( pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>(
allocator: &mut A, allocator: &mut A,
size: usize, size: usize,
) -> AllocResult<(Self, &'a mut [u8])> { ) -> (Self, &'a mut [u8]) {
let word_size = (size + 7) >> 3; let word_size = (size + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?; let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
Ok((noun, from_raw_parts_mut(ptr as *mut u8, size))) (noun, from_raw_parts_mut(ptr as *mut u8, size))
} }
/// Create an indirect atom backed by a fixed-size array /// Create an indirect atom backed by a fixed-size array
pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>( pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>(
allocator: &mut A, allocator: &mut A,
) -> AllocResult<(Self, &'a mut [u8; N])> { ) -> (Self, &'a mut [u8; N]) {
let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3; let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?; let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
Ok((noun, &mut *(ptr as *mut [u8; N]))) (noun, &mut *(ptr as *mut [u8; N]))
} }
/** Size of an indirect atom in 64-bit words */ /** Size of an indirect atom in 64-bit words */
@ -519,7 +508,7 @@ impl IndirectAtom {
BitSlice::from_slice_mut(self.as_mut_slice()) BitSlice::from_slice_mut(self.as_mut_slice())
} }
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> { pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> UBig {
UBig::from_le_bytes_stack(stack, self.as_bytes()) UBig::from_le_bytes_stack(stack, self.as_bytes())
} }
@ -649,34 +638,32 @@ impl Cell {
} }
} }
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> AllocResult<Cell> { pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> Cell {
unsafe { unsafe {
let (cell, memory) = Self::new_raw_mut(allocator)?; let (cell, memory) = Self::new_raw_mut(allocator);
(*memory).head = head; (*memory).head = head;
(*memory).tail = tail; (*memory).tail = tail;
Ok(cell) cell
} }
} }
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Cell> { pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Cell {
if tup.len() < 2 { if tup.len() < 2 {
panic!("Cannot create tuple with fewer than 2 elements"); panic!("Cannot create tuple with fewer than 2 elements");
} }
let len = tup.len(); let len = tup.len();
let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1])?; let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1]);
for i in (0..len - 2).rev() { for i in (0..len - 2).rev() {
cell = Cell::new(allocator, tup[i], cell.as_noun())?; cell = Cell::new(allocator, tup[i], cell.as_noun());
} }
Ok(cell) cell
} }
pub unsafe fn new_raw_mut<A: NounAllocator>( pub unsafe fn new_raw_mut<A: NounAllocator>(allocator: &mut A) -> (Cell, *mut CellMemory) {
allocator: &mut A, let memory = allocator.alloc_cell();
) -> AllocResult<(Cell, *mut CellMemory)> {
let memory = allocator.alloc_cell()?;
(*memory).metadata = 0; (*memory).metadata = 0;
Ok((Self::from_raw_pointer(memory), memory)) (Self::from_raw_pointer(memory), memory)
} }
pub fn head(&self) -> Noun { pub fn head(&self) -> Noun {
@ -761,21 +748,20 @@ pub union Atom {
} }
impl Atom { impl Atom {
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> AllocResult<Atom> { pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> Atom {
let res = if value <= DIRECT_MAX { if value <= DIRECT_MAX {
unsafe { DirectAtom::new_unchecked(value).as_atom() } unsafe { DirectAtom::new_unchecked(value).as_atom() }
} else { } else {
unsafe { IndirectAtom::new_raw(allocator, 1, &value)?.as_atom() } unsafe { IndirectAtom::new_raw(allocator, 1, &value).as_atom() }
}; }
Ok(res)
} }
// to_le_bytes and new_raw are copies. We should be able to do this completely without copies // to_le_bytes and new_raw are copies. We should be able to do this completely without copies
// if we integrate with ibig properly. // if we integrate with ibig properly.
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> AllocResult<Atom> { pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> Atom {
let bit_size = big.bit_len(); let bit_size = big.bit_len();
let buffer = big.to_le_bytes_stack(); let buffer = big.to_le_bytes_stack();
let atom = if bit_size < 64 { if bit_size < 64 {
let mut value = 0u64; let mut value = 0u64;
for i in (0..bit_size).step_by(8) { for i in (0..bit_size).step_by(8) {
value |= (buffer[i / 8] as u64) << i; value |= (buffer[i / 8] as u64) << i;
@ -783,9 +769,8 @@ impl Atom {
unsafe { DirectAtom::new_unchecked(value).as_atom() } unsafe { DirectAtom::new_unchecked(value).as_atom() }
} else { } else {
let byte_size = (big.bit_len() + 7) >> 3; let byte_size = (big.bit_len() + 7) >> 3;
unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr())?.as_atom() } unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr()).as_atom() }
}; }
Ok(atom)
} }
pub fn is_direct(&self) -> bool { pub fn is_direct(&self) -> bool {
@ -882,13 +867,12 @@ impl Atom {
} }
} }
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> { pub fn as_ubig<S: Stack>(self, stack: &mut S) -> UBig {
let ubig = if self.is_indirect() { if self.is_indirect() {
unsafe { self.indirect.as_ubig(stack)? } unsafe { self.indirect.as_ubig(stack) }
} else { } else {
unsafe { self.direct.as_ubig(stack) } unsafe { self.direct.as_ubig(stack) }
}; }
Ok(ubig)
} }
pub fn direct(&self) -> Option<DirectAtom> { pub fn direct(&self) -> Option<DirectAtom> {
@ -1314,13 +1298,13 @@ pub trait NounAllocator: Sized {
* *
* This should allocate *two more* `u64`s than `words` to make space for the size and metadata * This should allocate *two more* `u64`s than `words` to make space for the size and metadata
*/ */
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64>; unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64;
/** Allocate memory for a cell */ /** Allocate memory for a cell */
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory>; unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
/** Allocate space for a struct in a stack frame */ /** Allocate space for a struct in a stack frame */
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T>; unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T;
} }
/** /**

View File

@ -1,7 +1,7 @@
use crate::hamt::MutHamt; use crate::hamt::MutHamt;
use crate::interpreter::Error::{self, *}; use crate::interpreter::Error::{self, *};
use crate::interpreter::Mote::*; use crate::interpreter::Mote::*;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D}; use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
use bitvec::prelude::{BitSlice, Lsb0}; use bitvec::prelude::{BitSlice, Lsb0};
use either::Either::{Left, Right}; use either::Either::{Left, Right};
@ -103,13 +103,13 @@ enum CueStackEntry {
/// # Returns /// # Returns
/// A Result containing either the deserialized Noun or an Error /// A Result containing either the deserialized Noun or an Error
pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Result<Noun, Error> { pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Result<Noun, Error> {
let backref_map = MutHamt::<Noun>::new(stack)?; let backref_map = MutHamt::<Noun>::new(stack);
let mut result = D(0); let mut result = D(0);
let mut cursor = 0; let mut cursor = 0;
let res = unsafe { unsafe {
stack.with_frame(0, |stack: &mut NockStack| { stack.with_frame(0, |stack: &mut NockStack| {
*(stack.push::<CueStackEntry>()?) = *(stack.push::<CueStackEntry>()) =
CueStackEntry::DestinationPointer(&mut result as *mut Noun); CueStackEntry::DestinationPointer(&mut result as *mut Noun);
loop { loop {
if stack.stack_is_empty() { if stack.stack_is_empty() {
@ -125,43 +125,42 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Resu
// 11 tag: backref // 11 tag: backref
if next_bit(&mut cursor, buffer) { if next_bit(&mut cursor, buffer) {
let mut backref_noun = let mut backref_noun =
Atom::new(stack, rub_backref(&mut cursor, buffer)?)?.as_noun(); Atom::new(stack, rub_backref(&mut cursor, buffer)?).as_noun();
*dest_ptr = backref_map *dest_ptr = backref_map
.lookup(stack, &mut backref_noun)? .lookup(stack, &mut backref_noun)
.ok_or(Deterministic(Exit, D(0)))?; .ok_or(Deterministic(Exit, D(0)))?;
} else { } else {
// 10 tag: cell // 10 tag: cell
let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack)?; let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack);
*dest_ptr = cell.as_noun(); *dest_ptr = cell.as_noun();
let mut backref_atom = let mut backref_atom =
Atom::new(stack, (cursor - 2) as u64)?.as_noun(); Atom::new(stack, (cursor - 2) as u64).as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?; backref_map.insert(stack, &mut backref_atom, *dest_ptr);
*(stack.push()?) = CueStackEntry::BackRef( *(stack.push()) = CueStackEntry::BackRef(
cursor as u64 - 2, cursor as u64 - 2,
dest_ptr as *const Noun, dest_ptr as *const Noun,
); );
*(stack.push()?) = *(stack.push()) =
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail); CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail);
*(stack.push()?) = *(stack.push()) =
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head); CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head);
} }
} else { } else {
// 0 tag: atom // 0 tag: atom
let backref: u64 = (cursor - 1) as u64; let backref: u64 = (cursor - 1) as u64;
*dest_ptr = rub_atom(stack, &mut cursor, buffer)?.as_noun(); *dest_ptr = rub_atom(stack, &mut cursor, buffer)?.as_noun();
let mut backref_atom = Atom::new(stack, backref)?.as_noun(); let mut backref_atom = Atom::new(stack, backref).as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?; backref_map.insert(stack, &mut backref_atom, *dest_ptr);
} }
} }
CueStackEntry::BackRef(backref, noun_ptr) => { CueStackEntry::BackRef(backref, noun_ptr) => {
let mut backref_atom = Atom::new(stack, backref)?.as_noun(); let mut backref_atom = Atom::new(stack, backref).as_noun();
backref_map.insert(stack, &mut backref_atom, *noun_ptr)? backref_map.insert(stack, &mut backref_atom, *noun_ptr)
} }
} }
} }
})? })
}; }
res
} }
/// Deserialize a noun from an Atom /// Deserialize a noun from an Atom
@ -236,7 +235,7 @@ fn rub_atom(
} else { } else {
// Need an indirect atom // Need an indirect atom
let wordsize = (size + 63) >> 6; let wordsize = (size + 63) >> 6;
let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize)? }; let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize) };
slice[0..bits.len()].copy_from_bitslice(bits); slice[0..bits.len()].copy_from_bitslice(bits);
debug_assert!(atom.size() > 0); debug_assert!(atom.size() > 0);
unsafe { Ok(atom.normalize_as_atom()) } unsafe { Ok(atom.normalize_as_atom()) }
@ -273,71 +272,79 @@ struct JamState<'a> {
/// Corresponds to ++jam in the hoon stdlib. /// Corresponds to ++jam in the hoon stdlib.
/// ///
/// Implements a compact encoding scheme for nouns, with backreferences for shared structures. /// Implements a compact encoding scheme for nouns, with backreferences for shared structures.
pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult<Atom> { pub fn jam(stack: &mut NockStack, noun: Noun) -> Atom {
let backref_map = MutHamt::new(stack)?; let backref_map = MutHamt::new(stack);
let size = 8; let size = 8;
let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size)? }; let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size) };
let mut state = JamState { let mut state = JamState {
cursor: 0, cursor: 0,
size, size,
atom, atom,
slice, slice,
}; };
stack.frame_push(0);
unsafe { unsafe {
stack.with_frame(0, |stack| { *(stack.push::<Noun>()) = noun;
*(stack.push::<Noun>()?) = noun; };
'jam: loop { 'jam: loop {
if stack.stack_is_empty() { if stack.stack_is_empty() {
break; break;
} else { } else {
let mut noun = *(stack.top::<Noun>()); let mut noun = unsafe { *(stack.top::<Noun>()) };
if let Some(backref) = backref_map.lookup(stack, &mut noun)? { if let Some(backref) = backref_map.lookup(stack, &mut noun) {
match noun.as_either_atom_cell() { match noun.as_either_atom_cell() {
Left(atom) => { Left(atom) => {
let atom_size = met0_usize(atom); let atom_size = met0_usize(atom);
let backref_size = met0_u64_to_usize(backref); let backref_size = met0_u64_to_usize(backref);
if atom_size <= backref_size { if atom_size <= backref_size {
jam_atom(stack, &mut state, atom)?; jam_atom(stack, &mut state, atom);
} else { } else {
jam_backref(stack, &mut state, backref)?; jam_backref(stack, &mut state, backref);
}
}
Right(_cell) => {
jam_backref(stack, &mut state, backref)?;
}
}
stack.pop::<Noun>();
continue 'jam;
};
backref_map.insert(stack, &mut noun, state.cursor as u64)?;
match noun.as_either_atom_cell() {
Left(atom) => {
jam_atom(stack, &mut state, atom)?;
stack.pop::<Noun>();
continue;
}
Right(cell) => {
jam_cell(stack, &mut state)?;
stack.pop::<Noun>();
*(stack.push::<Noun>()?) = cell.tail();
*(stack.push::<Noun>()?) = cell.head();
continue;
} }
} }
Right(_cell) => {
jam_backref(stack, &mut state, backref);
}
}
unsafe {
stack.pop::<Noun>();
};
continue 'jam;
};
backref_map.insert(stack, &mut noun, state.cursor as u64);
match noun.as_either_atom_cell() {
Left(atom) => {
jam_atom(stack, &mut state, atom);
unsafe {
stack.pop::<Noun>();
};
continue;
}
Right(cell) => {
jam_cell(stack, &mut state);
unsafe {
stack.pop::<Noun>();
*(stack.push::<Noun>()) = cell.tail();
*(stack.push::<Noun>()) = cell.head();
};
continue;
} }
} }
let result = state.atom.normalize_as_atom(); }
Ok(result) }
})? unsafe {
let mut result = state.atom.normalize_as_atom();
stack.preserve(&mut result);
stack.frame_pop();
result
} }
} }
/// Serialize an atom into the jam state /// Serialize an atom into the jam state
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<()> { fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) {
loop { loop {
if state.cursor + 1 > state.slice.len() { if state.cursor + 1 > state.slice.len() {
double_atom_size(traversal, state)?; double_atom_size(traversal, state);
} else { } else {
break; break;
} }
@ -345,20 +352,19 @@ fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Allo
state.slice.set(state.cursor, false); // 0 tag for atom state.slice.set(state.cursor, false); // 0 tag for atom
state.cursor += 1; state.cursor += 1;
loop { loop {
if let Ok(()) = mat(traversal, state, atom)? { if let Ok(()) = mat(traversal, state, atom) {
break; break;
} else { } else {
double_atom_size(traversal, state)?; double_atom_size(traversal, state);
} }
} }
Ok(())
} }
/// Serialize a cell into the jam state /// Serialize a cell into the jam state
fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> { fn jam_cell(traversal: &mut NockStack, state: &mut JamState) {
loop { loop {
if state.cursor + 2 > state.slice.len() { if state.cursor + 2 > state.slice.len() {
double_atom_size(traversal, state)?; double_atom_size(traversal, state);
} else { } else {
break; break;
} }
@ -366,14 +372,13 @@ fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()>
state.slice.set(state.cursor, true); // 1 bit state.slice.set(state.cursor, true); // 1 bit
state.slice.set(state.cursor + 1, false); // 0 bit, forming 10 tag for cell state.slice.set(state.cursor + 1, false); // 0 bit, forming 10 tag for cell
state.cursor += 2; state.cursor += 2;
Ok(())
} }
/// Serialize a backreference into the jam state /// Serialize a backreference into the jam state
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) -> AllocResult<()> { fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) {
loop { loop {
if state.cursor + 2 > state.slice.len() { if state.cursor + 2 > state.slice.len() {
double_atom_size(traversal, state)?; double_atom_size(traversal, state);
} else { } else {
break; break;
} }
@ -381,46 +386,44 @@ fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) ->
state.slice.set(state.cursor, true); // 1 bit state.slice.set(state.cursor, true); // 1 bit
state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref
state.cursor += 2; state.cursor += 2;
let backref_atom = Atom::new(traversal, backref)?; let backref_atom = Atom::new(traversal, backref);
loop { loop {
if let Ok(()) = mat(traversal, state, backref_atom)? { if let Ok(()) = mat(traversal, state, backref_atom) {
break; break;
} else { } else {
double_atom_size(traversal, state)?; double_atom_size(traversal, state);
} }
} }
Ok(())
} }
/// Double the size of the atom in the jam state /// Double the size of the atom in the jam state
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> { fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) {
let new_size = state.size + state.size; let new_size = state.size + state.size;
let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size)? }; let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size) };
new_slice[0..state.cursor].copy_from_bitslice(&state.slice[0..state.cursor]); new_slice[0..state.cursor].copy_from_bitslice(&state.slice[0..state.cursor]);
state.size = new_size; state.size = new_size;
state.atom = new_atom; state.atom = new_atom;
state.slice = new_slice; state.slice = new_slice;
Ok(())
} }
/// Encode an atom's size and value into the jam state /// Encode an atom's size and value into the jam state
/// ///
/// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())` /// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())`
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<Result<(), ()>> { fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Result<(), ()> {
let b_atom_size = met0_usize(atom); let b_atom_size = met0_usize(atom);
let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64)?; let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64);
if b_atom_size == 0 { if b_atom_size == 0 {
if state.cursor + 1 > state.slice.len() { if state.cursor + 1 > state.slice.len() {
Ok(Err(())) Err(())
} else { } else {
state.slice.set(state.cursor, true); state.slice.set(state.cursor, true);
state.cursor += 1; state.cursor += 1;
Ok(Ok(())) Ok(())
} }
} else { } else {
let c_b_size = met0_usize(b_atom_size_atom); let c_b_size = met0_usize(b_atom_size_atom);
if state.cursor + c_b_size + c_b_size + b_atom_size > state.slice.len() { if state.cursor + c_b_size + c_b_size + b_atom_size > state.slice.len() {
Ok(Err(())) Err(())
} else { } else {
state.slice[state.cursor..state.cursor + c_b_size].fill(false); // a 0 bit for each bit in the atom size state.slice[state.cursor..state.cursor + c_b_size].fill(false); // a 0 bit for each bit in the atom size
state.slice.set(state.cursor + c_b_size, true); // a terminating 1 bit state.slice.set(state.cursor + c_b_size, true); // a terminating 1 bit
@ -430,7 +433,7 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
..state.cursor + c_b_size + c_b_size + b_atom_size] ..state.cursor + c_b_size + c_b_size + b_atom_size]
.copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]); .copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]);
state.cursor += c_b_size + c_b_size + b_atom_size; state.cursor += c_b_size + c_b_size + b_atom_size;
Ok(Ok(())) Ok(())
} }
} }
} }
@ -438,12 +441,14 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::mem::size_of;
use rand::prelude::*; use rand::prelude::*;
use super::*; use super::*;
use crate::jets::util::test::assert_noun_eq; use crate::jets::util::test::assert_noun_eq;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::noun::{Atom, Cell, Noun}; use crate::noun::{Atom, Cell, CellMemory, Noun};
fn setup_stack() -> NockStack { fn setup_stack() -> NockStack {
NockStack::new(1 << 30, 0) NockStack::new(1 << 30, 0)
} }
@ -451,8 +456,8 @@ mod tests {
#[test] #[test]
fn test_jam_cue_atom() { fn test_jam_cue_atom() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let atom = Atom::new(&mut stack, 42).unwrap(); let atom = Atom::new(&mut stack, 42);
let jammed = jam(&mut stack, atom.as_noun()).unwrap(); let jammed = jam(&mut stack, atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, atom.as_noun()); assert_noun_eq(&mut stack, cued, atom.as_noun());
} }
@ -460,10 +465,10 @@ mod tests {
#[test] #[test]
fn test_jam_cue_cell() { fn test_jam_cue_cell() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun(); let n1 = Atom::new(&mut stack, 1).as_noun();
let n2 = Atom::new(&mut stack, 2).unwrap().as_noun(); let n2 = Atom::new(&mut stack, 2).as_noun();
let cell = Cell::new(&mut stack, n1, n2).unwrap().as_noun(); let cell = Cell::new(&mut stack, n1, n2).as_noun();
let jammed = jam(&mut stack, cell).unwrap(); let jammed = jam(&mut stack, cell);
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell); assert_noun_eq(&mut stack, cued, cell);
} }
@ -471,12 +476,12 @@ mod tests {
#[test] #[test]
fn test_jam_cue_nested_cell() { fn test_jam_cue_nested_cell() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let n3 = Atom::new(&mut stack, 3).unwrap().as_noun(); let n3 = Atom::new(&mut stack, 3).as_noun();
let n4 = Atom::new(&mut stack, 4).unwrap().as_noun(); let n4 = Atom::new(&mut stack, 4).as_noun();
let inner_cell = Cell::new(&mut stack, n3, n4).unwrap(); let inner_cell = Cell::new(&mut stack, n3, n4);
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun(); let n1 = Atom::new(&mut stack, 1).as_noun();
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun()).unwrap(); let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun());
let jammed = jam(&mut stack, outer_cell.as_noun()).unwrap(); let jammed = jam(&mut stack, outer_cell.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, outer_cell.as_noun()); assert_noun_eq(&mut stack, cued, outer_cell.as_noun());
} }
@ -484,9 +489,9 @@ mod tests {
#[test] #[test]
fn test_jam_cue_shared_structure() { fn test_jam_cue_shared_structure() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let shared_atom = Atom::new(&mut stack, 42).unwrap(); let shared_atom = Atom::new(&mut stack, 42);
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun()).unwrap(); let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun());
let jammed = jam(&mut stack, cell.as_noun()).unwrap(); let jammed = jam(&mut stack, cell.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell.as_noun()); assert_noun_eq(&mut stack, cued, cell.as_noun());
} }
@ -494,8 +499,8 @@ mod tests {
#[test] #[test]
fn test_jam_cue_large_atom() { fn test_jam_cue_large_atom() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let large_atom = Atom::new(&mut stack, u64::MAX).unwrap(); let large_atom = Atom::new(&mut stack, u64::MAX);
let jammed = jam(&mut stack, large_atom.as_noun()).unwrap(); let jammed = jam(&mut stack, large_atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, large_atom.as_noun()); assert_noun_eq(&mut stack, cued, large_atom.as_noun());
} }
@ -503,8 +508,8 @@ mod tests {
#[test] #[test]
fn test_jam_cue_empty_atom() { fn test_jam_cue_empty_atom() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let empty_atom = Atom::new(&mut stack, 0).unwrap(); let empty_atom = Atom::new(&mut stack, 0);
let jammed = jam(&mut stack, empty_atom.as_noun()).unwrap(); let jammed = jam(&mut stack, empty_atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, empty_atom.as_noun()); assert_noun_eq(&mut stack, cued, empty_atom.as_noun());
} }
@ -512,12 +517,12 @@ mod tests {
#[test] #[test]
fn test_jam_cue_complex_structure() { fn test_jam_cue_complex_structure() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let atom1 = Atom::new(&mut stack, 1).unwrap(); let atom1 = Atom::new(&mut stack, 1);
let atom2 = Atom::new(&mut stack, 2).unwrap(); let atom2 = Atom::new(&mut stack, 2);
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun()).unwrap(); let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun());
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun()).unwrap(); let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun());
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun()).unwrap(); let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun());
let jammed = jam(&mut stack, cell3.as_noun()).unwrap(); let jammed = jam(&mut stack, cell3.as_noun());
let cued = cue(&mut stack, jammed).unwrap(); let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell3.as_noun()); assert_noun_eq(&mut stack, cued, cell3.as_noun());
} }
@ -525,7 +530,7 @@ mod tests {
#[test] #[test]
fn test_cue_invalid_input() { fn test_cue_invalid_input() {
let mut stack = setup_stack(); let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid tag let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid tag
let result = cue(&mut stack, invalid_atom); let result = cue(&mut stack, invalid_atom);
assert!(result.is_err()); assert!(result.is_err());
} }
@ -538,15 +543,14 @@ mod tests {
let mut stack = setup_stack(); let mut stack = setup_stack();
let mut rng_clone = rng.clone(); let mut rng_clone = rng.clone();
let (original, total_size) = let (original, total_size) = generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone);
generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone).unwrap();
println!( println!(
"Total size of all generated nouns: {:.2} KB", "Total size of all generated nouns: {:.2} KB",
total_size as f64 / 1024.0 total_size as f64 / 1024.0
); );
println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0); println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0);
let jammed = jam(&mut stack, original.clone()).unwrap(); let jammed = jam(&mut stack, original.clone());
println!( println!(
"Jammed size: {:.2} KB", "Jammed size: {:.2} KB",
jammed.as_noun().mass() as f64 / 1024.0 jammed.as_noun().mass() as f64 / 1024.0
@ -557,26 +561,7 @@ mod tests {
assert_noun_eq(&mut stack, cued, original); assert_noun_eq(&mut stack, cued, original);
} }
fn noun_size(noun: Noun) -> usize { fn generate_random_noun(stack: &mut NockStack, bits: usize, rng: &mut StdRng) -> (Noun, usize) {
let mut size = 0;
let mut stack = vec![noun];
while let Some(top) = stack.pop() {
if let Ok(i) = top.as_indirect() {
size += i.raw_size();
} else if let Ok(c) = top.as_cell() {
size += (std::mem::size_of::<crate::noun::CellMemory>() + 7) << 3;
stack.push(c.tail());
stack.push(c.head());
}
}
size
}
fn generate_random_noun(
stack: &mut NockStack,
bits: usize,
rng: &mut StdRng,
) -> AllocResult<(Noun, usize)> {
const MAX_DEPTH: usize = 100; // Adjust this value as needed const MAX_DEPTH: usize = 100; // Adjust this value as needed
fn inner( fn inner(
stack: &mut NockStack, stack: &mut NockStack,
@ -584,7 +569,7 @@ mod tests {
rng: &mut StdRng, rng: &mut StdRng,
depth: usize, depth: usize,
accumulated_size: usize, accumulated_size: usize,
) -> AllocResult<(Noun, usize)> { ) -> (Noun, usize) {
let mut done = false; let mut done = false;
if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 { if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 {
// println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0); // println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0);
@ -593,51 +578,78 @@ mod tests {
let result = if rng.gen_bool(0.5) || done { let result = if rng.gen_bool(0.5) || done {
let value = rng.gen::<u64>(); let value = rng.gen::<u64>();
let atom = Atom::new(stack, value).unwrap(); let atom = Atom::new(stack, value);
let noun = atom.as_noun(); let noun = atom.as_noun();
(noun, accumulated_size + noun.mass()) (noun, accumulated_size + noun.mass())
} else { } else {
let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size)?; let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size);
let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size)?; let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size);
let cell = Cell::new(stack, left, right).unwrap(); let cell = Cell::new(stack, left, right);
let noun = cell.as_noun(); let noun = cell.as_noun();
(noun, noun.mass()) (noun, noun.mass())
}; };
if noun_size(result.0) > stack.size() { if space_needed_noun(result.0, stack) > stack.size() {
eprintln!( eprintln!(
"Stack size exceeded with noun size {:.2} KB", "Stack size exceeded with noun size {:.2} KB",
result.0.mass() as f64 / 1024.0 result.0.mass() as f64 / 1024.0
); );
unsafe { unsafe {
let top_noun = *stack.top::<Noun>(); let top_noun = *stack.top::<Noun>();
Ok((top_noun, result.1)) (top_noun, result.1)
} }
} else { } else {
Ok(result) result
} }
} }
inner(stack, bits, rng, 0, 0) inner(stack, bits, rng, 0, 0)
} }
fn space_needed_noun(noun: Noun, stack: &mut NockStack) -> usize {
unsafe {
stack.with_frame(0, |stack| {
*(stack.push::<Noun>()) = noun;
let mut size = 0;
while !stack.stack_is_empty() {
let noun = *(stack.top::<Noun>());
stack.pop::<Noun>();
match noun.as_either_atom_cell() {
Left(atom) => match atom.as_either() {
Left(_) => {}
Right(indirect) => {
size += indirect.raw_size();
}
},
Right(cell) => {
size += size_of::<CellMemory>();
*(stack.push::<Noun>()) = cell.tail();
*(stack.push::<Noun>()) = cell.head();
}
}
}
size
})
}
}
fn generate_deeply_nested_noun( fn generate_deeply_nested_noun(
stack: &mut NockStack, stack: &mut NockStack,
depth: usize, depth: usize,
rng: &mut StdRng, rng: &mut StdRng,
) -> AllocResult<(Noun, usize)> { ) -> (Noun, usize) {
if depth == 0 { if depth == 0 {
let (noun, size) = generate_random_noun(stack, 100, rng)?; let (noun, size) = generate_random_noun(stack, 100, rng);
Ok((noun, size)) (noun, size)
} else { } else {
let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?; let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?; let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
let cell = Cell::new(stack, left, right).unwrap(); let cell = Cell::new(stack, left, right);
let noun = cell.as_noun(); let noun = cell.as_noun();
let total_size = left_size + right_size + noun.mass(); let total_size = left_size + right_size + noun.mass();
if noun_size(noun) > stack.size() { if { space_needed_noun(noun, stack) } > stack.size() {
eprintln!( eprintln!(
"Stack size exceeded at depth {} with noun size {:.2} KB", "Stack size exceeded at depth {} with noun size {:.2} KB",
depth, depth,
@ -645,11 +657,11 @@ mod tests {
); );
unsafe { unsafe {
let top_noun = *stack.top::<Noun>(); let top_noun = *stack.top::<Noun>();
Ok((top_noun, total_size)) (top_noun, total_size)
} }
} else { } else {
// println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth); // println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth);
Ok((noun, total_size)) (noun, total_size)
} }
} }
} }
@ -659,7 +671,7 @@ mod tests {
std::env::set_var("RUST_BACKTRACE", "full"); std::env::set_var("RUST_BACKTRACE", "full");
let mut stack = setup_stack(); let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid atom representation let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid atom representation
let result = cue(&mut stack, invalid_atom); let result = cue(&mut stack, invalid_atom);
assert!(result.is_err()); assert!(result.is_err());
@ -668,6 +680,8 @@ mod tests {
assert!(matches!(e, Error::Deterministic(_, _))); assert!(matches!(e, Error::Deterministic(_, _)));
} }
} }
#[ignore] // We will put this back when we have proper error catching
#[test] #[test]
fn test_cue_nondeterministic_error() { fn test_cue_nondeterministic_error() {
let mut big_stack = NockStack::new(1 << 30, 0); let mut big_stack = NockStack::new(1 << 30, 0);
@ -675,10 +689,10 @@ mod tests {
let mut rng = StdRng::seed_from_u64(1); let mut rng = StdRng::seed_from_u64(1);
// Create an atom with a very large value to potentially cause overflow // Create an atom with a very large value to potentially cause overflow
let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng).unwrap(); let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng);
// Attempt to jam and then cue the large atom in the big stack // Attempt to jam and then cue the large atom in the big stack
let jammed = jam(&mut big_stack, large_atom).unwrap(); let jammed = jam(&mut big_stack, large_atom);
// make a smaller stack to try to cause a nondeterministic error // make a smaller stack to try to cause a nondeterministic error
// NOTE: if the stack is big enough to fit the jammed atom, cue panics // NOTE: if the stack is big enough to fit the jammed atom, cue panics
@ -697,10 +711,7 @@ mod tests {
println!("Result: {:?}", result); println!("Result: {:?}", result);
assert!(result.is_err()); assert!(result.is_err());
if let Err(e) = result { if let Err(e) = result {
assert!(matches!( assert!(matches!(e, Error::NonDeterministic(_, _)));
e,
Error::NonDeterministic(crate::interpreter::Mote::Meme, _)
));
println!("got expected error: {:?}", e); println!("got expected error: {:?}", e);
} }
} }

View File

@ -5,7 +5,6 @@ use bitvec::slice::BitSlice;
use crate::interpreter::{interpret, Context}; use crate::interpreter::{interpret, Context};
use crate::jets::util::slot; use crate::jets::util::slot;
use crate::jets::{Jet, JetErr}; use crate::jets::{Jet, JetErr};
use crate::mem::AllocResult;
use crate::noun::{Noun, D, T}; use crate::noun::{Noun, D, T};
/// Return Err if the computation crashed or should punt to Nock /// Return Err if the computation crashed or should punt to Nock
@ -20,13 +19,13 @@ pub struct Site {
impl Site { impl Site {
/// Prepare a locally cached gate to call repeatedly. /// Prepare a locally cached gate to call repeatedly.
pub fn new(ctx: &mut Context, core: &mut Noun) -> AllocResult<Site> { pub fn new(ctx: &mut Context, core: &mut Noun) -> Site {
let mut battery = slot(*core, 2).unwrap(); let mut battery = slot(*core, 2).unwrap();
let context = slot(*core, 7).unwrap(); let context = slot(*core, 7).unwrap();
let warm_result = ctx let warm_result = ctx
.warm .warm
.find_jet(&mut ctx.stack, core, &mut battery)? .find_jet(&mut ctx.stack, core, &mut battery)
.filter(|(_jet, mut path)| { .filter(|(_jet, mut path)| {
// check that 7 is a prefix of the parent battery axis, // check that 7 is a prefix of the parent battery axis,
// to ensure that the sample (axis 6) is not part of the jet match. // to ensure that the sample (axis 6) is not part of the jet match.
@ -35,12 +34,10 @@ impl Site {
// jet and we only actually match one of them, but we check all of them and run // jet and we only actually match one of them, but we check all of them and run
// unjetted if any have an axis outside 7. // unjetted if any have an axis outside 7.
let axis_7_bits: &BitSlice<u64, Lsb0> = BitSlice::from_element(&7u64); let axis_7_bits: &BitSlice<u64, Lsb0> = BitSlice::from_element(&7u64);
// TODO: This panic is ugly but the code is awkward. let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path);
let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path).ok().expect("OOM'd on ctx.cold.find in Site::new");
let mut ret = true; let mut ret = true;
for mut batteries in batteries_list { for mut batteries in batteries_list {
if let Some((_, parent_axis)) = batteries.next() { if let Some((_battery, parent_axis)) = batteries.next() {
// let parent_axis = unsafe { (*battery.0).parent_axis };
let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3]; let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3];
if parent_axis_prefix_bits == axis_7_bits { if parent_axis_prefix_bits == axis_7_bits {
continue; continue;
@ -54,19 +51,19 @@ impl Site {
} }
} }
ret ret
}); });
Ok(Site { Site {
battery, battery,
context, context,
jet: warm_result.map(|(jet, _)| jet), jet: warm_result.map(|(jet, _)| jet),
path: warm_result.map(|(_, path)| path).unwrap_or(D(0)), path: warm_result.map(|(_, path)| path).unwrap_or(D(0)),
}) }
} }
} }
/// Slam a cached call site. /// Slam a cached call site.
pub fn site_slam(ctx: &mut Context, site: &Site, sample: Noun) -> Result { pub fn site_slam(ctx: &mut Context, site: &Site, sample: Noun) -> Result {
let subject = T(&mut ctx.stack, &[site.battery, sample, site.context])?; let subject = T(&mut ctx.stack, &[site.battery, sample, site.context]);
if site.jet.is_some() { if site.jet.is_some() {
let jet = site.jet.unwrap(); let jet = site.jet.unwrap();
jet(ctx, subject) jet(ctx, subject)

View File

@ -1,11 +0,0 @@
use crate::{mem::NockStack, noun::Noun};
#[allow(non_snake_case)]
pub fn T<A: crate::noun::NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
crate::noun::T(allocator, tup).unwrap()
}
#[allow(non_snake_case)]
pub fn A(stack: &mut NockStack, atom: &ibig::UBig) -> Noun {
crate::jets::util::test::A(stack, atom).unwrap()
}

View File

@ -2,7 +2,7 @@ use crate::flog;
use crate::interpreter::Context; use crate::interpreter::Context;
use crate::jets::bits::util::rap; use crate::jets::bits::util::rap;
use crate::jets::form::util::scow; use crate::jets::form::util::scow;
use crate::mem::{AllocResult, NockStack}; use crate::mem::NockStack;
use crate::mug::met3_usize; use crate::mug::met3_usize;
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun}; use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun};
use either::Either::*; use either::Either::*;
@ -153,7 +153,7 @@ pub unsafe fn write_nock_trace(
continue; continue;
} }
let pc = path_to_cord(stack, (*trace_stack).path)?; let pc = path_to_cord(stack, (*trace_stack).path);
let pc_len = met3_usize(pc); let pc_len = met3_usize(pc);
let pc_bytes = &pc.as_bytes()[0..pc_len]; let pc_bytes = &pc.as_bytes()[0..pc_len];
let pc_str = match std::str::from_utf8(pc_bytes) { let pc_str = match std::str::from_utf8(pc_bytes) {
@ -185,7 +185,7 @@ pub unsafe fn write_nock_trace(
} }
// XX: Need Rust string interpolation helper that doesn't allocate // XX: Need Rust string interpolation helper that doesn't allocate
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> { pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
let mut cursor = path; let mut cursor = path;
let mut length = 0usize; let mut length = 0usize;
@ -218,7 +218,7 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
// reset cursor, then actually write the path // reset cursor, then actually write the path
cursor = path; cursor = path;
let mut idx = 0; let mut idx = 0;
let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length)? }; let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length) };
let slash = (b"/")[0]; let slash = (b"/")[0];
while let Ok(c) = cursor.as_cell() { while let Ok(c) = cursor.as_cell() {
@ -254,5 +254,5 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
cursor = c.tail(); cursor = c.tail();
} }
Ok(unsafe { deres.normalize_as_atom() }) unsafe { deres.normalize_as_atom() }
} }

View File

@ -1,4 +1,4 @@
use crate::mem::{AllocResult, NockStack, ALLOC, FRAME, STACK}; use crate::mem::{NockStack, ALLOC, FRAME, STACK};
use crate::noun::Noun; use crate::noun::Noun;
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers}; use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
use either::Either::*; use either::Either::*;
@ -20,22 +20,7 @@ macro_rules! assert_no_junior_pointers {
( $x:expr, $y:expr ) => {}; ( $x:expr, $y:expr ) => {};
} }
#[cfg(test)] pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
pub(crate) mod test {
use crate::mem::NockStack;
use crate::noun::Noun;
/// Tests only, not part of the actual implementation. Use this outside of #[cfg(test)] and I will sic the linter on you.
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
super::unifying_equality(stack, a, b).expect("OOM error in test::unifying_equality")
}
}
pub unsafe fn unifying_equality(
stack: &mut NockStack,
a: *mut Noun,
b: *mut Noun,
) -> AllocResult<bool> {
/* This version of unifying equality is not like that of vere. /* This version of unifying equality is not like that of vere.
* Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug * Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug
* equality) and then unifies the nouns at the top level if they are equal. * equality) and then unifies the nouns at the top level if they are equal.
@ -68,109 +53,108 @@ pub unsafe fn unifying_equality(
// If the nouns are already word-equal we have nothing to do // If the nouns are already word-equal we have nothing to do
if (*a).raw_equals(*b) { if (*a).raw_equals(*b) {
return Ok(true); return true;
}; };
// If the nouns have cached mugs which are disequal we have nothing to do // If the nouns have cached mugs which are disequal we have nothing to do
if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) { if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) {
if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) { if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) {
if a_mug != b_mug { if a_mug != b_mug {
return Ok(false); return false;
}; };
}; };
}; };
stack.with_frame(0, |stack| { stack.frame_push(0);
*(stack.push::<(*mut Noun, *mut Noun)>()?) = (a, b); *(stack.push::<(*mut Noun, *mut Noun)>()) = (a, b);
loop { loop {
if stack.stack_is_empty() { if stack.stack_is_empty() {
break; break;
};
let (x, y): (*mut Noun, *mut Noun) = *(stack.top());
if (*x).raw_equals(*y) {
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
};
if let (Ok(x_alloc), Ok(y_alloc)) = (
// equal direct atoms return true for raw_equals()
(*x).as_allocated(),
(*y).as_allocated(),
) {
if let (Some(x_mug), Some(y_mug)) = (x_alloc.get_cached_mug(), y_alloc.get_cached_mug())
{
if x_mug != y_mug {
break; // short-circuit, the mugs differ therefore the nouns must differ
}
}; };
let (x, y): (*mut Noun, *mut Noun) = *(stack.top()); match (x_alloc.as_either(), y_alloc.as_either()) {
if (*x).raw_equals(*y) { (Left(x_indirect), Left(y_indirect)) => {
stack.pop::<(*mut Noun, *mut Noun)>(); let x_as_ptr = x_indirect.to_raw_pointer();
continue; let y_as_ptr = y_indirect.to_raw_pointer();
}; if x_indirect.size() == y_indirect.size()
if let (Ok(x_alloc), Ok(y_alloc)) = ( && memcmp(
// equal direct atoms return true for raw_equals() x_indirect.data_pointer() as *const c_void,
(*x).as_allocated(), y_indirect.data_pointer() as *const c_void,
(*y).as_allocated(), x_indirect.size() << 3,
) { ) == 0
if let (Some(x_mug), Some(y_mug)) = {
(x_alloc.get_cached_mug(), y_alloc.get_cached_mug()) let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
{ if x_as_ptr == junior {
if x_mug != y_mug { *x = *y;
break; // short-circuit, the mugs differ therefore the nouns must differ
}
};
match (x_alloc.as_either(), y_alloc.as_either()) {
(Left(x_indirect), Left(y_indirect)) => {
let x_as_ptr = x_indirect.to_raw_pointer();
let y_as_ptr = y_indirect.to_raw_pointer();
if x_indirect.size() == y_indirect.size()
&& memcmp(
x_indirect.data_pointer() as *const c_void,
y_indirect.data_pointer() as *const c_void,
x_indirect.size() << 3,
) == 0
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else { } else {
break; *y = *x;
} }
} stack.pop::<(*mut Noun, *mut Noun)>();
(Right(x_cell), Right(y_cell)) => { continue;
let x_as_ptr = x_cell.to_raw_pointer() as *const u64; } else {
let y_as_ptr = y_cell.to_raw_pointer() as *const u64; break;
if x_cell.head().raw_equals(y_cell.head())
&& x_cell.tail().raw_equals(y_cell.tail())
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else {
/* THIS ISN'T AN INFINITE LOOP
* If we discover a disequality in either side, we will
* short-circuit the entire loop and reset the work stack.
*
* If both sides are equal, then we will discover pointer
* equality when we return and unify the cell.
*/
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
(x_cell.head_as_mut(), y_cell.head_as_mut());
continue;
}
}
(_, _) => {
break; // cells don't unify with atoms
} }
} }
} else { (Right(x_cell), Right(y_cell)) => {
break; // direct atom not raw equal, so short circuit let x_as_ptr = x_cell.to_raw_pointer() as *const u64;
let y_as_ptr = y_cell.to_raw_pointer() as *const u64;
if x_cell.head().raw_equals(y_cell.head())
&& x_cell.tail().raw_equals(y_cell.tail())
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else {
/* THIS ISN'T AN INFINITE LOOP
* If we discover a disequality in either side, we will
* short-circuit the entire loop and reset the work stack.
*
* If both sides are equal, then we will discover pointer
* equality when we return and unify the cell.
*/
*(stack.push::<(*mut Noun, *mut Noun)>()) =
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
*(stack.push::<(*mut Noun, *mut Noun)>()) =
(x_cell.head_as_mut(), y_cell.head_as_mut());
continue;
}
}
(_, _) => {
break; // cells don't unify with atoms
}
} }
} else {
break; // direct atom not raw equal, so short circuit
} }
}
stack.frame_pop();
assert_acyclic!(*a); assert_acyclic!(*a);
assert_acyclic!(*b); assert_acyclic!(*b);
assert_no_forwarding_pointers!(*a); assert_no_forwarding_pointers!(*a);
assert_no_forwarding_pointers!(*b); assert_no_forwarding_pointers!(*b);
assert_no_junior_pointers!(stack, *a); assert_no_junior_pointers!(stack, *a);
assert_no_junior_pointers!(stack, *b); assert_no_junior_pointers!(stack, *b);
Ok((*a).raw_equals(*b)) (*a).raw_equals(*b)
})?
} }
unsafe fn senior_pointer_first( unsafe fn senior_pointer_first(