alloc_would_oom, guarding alloc now

This commit is contained in:
Chris Allen 2024-10-28 18:21:13 -05:00
parent 80c719b5cb
commit 795ef7a0d1
36 changed files with 1682 additions and 1252 deletions

View File

@ -531,9 +531,9 @@ impl UBig {
// given at least 2 words of extra capacity. However, this supports UBigs which have already
// been expanded through other operations.
#[inline]
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1),
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
let ubig = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1)?,
(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), Large(buffer1)) => {
@ -543,21 +543,23 @@ impl UBig {
UBig::add_large_stack(stack, buffer1, &buffer0)
}
}
}
};
Ok(ubig)
}
/// Add two `Word`s.
#[inline]
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
let (res, overflow) = a.overflowing_add(b);
if overflow {
let mut buffer = Buffer::allocate_stack(stack, 2);
let ubig = if overflow {
let mut buffer = Buffer::allocate_stack(stack, 2)?;
buffer.push(res);
buffer.push(1);
buffer.into()
} else {
UBig::from_word(res)
}
};
Ok(ubig)
}
/// Add a large number to a `Word`.

View File

@ -21,14 +21,14 @@ use core::{
pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>);
impl Buffer {
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Buffer {
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Result<Buffer, S::AllocError> {
if num_words > Buffer::MAX_CAPACITY {
UBig::panic_number_too_large();
}
let capacity = Buffer::default_capacity(num_words);
unsafe {
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity));
Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity))?;
Ok(Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity))))
}
}
@ -44,9 +44,11 @@ impl Buffer {
)))
}
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
if num_words > self.capacity() {
self.reallocate_stack(stack, num_words);
self.reallocate_stack(stack, num_words)
} else {
Ok(())
}
}
@ -69,11 +71,12 @@ impl Buffer {
// }
}
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
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);
*self = new_buffer
*self = new_buffer;
Ok(())
}
/// Change capacity to store `num_words` plus some extra space for future growth.

View File

@ -31,18 +31,19 @@ impl Default for IBig {
impl UBig {
#[inline]
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
if bytes.len() <= WORD_BYTES {
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
let ubig = if bytes.len() <= WORD_BYTES {
// fast path
UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
} else {
UBig::from_le_bytes_large_stack(stack, bytes)
}
UBig::from_le_bytes_large_stack(stack, bytes)?
};
Ok(ubig)
}
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
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);
for chunk in &mut chunks {
buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
@ -50,7 +51,7 @@ impl UBig {
if !chunks.remainder().is_empty() {
buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
}
buffer.into()
Ok(buffer.into())
}
/// Construct from little-endian bytes.
@ -552,17 +553,18 @@ impl TryFrom<&IBig> for UBig {
impl UBig {
#[inline]
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> UBig
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> Result<UBig, S::AllocError>
where
T: PrimitiveUnsigned,
{
match x.try_into() {
let ubig = match x.try_into() {
Ok(w) => UBig::from_word(w),
Err(_) => {
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)
}
/// Convert an unsigned primitive to [UBig].

View File

@ -1279,68 +1279,71 @@ impl_div_ibig_signed!(isize);
impl UBig {
#[inline]
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
match (lhs.into_repr(), rhs.into_repr()) {
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_word(word0, word1),
(Small(_), Large(_)) => UBig::from_word(0),
(Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::div_large_stack(stack, buffer0, buffer1)
UBig::div_large_stack(stack, buffer0, buffer1)?
} else {
UBig::from_word(0)
}
}
}
};
Ok(ubig_tuple)
}
#[inline]
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
match (lhs.into_repr(), rhs.into_repr()) {
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::rem_word(word0, word1),
(Small(word0), Large(_)) => UBig::from_word(word0),
(Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::rem_large_stack(stack, buffer0, buffer1)
UBig::rem_large_stack(stack, buffer0, buffer1)?
} else {
buffer0.into()
}
}
}
};
Ok(ubig_tuple)
}
#[inline]
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> (UBig, UBig) {
match (lhs.into_repr(), rhs.into_repr()) {
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<(UBig, UBig), S::AllocError> {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1),
(Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)),
(Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::div_rem_large_stack(stack, buffer0, buffer1)
UBig::div_rem_large_stack(stack, buffer0, buffer1)?
} else {
(UBig::from_word(0), buffer0.into())
}
}
}
};
Ok(ubig_tuple)
}
/// `lhs / rhs`
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);
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
lhs.erase_front(rhs.len());
lhs.into()
Ok(lhs.into())
}
/// `lhs % rhs`
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);
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0);
rhs.into()
Ok(rhs.into())
}
/// `(lhs / rhs, lhs % rhs)`
@ -1348,33 +1351,33 @@ impl UBig {
stack: &mut S,
mut lhs: Buffer,
mut rhs: Buffer,
) -> (UBig, UBig) {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
) -> Result<(UBig, UBig), S::AllocError> {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0);
lhs.erase_front(n);
(lhs.into(), rhs.into())
Ok((lhs.into(), rhs.into()))
}
/// lhs = (lhs / rhs, lhs % rhs)
///
/// Returns shift.
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> u32 {
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> Result<u32, S::AllocError> {
let (shift, fast_div_rhs_top) = div::normalize_large(rhs);
let lhs_carry = shift::shl_in_place(lhs, shift);
if lhs_carry != 0 {
lhs.push_may_reallocate_stack(stack, lhs_carry);
}
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 overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory);
if overflow {
lhs.push_may_reallocate(1);
}
shift
Ok(shift)
}
/// `lhs / rhs`

View File

@ -10,7 +10,10 @@ pub(crate) struct MemoryAllocation {
}
pub trait Stack: Sized {
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64;
// type AllocError: Debug;
// no-std bites me in the keister again
type AllocError;
unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<*mut u64, Self::AllocError>;
}
/// Chunk of memory.
@ -24,7 +27,7 @@ pub(crate) struct Memory<'a> {
}
impl MemoryAllocation {
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> MemoryAllocation {
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> Result<MemoryAllocation, S::AllocError> {
let start = if layout.size() == 0 {
// We should use layout.dangling(), but that is unstable.
layout.align() as *mut u8
@ -32,14 +35,17 @@ impl MemoryAllocation {
panic_out_of_memory()
} else {
// Safe because size is non-zero.
let ptr = unsafe { stack.alloc_layout(layout) as *mut u8 };
let ptr = unsafe {
let ep = stack.alloc_layout(layout)?;
ep as *mut u8
};
if ptr.is_null() {
panic_out_of_memory();
}
ptr
};
MemoryAllocation { layout, start }
Ok(MemoryAllocation { layout, start })
}
/// Allocate memory.

View File

@ -300,17 +300,18 @@ impl_mul_ibig_primitive!(isize);
impl UBig {
#[inline]
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1),
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
let res = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1)?,
(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), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1),
}
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1)?,
};
Ok(res)
}
#[inline]
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b))
}
@ -328,23 +329,23 @@ impl UBig {
}
}
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> UBig {
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> Result<UBig, S::AllocError> {
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
// This may be 1 too large.
const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1);
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);
let mut allocation = MemoryAllocation::new_stack(
stack,
mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())),
);
)?;
let mut memory = allocation.memory();
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
assert!(overflow == 0);
buffer.into()
Ok(buffer.into())
}
/// Multiply two `Word`s.

View File

@ -1,5 +1,5 @@
use crate::interpreter::Context;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::noun::{Atom, IndirectAtom};
use std::fmt::Arguments;
use std::io::{Result, Write};
@ -14,26 +14,27 @@ struct NockWriter<'s, 'b> {
const INITIAL_CAPACITY_BYTES: usize = 256;
impl<'s, 'b> NockWriter<'s, 'b> {
unsafe fn new(stack: &'s mut NockStack) -> Self {
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES);
NockWriter {
unsafe fn new(stack: &'s mut NockStack) -> AllocResult<Self> {
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES)?;
Ok(NockWriter {
stack,
buffer,
indirect,
cursor: 0,
}
})
}
unsafe fn finalize(mut self) -> Atom {
self.indirect.normalize_as_atom()
}
unsafe fn expand(&mut self) {
unsafe fn expand(&mut self) -> AllocResult<()> {
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);
self.buffer = new_buffer;
self.indirect = new_indirect;
Ok(())
}
}
@ -54,7 +55,7 @@ impl Write for NockWriter<'_, '_> {
}
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)?;
Ok(unsafe { nw.finalize() })
}

View File

@ -1,4 +1,4 @@
use crate::mem::{NockStack, Preserve};
use crate::mem::{AllocResult, NockStack, Preserve};
use crate::mug::mug_u32;
use crate::noun::Noun;
use crate::persist::{pma_contains, Persist};
@ -61,12 +61,12 @@ impl<T: Copy> MutStem<T> {
pub struct MutHamt<T: Copy>(*mut MutStem<T>);
impl<T: Copy> MutHamt<T> {
pub fn new(stack: &mut NockStack) -> MutHamt<T> {
pub fn new(stack: &mut NockStack) -> AllocResult<MutHamt<T>> {
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).typemap = 0;
MutHamt(new_stem)
Ok(MutHamt(new_stem))
}
}
@ -97,7 +97,7 @@ impl<T: Copy> MutHamt<T> {
}
}
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) {
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> {
let mut stem = self.0;
let mut mug = mug_u32(stack, *n);
let mut depth = 0u8;
@ -107,7 +107,7 @@ impl<T: Copy> MutHamt<T> {
mug >>= 5;
match (*stem).entry(chunk) {
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);
(*stem).bitmap |= chunk_to_bit(chunk);
(*stem).typemap &= !chunk_to_bit(chunk);
@ -132,7 +132,7 @@ impl<T: Copy> MutHamt<T> {
}
}
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);
*new_leaf_buffer.add(leaf.len) = (*n, t);
(*stem).buffer[chunk as usize] = MutEntry {
@ -144,7 +144,7 @@ impl<T: Copy> MutHamt<T> {
break;
} else {
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_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f;
(*new_stem).bitmap = chunk_to_bit(leaf_chunk);
@ -160,6 +160,7 @@ impl<T: Copy> MutHamt<T> {
}
}
}
Ok(())
}
}
@ -284,15 +285,15 @@ impl<T: Copy + Preserve> Hamt<T> {
unsafe { (*self.0).bitmap == 0 }
}
// Make a new, empty HAMT
pub fn new(stack: &mut NockStack) -> Self {
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
unsafe {
let stem_ptr = stack.struct_alloc::<Stem<T>>(1);
let stem_ptr = stack.struct_alloc::<Stem<T>>(1)?;
*stem_ptr = Stem {
bitmap: 0,
typemap: 0,
buffer: null_mut(),
};
Hamt(stem_ptr)
Ok(Hamt(stem_ptr))
}
}
@ -336,11 +337,11 @@ impl<T: Copy + Preserve> Hamt<T> {
// XX a delete function requires a stack, do we need one?
/// 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) -> Hamt<T> {
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<Hamt<T>> {
let mut mug = mug_u32(stack, *n);
let mut depth = 0u8;
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;
unsafe {
'insert: loop {
@ -349,10 +350,10 @@ impl<T: Copy + Preserve> Hamt<T> {
match stem.entry(chunk) {
// No entry found at mug chunk index; add Leaf to current Stem
None => {
let new_leaf_buffer = stack.struct_alloc(1);
let new_leaf_buffer = stack.struct_alloc(1)?;
*new_leaf_buffer = (*n, t);
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 {
copy_nonoverlapping(stem.buffer, new_buffer, split);
}
@ -374,11 +375,11 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap & !chunk_to_bit(chunk),
buffer: new_buffer,
};
break Hamt(stem_ret);
break Ok(Hamt(stem_ret));
}
// Stem found at mug chunk index; insert into found Stem
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());
*dest = Stem {
bitmap: stem.bitmap,
@ -395,10 +396,10 @@ impl<T: Copy + Preserve> Hamt<T> {
// Override existing value for key, if one exists
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
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);
(*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());
*new_buffer.add(idx) = Entry {
leaf: Leaf {
@ -411,16 +412,16 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap,
buffer: new_buffer,
};
break 'insert Hamt(stem_ret);
break 'insert Ok(Hamt(stem_ret));
}
}
// 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
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);
*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());
*new_buffer.add(idx) = Entry {
leaf: Leaf {
@ -433,7 +434,7 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap,
buffer: new_buffer,
};
break 'insert Hamt(stem_ret);
break 'insert Ok(Hamt(stem_ret));
// 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
// be making a linked list of pairs. Turn the Leaf into a Stem and insert
@ -443,7 +444,7 @@ impl<T: Copy + Preserve> Hamt<T> {
// Make a fake node pointing to the old leaf and "insert into it" the
// next time around
assert!(leaf.len == 1);
let fake_buffer = stack.struct_alloc(1);
let fake_buffer = stack.struct_alloc(1)?;
*fake_buffer = Entry { leaf };
// Get the mug chunk for the Noun at the *next* level so that we can
// build a fake stem for it
@ -454,7 +455,7 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: 0,
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());
*dest = Stem {
bitmap: stem.bitmap,
@ -906,10 +907,10 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack);
hamt = hamt.insert(&mut stack, &mut D(0), D(1));
hamt = hamt.insert(&mut stack, &mut D(2), D(3));
hamt = hamt.insert(&mut stack, &mut D(4), D(5));
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
hamt = hamt.insert(&mut stack, &mut D(0), D(1)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(2), D(3)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(4), D(5)).unwrap();
let mut iter = hamt.iter();
let three = cdr(&mut iter);
let one = cdr(&mut iter);
@ -927,10 +928,10 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut hs = HashSet::new();
for n in 0..100 {
hamt = hamt.insert(&mut stack, &mut D(n), D(n));
hamt = hamt.insert(&mut stack, &mut D(n), D(n)).unwrap();
hs.insert((n, n));
}
let mut iter = hamt.iter();
@ -945,16 +946,16 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut n = D(0);
let t = D(1);
hamt = hamt.insert(&mut stack, &mut n, t);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let lu = hamt.lookup(&mut stack, &mut n);
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 1);
let mut n = D(2);
let t = D(3);
hamt = hamt.insert(&mut stack, &mut n, t);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let lu = hamt.lookup(&mut stack, &mut D(2));
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 3);
@ -965,22 +966,22 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
// 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut n = D(0);
let t = D(0);
hamt = hamt.insert(&mut stack, &mut n, t);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let mut n = D(87699370);
let t = D(87699370);
hamt = hamt.insert(&mut stack, &mut n, t);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let mut n = D(317365951);
let t = D(317365951);
hamt = hamt.insert(&mut stack, &mut n, t);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let lu = hamt.lookup(&mut stack, &mut D(0));
let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() };
@ -1000,13 +1001,13 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
// 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut hs = HashSet::new();
for x in &[0, 87699370, 317365951] {
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x));
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)).unwrap();
hs.insert((*x, *x));
}
for x in hamt.iter() {

View File

@ -8,6 +8,7 @@ use crate::jets::cold::Cold;
use crate::jets::hot::Hot;
use crate::jets::warm::Warm;
use crate::jets::JetErr;
use crate::mem::AllocResult;
use crate::mem::NockStack;
use crate::mem::Preserve;
use crate::noun;
@ -266,10 +267,10 @@ pub trait Slogger {
* pri = debug priority
* tank = output as tank
*/
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun);
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()>;
/** Send %flog, raw debug output. */
fn flog(&mut self, stack: &mut NockStack, cord: Noun);
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()>;
}
impl<T: Slogger + DerefMut + Unpin + Sized> Slogger for Pin<&mut T>
@ -278,12 +279,14 @@ where
{
// + Unpin
// type SlogTarget = T::Target;
fn flog(&mut self, stack: &mut NockStack, cord: Noun) {
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
(*self).deref_mut().flog(stack, cord);
Ok(())
}
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
(**self).slog(stack, pri, tank);
Ok(())
}
}
@ -351,12 +354,21 @@ pub enum Mote {
Meme = tas!(b"meme") as isize,
}
#[derive(Clone, Copy, Debug)]
/// Interpreter errors, reused in [`JetErr::Fail`]
#[derive(Clone, Debug)]
pub enum Error {
ScryBlocked(Noun), // path
ScryCrashed(Noun), // trace
Deterministic(Mote, Noun), // mote, trace
NonDeterministic(Mote, Noun), // mote, trace
/// Allocation failed
AllocationError(crate::mem::AllocationError, Noun),
}
impl From<crate::mem::AllocationError> for Error {
fn from(err: crate::mem::AllocationError) -> Self {
Error::AllocationError(err, D(0))
}
}
impl Preserve for Error {
@ -366,6 +378,7 @@ impl Preserve for Error {
Error::ScryCrashed(ref mut trace) => trace.preserve(stack),
Error::Deterministic(_, ref mut trace) => trace.preserve(stack),
Error::NonDeterministic(_, ref mut trace) => trace.preserve(stack),
Error::AllocationError(_, ref mut trace) => trace.preserve(stack),
}
}
@ -375,6 +388,7 @@ impl Preserve for Error {
Error::ScryCrashed(ref trace) => trace.assert_in_stack(stack),
Error::Deterministic(_, ref trace) => trace.assert_in_stack(stack),
Error::NonDeterministic(_, ref trace) => trace.assert_in_stack(stack),
Error::AllocationError(_, ref trace) => trace.assert_in_stack(stack),
}
}
}
@ -391,11 +405,11 @@ impl From<cold::Error> for Error {
}
}
pub type Result = result::Result<Noun, Error>;
pub type Result<T> = result::Result<T, Error>;
const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0)));
const BAIL_FAIL: Result = Err(Error::NonDeterministic(Mote::Fail, D(0)));
const BAIL_INTR: Result = Err(Error::NonDeterministic(Mote::Intr, D(0)));
const BAIL_EXIT: Result<Noun> = Err(Error::Deterministic(Mote::Exit, D(0)));
const BAIL_FAIL: Result<Noun> = Err(Error::NonDeterministic(Mote::Fail, D(0)));
const BAIL_INTR: Result<Noun> = Err(Error::NonDeterministic(Mote::Intr, D(0)));
#[allow(unused_variables)]
fn debug_assertions(stack: &mut NockStack, noun: Noun) {
@ -405,7 +419,7 @@ fn debug_assertions(stack: &mut NockStack, noun: Noun) {
}
/** Interpret nock */
pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result {
pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result<Noun> {
let terminator = Arc::clone(&TERMINATOR);
let orig_subject = subject; // for debugging
let snapshot = context.save();
@ -449,7 +463,7 @@ pub fn interpret(context: &mut Context, subject: Noun, formula: Noun) -> Result
}
}
unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun, orig_subject: Noun, mut subject: Noun, mut res: Noun) -> Result {
unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun, orig_subject: Noun, mut subject: Noun, mut res: Noun) -> Result<Noun> {
push_formula(&mut context.stack, formula, true)?;
loop {
let work: NockWork = *context.stack.top();
@ -504,7 +518,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
}
TodoCons::Cons => {
let stack = &mut context.stack;
res = T(stack, &[cons.head, res]);
res = T(stack, &[cons.head, res])?;
stack.pop::<NockWork>();
}
},
@ -589,7 +603,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
}
Todo4::Increment => {
if let Ok(atom) = res.as_atom() {
res = inc(&mut context.stack, atom).as_noun();
res = inc(&mut context.stack, atom)?.as_noun();
context.stack.pop::<NockWork>();
} else {
// Cannot increment (Nock 4) a cell
@ -678,14 +692,14 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
Todo8::ComputeResult => {
let stack = &mut context.stack;
if pins.tail {
subject = T(stack, &[res, subject]);
subject = T(stack, &[res, subject])?;
stack.pop::<NockWork>();
push_formula(stack, pins.formula, true)?;
} else {
pins.todo = Todo8::RestoreSubject;
pins.pin = subject;
*stack.top() = NockWork::Work8(pins);
subject = T(stack, &[res, subject]);
subject = T(stack, &[res, subject])?;
push_formula(stack, pins.formula, false)?;
}
}
@ -803,7 +817,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
diet.axis.as_bitslice(),
res,
diet.tree,
);
)?;
context.stack.pop::<NockWork>();
}
}
@ -864,7 +878,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
Some(dint.hint),
dint.body,
res,
) {
)? {
res = found;
}
context.stack.pop::<NockWork>();
@ -897,7 +911,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
Todo11S::Done => {
if let Some(found) = hint::match_post_nock(
context, subject, sint.tag, None, sint.body, res,
) {
)? {
res = found;
}
context.stack.pop::<NockWork>();
@ -923,7 +937,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
let scry_stack = context.scry_stack;
let scry_handler = cell.head();
let scry_gate = scry_handler.as_cell()?;
let payload = T(&mut context.stack, &[scry.reff, res]);
let payload = T(&mut context.stack, &[scry.reff, res])?;
let scry_core = T(
&mut context.stack,
&[
@ -931,9 +945,9 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
payload,
scry_gate.tail().as_cell()?.tail(),
],
);
)?;
let scry_form =
T(&mut context.stack, &[D(9), D(2), D(1), scry_core]);
T(&mut context.stack, &[D(9), D(2), D(1), scry_core])?;
context.scry_stack = cell.tail();
// Alternately, we could use scry_core as the subject and [9 2 0 1] as
@ -959,7 +973,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
scry.reff,
scry.path,
],
);
)?;
mean_push(stack, hunk);
break Err(Error::ScryCrashed(D(0)));
}
@ -982,6 +996,9 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
Error::ScryBlocked(_) => {
break BAIL_FAIL;
}
Error::AllocationError(_, _) => {
break Err(error);
},
},
}
} else {
@ -993,7 +1010,7 @@ unsafe fn work(terminator: Arc<AtomicBool>, context: &mut Context, formula: Noun
};
}
}
fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result {
fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<Noun> {
unsafe {
if let Ok(formula_cell) = formula.as_cell() {
// Formula
@ -1228,8 +1245,10 @@ fn exit(
let h = *(stack.local_noun_pointer(0));
// XX: Small chance of clobbering something important after OOM?
// XX: what if we OOM while making a stack trace
T(stack, &[h, t])
T(stack, &[h, t]).expect("serf: failed to create trace, allocation error")
}
// TODO: What do we do with an allocation error here?
Error::AllocationError(allocation_error, noun) => todo!(),
};
while stack.get_frame_pointer() != virtual_frame {
@ -1242,6 +1261,7 @@ fn exit(
Error::NonDeterministic(mote, _) => Error::NonDeterministic(mote, preserve),
Error::ScryCrashed(_) => Error::ScryCrashed(preserve),
Error::ScryBlocked(_) => error,
Error::AllocationError(_, _) => error,
}
}
}
@ -1259,11 +1279,12 @@ fn mean_frame_push(stack: &mut NockStack, slots: usize) {
/** Push onto the mean stack.
*/
fn mean_push(stack: &mut NockStack, noun: Noun) {
fn mean_push(stack: &mut NockStack, noun: Noun) -> AllocResult<()>{
unsafe {
let cur_trace = *(stack.local_noun_pointer(0));
let new_trace = T(stack, &[noun, cur_trace]);
let new_trace = T(stack, &[noun, cur_trace])?;
*(stack.local_noun_pointer(0)) = new_trace;
Ok(())
}
}
@ -1283,7 +1304,7 @@ fn edit(
edit_axis: &BitSlice<u64, Lsb0>,
patch: Noun,
mut tree: Noun,
) -> Noun {
) -> AllocResult<Noun> {
let mut res = patch;
let mut dest: *mut Noun = &mut res;
let mut cursor = edit_axis
@ -1300,7 +1321,7 @@ fn edit(
cursor -= 1;
if edit_axis[cursor] {
unsafe {
let (cell, cellmem) = Cell::new_raw_mut(stack);
let (cell, cellmem) = Cell::new_raw_mut(stack)?;
*dest = cell.as_noun();
(*cellmem).head = tree_cell.head();
dest = &mut ((*cellmem).tail);
@ -1308,7 +1329,7 @@ fn edit(
tree = tree_cell.tail();
} else {
unsafe {
let (cell, cellmem) = Cell::new_raw_mut(stack);
let (cell, cellmem) = Cell::new_raw_mut(stack)?;
*dest = cell.as_noun();
(*cellmem).tail = tree_cell.tail();
dest = &mut ((*cellmem).head);
@ -1319,10 +1340,10 @@ fn edit(
panic!("Invalid axis for edit");
};
}
res
Ok(res)
}
pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom {
pub fn inc(stack: &mut NockStack, atom: Atom) -> AllocResult<Atom> {
match atom.as_either() {
Left(direct) => Atom::new(stack, direct.data() + 1),
Right(indirect) => {
@ -1331,17 +1352,17 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom {
None => {
// all ones, make an indirect one word bigger
let (new_indirect, new_slice) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size() + 1) };
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size() + 1)? };
new_slice.set(indirect_slice.len(), true);
new_indirect.as_atom()
Ok(new_indirect.as_atom())
}
Some(first_zero) => {
let (new_indirect, new_slice) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size()) };
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, indirect.size())? };
new_slice.set(first_zero, true);
new_slice[first_zero + 1..]
.copy_from_bitslice(&indirect_slice[first_zero + 1..]);
new_indirect.as_atom()
Ok(new_indirect.as_atom())
}
}
}
@ -1349,16 +1370,17 @@ pub fn inc(stack: &mut NockStack, atom: Atom) -> Atom {
}
/// Push onto the tracing stack
fn append_trace(stack: &mut NockStack, path: Noun) {
fn append_trace(stack: &mut NockStack, path: Noun) -> AllocResult<()> {
unsafe {
let trace_stack = *(stack.local_noun_pointer(1) as *const *const TraceStack);
let new_trace_entry = stack.struct_alloc(1);
let new_trace_entry = stack.struct_alloc(1)?;
*new_trace_entry = TraceStack {
path,
start: Instant::now(),
next: trace_stack,
};
*(stack.local_noun_pointer(1) as *mut *const TraceStack) = new_trace_entry;
Ok(())
}
}
@ -1404,7 +1426,7 @@ mod hint {
tag: Atom,
hint: Noun,
body: Noun,
) -> Option<Result> {
) -> Option<Result<Noun>> {
// XX: handle IndirectAtom tags
match tag.direct()?.data() {
tas!(b"sham") => {
@ -1476,7 +1498,11 @@ mod hint {
}
tas!(b"memo") => {
let stack = &mut context.stack;
let mut key = Cell::new(stack, subject, body).as_noun();
let key = match Cell::new(stack, subject, body) {
Ok(key) => key,
Err(_) => return Some(BAIL_EXIT),
};
let mut key = key.as_noun();
context.cache.lookup(stack, &mut key).map(Ok)
}
_ => None,
@ -1490,7 +1516,7 @@ mod hint {
tag: Atom,
hint: Option<(Noun, Noun)>,
_body: Noun,
) -> Option<Result> {
) -> Option<Result<Noun>> {
// XX: handle IndirectAtom tags
match tag.direct()?.data() {
tas!(b"dont") => {
@ -1521,7 +1547,10 @@ mod hint {
let stack = &mut context.stack;
let (_form, clue) = hint?;
let noun = T(stack, &[tag.as_noun(), clue]);
let noun = match T(stack, &[tag.as_noun(), clue]) {
Ok(noun) => noun,
Err(_) => return Some(BAIL_EXIT),
};
mean_push(stack, noun);
None
}
@ -1532,7 +1561,10 @@ mod hint {
// recursively work down frames to get the stack trace all
// the way to the root.
let mean = unsafe { *(context.stack.local_noun_pointer(0)) };
let tone = Cell::new(&mut context.stack, D(2), mean);
let tone = match Cell::new(&mut context.stack, D(2), mean) {
Ok(tone) => tone,
Err(_) => return Some(BAIL_EXIT),
};
match mook(context, tone, true) {
Ok(toon) => {
@ -1581,18 +1613,27 @@ mod hint {
hint: Option<Noun>,
body: Noun,
res: Noun,
) -> Option<Noun> {
) -> Result<Option<Noun>> {
// XX: handle IndirectAtom tags
// Yes it has to be a nested closure: Option<Result> -> Result<Option>
let mut f = move || {
let stack = &mut context.stack;
let slogger = &mut context.slogger;
let cold = &mut context.cold;
let hot = &context.hot;
let cache = &mut context.cache;
// XX: handle IndirectAtom tags
match tag.direct()?.data() {
tas!(b"memo") => {
let mut key = Cell::new(stack, subject, body).as_noun();
context.cache = cache.insert(stack, &mut key, res);
let key = match Cell::new(stack, subject, body) {
Ok(key) => key,
Err(err) => return Some(Err(err)),
};
let mut key = key.as_noun();
let cache_insert = cache.insert(stack, &mut key, res);
match cache_insert {
Ok(_) => (),
Err(cache_error) => return Some(Err(cache_error)),
};
}
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
mean_pop(stack);
@ -1633,6 +1674,10 @@ mod hint {
let tape = tape(
stack, "serf: cold: register: invalid root parent axis",
);
let tape = match tape {
Ok(tape) => tape,
Err(err) => return Some(Err(err)),
};
slog_leaf(stack, slogger, tape);
Ok(false)
}
@ -1642,7 +1687,12 @@ mod hint {
};
match cold_res {
Ok(true) => context.warm = Warm::init(stack, cold, hot),
Ok(true) => context.warm = match Warm::init(stack, cold, hot) {
Ok(warm) => warm,
Err(err) => {
return Some(Err(err));
}
},
Err(cold::Error::NoParent) => {
flog!(context, "serf: cold: register: could not match parent battery at given axis: {} {}", chum, parent_formula_ax);
}
@ -1657,14 +1707,16 @@ mod hint {
}
}
_ => {}
}
};
None
};
f().transpose().map_err(From::from)
}
fn slog_leaf(stack: &mut NockStack, slogger: &mut Pin<Box<dyn Slogger + Unpin>>, tape: Noun) {
let tank = T(stack, &[LEAF, tape]);
fn slog_leaf(stack: &mut NockStack, slogger: &mut Pin<Box<dyn Slogger + Unpin>>, tape: Noun) -> AllocResult<()> {
let tank = T(stack, &[LEAF, tape])?;
slogger.slog(stack, 0u64, tank);
Ok(())
}
}

View File

@ -42,19 +42,25 @@ use sword_macros::tas;
crate::gdb!();
/// Return Err if the computation crashed or should punt to Nock
pub type Result = std::result::Result<Noun, JetErr>;
pub type Jet = fn(&mut Context, Noun) -> Result;
pub type Result<T> = std::result::Result<T, JetErr>;
pub type Jet = fn(&mut Context, Noun) -> Result<Noun>;
/**
* Only return a deterministic error if the Nock would have deterministically
* crashed.
*/
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub enum JetErr {
Punt, // Retry with the raw nock
Fail(Error), // Error; do not retry
}
impl From<crate::mem::AllocationError> for JetErr {
fn from(err: crate::mem::AllocationError) -> Self {
JetErr::Fail(Error::AllocationError(err, D(0)))
}
}
impl Preserve for JetErr {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self {
@ -232,7 +238,7 @@ pub mod util {
bits_to_word(checked_left_shift(bloq, step)?)
}
pub fn slot(noun: Noun, axis: u64) -> Result {
pub fn slot(noun: Noun, axis: u64) -> Result<Noun> {
noun.slot(axis).map_err(|_e| BAIL_EXIT)
}
@ -288,7 +294,7 @@ pub mod util {
}
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)
}
@ -296,7 +302,7 @@ pub mod util {
let core: Noun = T(
&mut context.stack,
&[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()],
);
)?;
kick(context, core, D(2))
}
@ -304,7 +310,7 @@ pub mod util {
use super::*;
use crate::hamt::Hamt;
use crate::interpreter::Slogger;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::noun::{Atom, Noun, D, T};
use crate::unifying_equality::unifying_equality;
use assert_no_alloc::assert_no_alloc;
@ -313,24 +319,26 @@ pub mod util {
struct TestSlogger {}
impl Slogger for TestSlogger {
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) {
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) -> AllocResult<()> {
eprintln!("Jet slogged.");
Ok(())
}
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) {
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) -> AllocResult<()> {
eprintln!("Jet flogged.");
Ok(())
}
}
pub fn init_context() -> Context {
pub fn init_context() -> Result<Context> {
let mut stack = NockStack::new(8 << 10 << 10, 0);
let cold = Cold::new(&mut stack);
let warm = Warm::new(&mut stack);
let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
let cache = Hamt::<Noun>::new(&mut stack);
let cold = Cold::new(&mut stack)?;
let warm = Warm::new(&mut stack)?;
let hot = Hot::init(&mut stack, URBIT_HOT_STATE)?;
let cache = Hamt::<Noun>::new(&mut stack)?;
let slogger = std::boxed::Box::pin(TestSlogger {});
Context {
Ok(Context {
stack,
slogger,
cold,
@ -339,12 +347,12 @@ pub mod util {
cache,
scry_stack: D(0),
trace_info: None,
}
})
}
#[allow(non_snake_case)]
pub fn A(stack: &mut NockStack, ubig: &UBig) -> Noun {
Atom::from_ubig(stack, ubig).as_noun()
pub fn A(stack: &mut NockStack, ubig: &UBig) -> AllocResult<Noun> {
Ok(Atom::from_ubig(stack, ubig)?.as_noun())
}
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
@ -352,28 +360,29 @@ pub mod util {
assert!(eq, "got: {}, need: {}", a, b);
}
pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) -> AllocResult<()> {
assert_jet_door(context, jet, sam, D(0), res)
}
pub fn assert_jet_door(context: &mut Context, jet: Jet, sam: Noun, pay: Noun, res: Noun) {
let sam = T(&mut context.stack, &[D(0), sam, pay]);
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());
assert_noun_eq(&mut context.stack, jet_res, res);
Ok(())
}
pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
let res = A(&mut context.stack, &res);
assert_jet(context, jet, sam, res);
pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) -> AllocResult<()> {
let res = A(&mut context.stack, &res)?;
assert_jet(context, jet, sam, res)
}
pub fn assert_nary_jet_ubig(context: &mut Context, jet: Jet, sam: &[Noun], res: UBig) {
let sam = T(&mut context.stack, sam);
assert_jet_ubig(context, jet, sam, res);
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) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
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);
assert!(
jet_res.is_err(),
@ -383,10 +392,10 @@ pub mod util {
&jet_res
);
let jet_err = jet_res.unwrap_err();
match (jet_err, err) {
match (jet_err.clone(), err.clone()) {
(JetErr::Punt, JetErr::Punt) => {}
(JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => {
match (actual_err, expected_err) {
match (actual_err.clone(), expected_err.clone()) {
(Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected))
| (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected))
| (
@ -415,11 +424,12 @@ pub mod util {
sam, err, jet_err
);
}
}
};
Ok(())
}
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)]);
let sam = T(&mut context.stack, &[D(0), sam, D(0)]).unwrap();
let res = assert_no_alloc(|| jet(context, sam).unwrap());
assert!(res.is_atom(), "jet result not atom");
let res_siz = res.atom().unwrap().size();
@ -443,7 +453,7 @@ pub mod util {
res: Noun,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
let sam = T(&mut context.stack, &sam).unwrap();
assert_jet(context, jet, sam, res);
}
@ -454,7 +464,7 @@ pub mod util {
err: JetErr,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
let sam = T(&mut context.stack, &sam).unwrap();
assert_jet_err(context, jet, sam, err);
}
@ -465,7 +475,7 @@ pub mod util {
siz: usize,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
let sam = T(&mut context.stack, &sam).unwrap();
assert_jet_size(context, jet, sam, siz)
}
}

View File

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

View File

@ -1,5 +1,5 @@
use crate::hamt::Hamt;
use crate::mem::{self, NockStack, Preserve};
use crate::mem::{self, AllocResult, NockStack, Preserve};
use crate::noun::{self, IndirectAtom, NounAllocator};
use crate::noun::{Atom, DirectAtom, Noun, Slots, D, T};
use crate::persist::{pma_contains, Persist};
@ -8,9 +8,14 @@ use std::mem::size_of;
use std::ptr::copy_nonoverlapping;
use std::ptr::null_mut;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("No parent found")]
NoParent,
#[error("Bad nock")]
BadNock,
#[error("Allocation Error")]
AllocationError(#[from] crate::mem::AllocationError),
}
impl From<noun::Error> for Error {
@ -310,14 +315,14 @@ impl BatteriesList {
// NounList is a linked list of paths (path = list of nested core names) with an
// iterator; used to store all possible registered paths for a core
#[derive(Copy, Clone)]
pub struct NounList(*mut NounListMem);
pub struct NounList(pub(crate) *mut NounListMem);
const NOUN_LIST_NIL: NounList = NounList(null_mut());
pub const NOUN_LIST_NIL: NounList = NounList(null_mut());
#[derive(Copy, Clone)]
struct NounListMem {
element: Noun,
next: NounList,
pub(crate) struct NounListMem {
pub(crate) element: Noun,
pub(crate) next: NounList,
}
impl Persist for NounList {
@ -513,18 +518,18 @@ impl Cold {
}
}
pub fn new(stack: &mut NockStack) -> Self {
let battery_to_paths = Hamt::new(stack);
let root_to_paths = Hamt::new(stack);
let path_to_batteries = Hamt::new(stack);
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
let battery_to_paths = Hamt::new(stack)?;
let root_to_paths = Hamt::new(stack)?;
let path_to_batteries = Hamt::new(stack)?;
unsafe {
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1);
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1)?;
*cold_mem_ptr = ColdMem {
battery_to_paths,
root_to_paths,
path_to_batteries,
};
Cold(cold_mem_ptr)
Ok(Cold(cold_mem_ptr))
}
}
@ -533,18 +538,18 @@ impl Cold {
battery_to_paths: Vec<(Noun, NounList)>,
root_to_paths: Vec<(Noun, NounList)>,
path_to_batteries: Vec<(Noun, BatteriesList)>,
) -> Self {
let battery_to_paths = hamt_from_vec(stack, battery_to_paths);
let root_to_paths = hamt_from_vec(stack, root_to_paths);
let path_to_batteries = hamt_from_vec(stack, path_to_batteries);
) -> AllocResult<Self> {
let battery_to_paths = hamt_from_vec(stack, battery_to_paths)?;
let root_to_paths = hamt_from_vec(stack, root_to_paths)?;
let path_to_batteries = hamt_from_vec(stack, path_to_batteries)?;
unsafe {
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1);
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1)?;
*cold_mem_ptr = ColdMem {
battery_to_paths,
root_to_paths,
path_to_batteries,
};
Cold(cold_mem_ptr)
Ok(Cold(cold_mem_ptr))
}
}
@ -592,7 +597,7 @@ impl Cold {
// Are we registering a root?
if let Ok(parent_axis_direct) = parent_axis.as_direct() {
if parent_axis_direct.data() == 0 {
let mut root_path = T(stack, &[chum, D(0)]);
let mut root_path = T(stack, &[chum, D(0)])?;
if let Some(paths) = (*(self.0)).root_to_paths.lookup(stack, &mut core) {
for a_path in paths {
if unifying_equality(stack, &mut root_path, a_path) {
@ -600,7 +605,7 @@ impl Cold {
}
}
}
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1);
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1)?;
*batteries_mem_ptr = BatteriesMem {
battery: core,
parent_axis: DirectAtom::new_unchecked(0).as_atom(),
@ -612,7 +617,7 @@ impl Cold {
.lookup(stack, &mut root_path)
.unwrap_or(BATTERIES_LIST_NIL);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?;
*batteries_list_mem_ptr = BatteriesListMem {
batteries: Batteries(batteries_mem_ptr),
next: current_batteries_list,
@ -623,25 +628,25 @@ impl Cold {
.lookup(stack, &mut core)
.unwrap_or(NOUN_LIST_NIL);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?;
*paths_list_mem_ptr = NounListMem {
element: root_path,
next: current_paths_list,
};
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1);
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1)?;
*cold_mem_ptr = ColdMem {
battery_to_paths: (*(self.0)).battery_to_paths,
root_to_paths: (*(self.0)).root_to_paths.insert(
stack,
&mut core,
NounList(paths_list_mem_ptr),
),
)?,
path_to_batteries: (*(self.0)).path_to_batteries.insert(
stack,
&mut root_path,
BatteriesList(batteries_list_mem_ptr),
),
)?,
};
*self = Cold(cold_mem_ptr);
@ -684,9 +689,9 @@ impl Cold {
.lookup(stack, &mut *a_path)
.unwrap_or(BATTERIES_LIST_NIL);
if let Some(parent_batteries) = battery_list.matches(stack, parent) {
let mut my_path = T(stack, &[chum, *a_path]);
let mut my_path = T(stack, &[chum, *a_path])?;
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1);
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1)?;
*batteries_mem_ptr = BatteriesMem {
battery,
parent_axis,
@ -696,7 +701,7 @@ impl Cold {
let current_batteries_list = path_to_batteries
.lookup(stack, &mut my_path)
.unwrap_or(BATTERIES_LIST_NIL);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?;
*batteries_list_mem_ptr = BatteriesListMem {
batteries: Batteries(batteries_mem_ptr),
next: current_batteries_list,
@ -705,7 +710,7 @@ impl Cold {
let current_paths_list = battery_to_paths
.lookup(stack, &mut battery)
.unwrap_or(NOUN_LIST_NIL);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?;
*paths_list_mem_ptr = NounListMem {
element: my_path,
next: current_paths_list,
@ -715,12 +720,12 @@ impl Cold {
stack,
&mut my_path,
BatteriesList(batteries_list_mem_ptr),
);
)?;
battery_to_paths = battery_to_paths.insert(
stack,
&mut battery,
NounList(paths_list_mem_ptr),
);
)?;
ret = Ok(true);
}
}
@ -733,9 +738,9 @@ impl Cold {
.lookup(stack, &mut *a_path)
.unwrap_or(BATTERIES_LIST_NIL);
if let Some(parent_batteries) = battery_list.matches(stack, parent) {
let mut my_path = T(stack, &[chum, *a_path]);
let mut my_path = T(stack, &[chum, *a_path])?;
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1);
let batteries_mem_ptr: *mut BatteriesMem = stack.struct_alloc(1)?;
*batteries_mem_ptr = BatteriesMem {
battery,
parent_axis,
@ -745,7 +750,7 @@ impl Cold {
let current_batteries_list = path_to_batteries
.lookup(stack, &mut my_path)
.unwrap_or(BATTERIES_LIST_NIL);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1);
let batteries_list_mem_ptr: *mut BatteriesListMem = stack.struct_alloc(1)?;
*batteries_list_mem_ptr = BatteriesListMem {
batteries: Batteries(batteries_mem_ptr),
next: current_batteries_list,
@ -754,7 +759,7 @@ impl Cold {
let current_paths_list = battery_to_paths
.lookup(stack, &mut battery)
.unwrap_or(NOUN_LIST_NIL);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1);
let paths_list_mem_ptr: *mut NounListMem = stack.struct_alloc(1)?;
*paths_list_mem_ptr = NounListMem {
element: my_path,
next: current_paths_list,
@ -764,18 +769,18 @@ impl Cold {
stack,
&mut my_path,
BatteriesList(batteries_list_mem_ptr),
);
)?;
battery_to_paths = battery_to_paths.insert(
stack,
&mut battery,
NounList(paths_list_mem_ptr),
);
)?;
ret = Ok(true);
}
}
};
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1);
let cold_mem_ptr: *mut ColdMem = stack.struct_alloc(1)?;
*cold_mem_ptr = ColdMem {
battery_to_paths,
root_to_paths,
@ -816,6 +821,8 @@ pub enum FromNounError {
NounError(#[from] noun::Error),
#[error("UTF-8 error: {0}")]
Utf8Error(#[from] std::str::Utf8Error),
#[error("Allocation error: {0}")]
AllocationError(#[from] crate::mem::AllocationError),
}
pub type NounableResult<T> = std::result::Result<T, FromNounError>;
@ -824,7 +831,7 @@ pub trait Nounable {
type Target;
// type Allocator;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun>;
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target>
where
Self: Sized;
@ -833,8 +840,8 @@ pub trait Nounable {
impl Nounable for Atom {
type Target = Self;
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> Noun {
self.as_noun()
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> NounableResult<Noun> {
Ok(self.as_noun())
}
fn from_noun<A: NounAllocator>(_stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
noun.atom().ok_or(FromNounError::NotAtom)
@ -843,7 +850,7 @@ impl Nounable for Atom {
impl Nounable for u64 {
type Target = Self;
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> NounableResult<Noun> {
// Copied from Crown's IntoNoun, not sure why this isn't D(*self)
unsafe { Atom::from_raw(self).into_noun(_stack) }
}
@ -856,8 +863,8 @@ impl Nounable for u64 {
impl Nounable for Noun {
type Target = Self;
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> Noun {
self
fn into_noun<A: NounAllocator>(self, _stack: &mut A) -> NounableResult<Noun> {
Ok(self)
}
fn from_noun<A: NounAllocator>(_stack: &mut A, noun: &Self) -> NounableResult<Self::Target> {
@ -867,10 +874,10 @@ impl Nounable for Noun {
impl Nounable for &str {
type Target = String;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let contents_atom = unsafe {
let bytes = self.bytes().collect::<Vec<u8>>();
IndirectAtom::new_raw_bytes_ref(stack, bytes.as_slice()).normalize_as_atom()
IndirectAtom::new_raw_bytes_ref(stack, bytes.as_slice())?.normalize_as_atom()
};
contents_atom.into_noun(stack)
}
@ -885,13 +892,13 @@ impl Nounable for &str {
impl<T: Nounable + Copy> Nounable for &[T] {
type Target = Vec<T::Target>;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let mut list = D(0);
for item in self.iter().rev() {
let item_noun = item.into_noun(stack);
list = T(stack, &[item_noun, list]);
let item_noun = item.into_noun(stack)?;
list = T(stack, &[item_noun, list])?;
}
list
Ok(list)
}
fn from_noun<A: NounAllocator>(_stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -906,13 +913,13 @@ impl<T: Nounable + Copy> Nounable for &[T] {
impl<T: Nounable, U: Nounable, V: Nounable> Nounable for (T, U, V) {
type Target = (T::Target, U::Target, V::Target);
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
// It's a three-tuple now
let (a, b, c) = self;
let a_noun = a.into_noun(stack);
let b_noun = b.into_noun(stack);
let c_noun = c.into_noun(stack);
T(stack, &[a_noun, b_noun, c_noun])
let a_noun = a.into_noun(stack)?;
let b_noun = b.into_noun(stack)?;
let c_noun = c.into_noun(stack)?;
Ok(T(stack, &[a_noun, b_noun, c_noun])?)
}
fn from_noun<A: NounAllocator>(_stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -930,11 +937,11 @@ impl<T: Nounable, U: Nounable, V: Nounable> Nounable for (T, U, V) {
impl<T: Nounable, U: Nounable> Nounable for (T, U) {
type Target = (T::Target, U::Target);
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let (a, b) = self;
let a_noun = a.into_noun(stack);
let b_noun = b.into_noun(stack);
T(stack, &[a_noun, b_noun])
let a_noun = a.into_noun(stack)?;
let b_noun = b.into_noun(stack)?;
Ok(T(stack, &[a_noun, b_noun])?)
}
fn from_noun<A: NounAllocator>(_stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -949,7 +956,7 @@ impl<T: Nounable, U: Nounable> Nounable for (T, U) {
impl Nounable for NounList {
type Target = NounList;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let mut list = D(0);
let mut reverse = Vec::new();
for item in self {
@ -958,15 +965,15 @@ impl Nounable for NounList {
reverse.reverse();
for item in reverse {
let gimme = unsafe { *item };
list = T(stack, &[gimme, list]);
list = T(stack, &[gimme, list])?;
}
list
Ok(list)
}
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
let mut items = NOUN_LIST_NIL;
for item in NounListIterator(noun.clone()) {
let list_mem_ptr: *mut NounListMem = unsafe { stack.alloc_struct(1) };
let list_mem_ptr: *mut NounListMem = unsafe { stack.alloc_struct(1)? };
unsafe {
list_mem_ptr.write(NounListMem {
element: item,
@ -981,15 +988,15 @@ impl Nounable for NounList {
impl Nounable for Batteries {
type Target = Batteries;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let mut list = D(0);
for (battery, parent_axis) in self {
let battery_noun = unsafe { *battery };
let parent_axis_noun = parent_axis.as_noun();
let item = T(stack, &[battery_noun, parent_axis_noun]);
list = T(stack, &[item, list]);
let item = T(stack, &[battery_noun, parent_axis_noun])?;
list = T(stack, &[item, list])?;
}
list
Ok(list)
}
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -998,7 +1005,7 @@ impl Nounable for Batteries {
let cell = item.cell().ok_or(FromNounError::NotCell)?;
let battery = cell.head();
let parent_axis = cell.tail().as_atom()?;
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1) };
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_mem.write(BatteriesMem {
battery,
@ -1014,20 +1021,20 @@ impl Nounable for Batteries {
impl Nounable for BatteriesList {
type Target = BatteriesList;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let mut list = D(0);
for batteries in self {
let batteries_noun = batteries.into_noun(stack);
list = T(stack, &[batteries_noun, list]);
let batteries_noun = batteries.into_noun(stack)?;
list = T(stack, &[batteries_noun, list])?;
}
list
Ok(list)
}
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
let mut batteries_list = BATTERIES_LIST_NIL;
for item in NounListIterator(noun.clone()) {
let batteries = Batteries::from_noun(stack, &item)?;
let batteries_list_mem: *mut BatteriesListMem = unsafe { stack.alloc_struct(1) };
let batteries_list_mem: *mut BatteriesListMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_list_mem.write(BatteriesListMem {
batteries,
@ -1043,7 +1050,7 @@ impl Nounable for BatteriesList {
impl<T: Nounable + Copy + mem::Preserve> Nounable for Hamt<T> {
type Target = Vec<(Noun, T::Target)>;
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let mut list = D(0);
let mut reverse = Vec::new();
for item in self.iter() {
@ -1052,12 +1059,12 @@ impl<T: Nounable + Copy + mem::Preserve> Nounable for Hamt<T> {
reverse.reverse();
for slice in reverse {
for (key, value) in slice {
let value_noun = value.into_noun(stack);
let items = T(stack, &[*key, value_noun]);
list = T(stack, &[items, list]);
let value_noun = value.into_noun(stack)?;
let items = T(stack, &[*key, value_noun])?;
list = T(stack, &[items, list])?;
}
}
list
Ok(list)
}
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -1077,12 +1084,12 @@ impl<T: Nounable + Copy + mem::Preserve> Nounable for Hamt<T> {
pub fn hamt_from_vec<T: Nounable + Copy + mem::Preserve>(
stack: &mut NockStack,
items: Vec<(Noun, T)>,
) -> Hamt<T> {
let mut hamt = Hamt::new(stack);
) -> AllocResult<Hamt<T>> {
let mut hamt = Hamt::new(stack)?;
for (mut key, value) in items {
hamt = hamt.insert(stack, &mut key, value);
hamt = hamt.insert(stack, &mut key, value)?;
}
hamt
Ok(hamt)
}
impl Nounable for Cold {
@ -1092,7 +1099,7 @@ impl Nounable for Cold {
Vec<(Noun, BatteriesList)>,
);
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> Noun {
fn into_noun<A: NounAllocator>(self, stack: &mut A) -> NounableResult<Noun> {
let cold_mem = self.0;
let mut root_to_paths_noun = D(0);
let mut battery_to_paths_noun = D(0);
@ -1100,37 +1107,37 @@ impl Nounable for Cold {
unsafe {
for slice in (*cold_mem).root_to_paths.iter() {
for (root, paths) in slice {
let root_noun = root.into_noun(stack);
let paths_noun = paths.into_noun(stack);
let root_noun = root.into_noun(stack)?;
let paths_noun = paths.into_noun(stack)?;
// two-step the cons'ing for correct associativity
let items = T(stack, &[root_noun, paths_noun]);
root_to_paths_noun = T(stack, &[items, root_to_paths_noun]);
let items = T(stack, &[root_noun, paths_noun])?;
root_to_paths_noun = T(stack, &[items, root_to_paths_noun])?;
}
}
for slice in (*cold_mem).battery_to_paths.iter() {
for (battery, paths) in slice {
let battery_noun = battery.into_noun(stack);
let paths_noun = paths.into_noun(stack);
let battery_noun = battery.into_noun(stack)?;
let paths_noun = paths.into_noun(stack)?;
// two-step the cons'ing for correct associativity
let items = T(stack, &[battery_noun, paths_noun]);
battery_to_paths_noun = T(stack, &[items, battery_to_paths_noun]);
let items = T(stack, &[battery_noun, paths_noun])?;
battery_to_paths_noun = T(stack, &[items, battery_to_paths_noun])?;
}
}
for slice in (*cold_mem).path_to_batteries.iter() {
for (path, batteries) in slice {
let path_noun = path.into_noun(stack);
let batteries_noun = batteries.into_noun(stack);
let path_noun = path.into_noun(stack)?;
let batteries_noun = batteries.into_noun(stack)?;
// two-step the cons'ing for correct associativity
let items = T(stack, &[path_noun, batteries_noun]);
path_to_batteries_noun = T(stack, &[items, path_to_batteries_noun]);
let items = T(stack, &[path_noun, batteries_noun])?;
path_to_batteries_noun = T(stack, &[items, path_to_batteries_noun])?;
}
}
}
let cold_noun = T(
stack,
&[battery_to_paths_noun, root_to_paths_noun, path_to_batteries_noun],
);
cold_noun
)?;
Ok(cold_noun)
}
fn from_noun<A: NounAllocator>(stack: &mut A, noun: &Noun) -> NounableResult<Self::Target> {
@ -1176,7 +1183,9 @@ impl Nounable for Cold {
}
#[cfg(test)]
mod test {
pub(crate) mod test {
use std::iter::FromIterator;
use super::*;
use crate::{
hamt::Hamt,
@ -1184,46 +1193,47 @@ mod test {
noun::{Cell, Noun, D},
};
fn make_test_stack() -> NockStack {
let size = 1 << 27;
/// Default stack size for tests where you aren't intending to run out of space
pub(crate) const DEFAULT_STACK_SIZE: usize = 1 << 27;
pub(crate) fn make_test_stack(size: usize) -> NockStack {
let top_slots = 100;
let stack = NockStack::new(size, top_slots);
stack
}
fn make_cold_state(stack: &mut NockStack) -> Cold {
let cold = Cold::new(stack);
let cold = Cold::new(stack).unwrap();
unsafe {
let root_noun_list = make_noun_list(stack, &[1, 2]);
let root_noun_list = make_noun_list(stack, &[1, 2]).unwrap();
(*cold.0).root_to_paths =
(*cold.0)
.root_to_paths
.insert(stack, &mut D(100), root_noun_list);
let root_noun_list = make_noun_list(stack, &[3, 4]);
.insert(stack, &mut D(100), root_noun_list).unwrap();
let root_noun_list = make_noun_list(stack, &[3, 4]).unwrap();
(*cold.0).root_to_paths =
(*cold.0)
.root_to_paths
.insert(stack, &mut D(101), root_noun_list);
.insert(stack, &mut D(101), root_noun_list).unwrap();
let battery_to_paths_list = make_noun_list(stack, &[5, 6]);
let battery_to_paths_list = make_noun_list(stack, &[5, 6]).unwrap();
(*cold.0).battery_to_paths =
(*cold.0)
.battery_to_paths
.insert(stack, &mut D(200), battery_to_paths_list);
let batteries_list = make_batteries_list(stack, &[7, 8]);
.insert(stack, &mut D(200), battery_to_paths_list).unwrap();
let batteries_list = make_batteries_list(stack, &[7, 8]).unwrap();
(*cold.0).path_to_batteries =
(*cold.0)
.path_to_batteries
.insert(stack, &mut D(300), batteries_list);
.insert(stack, &mut D(300), batteries_list).unwrap();
}
cold
}
#[test]
fn cold_bidirectional_conversion() {
let mut stack = make_test_stack();
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let cold = make_cold_state(&mut stack);
let cold_noun = cold.into_noun(&mut stack);
let cold_noun = cold.into_noun(&mut stack).unwrap();
let new_cold =
Cold::from_noun(&mut stack, &cold_noun).expect("Failed to convert noun to cold");
// Use zipped iteration to compare the two cold states
@ -1242,8 +1252,8 @@ mod test {
a.0,
b.0
);
let mut value_a_noun = a.1.into_noun(&mut stack);
let mut value_b_noun = b.1.into_noun(&mut stack);
let mut value_a_noun = a.1.into_noun(&mut stack).unwrap();
let mut value_b_noun = b.1.into_noun(&mut stack).unwrap();
let value_a = &mut value_a_noun as *mut Noun;
let value_b = &mut value_b_noun as *mut Noun;
assert!(
@ -1269,8 +1279,8 @@ mod test {
a.0,
b.0
);
let mut value_a_noun = a.1.into_noun(&mut stack);
let mut value_b_noun = b.1.into_noun(&mut stack);
let mut value_a_noun = a.1.into_noun(&mut stack).unwrap();
let mut value_b_noun = b.1.into_noun(&mut stack).unwrap();
let value_a = &mut value_a_noun as *mut Noun;
let value_b = &mut value_b_noun as *mut Noun;
assert!(
@ -1296,8 +1306,8 @@ mod test {
a.0,
b.0
);
let mut value_a_noun = a.1.into_noun(&mut stack);
let mut value_b_noun = b.1.into_noun(&mut stack);
let mut value_a_noun = a.1.into_noun(&mut stack).unwrap();
let mut value_b_noun = b.1.into_noun(&mut stack).unwrap();
let value_a = &mut value_a_noun as *mut Noun;
let value_b = &mut value_b_noun as *mut Noun;
assert!(
@ -1311,10 +1321,10 @@ mod test {
#[test]
fn hamt_bidirectional_conversion() {
let mut stack = make_test_stack();
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let items = vec![(D(0), D(1)), (D(2), D(3))];
let hamt = super::hamt_from_vec(&mut stack, items);
let noun = hamt.into_noun(&mut stack);
let hamt = super::hamt_from_vec(&mut stack, items).unwrap();
let noun = hamt.into_noun(&mut stack).unwrap();
let new_hamt: Vec<(Noun, Noun)> =
<Hamt<Noun> as Nounable>::from_noun::<NockStack>(&mut stack, &noun).unwrap();
let flat_hamt: Vec<(Noun, Noun)> = hamt.iter().flatten().cloned().collect();
@ -1338,10 +1348,10 @@ mod test {
}
}
fn make_batteries_list(stack: &mut NockStack, v: &[u64]) -> BatteriesList {
fn make_batteries_list(stack: &mut NockStack, v: &[u64]) -> AllocResult<BatteriesList> {
let mut batteries_list = BATTERIES_LIST_NIL;
for &item in v.iter().rev() {
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1) };
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_mem.write(BatteriesMem {
battery: D(item),
@ -1350,7 +1360,7 @@ mod test {
});
}
let batteries = Batteries(batteries_mem);
let batteries_list_mem: *mut BatteriesListMem = unsafe { stack.alloc_struct(1) };
let batteries_list_mem: *mut BatteriesListMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_list_mem.write(BatteriesListMem {
batteries,
@ -1359,19 +1369,19 @@ mod test {
}
batteries_list = BatteriesList(batteries_list_mem);
}
batteries_list
Ok(batteries_list)
}
#[test]
fn batteries_list_bidirectional_conversion() {
let mut stack = make_test_stack();
let batteries_list2 = make_batteries_list(&mut stack, &[1, 2]);
let batteries_list_noun = batteries_list2.into_noun(&mut stack);
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let batteries_list2 = make_batteries_list(&mut stack, &[1, 2]).unwrap();
let batteries_list_noun = batteries_list2.into_noun(&mut stack).unwrap();
let new_batteries_list2 = BatteriesList::from_noun(&mut stack, &batteries_list_noun)
.expect("Failed to convert noun to batteries list");
for (a, b) in batteries_list2.zip(new_batteries_list2) {
let mut a_noun = a.into_noun(&mut stack);
let mut b_noun = b.into_noun(&mut stack);
let mut a_noun = a.into_noun(&mut stack).unwrap();
let mut b_noun = b.into_noun(&mut stack).unwrap();
let a_ptr = &mut a_noun as *mut Noun;
let b_ptr = &mut b_noun as *mut Noun;
assert!(
@ -1381,8 +1391,8 @@ mod test {
}
}
fn make_batteries(stack: &mut NockStack) -> Batteries {
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1) };
fn make_batteries(stack: &mut NockStack) -> AllocResult<Batteries> {
let batteries_mem: *mut BatteriesMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_mem.write(BatteriesMem {
battery: D(0),
@ -1391,7 +1401,7 @@ mod test {
});
}
let batteries = Batteries(batteries_mem);
let batteries_mem2: *mut BatteriesMem = unsafe { stack.alloc_struct(1) };
let batteries_mem2: *mut BatteriesMem = unsafe { stack.alloc_struct(1)? };
unsafe {
batteries_mem2.write(BatteriesMem {
battery: D(2),
@ -1400,14 +1410,14 @@ mod test {
});
}
let batteries2 = Batteries(batteries_mem2);
batteries2
Ok(batteries2)
}
#[test]
fn batteries_bidirectional_conversion() {
let mut stack = make_test_stack();
let batteries2 = make_batteries(&mut stack);
let batteries_noun = batteries2.into_noun(&mut stack);
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let batteries2 = make_batteries(&mut stack).unwrap();
let batteries_noun = batteries2.into_noun(&mut stack).unwrap();
let new_batteries = Batteries::from_noun(&mut stack, &batteries_noun)
.expect("Failed to convert noun to batteries");
assert_eq!(new_batteries.count(), 2);
@ -1423,8 +1433,8 @@ mod test {
a_val,
b_val
);
let a_atom_noun = a_atom.into_noun(&mut stack);
let b_atom_noun = b_atom.into_noun(&mut stack);
let a_atom_noun = a_atom.into_noun(&mut stack).unwrap();
let b_atom_noun = b_atom.into_noun(&mut stack).unwrap();
let a_atom_noun_ptr = &mut a_atom_noun.clone() as *mut Noun;
let b_atom_noun_ptr = &mut b_atom_noun.clone() as *mut Noun;
assert!(
@ -1438,9 +1448,9 @@ mod test {
#[test]
fn tuple_bidirectional_conversion() {
let mut stack = make_test_stack();
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let tup = (D(1), D(2), D(3));
let noun = tup.into_noun(&mut stack);
let noun = tup.into_noun(&mut stack).unwrap();
let new_tup: (Noun, Noun, Noun) =
<(Noun, Noun, Noun) as Nounable>::from_noun::<NockStack>(&mut stack, &noun).unwrap();
let (a, b, c) = new_tup;
@ -1461,33 +1471,39 @@ mod test {
);
}
fn make_noun_list(stack: &mut NockStack, v: &[u64]) -> NounList {
pub(crate) fn make_noun_list(stack: &mut NockStack, v: &[u64]) -> AllocResult<NounList> {
let mut noun_list = NOUN_LIST_NIL;
for &item in v.iter().rev() {
let noun_list_mem: *mut NounListMem = unsafe { stack.alloc_struct(1) };
// let mut prev = noun_list;
for &item in v.iter() {
let noun_list_mem: *mut NounListMem = unsafe { stack.alloc_struct(1)? };
unsafe {
noun_list_mem.write(NounListMem {
element: D(item),
next: NOUN_LIST_NIL,
next: noun_list,
});
}
noun_list = NounList(noun_list_mem);
}
noun_list
Ok(noun_list)
}
#[test]
fn noun_list_bidirectional_conversion() {
let mut stack = make_test_stack();
let items = vec![D(1), D(2)];
let noun_list = make_noun_list(&mut stack, &[1, 2]);
let noun = noun_list.into_noun(&mut stack);
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
const ITEM_COUNT: u64 = 2;
let vec = Vec::from_iter(1..=ITEM_COUNT);
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
let slice = vec.as_slice();
let noun_list = make_noun_list(&mut stack, slice).unwrap();
let noun = noun_list.into_noun(&mut stack).unwrap();
let new_noun_list: NounList =
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun).unwrap();
let mut item_count = 0;
for (a, b) in new_noun_list.zip(items.iter()) {
let a_ptr = a;
let b_ptr = &mut b.clone() as *mut Noun;
let a_val = unsafe { *a_ptr };
item_count += 1;
assert!(
unsafe { unifying_equality(&mut stack, a_ptr, b_ptr) },
"Items don't match: {:?} {:?}",
@ -1495,13 +1511,14 @@ mod test {
b
);
}
assert_eq!(item_count, ITEM_COUNT as usize);
}
#[test]
fn how_to_noun() {
let mut stack = make_test_stack();
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let tup: &[Noun] = &[D(0), D(1)];
let cell = Cell::new_tuple(&mut stack, tup);
let cell = Cell::new_tuple(&mut stack, tup).unwrap();
let noun: Noun = cell.as_noun();
let car = noun.cell().unwrap().head().direct().unwrap().data();
let cdr = noun.cell().unwrap().tail().direct().unwrap().data();
@ -1511,9 +1528,9 @@ mod test {
#[test]
fn how_to_noun_but_listy() {
let mut stack = make_test_stack();
let mut stack = make_test_stack(DEFAULT_STACK_SIZE);
let tup: &[Noun] = &[D(0), D(1)];
let cell = Cell::new_tuple(&mut stack, tup);
let cell = Cell::new_tuple(&mut stack, tup).unwrap();
let noun: Noun = cell.as_noun();
let car = noun.cell().unwrap().head().direct().unwrap().data();
let cdr = noun.cell().unwrap().tail().direct().unwrap().data();

View File

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

View File

@ -8,7 +8,7 @@ use crate::noun::Noun;
crate::gdb!();
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result<Noun> {
let arg = slot(subject, 6)?;
Ok(mug(&mut context.stack, arg).as_noun())
}
@ -16,10 +16,12 @@ pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::{assert_jet, init_context, A};
use crate::jets::util::test::{assert_jet, init_context};
use crate::mem::NockStack;
use crate::noun::{Noun, D, T};
use crate::noun::{Noun, D};
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
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))
@ -47,7 +49,7 @@ mod tests {
#[test]
fn test_mug() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
assert_jet(c, jet_mug, a0, D(0x79ff04e8));

View File

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

View File

@ -8,17 +8,17 @@ use crate::site::{site_slam, Site};
crate::gdb!();
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result {
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
util::flop(&mut context.stack, sam)
}
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result<Noun> {
let list = slot(subject, 6)?;
util::lent(list).map(|x| D(x as u64))
}
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?;
@ -28,7 +28,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
loop {
if let Ok(list_cell) = list.as_cell() {
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)?;
} else {
if unsafe { !list.raw_equals(D(0)) } {
@ -39,7 +39,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let index = slot(sam, 2)?;
let list = slot(sam, 3)?;
@ -47,12 +47,12 @@ pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result {
util::snag(list, index)
}
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result {
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result<Noun> {
let list = slot(subject, 6)?;
util::snip(&mut context.stack, list)
}
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?;
@ -66,7 +66,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
if let Ok(list_cell) = list.as_cell() {
list = list_cell.tail();
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())?;
*dest = new_cell.as_noun();
dest = &mut (*new_mem).tail;
@ -83,7 +83,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result {
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result<Noun> {
let list = slot(subject, 6)?;
let stack = &mut context.stack;
@ -98,7 +98,7 @@ pub mod util {
use std::result;
/// Reverse order of list
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result {
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result<Noun> {
let mut list = noun;
let mut tsil = D(0);
loop {
@ -107,7 +107,7 @@ pub mod util {
}
let cell = list.as_cell()?;
tsil = T(stack, &[cell.head(), tsil]);
tsil = T(stack, &[cell.head(), tsil])?;
list = cell.tail();
}
@ -133,7 +133,7 @@ pub mod util {
Ok(len)
}
pub fn snag(tape: Noun, index: Noun) -> Result {
pub fn snag(tape: Noun, index: Noun) -> Result<Noun> {
let mut list = tape;
let mut idx = index.as_atom()?.as_u64()? as usize;
loop {
@ -149,7 +149,7 @@ pub mod util {
}
}
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result {
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result<Noun> {
let mut ret = D(0);
let mut dest = &mut ret as *mut Noun;
let mut list = tape;
@ -170,7 +170,7 @@ pub mod util {
}
}
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();
*dest = new_cell.as_noun();
dest = &mut (*new_mem).tail;
@ -181,7 +181,7 @@ pub mod util {
Ok(ret)
}
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result {
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result<Noun> {
unsafe {
let mut res: Noun = D(0);
let mut dest = &mut res as *mut Noun;
@ -196,7 +196,7 @@ pub mod util {
let i = it.head();
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;
*dest = new_cell.as_noun();
dest = &mut (*new_memory).tail;
@ -214,11 +214,13 @@ mod tests {
use super::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context};
use crate::jets::util::BAIL_EXIT;
use crate::noun::{D, T};
use crate::noun::D;
// Override T with the panicky variants
use crate::test_fns::T;
#[test]
fn test_flop() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
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)]);
@ -255,7 +257,7 @@ mod tests {
#[test]
fn test_lent() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
assert_jet(c, jet_lent, D(0), D(0));
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
@ -269,7 +271,7 @@ mod tests {
#[test]
fn test_snag() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
let sam = T(&mut c.stack, &[D(1), list1]);
assert_jet(c, jet_snag, sam, D(2));
@ -287,7 +289,7 @@ mod tests {
#[test]
fn test_snip() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet(c, jet_snip, sam, D(0));
@ -313,7 +315,7 @@ mod tests {
#[test]
fn test_zing() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
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)]);

View File

@ -11,7 +11,7 @@ crate::gdb!();
// have fixed maximum key sizes, therefore we must punt if the key is
// too large.
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result {
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -27,7 +27,7 @@ pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result {
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -45,7 +45,7 @@ pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -61,7 +61,7 @@ pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -79,7 +79,7 @@ pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -95,7 +95,7 @@ pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -142,7 +142,7 @@ mod util {
let length = list::util::lent(ads)?;
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)
};
@ -153,7 +153,7 @@ mod util {
let bytes = head.as_bytes();
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]));
item.length = bytes.len();
@ -171,7 +171,7 @@ mod util {
key: &mut [u8; N],
ads: Noun,
txt: Atom,
) -> Result {
) -> Result<Noun> {
unsafe {
let ac_siv_data = _allocate_ads(stack, ads)?;
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 (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
// to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes.
match txt_len {
0 => {
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]);
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();
Ok(T(
stack,
@ -202,7 +202,7 @@ mod util {
D(txt_len as u64),
out_atom.normalize_as_atom().as_noun(),
],
))
)?)
}
}
}
@ -215,7 +215,7 @@ mod util {
iv: Atom,
len: Atom,
txt: Atom,
) -> Result {
) -> Result<Noun> {
unsafe {
let txt_len = match len.as_direct() {
Ok(direct) => direct.data() as usize,
@ -231,20 +231,20 @@ mod util {
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 {
0 => {
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]);
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()])?)
}
}
}
@ -254,7 +254,7 @@ mod tests {
use super::*;
use crate::jets::util::test::{assert_noun_eq, init_context, A};
use crate::jets::Jet;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::noun::{Cell, D, T};
use ibig::ubig;
@ -262,32 +262,33 @@ mod tests {
c: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
ctx: &[fn(&mut NockStack) -> AllocResult<Noun>], // door sample as context
res: Noun,
) {
) -> AllocResult<()> {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect();
let ctx: Vec<Noun> = ctx.iter().map(|f| f(&mut c.stack)).collect();
let ctx: Vec<Noun> = ctx.iter().flat_map(|f| f(&mut c.stack)).collect();
let sam = if sam.len() > 1 {
T(&mut c.stack, &sam)
T(&mut c.stack, &sam)?
} else {
sam[0]
};
let ctx = if ctx.len() > 1 {
T(&mut c.stack, &ctx)
T(&mut c.stack, &ctx)?
} else {
ctx[0]
};
let pay = Cell::new(&mut c.stack, sam, ctx).as_noun();
let sbj = Cell::new(&mut c.stack, D(0), pay).as_noun();
let pay = Cell::new(&mut c.stack, sam, ctx)?.as_noun();
let sbj = Cell::new(&mut c.stack, D(0), pay)?.as_noun();
// std::io::stderr().flush().unwrap();
let jet_res = jet(c, sbj).unwrap();
// std::io::stderr().flush().unwrap();
assert_noun_eq(&mut c.stack, jet_res, res);
Ok(())
}
#[test]
pub fn test_siva_en() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/*
> (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0)
[p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0]
@ -295,44 +296,44 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee))
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(
s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
);
)?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
let res = T(&mut c.stack, &[iv, len, cyp]);
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivb_en() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/*
> (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -341,41 +342,41 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee))
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740));
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c));
let res = T(&mut c.stack, &[iv, len, cyp]);
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivc_en() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/*
> (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -384,122 +385,122 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee))
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0));
let res = T(&mut c.stack, &[iv, len, cyp]);
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_siva_de() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
let len = D(14);
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
T(s, &[iv, len, cyp])
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(
s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
);
)?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivb_de() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740));
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
let len = D(14);
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c));
T(s, &[iv, len, cyp])
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivc_de() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
let len = D(14);
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0));
T(s, &[iv, len, cyp])
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
}
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
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!();
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result {
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sed = slot(subject, 6)?.as_atom()?;
@ -21,14 +21,14 @@ pub fn jet_puck(context: &mut Context, subject: Noun) -> Result {
let sed_bytes = &mut [0u8; 32];
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);
Ok(pub_ida.normalize_as_atom().as_noun())
}
}
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let pub_key = slot(subject, 12)?.as_atom()?;
let sec_key = slot(subject, 13)?.as_atom()?;
@ -53,14 +53,14 @@ pub fn jet_shar(context: &mut Context, subject: Noun) -> Result {
public[0..pub_bytes.len()].copy_from_slice(pub_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);
Ok(shar_ida.normalize_as_atom().as_noun())
}
}
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let msg = slot(subject, 12)?.as_atom()?;
let sed = slot(subject, 13)?.as_atom()?;
@ -74,11 +74,11 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
let seed = &mut [0u8; 32];
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);
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]);
ac_ed_sign(message, seed, sig);
} else {
@ -90,7 +90,7 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
let sig = slot(subject, 12)?.as_atom()?;
let msg = slot(subject, 26)?.as_atom()?;
let puk = slot(subject, 27)?.as_atom()?;
@ -129,55 +129,55 @@ mod tests {
#[test]
fn test_puck() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = A(&mut c.stack, &ubig!(_0x0));
let sam = A(&mut c.stack, &ubig!(_0x0)).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b),
);
).unwrap();
assert_jet(c, jet_puck, sam, ret);
let sam = A(
&mut c.stack,
&ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d),
);
).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7),
);
).unwrap();
assert_jet(c, jet_puck, sam, ret);
}
#[test]
fn test_shar() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x0));
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x0)).unwrap();
assert_jet(c, jet_shar, sam, ret);
let sam = T(&mut c.stack, &[D(234), D(234)]);
let sam = T(&mut c.stack, &[D(234), D(234)]).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5),
);
).unwrap();
assert_jet(c, jet_shar, sam, ret);
let sam = A(
&mut c.stack,
&ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b),
);
).unwrap();
assert_jet_err(c, jet_shar, sam, BAIL_EXIT);
}
#[test]
fn test_sign() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
unsafe {
let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803));
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803)).unwrap();
assert_jet(c, jet_sign, sam, ret);
let message = D(0x72);
@ -187,16 +187,18 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes();
let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00));
let sam = T(&mut c.stack, &[message, seed]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00)).unwrap();
assert_jet(c, jet_sign, sam, ret);
let msg_ubig = ubig!(_0xaf82);
let msg_bytes = msg_ubig.to_be_bytes();
let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun();
let sed_ubig =
@ -204,26 +206,28 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes();
let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a));
let sam = T(&mut c.stack, &[message, seed]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a)).unwrap();
assert_jet(c, jet_sign, sam, ret);
}
}
#[test]
fn test_veri() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
unsafe {
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]);
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]).unwrap();
assert_jet(c, jet_veri, sam, NO);
let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00);
let sig_bytes = sig_ubig.to_be_bytes();
let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun();
let message = D(0x72);
@ -233,21 +237,24 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes();
let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]);
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
assert_jet(c, jet_veri, sam, YES);
let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a);
let sig_bytes = sig_ubig.to_be_bytes();
let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun();
let msg_ubig = ubig!(0xaf82);
let msg_bytes = msg_ubig.to_be_bytes();
let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun();
let pub_ubig =
@ -255,9 +262,10 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes();
let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]);
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
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!();
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let sal = slot(sam, 2)?.as_atom()?;
let ruz = slot(sam, 3)?.as_atom()?;
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 (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);
let msg_len = met(3, ruz);
if msg_len > 0 {
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);
ac_shas(msg, salt, out);
} else {
@ -34,18 +34,18 @@ pub fn jet_shas(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let ruz = sam.as_atom()?;
let msg_len = met(3, ruz);
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 {
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);
ac_shay(msg, out);
} else {
@ -56,7 +56,7 @@ pub fn jet_shax(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -69,16 +69,16 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
let msg_len = met(3, ruz);
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 {
ac_shay(&mut [], out);
} 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]);
ac_shay(msg, out);
} else {
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);
ac_shay(msg, out);
}
@ -87,7 +87,7 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -100,16 +100,16 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
let msg_len = met(3, ruz);
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 {
ac_shal(&mut [], out);
} 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]);
ac_shal(msg, out);
} else {
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);
ac_shal(msg, out);
}
@ -118,7 +118,7 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result {
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -131,16 +131,16 @@ pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result {
let msg_len = met(3, ruz);
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 {
ac_sha1(&mut [], out);
} 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]);
ac_sha1(msg, out);
} else {
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);
ac_sha1(msg, out);
}
@ -158,9 +158,9 @@ mod tests {
#[test]
fn test_shas() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
assert_jet_ubig(
c,
jet_shas,
@ -168,7 +168,7 @@ mod tests {
ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60),
);
let sam = T(&mut c.stack, &[D(1), D(1)]);
let sam = T(&mut c.stack, &[D(1), D(1)]).unwrap();
assert_jet_ubig(
c,
jet_shas,
@ -176,7 +176,7 @@ mod tests {
ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc),
);
let sam = T(&mut c.stack, &[D(2), D(2)]);
let sam = T(&mut c.stack, &[D(2), D(2)]).unwrap();
assert_jet_ubig(
c,
jet_shas,
@ -187,12 +187,12 @@ mod tests {
let a = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
).unwrap();
let b = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
);
let sam = T(&mut c.stack, &[a, b]);
).unwrap();
let sam = T(&mut c.stack, &[a, b]).unwrap();
assert_jet_ubig(
c,
jet_shas,
@ -203,7 +203,7 @@ mod tests {
#[test]
fn test_shax() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
assert_jet_ubig(
c,
@ -222,7 +222,7 @@ mod tests {
let a = A(
&mut c.stack,
&ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
);
).unwrap();
assert_jet_ubig(
c,
jet_shax,
@ -240,74 +240,74 @@ mod tests {
let a = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
).unwrap();
assert_jet_ubig(
c,
jet_shax,
a,
ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9),
)
);
}
#[test]
fn test_shay() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
);
).unwrap();
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(0)]);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e),
);
).unwrap();
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(0), D(1)]);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
let ret = A(
&mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
);
).unwrap();
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(478560413032)]); // [1 'hello']
let sam = T(&mut c.stack, &[D(1), D(478560413032)]).unwrap(); // [1 'hello']
let ret = A(
&mut c.stack,
&ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa),
);
).unwrap();
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(2), D(478560413032)]); // [2 'hello']
let sam = T(&mut c.stack, &[D(2), D(478560413032)]).unwrap(); // [2 'hello']
let ret = A(
&mut c.stack,
&ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37),
);
).unwrap();
assert_jet(c, jet_shay, sam, ret);
let big = DIRECT_MAX + 1;
let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8)
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8).unwrap()
};
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
let big: u128 = (DIRECT_MAX as u128) << 64;
let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8)
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8).unwrap()
};
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
}
#[test]
fn test_shal() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
assert_jet_ubig(
c,
jet_shal,
@ -315,7 +315,7 @@ mod tests {
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
);
let sam = T(&mut c.stack, &[D(1), D(0)]);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
assert_jet_ubig(
c,
jet_shal,
@ -323,7 +323,7 @@ mod tests {
ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8)
);
let sam = T(&mut c.stack, &[D(0), D(1)]);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
assert_jet_ubig(
c,
jet_shal,
@ -334,27 +334,27 @@ mod tests {
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
).unwrap();
let dat = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
);
let sam = T(&mut c.stack, &[wid, dat]);
).unwrap();
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
let sam = T(&mut c.stack, &[wid, D(1)]);
).unwrap();
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
}
#[test]
fn test_sha1() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
assert_jet_ubig(
c,
jet_sha1,
@ -362,7 +362,7 @@ mod tests {
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
);
let sam = T(&mut c.stack, &[D(1), D(0)]);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
assert_jet_ubig(
c,
jet_sha1,
@ -370,7 +370,7 @@ mod tests {
ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f),
);
let sam = T(&mut c.stack, &[D(0), D(1)]);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
assert_jet_ubig(
c,
jet_sha1,
@ -381,19 +381,19 @@ mod tests {
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
).unwrap();
let dat = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
);
let sam = T(&mut c.stack, &[wid, dat]);
).unwrap();
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
);
let sam = T(&mut c.stack, &[wid, D(1)]);
).unwrap();
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
}
}

View File

@ -8,7 +8,7 @@ use sword_macros::tas;
crate::gdb!();
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -25,19 +25,19 @@ pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}
}
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
// axe must be Atom, though we use it as Noun
let axe = slot(subject, 6)?.as_atom()?;
let van = slot(subject, 7)?;
@ -55,19 +55,19 @@ pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}
}
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -84,19 +84,19 @@ pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}
}
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
let gol = slot(subject, 12)?;
let gen = slot(subject, 13)?;
let van = slot(subject, 7)?;
@ -106,19 +106,19 @@ pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
let fun = 141 + tas!(b"mint");
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}
}
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
let gol = slot(subject, 12)?;
let dox = slot(subject, 26)?;
let gen = slot(subject, 27)?;
@ -137,19 +137,19 @@ pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}
}
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
let nest_in_core = slot(subject, 3)?;
let seg = slot(nest_in_core, 12)?;
@ -172,7 +172,7 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
@ -181,14 +181,14 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
if unsafe { pro.raw_equals(YES) && reg.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)
}
}
}
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
let leg = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -205,13 +205,13 @@ pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
1
};
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) {
Some(pro) => Ok(pro),
None => {
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)
}
}

View File

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

View File

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

View File

@ -13,7 +13,7 @@ crate::gdb!();
//
// Text conversion
//
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?.as_atom()?;
let chars = met(3, sam);
if chars == 0 {
@ -27,7 +27,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
for byte in bytes {
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
(*it_mem).head = D((*byte) as u64);
@ -44,7 +44,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
// Tracing
//
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let zyc = slot(sam, 2)?;
let naz = slot(sam, 3)?;
@ -56,7 +56,7 @@ pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
// Combinators
//
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -81,25 +81,25 @@ pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
let yur = util::last(p_vex, p_yit)?;
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 {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
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)?;
if unsafe { vux.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex]))
Ok(T(&mut context.stack, &[yur, q_vex])?)
} else {
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 {
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -124,19 +124,19 @@ pub fn jet_comp(context: &mut Context, subject: Noun) -> Result {
let yur = util::last(p_vex, p_yit)?;
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 {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
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)?;
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 {
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -161,7 +161,7 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
let yur = util::last(p_vex, p_yit)?;
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 {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail();
@ -173,19 +173,19 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
let goy = util::last(yur, p_wam)?;
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 {
let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
let puq_wam = uq_wam.head();
let quq_wam = uq_wam.tail();
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam]);
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam]))
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam])?;
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam])?)
}
}
}
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -207,10 +207,10 @@ pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
// 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)?;
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 {
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?;
let p_vex = vex.head();
@ -230,19 +230,19 @@ pub fn jet_plug(context: &mut Context, subject: Noun) -> Result {
let yur = util::last(p_vex, p_yit)?;
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 {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let inner = T(&mut context.stack, &[puq_vex, puq_yit]);
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit]))
let inner = T(&mut context.stack, &[puq_vex, puq_yit])?;
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit])?)
}
}
}
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?;
@ -255,10 +255,10 @@ pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
let roq = kick(context, sab, D(2))?.as_cell()?;
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 {
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -281,12 +281,12 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result {
let yur = util::last(p_vex, p_yit)?;
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 {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
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 {
// Rule Builders
//
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result {
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let cus = slot(van, 12)?;
@ -309,11 +309,11 @@ pub fn jet_cold(context: &mut Context, subject: Noun) -> Result {
} else {
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 {
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let poq = slot(van, 12)?;
@ -331,11 +331,11 @@ pub fn jet_cook(context: &mut Context, subject: Noun) -> Result {
let quq_vex = uq_vex.tail();
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 {
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let huf = slot(van, 6)?;
@ -343,10 +343,10 @@ pub fn jet_easy(context: &mut Context, subject: Noun) -> Result {
Ok(T(
&mut context.stack,
&[tub.as_cell()?.head(), D(0), huf, tub],
))
)?)
}
pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let hez = slot(van, 12)?;
@ -368,14 +368,14 @@ pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
let quq_vex = uq_vex.tail();
let pquq_vex = quq_vex.as_cell()?.head();
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex]);
let gud = T(&mut context.stack, &[inner_gud, puq_vex]);
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex])?;
let gud = T(&mut context.stack, &[inner_gud, puq_vex])?;
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 {
pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let daf = slot(van, 6)?;
@ -390,7 +390,7 @@ pub fn jet_just(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let mut bud = slot(van, 6)?;
@ -413,7 +413,7 @@ pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
util::fail(context, p_tub)
}
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result {
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?.as_cell()?;
let van = slot(subject, 7)?;
let zep = slot(van, 6)?.as_cell()?;
@ -442,7 +442,7 @@ pub fn jet_shim(context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let gob = slot(van, 12)?;
@ -459,12 +459,12 @@ pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let wag = T(&mut context.stack, &[gob, puq_vex]);
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
let wag = T(&mut context.stack, &[gob, puq_vex])?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
}
}
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
let tub = slot(subject, 6)?.as_cell()?;
let con = slot(subject, 7)?;
let mut hel = slot(con, 2)?;
@ -505,8 +505,8 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
match (hpn_hel.as_either(), tpn_hel.as_either()) {
(Left(_), Left(_)) => {
gte_b(&mut context.stack, iq_tub, hpn_hel)
&& lte_b(&mut context.stack, iq_tub, tpn_hel)
gte_b(&mut context.stack, iq_tub, hpn_hel)?
&& lte_b(&mut context.stack, iq_tub, tpn_hel)?
}
_ => {
// XX: Fixes jet mismatch in Vere
@ -525,7 +525,7 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
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;
} else {
hel = r_hel;
@ -542,7 +542,7 @@ struct StirPair {
pub res: Noun, // p.u.q.edge
}
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result {
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
unsafe {
context.with_stack_frame(0, |context| {
let mut tub = slot(subject, 6)?;
@ -586,12 +586,12 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result {
while !context.stack.stack_is_empty() {
let par_u = *(context.stack.top::<StirPair>());
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)?;
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)
})
}
@ -603,7 +603,7 @@ pub mod util {
use crate::noun::{Noun, D, T};
use std::cmp::Ordering;
pub fn last(zyc: Noun, naz: Noun) -> Result {
pub fn last(zyc: Noun, naz: Noun) -> Result<Noun> {
let zyl = zyc.as_cell()?;
let nal = naz.as_cell()?;
@ -626,7 +626,7 @@ pub mod util {
}
// 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 {
pub fn next(context: &mut Context, tub: Noun) -> Result<Noun> {
let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail();
@ -638,25 +638,25 @@ pub mod util {
let tq_tub = q_tub.as_cell()?.tail();
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.
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result {
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result<Noun> {
let p_naz = naz.as_cell()?.head().as_atom()?;
let q_naz = naz.as_cell()?.tail().as_atom()?;
if unsafe { weq.raw_equals(D(10)) } {
let arg = inc(&mut context.stack, p_naz).as_noun();
Ok(T(&mut context.stack, &[arg, D(1)]))
let arg = inc(&mut context.stack, p_naz)?.as_noun();
Ok(T(&mut context.stack, &[arg, D(1)])?)
} else {
let arg = inc(&mut context.stack, q_naz).as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg]))
let arg = inc(&mut context.stack, q_naz)?.as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg])?)
}
}
pub fn fail(context: &mut Context, hair: Noun) -> Result {
Ok(T(&mut context.stack, &[hair, D(0)]))
pub fn fail(context: &mut Context, hair: Noun) -> Result<Noun> {
Ok(T(&mut context.stack, &[hair, D(0)])?)
}
}
@ -664,9 +664,11 @@ pub mod util {
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::noun::{D, T};
use crate::noun::D;
use crate::serialization::cue;
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
// XX: need unit tests for:
// +last
@ -683,7 +685,7 @@ mod tests {
#[test]
fn test_easy() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
// ((easy 'a') [[1 1] "abc"])
// [[1 1] "abc"]

View File

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

View File

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

View File

@ -8,7 +8,7 @@ use crate::noun::{IndirectAtom, Noun, D};
crate::gdb!();
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let met = met(0, tom);
@ -24,7 +24,7 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
}
}
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let tom = slot(subject, 6)?.as_atom()?;
let met = met(0, tom);
@ -35,7 +35,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
let out_bits = met - 1;
let out_words = (out_bits + 63) >> 6;
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
if 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 {
}
}
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -67,7 +67,7 @@ pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
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[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]);
@ -82,6 +82,8 @@ mod tests {
use crate::mem::NockStack;
use crate::noun::{Noun, D, DIRECT_MAX};
use ibig::ubig;
// Override with the panicky variant
use crate::test_fns::A;
fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x0)
@ -125,7 +127,7 @@ mod tests {
#[test]
fn test_cap() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
assert_jet_err(c, jet_cap, D(0), BAIL_EXIT);
assert_jet_err(c, jet_cap, D(1), BAIL_EXIT);
@ -141,7 +143,7 @@ mod tests {
#[test]
fn test_mas() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
let a63 = atom_63(&mut c.stack);
let a64 = atom_64(&mut c.stack);
let a65 = atom_65(&mut c.stack);
@ -173,7 +175,7 @@ mod tests {
#[test]
fn test_peg() {
let c = &mut init_context();
let c = &mut init_context().unwrap();
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);

View File

@ -2,7 +2,7 @@ use crate::hamt::Hamt;
use crate::jets::cold::{Batteries, Cold};
use crate::jets::hot::Hot;
use crate::jets::Jet;
use crate::mem::{NockStack, Preserve};
use crate::mem::{AllocResult, NockStack, Preserve};
use crate::noun::{Noun, Slots};
use std::ptr::{copy_nonoverlapping, null_mut};
@ -86,8 +86,8 @@ impl Iterator for WarmEntry {
impl Warm {
#[allow(clippy::new_without_default)]
pub fn new(stack: &mut NockStack) -> Self {
Warm(Hamt::new(stack))
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
Ok(Warm(Hamt::new(stack)?))
}
fn insert(
@ -97,22 +97,23 @@ impl Warm {
path: Noun,
batteries: Batteries,
jet: Jet,
) {
) -> AllocResult<()> {
let current_warm_entry = self.0.lookup(stack, formula).unwrap_or(WARM_ENTRY_NIL);
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 {
batteries,
jet,
path,
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) -> Self {
let mut warm = Self::new(stack);
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> AllocResult<Self> {
let mut warm = Self::new(stack)?;
for (mut path, axis, jet) in *hot {
let batteries_list = cold.find(stack, &mut path);
for batteries in batteries_list {
@ -121,7 +122,7 @@ impl Warm {
.next()
.expect("IMPOSSIBLE: empty battery entry in cold state");
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 {
// XX: need NockStack allocated string interpolation
// eprintln!("Bad axis {} into formula {:?}", axis, battery);
@ -129,7 +130,7 @@ impl Warm {
}
}
}
warm
Ok(warm)
}
/// Walk through the linked list of WarmEntry objects and do a partial check

View File

@ -3,6 +3,8 @@ extern crate num_derive;
extern crate lazy_static;
#[macro_use]
extern crate static_assertions;
//pub mod bytecode;
pub mod flog;
pub mod guard;
pub mod hamt;
@ -12,11 +14,14 @@ pub mod mem;
pub mod mug;
pub mod newt;
pub mod noun;
pub mod serf;
pub mod site;
//pub mod bytecode;
pub mod persist;
pub mod serf;
pub mod serialization;
pub mod site;
#[cfg(test)]
pub mod test_fns;
pub mod trace;
pub mod unifying_equality;
@ -77,10 +82,10 @@ mod tests {
use crate::noun::*;
use crate::serialization::jam;
let mut stack = NockStack::new(8 << 10 << 10, 0);
let head = Atom::new(&mut stack, 0).as_noun();
let tail = Atom::new(&mut stack, 1).as_noun();
let cell = Cell::new(&mut stack, head, tail).as_noun();
let res = jam(&mut stack, cell).as_direct().unwrap().data();
let head = Atom::new(&mut stack, 0).unwrap().as_noun();
let tail = Atom::new(&mut stack, 1).unwrap().as_noun();
let cell = Cell::new(&mut stack, head, tail).unwrap().as_noun();
let res = jam(&mut stack, cell).unwrap().as_direct().unwrap().data();
assert_eq!(res, 201);
}
}

View File

@ -6,6 +6,7 @@ use assert_no_alloc::permit_alloc;
use either::Either::{self, Left, Right};
use ibig::Stack;
use memmap::MmapMut;
use thiserror::Error;
use std::alloc::Layout;
use std::mem;
use std::ptr;
@ -26,36 +27,103 @@ pub const fn word_size_of<T>() -> usize {
(mem::size_of::<T>() + 7) >> 3
}
/** Utility function to compute the raw memory usage of an IndirectAtom */
/** Utility function to compute the raw memory usage of an [IndirectAtom] */
fn indirect_raw_size(atom: IndirectAtom) -> usize {
debug_assert!(atom.size() > 0);
atom.size() + 2
}
/** A stack for Nock computation, which supports stack allocation and delimited copying collection
* for returned nouns
*/
#[derive(Debug, Clone)]
pub struct MemoryState {
pub intended_alloc_words: Option<usize>,
pub frame_pointer: usize,
pub stack_pointer: usize,
pub alloc_pointer: usize,
pub pc: bool,
}
/// Error type for when a potential allocation would cause an OOM error
#[derive(Debug, Clone)]
pub struct OutOfMemoryError(pub MemoryState);
/// Error type for allocation errors in [NockStack]
#[derive(Debug, Clone, Error)]
pub enum AllocationError {
#[error("Out of memory: {0:?}")]
OutOfMemory(OutOfMemoryError),
#[error("Cannot allocate in copy phase: {0:?}")]
CannotAllocateInPreCopy(MemoryState),
}
impl From<AllocationError> for std::io::Error {
fn from(_e: AllocationError) -> std::io::Error {
std::io::ErrorKind::OutOfMemory.into()
}
}
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
#[derive(Debug, Clone)]
pub enum ArenaOrientation {
/// stack_pointer < alloc_pointer
/// stack_pointer increases on push
/// frame_pointer increases on push
/// alloc_pointer decreases on alloc
West,
/// stack_pointer > alloc_pointer
/// stack_pointer decreases on push
/// frame_pointer decreases on push
/// alloc_pointer increases on alloc
East,
}
#[derive(Debug, Clone)]
pub enum AllocationType {
/// alloc pointer moves
Alloc,
/// stack pointer moves
Push,
/// frame_pointer and stack_pointer move
FramePush,
}
/// Non-size parameters for validating an allocation
#[derive(Debug, Clone)]
pub struct Allocation {
pub direction: ArenaOrientation,
pub alloc_type: AllocationType,
pub pc: bool,
}
#[derive(Debug, Clone)]
pub enum Direction {
Increasing,
Decreasing,
}
/// A stack for Nock computation, which supports stack allocation and delimited copying collection
/// for returned nouns
#[allow(dead_code)] // We need the memory field to keep our memory from being unmapped
pub struct NockStack {
/** The base pointer */
/// The base pointer
start: *const u64,
/** The size of the memory region */
/// The size of the memory region
size: usize,
/** Base pointer for the current stack frame. Accesses to slots are computed from this base. */
/// Base pointer for the current stack frame. Accesses to slots are computed from this base.
frame_pointer: *mut u64,
/** Stack pointer for the current stack frame. */
/// Stack pointer for the current stack frame.
stack_pointer: *mut u64,
/** Alloc pointer for the current stack frame. */
/// Alloc pointer for the current stack frame.
alloc_pointer: *mut u64,
/** MMap which must be kept alive as long as this NockStack is */
/// MMap which must be kept alive as long as this [NockStack] is
memory: MmapMut,
/** PMA from which we will copy into the NockStack */
/** Whether or not pre_copy() has been called on the current stack frame. */
/// PMA from which we will copy into the [NockStack]
/// Whether or not [`Self::pre_copy()`] has been called on the current stack frame.
pc: bool,
}
impl NockStack {
/** Initialization
/** Initialization:
* The initial frame is a west frame. When the stack is initialized, a number of slots is given.
* We add three extra slots to store the previous frame, stack, and allocation pointer. For the
* initial frame, the previous allocation pointer is set to the beginning (low boundary) of the
@ -87,9 +155,39 @@ impl NockStack {
}
}
pub fn middle_of_stack(&self) -> *const u64 {
// is that right? off by one?
unsafe { self.start.add(self.size >> 1) }
// pub fn middle_of_stack(&self) -> *const u64 {
// // is that right? off by one?
// unsafe { self.start.add(self.size >> 1) }
// }
fn memory_state(&self, words: Option<usize>) -> MemoryState {
MemoryState {
intended_alloc_words: words,
frame_pointer: self.frame_pointer as usize,
stack_pointer: self.stack_pointer as usize,
alloc_pointer: self.alloc_pointer as usize,
pc: self.pc,
}
}
fn cannot_alloc_in_pc(&self, size: Option<usize>) -> AllocationError {
AllocationError::CannotAllocateInPreCopy(self.memory_state(size))
}
fn out_of_memory(&self, words: Option<usize>) -> AllocationError {
AllocationError::OutOfMemory(OutOfMemoryError(self.memory_state(words)))
}
pub(crate) fn get_alloc_config(&self, alloc_type: AllocationType) -> Allocation {
Allocation {
direction: if self.is_west() {
ArenaOrientation::West
} else {
ArenaOrientation::East
},
alloc_type,
pc: self.pc,
}
}
// When frame_pointer < alloc_pointer, the frame is West
@ -117,16 +215,90 @@ impl NockStack {
// if you're allocating you're just bumping the alloc pointer
// pushing a frame is more complicated
// it's fine to cross the middle of the stack, it's not fine for them to cross each other
pub fn alloc_would_overlap_middle(&self, size: usize) -> bool {
if self.is_west() {
let stack_pointer = self.stack_pointer as usize;
let end_point = stack_pointer + size;
end_point <= self.middle_of_stack() as usize
} else {
let stack_pointer = self.stack_pointer as usize;
let end_point = stack_pointer + size;
end_point >= self.middle_of_stack() as usize
// TODO: #684: We aren't accounting for self.pc
// TODO: #684: is <= always correct? Maybe it should be a 2x2 of (West/East) & (stack/alloc)?
// push vs. frame_push
// push_east/push_west use prev_alloc_pointer_pointer instead of alloc_pointer when self.pc is true
// Species of allocation: alloc, push, frame_push
// Size modifiers: raw, indirect, struct, layout
// Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false)
// Types of size: word (words: usize)
/// Check if an allocation of `size` would cause an OOM error
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> Result<(), AllocationError> {
if self.pc {
return Err(self.cannot_alloc_in_pc(Some(words)));
}
// When self.pc is true
// west:
// *prev_alloc_ptr + size <= noun_ptr
let bytes = words * 8;
// east:
// noun_ptr <= *prev_alloc_ptr - size
// West: the stack pointer must not overlap the alloc pointer
let (target_point, limit_point, direction) = match (alloc.alloc_type, alloc.direction) {
// West + Alloc, alloc is decreasing
(AllocationType::Alloc, ArenaOrientation::West) => {
let start_point = self.alloc_pointer as usize;
let limit_point = self.stack_pointer as usize;
let target_point = start_point - bytes;
(target_point, limit_point, Direction::Decreasing)
},
// East + Alloc, alloc is increasing
(AllocationType::Alloc, ArenaOrientation::East) => {
let start_point = self.alloc_pointer as usize;
let limit_point = self.stack_pointer as usize;
let target_point = start_point + bytes;
(target_point, limit_point, Direction::Increasing)
},
// West + Push, stack is increasing
(AllocationType::Push, ArenaOrientation::West) => {
let start_point = self.stack_pointer as usize;
let limit_point = self.alloc_pointer as usize;
let target_point = start_point + bytes;
(target_point, limit_point, Direction::Increasing)
},
// East + Push, stack is decreasing
(AllocationType::Push, ArenaOrientation::East) => {
let start_point = self.stack_pointer as usize;
let limit_point = self.alloc_pointer as usize;
let target_point = start_point - bytes;
(target_point, limit_point, Direction::Decreasing)
},
// West + FramePush, stack is increasing (TODO: does fp matter?)
(AllocationType::FramePush, ArenaOrientation::West) => {
let start_point = self.stack_pointer as usize;
let limit_point = self.alloc_pointer as usize;
let target_point = start_point + bytes;
(target_point, limit_point, Direction::Increasing)
},
// East + FramePush, stack is decreasing (TODO: does fp matter?)
(AllocationType::FramePush, ArenaOrientation::East) => {
let start_point = self.stack_pointer as usize;
let limit_point = self.alloc_pointer as usize;
let target_point = start_point - bytes;
(target_point, limit_point, Direction::Decreasing)
},
};
match direction {
Direction::Increasing => {
if target_point <= limit_point {
Ok(())
} else {
Err(self.out_of_memory(Some(words)))
}
},
Direction::Decreasing => {
if target_point >= limit_point {
Ok(())
} else {
Err(self.out_of_memory(Some(words)))
}
},
}
}
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) -> Result<(), AllocationError> {
let alloc = self.get_alloc_config(alloc_type);
self.alloc_would_oom_(alloc, words)
}
/** Resets the NockStack but flipping the top-frame polarity and unsetting PC. Sets the alloc
@ -136,6 +308,8 @@ impl NockStack {
*/
// TODO: #684: Add OOM checks here
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) {
// TODO: #684: How many words?
// let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
// Assert that we are at the top
assert!((*self.prev_frame_pointer_pointer()).is_null());
assert!((*self.prev_stack_pointer_pointer()).is_null());
@ -163,7 +337,7 @@ impl NockStack {
self.alloc_pointer = new_alloc_pointer;
self.pc = false;
assert!(self.is_west());
}
};
}
/// Resets the NockStack. The top frame is west as in the initial creation of the NockStack.
@ -334,38 +508,42 @@ impl NockStack {
* 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 */
// TODO: #684: Add OOM checks here
unsafe fn raw_alloc_west(&mut self, words: usize) -> *mut u64 {
unsafe fn raw_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
if self.pc {
panic!("Allocation during cleanup phase is prohibited.");
}
self.alloc_pointer = self.alloc_pointer.sub(words);
self.alloc_pointer
Ok(self.alloc_pointer)
}
/** Bump the alloc pointer for an east frame to make space for an allocation */
// TODO: #684: Add OOM checks here
unsafe fn raw_alloc_east(&mut self, words: usize) -> *mut u64 {
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
// println!("allocating struct, words: {}, is_west: {}", words, self.is_west());
// println!("pc: {}, sp: {}, ap: {}", self.pc, self.stack_pointer as usize, self.alloc_pointer as usize);
// let alloc = self.get_alloc_config(AllocationType::Alloc);
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
// println!("memory_state: {:#?}, alloc: {alloc:#?}, alloc_would_oom: {:?}\n", self.memory_state(Some(words)), would_oom);
if self.pc {
panic!("Allocation during cleanup phase is prohibited.");
}
let alloc = self.alloc_pointer;
self.alloc_pointer = self.alloc_pointer.add(words);
alloc
Ok(alloc)
}
/** Allocate space for an indirect pointer in a west frame */
unsafe fn indirect_alloc_west(&mut self, words: usize) -> *mut u64 {
unsafe fn indirect_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
self.raw_alloc_west(words + 2)
}
/** Allocate space for an indirect pointer in an east frame */
unsafe fn indirect_alloc_east(&mut self, words: usize) -> *mut u64 {
unsafe fn indirect_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
self.raw_alloc_east(words + 2)
}
/** Allocate space for an indirect pointer in a stack frame */
unsafe fn indirect_alloc(&mut self, words: usize) -> *mut u64 {
unsafe fn indirect_alloc(&mut self, words: usize) -> AllocResult<*mut u64> {
if self.is_west() {
self.indirect_alloc_west(words)
} else {
@ -374,17 +552,19 @@ impl NockStack {
}
/** Allocate space for a struct in a west frame */
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> *mut T {
self.raw_alloc_west(word_size_of::<T>() * count) as *mut T
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> AllocResult<*mut T> {
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count)?;
Ok(eigen_pointer as *mut T)
}
/** Allocate space for a struct in an east frame */
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> *mut T {
self.raw_alloc_east(word_size_of::<T>() * count) as *mut T
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> AllocResult<*mut T> {
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count)?;
Ok(eigen_pointer as *mut T)
}
/** Allocate space for a struct in a stack frame */
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> *mut T {
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> AllocResult<*mut T> {
if self.is_west() {
self.struct_alloc_west::<T>(count)
} else {
@ -430,7 +610,7 @@ impl NockStack {
}
/** Allocate space for an alloc::Layout in a stack frame */
unsafe fn layout_alloc(&mut self, layout: Layout) -> *mut u64 {
unsafe fn layout_alloc(&mut self, layout: Layout) -> AllocResult<*mut u64> {
assert!(layout.align() <= 64, "layout alignment must be <= 64");
if self.is_west() {
self.raw_alloc_west((layout.size() + 7) >> 3)
@ -679,6 +859,7 @@ impl NockStack {
/** Push a frame onto the stack with 0 or more local variable slots. */
// TODO: #684: Add OOM checks here
// TODO: Basic alloc function
pub fn frame_push(&mut self, num_locals: usize) {
if self.pc {
panic!("frame_push during cleanup phase is prohibited.");
@ -752,6 +933,7 @@ impl NockStack {
/** Push onto a west-oriented lightweight stack, moving the stack_pointer. */
// TODO: #684: Add OOM checks here
// TODO: Basic alloc function
unsafe fn push_west<T>(&mut self) -> *mut T {
let ap = if self.pc {
*(self.prev_alloc_pointer_pointer())
@ -770,6 +952,7 @@ impl NockStack {
/** Push onto an east-oriented ligthweight stack, moving the stack_pointer */
// TODO: #684: Add OOM checks here
// TODO: Basic alloc function
unsafe fn push_east<T>(&mut self) -> *mut T {
let ap = if self.pc {
*(self.prev_alloc_pointer_pointer())
@ -1015,15 +1198,15 @@ impl NockStack {
}
impl NounAllocator for NockStack {
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64> {
self.indirect_alloc(words)
}
unsafe fn alloc_cell(&mut self) -> *mut CellMemory {
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory> {
self.struct_alloc::<CellMemory>(1)
}
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T {
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T> {
self.struct_alloc::<T>(count)
}
}
@ -1072,7 +1255,8 @@ impl Preserve for Noun {
}
impl Stack for NockStack {
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64 {
type AllocError = AllocationError;
unsafe fn alloc_layout(&mut self, layout: Layout) -> AllocResult<*mut u64> {
self.layout_alloc(layout)
}
}
@ -1092,3 +1276,53 @@ impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
}
}
}
#[cfg(test)]
mod test {
use std::iter::FromIterator;
use super::*;
use crate::{
jets::cold::{test::{make_noun_list, make_test_stack}, NounList, Nounable}, mem::NockStack, noun::D, unifying_equality::unifying_equality,
};
// cargo test -- test_noun_list_alloc --nocapture
#[test]
fn test_noun_list_alloc() {
unsafe {
// fails at 512, works at 1024
const STACK_SIZE: usize = 1;
println!("TEST_SIZE: {}", STACK_SIZE);
let mut stack = make_test_stack(STACK_SIZE);
// Stack size 1 works until 15 elements, 14 passes, 15 fails.
const ITEM_COUNT: u64 = 15;
let vec = Vec::from_iter(0..ITEM_COUNT);
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
let slice = vec.as_slice();
let noun_list = make_noun_list(&mut stack, slice).unwrap();
assert!(!noun_list.0.is_null());
// This always reports 16, what gives?
// let space_needed = noun_list.space_needed(&mut stack);
// assert!(space_needed <= TEST_SIZE, "space_needed = {}, TEST_SIZE: {}", space_needed, TEST_SIZE);
let noun = noun_list.into_noun(&mut stack).unwrap();
let new_noun_list: NounList =
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun).unwrap();
let mut item_count = 0;
println!("items: {:?}", items);
for (a, b) in new_noun_list.zip(items.iter()) {
let a_ptr = a;
let b_ptr = &mut b.clone() as *mut Noun;
let a_val = *a_ptr;
println!("a: {:?}, b: {:?}", a_val, b);
assert!(
unifying_equality(&mut stack, a_ptr, b_ptr),
"Items don't match: {:?} {:?}",
a_val,
b
);
item_count += 1;
}
assert_eq!(item_count, ITEM_COUNT as usize);
}
}
}

View File

@ -51,7 +51,7 @@ use crate::interpreter::Slogger;
*
* It's important to not use io::Stdin and io::Stdout directly. All printfs should use stderr.
*/
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::noun::{IndirectAtom, Noun, D, T};
use crate::serialization::{cue, jam};
use either::Either;
@ -97,11 +97,11 @@ impl 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) {
let atom = jam(stack, noun);
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) };
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;
@ -125,6 +125,7 @@ impl Newt {
},
};
self.output.write_all(buf).unwrap();
Ok(())
}
/** Send %ripe, the first event.
@ -132,7 +133,7 @@ impl Newt {
* eve = event number
* mug = mug of Arvo after above event
*/
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) {
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) -> AllocResult<()> {
let version = T(
stack,
&[
@ -140,39 +141,44 @@ impl Newt {
D(139), // hoon kelvin
D(4), // nock kelvin
],
);
let ripe = T(stack, &[D(tas!(b"ripe")), version, D(eve), D(mug)]);
)?;
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) {
let live = T(stack, &[D(tas!(b"live")), D(0)]);
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) {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"done")), dat]);
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) {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud]);
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) {
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)]);
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.
@ -181,12 +187,13 @@ impl Newt {
* 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) {
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.
@ -195,12 +202,13 @@ impl Newt {
* 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) {
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.
@ -210,12 +218,13 @@ impl Newt {
* 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) {
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> {
@ -228,17 +237,18 @@ impl Newt {
*
* lud = list of goof
*/
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) {
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud]);
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) -> Option<Noun> {
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 None;
return Ok(None);
} else {
panic!("Newt::next: Error reading header: {}", err);
}
@ -247,10 +257,10 @@ impl Newt {
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);
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 None;
return Ok(None);
} else {
panic!("Newt::next: Error reading body: {}", err);
}
@ -258,19 +268,21 @@ impl Newt {
atom.normalize_as_atom()
};
Some(cue(stack, atom).expect("Newt::next: bad jammed noun"))
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) {
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank]);
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) {
let flog = T(stack, &[D(tas!(b"flog")), cord]);
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(())
}
}
@ -283,11 +295,13 @@ impl Default for Newt {
struct NewtSlogger(Newt);
impl Slogger for NewtSlogger {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) {
self.0.slog(stack, pri, tank);
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) {
self.0.flog(stack, cord);
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, NockStack};
use crate::mem::{word_size_of, AllocResult, NockStack};
use crate::persist::{pma_contains, pma_dirty};
use bitvec::prelude::{BitSlice, Lsb0};
use either::{Either, Left, Right};
@ -158,7 +158,7 @@ fn is_cell(noun: u64) -> bool {
}
/** A noun-related error. */
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub enum Error {
/** Expected type [`Allocated`]. */
NotAllocated,
@ -172,6 +172,7 @@ pub enum Error {
NotIndirectAtom,
/** The value can't be represented by the given type. */
NotRepresentable,
AllocationError(crate::mem::AllocationError),
}
impl error::Error for Error {}
@ -185,10 +186,17 @@ impl std::fmt::Display for Error {
Error::NotDirectAtom => f.write_str("not a direct atom"),
Error::NotIndirectAtom => f.write_str("not an indirect atom"),
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 () {
fn from(_: Error) -> Self {}
}
@ -303,18 +311,18 @@ pub const fn D(n: u64) -> Noun {
}
#[allow(non_snake_case)]
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
Cell::new_tuple(allocator, tup).as_noun()
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Noun> {
Ok(Cell::new_tuple(allocator, tup)?.as_noun())
}
/// Create $tape Noun from ASCII string
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> Noun {
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> AllocResult<Noun> {
// XX: Needs unit tests
let mut res = D(0);
for c in text.bytes().rev() {
res = T(allocator, &[D(c as u64), res])
res = T(allocator, &[D(c as u64), res])?
}
res
Ok(res)
}
/** An indirect atom.
@ -375,10 +383,10 @@ impl IndirectAtom {
allocator: &mut A,
size: usize,
data: *const u64,
) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size);
) -> AllocResult<Self> {
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size)?;
ptr::copy_nonoverlapping(data, buffer, size);
*(indirect.normalize())
Ok(*(indirect.normalize()))
}
/** Make an indirect atom by copying from other memory.
@ -389,13 +397,13 @@ impl IndirectAtom {
allocator: &mut A,
size: usize,
data: *const u8,
) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size);
) -> AllocResult<Self> {
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size)?;
ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size);
*(indirect.normalize())
Ok(*(indirect.normalize()))
}
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(allocator: &mut A, data: &[u8]) -> Self {
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(allocator: &mut A, data: &[u8]) -> AllocResult<Self> {
IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr())
}
@ -406,12 +414,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut<A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> (Self, *mut u64) {
) -> AllocResult<(Self, *mut u64)> {
debug_assert!(size > 0);
let buffer = allocator.alloc_indirect(size);
let buffer = allocator.alloc_indirect(size)?;
*buffer = 0;
*buffer.add(1) = size as u64;
(Self::from_raw_pointer(buffer), buffer.add(2))
Ok((Self::from_raw_pointer(buffer), buffer.add(2)))
}
/** Make an indirect atom that can be written into, and zero the whole data buffer.
@ -421,10 +429,10 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> (Self, *mut u64) {
let allocation = Self::new_raw_mut(allocator, size);
) -> AllocResult<(Self, *mut u64)> {
let allocation = Self::new_raw_mut(allocator, size)?;
ptr::write_bytes(allocation.1, 0, size);
allocation
Ok(allocation)
}
/** Make an indirect atom that can be written into as a bitslice. The constraints of
@ -433,12 +441,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> (Self, &'a mut BitSlice<u64, Lsb0>) {
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size);
(
) -> AllocResult<(Self, &'a mut BitSlice<u64, Lsb0>)> {
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size)?;
Ok((
noun,
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
@ -449,19 +457,19 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> (Self, &'a mut [u8]) {
) -> AllocResult<(Self, &'a mut [u8])> {
let word_size = (size + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
(noun, from_raw_parts_mut(ptr as *mut u8, size))
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
Ok((noun, from_raw_parts_mut(ptr as *mut u8, size)))
}
/// Create an indirect atom backed by a fixed-size array
pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>(
allocator: &mut A,
) -> (Self, &'a mut [u8; N]) {
) -> AllocResult<(Self, &'a mut [u8; N])> {
let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
(noun, &mut *(ptr as *mut [u8; N]))
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
Ok((noun, &mut *(ptr as *mut [u8; N])))
}
/** Size of an indirect atom in 64-bit words */
@ -511,7 +519,7 @@ impl IndirectAtom {
BitSlice::from_slice_mut(self.as_mut_slice())
}
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> UBig {
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
UBig::from_le_bytes_stack(stack, self.as_bytes())
}
@ -641,32 +649,32 @@ impl Cell {
}
}
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> Cell {
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> AllocResult<Cell> {
unsafe {
let (cell, memory) = Self::new_raw_mut(allocator);
let (cell, memory) = Self::new_raw_mut(allocator)?;
(*memory).head = head;
(*memory).tail = tail;
cell
Ok(cell)
}
}
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Cell {
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Cell> {
if tup.len() < 2 {
panic!("Cannot create tuple with fewer than 2 elements");
}
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() {
cell = Cell::new(allocator, tup[i], cell.as_noun());
cell = Cell::new(allocator, tup[i], cell.as_noun())?;
}
cell
Ok(cell)
}
pub unsafe fn new_raw_mut<A: NounAllocator>(allocator: &mut A) -> (Cell, *mut CellMemory) {
let memory = allocator.alloc_cell();
pub unsafe fn new_raw_mut<A: NounAllocator>(allocator: &mut A) -> AllocResult<(Cell, *mut CellMemory)> {
let memory = allocator.alloc_cell()?;
(*memory).metadata = 0;
(Self::from_raw_pointer(memory), memory)
Ok((Self::from_raw_pointer(memory), memory))
}
pub fn head(&self) -> Noun {
@ -751,20 +759,21 @@ pub union Atom {
}
impl Atom {
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> Atom {
if value <= DIRECT_MAX {
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> AllocResult<Atom> {
let res = if value <= DIRECT_MAX {
unsafe { DirectAtom::new_unchecked(value).as_atom() }
} 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
// if we integrate with ibig properly.
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> Atom {
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> AllocResult<Atom> {
let bit_size = big.bit_len();
let buffer = big.to_le_bytes_stack();
if bit_size < 64 {
let atom = if bit_size < 64 {
let mut value = 0u64;
for i in (0..bit_size).step_by(8) {
value |= (buffer[i / 8] as u64) << i;
@ -772,8 +781,9 @@ impl Atom {
unsafe { DirectAtom::new_unchecked(value).as_atom() }
} else {
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 {
@ -870,12 +880,13 @@ impl Atom {
}
}
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> UBig {
if self.is_indirect() {
unsafe { self.indirect.as_ubig(stack) }
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
let ubig = if self.is_indirect() {
unsafe { self.indirect.as_ubig(stack)? }
} else {
unsafe { self.direct.as_ubig(stack) }
}
};
Ok(ubig)
}
pub fn direct(&self) -> Option<DirectAtom> {
@ -1305,13 +1316,13 @@ pub trait NounAllocator: Sized {
*
* 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) -> *mut u64;
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64>;
/** Allocate memory for a cell */
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory>;
/** Allocate space for a struct in a stack frame */
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T;
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T>;
}
/**

View File

@ -5,7 +5,7 @@ use crate::jets::hot::{Hot, HotEntry};
use crate::jets::list::util::{lent, zing};
use crate::jets::nock::util::mook;
use crate::jets::warm::Warm;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::mug::*;
use crate::newt::Newt;
use crate::noun::{Atom, Cell, DirectAtom, Noun, Slots, D, T};
@ -94,7 +94,7 @@ impl Context {
snap_path: PathBuf,
trace_info: Option<TraceInfo>,
constant_hot_state: &[HotEntry],
) -> Context {
) -> AllocResult<Context> {
pma_open(snap_path).expect("serf: pma open failed");
let snapshot_version = pma_meta_get(BTMetaField::SnapshotVersion as usize);
@ -110,10 +110,10 @@ impl Context {
Context::new(trace_info, snapshot, constant_hot_state)
}
pub unsafe fn save(&mut self) {
pub unsafe fn save(&mut self) -> AllocResult<()> {
let handle = {
let mut snapshot = Snapshot({
let snapshot_mem_ptr: *mut SnapshotMem = self.nock_context.stack.struct_alloc(1);
let snapshot_mem_ptr: *mut SnapshotMem = self.nock_context.stack.struct_alloc(1)?;
// Save into PMA (does not sync)
(*snapshot_mem_ptr).epoch = self.epoch;
@ -137,16 +137,17 @@ impl Context {
PMA_CURRENT_SNAPSHOT_VERSION,
);
pma_meta_set(BTMetaField::Snapshot as usize, handle);
Ok(())
}
fn new(
trace_info: Option<TraceInfo>,
snapshot: Option<Snapshot>,
constant_hot_state: &[HotEntry],
) -> Self {
) -> AllocResult<Self> {
let mut stack = NockStack::new(2048 << 10 << 10, 0);
let newt = Newt::new();
let cache = Hamt::<Noun>::new(&mut stack);
let cache = Hamt::<Noun>::new(&mut stack)?;
let (epoch, event_num, arvo, mut cold) = unsafe {
match snapshot {
@ -156,12 +157,12 @@ impl Context {
(*(snapshot.0)).arvo,
(*(snapshot.0)).cold,
),
None => (0, 0, D(0), Cold::new(&mut stack)),
None => (0, 0, D(0), Cold::new(&mut stack)?),
}
};
let hot = Hot::init(&mut stack, constant_hot_state);
let warm = Warm::init(&mut stack, &mut cold, &hot);
let hot = Hot::init(&mut stack, constant_hot_state)?;
let warm = Warm::init(&mut stack, &mut cold, &hot)?;
let mug = mug_u32(&mut stack, arvo);
let slogger = newt.slogger().expect("Newt should make slogger");
@ -176,14 +177,14 @@ impl Context {
trace_info,
};
Context {
Ok(Context {
epoch,
event_num,
arvo,
newt,
mug,
nock_context,
}
})
}
//
@ -195,17 +196,18 @@ impl Context {
///
/// calls save(), which invalidates all nouns not in the context
/// until [preserve_event_update_leftovers] is called to resolve forwarding pointers.
pub unsafe fn event_update(&mut self, new_event_num: u64, new_arvo: Noun) {
pub unsafe fn event_update(&mut self, new_event_num: u64, new_arvo: Noun) -> AllocResult<()> {
// XX: assert event numbers are continuous
self.arvo = new_arvo;
self.event_num = new_event_num;
self.save();
self.nock_context.cache = Hamt::new(&mut self.nock_context.stack);
self.nock_context.cache = Hamt::new(&mut self.nock_context.stack)?;
self.nock_context.scry_stack = D(0);
// XX save to PMA
self.mug = mug_u32(&mut self.nock_context.stack, self.arvo);
Ok(())
}
///
@ -225,7 +227,7 @@ impl Context {
// Newt functions
//
pub fn next(&mut self) -> Option<Noun> {
pub fn next(&mut self) -> AllocResult<Option<Noun>> {
self.newt.next(&mut self.nock_context.stack)
}
@ -325,13 +327,13 @@ pub fn serf(constant_hot_state: &[HotEntry]) -> io::Result<()> {
}
}
let mut context = Context::load(snap_path, trace_info, constant_hot_state);
let mut context = Context::load(snap_path, trace_info, constant_hot_state)?;
context.ripe();
// Can't use for loop because it borrows newt
while let Some(writ) = context.next() {
while let Some(writ) = context.next()? {
// Reset the local cache and scry handler stack
context.nock_context.cache = Hamt::<Noun>::new(&mut context.nock_context.stack);
context.nock_context.cache = Hamt::<Noun>::new(&mut context.nock_context.stack)?;
context.nock_context.scry_stack = D(0);
let tag = slot(writ, 2)?.as_direct().unwrap();
@ -393,10 +395,10 @@ pub fn serf(constant_hot_state: &[HotEntry]) -> io::Result<()> {
fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result<Noun, Error> {
let arvo = context.arvo;
let stack = &mut context.nock_context.stack;
let pul = T(stack, &[D(9), D(axis), D(0), D(2)]);
let sam = T(stack, &[D(6), D(0), D(7)]);
let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]);
let sub = T(stack, &[arvo, ovo]);
let pul = T(stack, &[D(9), D(axis), D(0), D(2)])?;
let sam = T(stack, &[D(6), D(0), D(7)])?;
let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)])?;
let sub = T(stack, &[arvo, ovo])?;
interpret(&mut context.nock_context, sub, fol)
}
@ -415,9 +417,9 @@ fn peek(context: &mut Context, ovo: Noun) -> Noun {
}
}
fn goof(context: &mut Context, mote: Mote, traces: Noun) -> Noun {
fn goof(context: &mut Context, mote: Mote, traces: Noun) -> AllocResult<Noun> {
let trace = zing(&mut context.nock_context.stack, traces).expect("serf: goof: zing failed");
let tone = Cell::new(&mut context.nock_context.stack, D(2), trace);
let tone = Cell::new(&mut context.nock_context.stack, D(2), trace)?;
let tang = mook(&mut context.nock_context, tone, false)
.expect("serf: goof: +mook crashed on bail")
.tail();
@ -446,31 +448,33 @@ fn soft(context: &mut Context, ovo: Noun, trace_name: Option<String>) -> Result<
Ok(res) => Ok(res),
Err(error) => match error {
Error::Deterministic(mote, traces) | Error::NonDeterministic(mote, traces) => {
Err(goof(context, mote, traces))
Err(goof(context, mote, traces).expect("serf: soft: goof failed"))
}
Error::ScryBlocked(_) | Error::ScryCrashed(_) => {
panic!("serf: soft: .^ invalid outside of virtual Nock")
}
Error::AllocationError(allocation_error, _noun) => {
panic!("serf: soft: allocation error: {:?}", allocation_error)
},
},
}
}
fn play_life(context: &mut Context, eve: Noun) {
fn play_life(context: &mut Context, eve: Noun) -> crate::jets::Result<()> {
let stack = &mut context.nock_context.stack;
let sub = T(stack, &[D(0), D(3)]);
let lyf = T(stack, &[D(2), sub, D(0), D(2)]);
let sub = T(stack, &[D(0), D(3)])?;
let lyf = T(stack, &[D(2), sub, D(0), D(2)])?;
let res = if context.nock_context.trace_info.is_some() {
let trace_name = "boot";
let start = Instant::now();
let boot_res = interpret(&mut context.nock_context, eve, lyf);
let boot_res = interpret(&mut context.nock_context, eve, lyf)?;
write_serf_trace_safe(&mut context.nock_context, trace_name, start);
boot_res
Ok(boot_res)
} else {
interpret(&mut context.nock_context, eve, lyf)
};
match res {
let res = match res {
Ok(gat) => {
let eved = lent(eve).expect("serf: play: boot event number failure") as u64;
let arvo = slot(gat, 7).expect("serf: play: lifecycle didn't return initial Arvo");
@ -483,14 +487,18 @@ fn play_life(context: &mut Context, eve: Noun) {
}
Err(error) => match error {
Error::Deterministic(mote, traces) | Error::NonDeterministic(mote, traces) => {
let goof = goof(context, mote, traces);
let goof = goof(context, mote, traces)?;
context.play_bail(goof);
}
Error::ScryBlocked(_) | Error::ScryCrashed(_) => {
panic!("serf: play: .^ invalid outside of virtual Nock")
}
Error::AllocationError(allocation_error, _noun) => {
panic!("serf: play: allocation error: {:?}", allocation_error)
},
}
},
};
Ok(res)
}
fn play_list(context: &mut Context, mut lit: Noun) {
@ -526,7 +534,7 @@ fn play_list(context: &mut Context, mut lit: Noun) {
context.play_done();
}
fn work(context: &mut Context, job: Noun) {
fn work(context: &mut Context, job: Noun) -> AllocResult<()> {
let trace_name = if context.nock_context.trace_info.is_some() {
// XX: good luck making this safe AND rust idiomatic!
let wire = job.slot(6).expect("serf: work: job missing wire");
@ -536,12 +544,12 @@ fn work(context: &mut Context, job: Noun) {
.as_atom()
.expect("serf: work: event tag not atom");
Some(work_trace_name(&mut context.nock_context.stack, wire, vent))
Some(work_trace_name(&mut context.nock_context.stack, wire, vent)?)
} else {
None
};
match soft(context, job, trace_name) {
let res = match soft(context, job, trace_name) {
Ok(res) => {
let cell = res.as_cell().expect("serf: work: +slam returned atom");
let mut fec = cell.head();
@ -557,10 +565,11 @@ fn work(context: &mut Context, job: Noun) {
Err(goof) => {
work_swap(context, job, goof);
}
}
};
Ok(res)
}
fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
fn work_swap(context: &mut Context, job: Noun, goof: Noun) -> AllocResult<()> {
// TODO: on decryption failure in aes_siv, should bail as fast as
// possible, without rendering stack trace or injecting crud event. See
// c3__evil in vere.
@ -568,20 +577,20 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
clear_interrupt();
let stack = &mut context.nock_context.stack;
context.nock_context.cache = Hamt::<Noun>::new(stack);
context.nock_context.cache = Hamt::<Noun>::new(stack)?;
// crud ovo = [+(now) [%$ %arvo ~] [%crud goof ovo]]
let job_cell = job.as_cell().expect("serf: work: job not a cell");
let job_now = job_cell.head().as_atom().expect("serf: work: now not atom");
let now = inc(stack, job_now).as_noun();
let wire = T(stack, &[D(0), D(tas!(b"arvo")), D(0)]);
let now = inc(stack, job_now)?.as_noun();
let wire = T(stack, &[D(0), D(tas!(b"arvo")), D(0)])?;
let crud = DirectAtom::new_panic(tas!(b"crud"));
let mut ovo = T(stack, &[now, wire, crud.as_noun(), goof, job_cell.tail()]);
let mut ovo = T(stack, &[now, wire, crud.as_noun(), goof, job_cell.tail()])?;
let trace_name = if context.nock_context.trace_info.is_some() {
Some(work_trace_name(
&mut context.nock_context.stack,
wire,
crud.as_atom(),
))
)?)
} else {
None
};
@ -603,14 +612,15 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
Err(goof_crud) => {
flog!(&mut context.nock_context, "\rserf: bail");
let stack = &mut context.nock_context.stack;
let lud = T(stack, &[goof_crud, goof, D(0)]);
let lud = T(stack, &[goof_crud, goof, D(0)])?;
context.work_bail(lud);
}
}
};
Ok(())
}
fn work_trace_name(stack: &mut NockStack, wire: Noun, vent: Atom) -> String {
let wpc = path_to_cord(stack, wire);
fn work_trace_name(stack: &mut NockStack, wire: Noun, vent: Atom) -> AllocResult<String> {
let wpc = path_to_cord(stack, wire)?;
let wpc_len = met3_usize(wpc);
let wpc_bytes = &wpc.as_bytes()[0..wpc_len];
let wpc_str = match std::str::from_utf8(wpc_bytes) {
@ -631,7 +641,7 @@ fn work_trace_name(stack: &mut NockStack, wire: Noun, vent: Atom) -> String {
}
};
format!("work [{} {}]", wpc_str, vc_str)
Ok(format!("work [{} {}]", wpc_str, vc_str))
}
fn slot(noun: Noun, axis: u64) -> io::Result<Noun> {

View File

@ -1,7 +1,7 @@
use crate::hamt::MutHamt;
use crate::interpreter::Error::{self, *};
use crate::interpreter::Mote::*;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
use bitvec::prelude::{BitSlice, Lsb0};
use either::Either::{Left, Right};
@ -103,7 +103,7 @@ enum CueStackEntry {
/// # Returns
/// A Result containing either the deserialized Noun or an 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 cursor = 0;
@ -125,16 +125,16 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Resu
// 11 tag: backref
if next_bit(&mut cursor, buffer) {
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
.lookup(stack, &mut backref_noun)
.ok_or(Deterministic(Exit, D(0)))?;
} else {
// 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();
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);
*(stack.push()) = CueStackEntry::BackRef(
cursor as u64 - 2,
@ -149,13 +149,13 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Resu
// 0 tag: atom
let backref: u64 = (cursor - 1) as u64;
*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);
}
}
CueStackEntry::BackRef(backref, noun_ptr) => {
let mut backref_atom = Atom::new(stack, backref).as_noun();
backref_map.insert(stack, &mut backref_atom, *noun_ptr)
let mut backref_atom = Atom::new(stack, backref)?.as_noun();
backref_map.insert(stack, &mut backref_atom, *noun_ptr)?
}
}
}
@ -235,7 +235,7 @@ fn rub_atom(
} else {
// Need an indirect atom
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);
debug_assert!(atom.size() > 0);
unsafe { Ok(atom.normalize_as_atom()) }
@ -272,10 +272,10 @@ struct JamState<'a> {
/// Corresponds to ++jam in the hoon stdlib.
///
/// Implements a compact encoding scheme for nouns, with backreferences for shared structures.
pub fn jam(stack: &mut NockStack, noun: Noun) -> Atom {
let backref_map = MutHamt::new(stack);
pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult<Atom> {
let backref_map = MutHamt::new(stack)?;
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 {
cursor: 0,
size,
@ -336,12 +336,12 @@ pub fn jam(stack: &mut NockStack, noun: Noun) -> Atom {
let mut result = state.atom.normalize_as_atom();
stack.preserve(&mut result);
stack.frame_pop();
result
Ok(result)
}
}
/// Serialize an atom into the jam state
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) {
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<()> {
loop {
if state.cursor + 1 > state.slice.len() {
double_atom_size(traversal, state);
@ -352,12 +352,13 @@ fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) {
state.slice.set(state.cursor, false); // 0 tag for atom
state.cursor += 1;
loop {
if let Ok(()) = mat(traversal, state, atom) {
if let Ok(()) = mat(traversal, state, atom)? {
break;
} else {
double_atom_size(traversal, state);
}
}
};
Ok(())
}
/// Serialize a cell into the jam state
@ -375,7 +376,7 @@ fn jam_cell(traversal: &mut NockStack, state: &mut JamState) {
}
/// Serialize a backreference into the jam state
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) {
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) -> AllocResult<()> {
loop {
if state.cursor + 2 > state.slice.len() {
double_atom_size(traversal, state);
@ -386,44 +387,46 @@ fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) {
state.slice.set(state.cursor, true); // 1 bit
state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref
state.cursor += 2;
let backref_atom = Atom::new(traversal, backref);
let backref_atom = Atom::new(traversal, backref)?;
loop {
if let Ok(()) = mat(traversal, state, backref_atom) {
if let Ok(()) = mat(traversal, state, backref_atom)? {
break;
} else {
double_atom_size(traversal, state);
}
}
};
Ok(())
}
/// Double the size of the atom in the jam state
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) {
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> {
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]);
state.size = new_size;
state.atom = new_atom;
state.slice = new_slice;
Ok(())
}
/// Encode an atom's size and value into the jam state
///
/// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())`
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Result<(), ()> {
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<Result<(), ()>> {
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 state.cursor + 1 > state.slice.len() {
Err(())
Ok(Err(()))
} else {
state.slice.set(state.cursor, true);
state.cursor += 1;
Ok(())
Ok(Ok(()))
}
} else {
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() {
Err(())
Ok(Err(()))
} else {
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
@ -433,7 +436,7 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Result<()
..state.cursor + c_b_size + c_b_size + b_atom_size]
.copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]);
state.cursor += c_b_size + c_b_size + b_atom_size;
Ok(())
Ok(Ok(()))
}
}
}
@ -455,8 +458,8 @@ mod tests {
#[test]
fn test_jam_cue_atom() {
let mut stack = setup_stack();
let atom = Atom::new(&mut stack, 42);
let jammed = jam(&mut stack, atom.as_noun());
let atom = Atom::new(&mut stack, 42).unwrap();
let jammed = jam(&mut stack, atom.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, atom.as_noun());
}
@ -464,10 +467,10 @@ mod tests {
#[test]
fn test_jam_cue_cell() {
let mut stack = setup_stack();
let n1 = Atom::new(&mut stack, 1).as_noun();
let n2 = Atom::new(&mut stack, 2).as_noun();
let cell = Cell::new(&mut stack, n1, n2).as_noun();
let jammed = jam(&mut stack, cell);
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
let n2 = Atom::new(&mut stack, 2).unwrap().as_noun();
let cell = Cell::new(&mut stack, n1, n2).unwrap().as_noun();
let jammed = jam(&mut stack, cell).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell);
}
@ -475,12 +478,12 @@ mod tests {
#[test]
fn test_jam_cue_nested_cell() {
let mut stack = setup_stack();
let n3 = Atom::new(&mut stack, 3).as_noun();
let n4 = Atom::new(&mut stack, 4).as_noun();
let inner_cell = Cell::new(&mut stack, n3, n4);
let n1 = Atom::new(&mut stack, 1).as_noun();
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun());
let jammed = jam(&mut stack, outer_cell.as_noun());
let n3 = Atom::new(&mut stack, 3).unwrap().as_noun();
let n4 = Atom::new(&mut stack, 4).unwrap().as_noun();
let inner_cell = Cell::new(&mut stack, n3, n4).unwrap();
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun()).unwrap();
let jammed = jam(&mut stack, outer_cell.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, outer_cell.as_noun());
}
@ -488,9 +491,9 @@ mod tests {
#[test]
fn test_jam_cue_shared_structure() {
let mut stack = setup_stack();
let shared_atom = Atom::new(&mut stack, 42);
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun());
let jammed = jam(&mut stack, cell.as_noun());
let shared_atom = Atom::new(&mut stack, 42).unwrap();
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun()).unwrap();
let jammed = jam(&mut stack, cell.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell.as_noun());
}
@ -498,8 +501,8 @@ mod tests {
#[test]
fn test_jam_cue_large_atom() {
let mut stack = setup_stack();
let large_atom = Atom::new(&mut stack, u64::MAX);
let jammed = jam(&mut stack, large_atom.as_noun());
let large_atom = Atom::new(&mut stack, u64::MAX).unwrap();
let jammed = jam(&mut stack, large_atom.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, large_atom.as_noun());
}
@ -507,8 +510,8 @@ mod tests {
#[test]
fn test_jam_cue_empty_atom() {
let mut stack = setup_stack();
let empty_atom = Atom::new(&mut stack, 0);
let jammed = jam(&mut stack, empty_atom.as_noun());
let empty_atom = Atom::new(&mut stack, 0).unwrap();
let jammed = jam(&mut stack, empty_atom.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, empty_atom.as_noun());
}
@ -516,12 +519,12 @@ mod tests {
#[test]
fn test_jam_cue_complex_structure() {
let mut stack = setup_stack();
let atom1 = Atom::new(&mut stack, 1);
let atom2 = Atom::new(&mut stack, 2);
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun());
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun());
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun());
let jammed = jam(&mut stack, cell3.as_noun());
let atom1 = Atom::new(&mut stack, 1).unwrap();
let atom2 = Atom::new(&mut stack, 2).unwrap();
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun()).unwrap();
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun()).unwrap();
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun()).unwrap();
let jammed = jam(&mut stack, cell3.as_noun()).unwrap();
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell3.as_noun());
}
@ -529,7 +532,7 @@ mod tests {
#[test]
fn test_cue_invalid_input() {
let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid tag
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid tag
let result = cue(&mut stack, invalid_atom);
assert!(result.is_err());
}
@ -549,7 +552,7 @@ mod tests {
total_size as f64 / 1024.0
);
println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0);
let jammed = jam(&mut stack, original.clone());
let jammed = jam(&mut stack, original.clone()).unwrap();
println!(
"Jammed size: {:.2} KB",
jammed.as_noun().mass() as f64 / 1024.0
@ -577,14 +580,14 @@ mod tests {
let mut result = if rng.gen_bool(0.5) || done {
let value = rng.gen::<u64>();
let atom = Atom::new(stack, value);
let atom = Atom::new(stack, value).unwrap();
let noun = atom.as_noun();
(noun, accumulated_size + noun.mass())
} else {
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 cell = Cell::new(stack, left, right);
let cell = Cell::new(stack, left, right).unwrap();
let noun = cell.as_noun();
(noun, noun.mass())
};
@ -617,7 +620,7 @@ mod tests {
} else {
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 cell = Cell::new(stack, left, right);
let cell = Cell::new(stack, left, right).unwrap();
let mut noun = cell.as_noun();
let total_size = left_size + right_size + noun.mass();
@ -643,7 +646,7 @@ mod tests {
std::env::set_var("RUST_BACKTRACE", "full");
let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid atom representation
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid atom representation
let result = cue(&mut stack, invalid_atom);
assert!(result.is_err());
@ -662,7 +665,7 @@ mod tests {
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
let jammed = jam(&mut big_stack, large_atom);
let jammed = jam(&mut big_stack, large_atom).unwrap();
// 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

View File

@ -63,7 +63,7 @@ impl Site {
/// Slam a cached call site.
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() {
let jet = site.jet.unwrap();
jet(ctx, subject)

View File

@ -0,0 +1,11 @@
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::jets::bits::util::rap;
use crate::jets::form::util::scow;
use crate::mem::NockStack;
use crate::mem::{AllocResult, NockStack};
use crate::mug::met3_usize;
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun};
use either::Either::*;
@ -153,7 +153,7 @@ pub unsafe fn write_nock_trace(
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_bytes = &pc.as_bytes()[0..pc_len];
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
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
let mut cursor = path;
let mut length = 0usize;
@ -218,7 +218,7 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
// reset cursor, then actually write the path
cursor = path;
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];
while let Ok(c) = cursor.as_cell() {
@ -254,5 +254,5 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
cursor = c.tail();
}
unsafe { deres.normalize_as_atom() }
Ok(unsafe { deres.normalize_as_atom() })
}