mirror of
https://github.com/urbit/ares.git
synced 2024-11-25 05:03:19 +03:00
alloc_would_oom, guarding alloc now
This commit is contained in:
parent
80c719b5cb
commit
795ef7a0d1
@ -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`.
|
||||
|
@ -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.
|
||||
|
@ -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].
|
||||
|
@ -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`
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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() })
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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,90 +1613,110 @@ mod hint {
|
||||
hint: Option<Noun>,
|
||||
body: Noun,
|
||||
res: Noun,
|
||||
) -> Option<Noun> {
|
||||
let stack = &mut context.stack;
|
||||
let slogger = &mut context.slogger;
|
||||
let cold = &mut context.cold;
|
||||
let hot = &context.hot;
|
||||
let cache = &mut context.cache;
|
||||
|
||||
) -> Result<Option<Noun>> {
|
||||
// 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);
|
||||
}
|
||||
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
|
||||
mean_pop(stack);
|
||||
}
|
||||
tas!(b"fast") => {
|
||||
if !cfg!(feature = "sham_hints") {
|
||||
if let Some(clue) = hint {
|
||||
let chum = clue.slot(2).ok()?;
|
||||
let mut parent = clue.slot(6).ok()?;
|
||||
loop {
|
||||
if let Ok(parent_cell) = parent.as_cell() {
|
||||
if unsafe { parent_cell.head().raw_equals(D(11)) } {
|
||||
match parent.slot(7) {
|
||||
Ok(noun) => {
|
||||
parent = noun;
|
||||
}
|
||||
Err(_) => {
|
||||
return None;
|
||||
// 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;
|
||||
match tag.direct()?.data() {
|
||||
tas!(b"memo") => {
|
||||
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);
|
||||
}
|
||||
tas!(b"fast") => {
|
||||
if !cfg!(feature = "sham_hints") {
|
||||
if let Some(clue) = hint {
|
||||
let chum = clue.slot(2).ok()?;
|
||||
let mut parent = clue.slot(6).ok()?;
|
||||
loop {
|
||||
if let Ok(parent_cell) = parent.as_cell() {
|
||||
if unsafe { parent_cell.head().raw_equals(D(11)) } {
|
||||
match parent.slot(7) {
|
||||
Ok(noun) => {
|
||||
parent = noun;
|
||||
}
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let parent_formula_op = parent.slot(2).ok()?.atom()?.direct()?;
|
||||
let parent_formula_ax = parent.slot(3).ok()?.atom()?;
|
||||
let parent_formula_op = parent.slot(2).ok()?.atom()?.direct()?;
|
||||
let parent_formula_ax = parent.slot(3).ok()?.atom()?;
|
||||
|
||||
let cold_res: cold::Result = {
|
||||
if parent_formula_op.data() == 1 {
|
||||
if parent_formula_ax.direct()?.data() == 0 {
|
||||
cold.register(stack, res, parent_formula_ax, chum)
|
||||
let cold_res: cold::Result = {
|
||||
if parent_formula_op.data() == 1 {
|
||||
if parent_formula_ax.direct()?.data() == 0 {
|
||||
cold.register(stack, res, parent_formula_ax, chum)
|
||||
} else {
|
||||
// XX: flog! is ideal, but it runs afoul of the borrow checker
|
||||
// flog!(context, "invalid root parent formula: {} {}", chum, parent);
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
// XX: flog! is ideal, but it runs afoul of the borrow checker
|
||||
// flog!(context, "invalid root parent formula: {} {}", chum, parent);
|
||||
let tape = tape(
|
||||
stack, "serf: cold: register: invalid root parent axis",
|
||||
);
|
||||
slog_leaf(stack, slogger, tape);
|
||||
Ok(false)
|
||||
cold.register(stack, res, parent_formula_ax, chum)
|
||||
}
|
||||
} else {
|
||||
cold.register(stack, res, parent_formula_ax, chum)
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
match cold_res {
|
||||
Ok(true) => context.warm = Warm::init(stack, cold, hot),
|
||||
Err(cold::Error::NoParent) => {
|
||||
flog!(context, "serf: cold: register: could not match parent battery at given axis: {} {}", chum, parent_formula_ax);
|
||||
match cold_res {
|
||||
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);
|
||||
}
|
||||
Err(cold::Error::BadNock) => {
|
||||
flog!(context, "serf: cold: register: bad clue formula: {}", clue);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Err(cold::Error::BadNock) => {
|
||||
flog!(context, "serf: cold: register: bad clue formula: {}", clue);
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
flog!(context, "serf: cold: register: no clue for %fast");
|
||||
}
|
||||
} else {
|
||||
flog!(context, "serf: cold: register: no clue for %fast");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
None
|
||||
_ => {}
|
||||
};
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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)]);
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)]);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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"]
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
11
rust/sword/src/test_fns.rs
Normal file
11
rust/sword/src/test_fns.rs
Normal 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()
|
||||
}
|
@ -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() })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user