mirror of
https://github.com/urbit/ares.git
synced 2024-12-23 05:12:15 +03:00
Sword OOM round 2: PANIC! in alloc_would_oom_ (#286)
* Revert "fix build error in assert_no_alloc (#284)" This reverts commit14124d804e
. * Revert "NockStack: explicitly catch OOM (#283)" This reverts commitbd27200ef3
. * Panic instead of Result for OOM * panic_any, don't use expect * Buh-bye to PMA + guard * fix tests --------- Co-authored-by: Chris Allen <cma@bitemyapp.com>
This commit is contained in:
parent
14124d804e
commit
f9915a75ea
@ -173,7 +173,6 @@ pub struct AllocDisabler;
|
|||||||
|
|
||||||
#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled
|
#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled
|
||||||
impl AllocDisabler {
|
impl AllocDisabler {
|
||||||
#[allow(unused_variables)]
|
|
||||||
fn check(&self, layout: Layout) {
|
fn check(&self, layout: Layout) {
|
||||||
let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get());
|
let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get());
|
||||||
let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get());
|
let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get());
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
//! Addition and subtraction operators.
|
//! Addition and subtraction operators.
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::word::Word;
|
||||||
add,
|
use crate::buffer::Buffer;
|
||||||
arch::word::Word,
|
use crate::ibig::IBig;
|
||||||
buffer::Buffer,
|
use crate::memory::Stack;
|
||||||
helper_macros,
|
use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
|
||||||
ibig::IBig,
|
use crate::sign::Sign::*;
|
||||||
memory::Stack,
|
use crate::ubig::Repr::*;
|
||||||
primitive::{PrimitiveSigned, PrimitiveUnsigned},
|
use crate::ubig::UBig;
|
||||||
sign::Sign::*,
|
use crate::{add, helper_macros};
|
||||||
ubig::{Repr::*, UBig},
|
use core::mem;
|
||||||
};
|
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
use core::{
|
|
||||||
mem,
|
|
||||||
ops::{Add, AddAssign, Sub, SubAssign},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Add<UBig> for UBig {
|
impl Add<UBig> for UBig {
|
||||||
type Output = UBig;
|
type Output = UBig;
|
||||||
@ -531,58 +527,58 @@ impl UBig {
|
|||||||
// given at least 2 words of extra capacity. However, this supports UBigs which have already
|
// given at least 2 words of extra capacity. However, this supports UBigs which have already
|
||||||
// been expanded through other operations.
|
// been expanded through other operations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
|
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
|
||||||
let ubig = match (lhs.into_repr(), rhs.into_repr()) {
|
let ubig = match (lhs.into_repr(), rhs.into_repr()) {
|
||||||
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1)?,
|
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1),
|
||||||
(Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0)?,
|
(Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0),
|
||||||
(Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1)?,
|
(Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1),
|
||||||
(Large(buffer0), Large(buffer1)) => {
|
(Large(buffer0), Large(buffer1)) => {
|
||||||
if buffer0.len() >= buffer1.len() {
|
if buffer0.len() >= buffer1.len() {
|
||||||
UBig::add_large_stack(stack, buffer0, &buffer1)?
|
UBig::add_large_stack(stack, buffer0, &buffer1)
|
||||||
} else {
|
} else {
|
||||||
UBig::add_large_stack(stack, buffer1, &buffer0)?
|
UBig::add_large_stack(stack, buffer1, &buffer0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(ubig)
|
ubig
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add two `Word`s.
|
/// Add two `Word`s.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
|
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
|
||||||
let (res, overflow) = a.overflowing_add(b);
|
let (res, overflow) = a.overflowing_add(b);
|
||||||
let ubig = if overflow {
|
let ubig = if overflow {
|
||||||
let mut buffer = Buffer::allocate_stack(stack, 2)?;
|
let mut buffer = Buffer::allocate_stack(stack, 2);
|
||||||
buffer.push(res);
|
buffer.push(res);
|
||||||
buffer.push(1);
|
buffer.push(1);
|
||||||
buffer.into()
|
buffer.into()
|
||||||
} else {
|
} else {
|
||||||
UBig::from_word(res)
|
UBig::from_word(res)
|
||||||
};
|
};
|
||||||
Ok(ubig)
|
ubig
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a large number to a `Word`.
|
/// Add a large number to a `Word`.
|
||||||
fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> Result<UBig, S::AllocError> {
|
fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> UBig {
|
||||||
debug_assert!(buffer.len() >= 2);
|
debug_assert!(buffer.len() >= 2);
|
||||||
if add::add_word_in_place(&mut buffer, rhs) {
|
if add::add_word_in_place(&mut buffer, rhs) {
|
||||||
buffer.push_may_reallocate_stack(stack, 1)?;
|
buffer.push_may_reallocate_stack(stack, 1);
|
||||||
}
|
}
|
||||||
Ok(buffer.into())
|
buffer.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add two large numbers.
|
/// Add two large numbers.
|
||||||
fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> Result<UBig, S::AllocError> {
|
fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> UBig {
|
||||||
let n = buffer.len().min(rhs.len());
|
let n = buffer.len().min(rhs.len());
|
||||||
let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
|
let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
|
||||||
if rhs.len() > n {
|
if rhs.len() > n {
|
||||||
buffer.ensure_capacity_stack(stack, rhs.len())?;
|
buffer.ensure_capacity_stack(stack, rhs.len());
|
||||||
buffer.extend(&rhs[n..]);
|
buffer.extend(&rhs[n..]);
|
||||||
}
|
}
|
||||||
if overflow && add::add_one_in_place(&mut buffer[n..]) {
|
if overflow && add::add_one_in_place(&mut buffer[n..]) {
|
||||||
buffer.push_may_reallocate_stack(stack, 1)?;
|
buffer.push_may_reallocate_stack(stack, 1);
|
||||||
}
|
}
|
||||||
Ok(buffer.into())
|
buffer.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add two `Word`s.
|
/// Add two `Word`s.
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
//! Word buffer.
|
//! Word buffer.
|
||||||
|
|
||||||
use crate::{arch::word::Word, memory, memory::Stack, ubig::UBig};
|
use crate::arch::word::Word;
|
||||||
|
use crate::memory;
|
||||||
|
use crate::memory::Stack;
|
||||||
|
use crate::ubig::UBig;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{
|
use core::iter;
|
||||||
iter,
|
use core::mem::ManuallyDrop;
|
||||||
mem::ManuallyDrop,
|
use core::ops::{Deref, DerefMut};
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Buffer for Words.
|
/// Buffer for Words.
|
||||||
///
|
///
|
||||||
@ -21,14 +22,14 @@ use core::{
|
|||||||
pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>);
|
pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>);
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Result<Buffer, S::AllocError> {
|
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Buffer {
|
||||||
if num_words > Buffer::MAX_CAPACITY {
|
if num_words > Buffer::MAX_CAPACITY {
|
||||||
UBig::panic_number_too_large();
|
UBig::panic_number_too_large();
|
||||||
}
|
}
|
||||||
let capacity = Buffer::default_capacity(num_words);
|
let capacity = Buffer::default_capacity(num_words);
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity))?;
|
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity));
|
||||||
Ok(Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity))))
|
Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,11 +45,9 @@ impl Buffer {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
|
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
|
||||||
if num_words > self.capacity() {
|
if num_words > self.capacity() {
|
||||||
self.reallocate_stack(stack, num_words)
|
self.reallocate_stack(stack, num_words)
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,12 +70,11 @@ impl Buffer {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
|
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
|
||||||
assert!(num_words >= self.len());
|
assert!(num_words >= self.len());
|
||||||
let mut new_buffer = Buffer::allocate_stack(stack, num_words)?;
|
let mut new_buffer = Buffer::allocate_stack(stack, num_words);
|
||||||
new_buffer.clone_from(self);
|
new_buffer.clone_from(self);
|
||||||
*self = new_buffer;
|
*self = new_buffer;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change capacity to store `num_words` plus some extra space for future growth.
|
/// Change capacity to store `num_words` plus some extra space for future growth.
|
||||||
@ -109,10 +107,9 @@ impl Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) -> Result<(), S::AllocError> {
|
pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) {
|
||||||
self.ensure_capacity_stack(stack, self.len() + 1)?;
|
self.ensure_capacity_stack(stack, self.len() + 1);
|
||||||
self.push(word);
|
self.push(word);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a Word and reallocate if necessary.
|
/// Append a Word and reallocate if necessary.
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
//! Conversions between types.
|
//! Conversions between types.
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::word::Word;
|
||||||
arch::word::Word,
|
use crate::buffer::Buffer;
|
||||||
buffer::Buffer,
|
use crate::error::OutOfBoundsError;
|
||||||
error::OutOfBoundsError,
|
use crate::ibig::IBig;
|
||||||
ibig::IBig,
|
use crate::memory::Stack;
|
||||||
memory::Stack,
|
use crate::primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES};
|
||||||
primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES},
|
use crate::sign::Sign::*;
|
||||||
sign::Sign::*,
|
use crate::ubig::Repr::*;
|
||||||
ubig::{Repr::*, UBig},
|
use crate::ubig::UBig;
|
||||||
};
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::convert::{TryFrom, TryInto};
|
use core::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
@ -31,19 +30,19 @@ impl Default for IBig {
|
|||||||
|
|
||||||
impl UBig {
|
impl UBig {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
|
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
|
||||||
let ubig = if bytes.len() <= WORD_BYTES {
|
let ubig = if bytes.len() <= WORD_BYTES {
|
||||||
// fast path
|
// fast path
|
||||||
UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
|
UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
|
||||||
} else {
|
} else {
|
||||||
UBig::from_le_bytes_large_stack(stack, bytes)?
|
UBig::from_le_bytes_large_stack(stack, bytes)
|
||||||
};
|
};
|
||||||
Ok(ubig)
|
ubig
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
|
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
|
||||||
debug_assert!(bytes.len() > WORD_BYTES);
|
debug_assert!(bytes.len() > WORD_BYTES);
|
||||||
let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1)?;
|
let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1);
|
||||||
let mut chunks = bytes.chunks_exact(WORD_BYTES);
|
let mut chunks = bytes.chunks_exact(WORD_BYTES);
|
||||||
for chunk in &mut chunks {
|
for chunk in &mut chunks {
|
||||||
buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
|
buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
|
||||||
@ -51,7 +50,7 @@ impl UBig {
|
|||||||
if !chunks.remainder().is_empty() {
|
if !chunks.remainder().is_empty() {
|
||||||
buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
|
buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
|
||||||
}
|
}
|
||||||
Ok(buffer.into())
|
buffer.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct from little-endian bytes.
|
/// Construct from little-endian bytes.
|
||||||
@ -553,7 +552,7 @@ impl TryFrom<&IBig> for UBig {
|
|||||||
|
|
||||||
impl UBig {
|
impl UBig {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> Result<UBig, S::AllocError>
|
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> UBig
|
||||||
where
|
where
|
||||||
T: PrimitiveUnsigned,
|
T: PrimitiveUnsigned,
|
||||||
{
|
{
|
||||||
@ -561,10 +560,10 @@ impl UBig {
|
|||||||
Ok(w) => UBig::from_word(w),
|
Ok(w) => UBig::from_word(w),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let repr = x.to_le_bytes();
|
let repr = x.to_le_bytes();
|
||||||
UBig::from_le_bytes_stack(stack, repr.as_ref())?
|
UBig::from_le_bytes_stack(stack, repr.as_ref())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(ubig)
|
ubig
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert an unsigned primitive to [UBig].
|
/// Convert an unsigned primitive to [UBig].
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
//! Division operators.
|
//! Division operators.
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::word::Word;
|
||||||
arch::word::Word,
|
use crate::buffer::Buffer;
|
||||||
buffer::Buffer,
|
use crate::ibig::IBig;
|
||||||
div, helper_macros,
|
use crate::memory::{MemoryAllocation, Stack};
|
||||||
ibig::IBig,
|
use crate::ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid};
|
||||||
memory::{MemoryAllocation, Stack},
|
use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
|
||||||
ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid},
|
use crate::sign::Sign::*;
|
||||||
primitive::{PrimitiveSigned, PrimitiveUnsigned},
|
use crate::ubig::Repr::*;
|
||||||
shift,
|
use crate::ubig::UBig;
|
||||||
sign::Sign::*,
|
use crate::{div, helper_macros, shift};
|
||||||
ubig::{Repr::*, UBig},
|
use core::convert::TryFrom;
|
||||||
};
|
use core::fmt::Debug;
|
||||||
use core::{
|
use core::mem;
|
||||||
convert::TryFrom,
|
use core::ops::{Div, DivAssign, Rem, RemAssign};
|
||||||
fmt::Debug,
|
|
||||||
mem,
|
|
||||||
ops::{Div, DivAssign, Rem, RemAssign},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Div<UBig> for UBig {
|
impl Div<UBig> for UBig {
|
||||||
type Output = UBig;
|
type Output = UBig;
|
||||||
@ -1279,71 +1275,71 @@ impl_div_ibig_signed!(isize);
|
|||||||
|
|
||||||
impl UBig {
|
impl UBig {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
|
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
|
||||||
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
||||||
(Small(word0), Small(word1)) => UBig::div_word(word0, word1),
|
(Small(word0), Small(word1)) => UBig::div_word(word0, word1),
|
||||||
(Small(_), Large(_)) => UBig::from_word(0),
|
(Small(_), Large(_)) => UBig::from_word(0),
|
||||||
(Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1),
|
(Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1),
|
||||||
(Large(buffer0), Large(buffer1)) => {
|
(Large(buffer0), Large(buffer1)) => {
|
||||||
if buffer0.len() >= buffer1.len() {
|
if buffer0.len() >= buffer1.len() {
|
||||||
UBig::div_large_stack(stack, buffer0, buffer1)?
|
UBig::div_large_stack(stack, buffer0, buffer1)
|
||||||
} else {
|
} else {
|
||||||
UBig::from_word(0)
|
UBig::from_word(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(ubig_tuple)
|
ubig_tuple
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
|
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
|
||||||
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
||||||
(Small(word0), Small(word1)) => UBig::rem_word(word0, word1),
|
(Small(word0), Small(word1)) => UBig::rem_word(word0, word1),
|
||||||
(Small(word0), Large(_)) => UBig::from_word(word0),
|
(Small(word0), Large(_)) => UBig::from_word(word0),
|
||||||
(Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1),
|
(Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1),
|
||||||
(Large(buffer0), Large(buffer1)) => {
|
(Large(buffer0), Large(buffer1)) => {
|
||||||
if buffer0.len() >= buffer1.len() {
|
if buffer0.len() >= buffer1.len() {
|
||||||
UBig::rem_large_stack(stack, buffer0, buffer1)?
|
UBig::rem_large_stack(stack, buffer0, buffer1)
|
||||||
} else {
|
} else {
|
||||||
buffer0.into()
|
buffer0.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(ubig_tuple)
|
ubig_tuple
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<(UBig, UBig), S::AllocError> {
|
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> (UBig, UBig) {
|
||||||
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
|
||||||
(Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1),
|
(Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1),
|
||||||
(Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)),
|
(Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)),
|
||||||
(Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1),
|
(Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1),
|
||||||
(Large(buffer0), Large(buffer1)) => {
|
(Large(buffer0), Large(buffer1)) => {
|
||||||
if buffer0.len() >= buffer1.len() {
|
if buffer0.len() >= buffer1.len() {
|
||||||
UBig::div_rem_large_stack(stack, buffer0, buffer1)?
|
UBig::div_rem_large_stack(stack, buffer0, buffer1)
|
||||||
} else {
|
} else {
|
||||||
(UBig::from_word(0), buffer0.into())
|
(UBig::from_word(0), buffer0.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(ubig_tuple)
|
ubig_tuple
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `lhs / rhs`
|
/// `lhs / rhs`
|
||||||
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
|
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
|
||||||
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
|
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
|
||||||
lhs.erase_front(rhs.len());
|
lhs.erase_front(rhs.len());
|
||||||
Ok(lhs.into())
|
lhs.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `lhs % rhs`
|
/// `lhs % rhs`
|
||||||
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
|
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
|
||||||
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
|
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
|
||||||
let n = rhs.len();
|
let n = rhs.len();
|
||||||
rhs.copy_from_slice(&lhs[..n]);
|
rhs.copy_from_slice(&lhs[..n]);
|
||||||
let low_bits = shift::shr_in_place(&mut rhs, shift);
|
let low_bits = shift::shr_in_place(&mut rhs, shift);
|
||||||
debug_assert!(low_bits == 0);
|
debug_assert!(low_bits == 0);
|
||||||
Ok(rhs.into())
|
rhs.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `(lhs / rhs, lhs % rhs)`
|
/// `(lhs / rhs, lhs % rhs)`
|
||||||
@ -1351,33 +1347,33 @@ impl UBig {
|
|||||||
stack: &mut S,
|
stack: &mut S,
|
||||||
mut lhs: Buffer,
|
mut lhs: Buffer,
|
||||||
mut rhs: Buffer,
|
mut rhs: Buffer,
|
||||||
) -> Result<(UBig, UBig), S::AllocError> {
|
) -> (UBig, UBig) {
|
||||||
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
|
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
|
||||||
let n = rhs.len();
|
let n = rhs.len();
|
||||||
rhs.copy_from_slice(&lhs[..n]);
|
rhs.copy_from_slice(&lhs[..n]);
|
||||||
let low_bits = shift::shr_in_place(&mut rhs, shift);
|
let low_bits = shift::shr_in_place(&mut rhs, shift);
|
||||||
debug_assert!(low_bits == 0);
|
debug_assert!(low_bits == 0);
|
||||||
lhs.erase_front(n);
|
lhs.erase_front(n);
|
||||||
Ok((lhs.into(), rhs.into()))
|
(lhs.into(), rhs.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// lhs = (lhs / rhs, lhs % rhs)
|
/// lhs = (lhs / rhs, lhs % rhs)
|
||||||
///
|
///
|
||||||
/// Returns shift.
|
/// Returns shift.
|
||||||
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> Result<u32, S::AllocError> {
|
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> u32 {
|
||||||
let (shift, fast_div_rhs_top) = div::normalize_large(rhs);
|
let (shift, fast_div_rhs_top) = div::normalize_large(rhs);
|
||||||
let lhs_carry = shift::shl_in_place(lhs, shift);
|
let lhs_carry = shift::shl_in_place(lhs, shift);
|
||||||
if lhs_carry != 0 {
|
if lhs_carry != 0 {
|
||||||
lhs.push_may_reallocate_stack(stack, lhs_carry)?;
|
lhs.push_may_reallocate_stack(stack, lhs_carry);
|
||||||
}
|
}
|
||||||
let mut allocation =
|
let mut allocation =
|
||||||
MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()))?;
|
MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()));
|
||||||
let mut memory = allocation.memory();
|
let mut memory = allocation.memory();
|
||||||
let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory);
|
let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory);
|
||||||
if overflow {
|
if overflow {
|
||||||
lhs.push_may_reallocate(1);
|
lhs.push_may_reallocate(1);
|
||||||
}
|
}
|
||||||
Ok(shift)
|
shift
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `lhs / rhs`
|
/// `lhs / rhs`
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
//! Memory allocation.
|
//! Memory allocation.
|
||||||
|
|
||||||
use alloc::alloc::Layout;
|
use alloc::alloc::Layout;
|
||||||
use core::{marker::PhantomData, mem, slice};
|
use core::marker::PhantomData;
|
||||||
|
use core::{mem, slice};
|
||||||
|
|
||||||
/// Chunk of memory directly allocated from the global allocator.
|
/// Chunk of memory directly allocated from the global allocator.
|
||||||
pub(crate) struct MemoryAllocation {
|
pub(crate) struct MemoryAllocation {
|
||||||
@ -10,10 +11,8 @@ pub(crate) struct MemoryAllocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Stack: Sized {
|
pub trait Stack: Sized {
|
||||||
// type AllocError: Debug;
|
|
||||||
// no-std bites me in the keister again
|
// no-std bites me in the keister again
|
||||||
type AllocError;
|
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64;
|
||||||
unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<*mut u64, Self::AllocError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chunk of memory.
|
/// Chunk of memory.
|
||||||
@ -27,7 +26,7 @@ pub(crate) struct Memory<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryAllocation {
|
impl MemoryAllocation {
|
||||||
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> Result<MemoryAllocation, S::AllocError> {
|
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> MemoryAllocation {
|
||||||
let start = if layout.size() == 0 {
|
let start = if layout.size() == 0 {
|
||||||
// We should use layout.dangling(), but that is unstable.
|
// We should use layout.dangling(), but that is unstable.
|
||||||
layout.align() as *mut u8
|
layout.align() as *mut u8
|
||||||
@ -36,7 +35,7 @@ impl MemoryAllocation {
|
|||||||
} else {
|
} else {
|
||||||
// Safe because size is non-zero.
|
// Safe because size is non-zero.
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
let ep = stack.alloc_layout(layout)?;
|
let ep = stack.alloc_layout(layout);
|
||||||
ep as *mut u8
|
ep as *mut u8
|
||||||
};
|
};
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
@ -45,7 +44,7 @@ impl MemoryAllocation {
|
|||||||
ptr
|
ptr
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(MemoryAllocation { layout, start })
|
MemoryAllocation { layout, start }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate memory.
|
/// Allocate memory.
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
//! Multiplication operators.
|
//! Multiplication operators.
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::word::Word;
|
||||||
arch::word::Word,
|
use crate::buffer::Buffer;
|
||||||
buffer::Buffer,
|
use crate::ibig::IBig;
|
||||||
helper_macros,
|
use crate::memory::{MemoryAllocation, Stack};
|
||||||
ibig::IBig,
|
use crate::primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned};
|
||||||
memory::{MemoryAllocation, Stack},
|
use crate::sign::Sign::{self, *};
|
||||||
mul,
|
use crate::ubig::Repr::*;
|
||||||
primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned},
|
use crate::ubig::UBig;
|
||||||
sign::Sign::{self, *},
|
use crate::{helper_macros, mul};
|
||||||
ubig::{Repr::*, UBig},
|
use core::mem;
|
||||||
};
|
use core::ops::{Mul, MulAssign};
|
||||||
use core::{
|
|
||||||
mem,
|
|
||||||
ops::{Mul, MulAssign},
|
|
||||||
};
|
|
||||||
use static_assertions::const_assert;
|
use static_assertions::const_assert;
|
||||||
|
|
||||||
impl Mul<UBig> for UBig {
|
impl Mul<UBig> for UBig {
|
||||||
@ -300,52 +296,52 @@ impl_mul_ibig_primitive!(isize);
|
|||||||
|
|
||||||
impl UBig {
|
impl UBig {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
|
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
|
||||||
let res = match (lhs.into_repr(), rhs.into_repr()) {
|
let res = match (lhs.into_repr(), rhs.into_repr()) {
|
||||||
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1)?,
|
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1),
|
||||||
(Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0)?,
|
(Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0),
|
||||||
(Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1)?,
|
(Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1),
|
||||||
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1)?,
|
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1),
|
||||||
};
|
};
|
||||||
Ok(res)
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
|
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
|
||||||
UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b))
|
UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> Result<UBig, S::AllocError> {
|
fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> UBig {
|
||||||
match a {
|
match a {
|
||||||
0 => Ok(UBig::from_word(0)),
|
0 => UBig::from_word(0),
|
||||||
1 => Ok(buffer.into()),
|
1 => buffer.into(),
|
||||||
_ => {
|
_ => {
|
||||||
let carry = mul::mul_word_in_place(&mut buffer, a);
|
let carry = mul::mul_word_in_place(&mut buffer, a);
|
||||||
if carry != 0 {
|
if carry != 0 {
|
||||||
buffer.push_may_reallocate_stack(stack, carry)?;
|
buffer.push_may_reallocate_stack(stack, carry);
|
||||||
}
|
}
|
||||||
Ok(buffer.into())
|
buffer.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> Result<UBig, S::AllocError> {
|
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> UBig {
|
||||||
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
|
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
|
||||||
|
|
||||||
// This may be 1 too large.
|
// This may be 1 too large.
|
||||||
const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1);
|
const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1);
|
||||||
let res_len = lhs.len() + rhs.len();
|
let res_len = lhs.len() + rhs.len();
|
||||||
let mut buffer = Buffer::allocate_stack(stack, res_len)?;
|
let mut buffer = Buffer::allocate_stack(stack, res_len);
|
||||||
buffer.push_zeros(res_len);
|
buffer.push_zeros(res_len);
|
||||||
|
|
||||||
let mut allocation = MemoryAllocation::new_stack(
|
let mut allocation = MemoryAllocation::new_stack(
|
||||||
stack,
|
stack,
|
||||||
mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())),
|
mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())),
|
||||||
)?;
|
);
|
||||||
let mut memory = allocation.memory();
|
let mut memory = allocation.memory();
|
||||||
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
|
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
|
||||||
assert!(overflow == 0);
|
assert!(overflow == 0);
|
||||||
Ok(buffer.into())
|
buffer.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply two `Word`s.
|
/// Multiply two `Word`s.
|
||||||
|
@ -17,7 +17,7 @@ fn main() -> io::Result<()> {
|
|||||||
let jammed_input = unsafe {
|
let jammed_input = unsafe {
|
||||||
let in_map = memmap::Mmap::map(&f)?;
|
let in_map = memmap::Mmap::map(&f)?;
|
||||||
let word_len = (in_len + 7) >> 3;
|
let word_len = (in_len + 7) >> 3;
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize).expect("Out of memory condition on IndirectAtom allocation in main()");
|
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize);
|
||||||
write_bytes(dest.add(word_len as usize - 1), 0, 8);
|
write_bytes(dest.add(word_len as usize - 1), 0, 8);
|
||||||
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
|
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
|
||||||
mem::drop(in_map);
|
mem::drop(in_map);
|
||||||
@ -45,7 +45,7 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
let nuw = SystemTime::now();
|
let nuw = SystemTime::now();
|
||||||
|
|
||||||
let jammed_output = jam(&mut stack, input).expect("Out of memory condition on jam in main()");
|
let jammed_output = jam(&mut stack, input);
|
||||||
|
|
||||||
match nuw.elapsed() {
|
match nuw.elapsed() {
|
||||||
Ok(elapse) => {
|
Ok(elapse) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::interpreter::Context;
|
use crate::interpreter::Context;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, IndirectAtom};
|
use crate::noun::{Atom, IndirectAtom};
|
||||||
use std::fmt::Arguments;
|
use std::fmt::Arguments;
|
||||||
use std::io::{Result, Write};
|
use std::io::{Result, Write};
|
||||||
@ -14,27 +14,26 @@ struct NockWriter<'s, 'b> {
|
|||||||
const INITIAL_CAPACITY_BYTES: usize = 256;
|
const INITIAL_CAPACITY_BYTES: usize = 256;
|
||||||
|
|
||||||
impl<'s, 'b> NockWriter<'s, 'b> {
|
impl<'s, 'b> NockWriter<'s, 'b> {
|
||||||
unsafe fn new(stack: &'s mut NockStack) -> AllocResult<Self> {
|
unsafe fn new(stack: &'s mut NockStack) -> Self {
|
||||||
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES)?;
|
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES);
|
||||||
Ok(NockWriter {
|
NockWriter {
|
||||||
stack,
|
stack,
|
||||||
buffer,
|
buffer,
|
||||||
indirect,
|
indirect,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn finalize(mut self) -> Atom {
|
unsafe fn finalize(mut self) -> Atom {
|
||||||
self.indirect.normalize_as_atom()
|
self.indirect.normalize_as_atom()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn expand(&mut self) -> AllocResult<()> {
|
unsafe fn expand(&mut self) {
|
||||||
let sz = self.buffer.len();
|
let sz = self.buffer.len();
|
||||||
let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2)?;
|
let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2);
|
||||||
new_buffer[0..sz].copy_from_slice(self.buffer);
|
new_buffer[0..sz].copy_from_slice(self.buffer);
|
||||||
self.buffer = new_buffer;
|
self.buffer = new_buffer;
|
||||||
self.indirect = new_indirect;
|
self.indirect = new_indirect;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ impl Write for NockWriter<'_, '_> {
|
|||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
let sz = buf.len();
|
let sz = buf.len();
|
||||||
while (self.buffer.len() - self.cursor) < sz {
|
while (self.buffer.len() - self.cursor) < sz {
|
||||||
unsafe { self.expand()? };
|
unsafe { self.expand() };
|
||||||
}
|
}
|
||||||
self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf);
|
self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf);
|
||||||
self.cursor += sz;
|
self.cursor += sz;
|
||||||
@ -55,14 +54,14 @@ impl Write for NockWriter<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<Atom> {
|
pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<Atom> {
|
||||||
let mut nw = unsafe { NockWriter::new(&mut context.stack)? };
|
let mut nw = unsafe { NockWriter::new(&mut context.stack) };
|
||||||
nw.write_fmt(fmt)?;
|
nw.write_fmt(fmt)?;
|
||||||
Ok(unsafe { nw.finalize() })
|
Ok(unsafe { nw.finalize() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> {
|
pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> {
|
||||||
let cord = nock_fmt(context, fmt)?;
|
let cord = nock_fmt(context, fmt)?;
|
||||||
context.slogger.flog(&mut context.stack, cord.as_noun())?;
|
context.slogger.flog(&mut context.stack, cord.as_noun());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::mem::{AllocResult, NockStack, Preserve};
|
use crate::mem::{NockStack, Preserve};
|
||||||
use crate::mug::mug_u32;
|
use crate::mug::mug_u32;
|
||||||
use crate::noun::Noun;
|
use crate::noun::Noun;
|
||||||
use crate::unifying_equality::unifying_equality;
|
use crate::unifying_equality::unifying_equality;
|
||||||
@ -59,45 +59,45 @@ impl<T: Copy> MutStem<T> {
|
|||||||
pub struct MutHamt<T: Copy>(*mut MutStem<T>);
|
pub struct MutHamt<T: Copy>(*mut MutStem<T>);
|
||||||
|
|
||||||
impl<T: Copy> MutHamt<T> {
|
impl<T: Copy> MutHamt<T> {
|
||||||
pub fn new(stack: &mut NockStack) -> AllocResult<MutHamt<T>> {
|
pub fn new(stack: &mut NockStack) -> MutHamt<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?;
|
let new_stem = stack.struct_alloc::<MutStem<T>>(1);
|
||||||
(*new_stem).bitmap = 0;
|
(*new_stem).bitmap = 0;
|
||||||
(*new_stem).typemap = 0;
|
(*new_stem).typemap = 0;
|
||||||
Ok(MutHamt(new_stem))
|
MutHamt(new_stem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> {
|
pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
|
||||||
let mut stem = self.0;
|
let mut stem = self.0;
|
||||||
let mut mug = mug_u32(stack, *n)?;
|
let mut mug = mug_u32(stack, *n);
|
||||||
unsafe {
|
unsafe {
|
||||||
'lookup: loop {
|
'lookup: loop {
|
||||||
let chunk = mug & 0x1f;
|
let chunk = mug & 0x1f;
|
||||||
mug >>= 5;
|
mug >>= 5;
|
||||||
match (*stem).entry(chunk) {
|
match (*stem).entry(chunk) {
|
||||||
None => {
|
None => {
|
||||||
break Ok(None);
|
break None;
|
||||||
}
|
}
|
||||||
Some(Left(next_stem)) => {
|
Some(Left(next_stem)) => {
|
||||||
stem = next_stem;
|
stem = next_stem;
|
||||||
}
|
}
|
||||||
Some(Right(leaf)) => {
|
Some(Right(leaf)) => {
|
||||||
for pair in leaf.to_mut_slice().iter_mut() {
|
for pair in leaf.to_mut_slice().iter_mut() {
|
||||||
if unifying_equality(stack, n, &mut pair.0)? {
|
if unifying_equality(stack, n, &mut pair.0) {
|
||||||
break 'lookup Ok(Some(pair.1));
|
break 'lookup Some(pair.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break Ok(None);
|
break None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> {
|
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) {
|
||||||
let mut stem = self.0;
|
let mut stem = self.0;
|
||||||
let mut mug = mug_u32(stack, *n)?;
|
let mut mug = mug_u32(stack, *n);
|
||||||
let mut depth = 0u8;
|
let mut depth = 0u8;
|
||||||
unsafe {
|
unsafe {
|
||||||
'insert: loop {
|
'insert: loop {
|
||||||
@ -105,7 +105,7 @@ impl<T: Copy> MutHamt<T> {
|
|||||||
mug >>= 5;
|
mug >>= 5;
|
||||||
match (*stem).entry(chunk) {
|
match (*stem).entry(chunk) {
|
||||||
None => {
|
None => {
|
||||||
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1)?;
|
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1);
|
||||||
*new_leaf_buffer = (*n, t);
|
*new_leaf_buffer = (*n, t);
|
||||||
(*stem).bitmap |= chunk_to_bit(chunk);
|
(*stem).bitmap |= chunk_to_bit(chunk);
|
||||||
(*stem).typemap &= !chunk_to_bit(chunk);
|
(*stem).typemap &= !chunk_to_bit(chunk);
|
||||||
@ -124,13 +124,13 @@ impl<T: Copy> MutHamt<T> {
|
|||||||
}
|
}
|
||||||
Some(Right(leaf)) => {
|
Some(Right(leaf)) => {
|
||||||
for pair in leaf.to_mut_slice().iter_mut() {
|
for pair in leaf.to_mut_slice().iter_mut() {
|
||||||
if unifying_equality(stack, n, &mut pair.0)? {
|
if unifying_equality(stack, n, &mut pair.0) {
|
||||||
pair.1 = t;
|
pair.1 = t;
|
||||||
break 'insert;
|
break 'insert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if depth >= 5 {
|
if depth >= 5 {
|
||||||
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1)?;
|
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1);
|
||||||
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
||||||
*new_leaf_buffer.add(leaf.len) = (*n, t);
|
*new_leaf_buffer.add(leaf.len) = (*n, t);
|
||||||
(*stem).buffer[chunk as usize] = MutEntry {
|
(*stem).buffer[chunk as usize] = MutEntry {
|
||||||
@ -142,8 +142,8 @@ impl<T: Copy> MutHamt<T> {
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
assert!(leaf.len == 1);
|
assert!(leaf.len == 1);
|
||||||
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?;
|
let new_stem = stack.struct_alloc::<MutStem<T>>(1);
|
||||||
let leaf_mug = mug_u32(stack, (*leaf.buffer).0)?;
|
let leaf_mug = mug_u32(stack, (*leaf.buffer).0);
|
||||||
let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f;
|
let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f;
|
||||||
(*new_stem).bitmap = chunk_to_bit(leaf_chunk);
|
(*new_stem).bitmap = chunk_to_bit(leaf_chunk);
|
||||||
(*new_stem).typemap = 0;
|
(*new_stem).typemap = 0;
|
||||||
@ -158,7 +158,6 @@ impl<T: Copy> MutHamt<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,15 +282,15 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
unsafe { (*self.0).bitmap == 0 }
|
unsafe { (*self.0).bitmap == 0 }
|
||||||
}
|
}
|
||||||
// Make a new, empty HAMT
|
// Make a new, empty HAMT
|
||||||
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
|
pub fn new(stack: &mut NockStack) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let stem_ptr = stack.struct_alloc::<Stem<T>>(1)?;
|
let stem_ptr = stack.struct_alloc::<Stem<T>>(1);
|
||||||
*stem_ptr = Stem {
|
*stem_ptr = Stem {
|
||||||
bitmap: 0,
|
bitmap: 0,
|
||||||
typemap: 0,
|
typemap: 0,
|
||||||
buffer: null_mut(),
|
buffer: null_mut(),
|
||||||
};
|
};
|
||||||
Ok(Hamt(stem_ptr))
|
Hamt(stem_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,15 +305,15 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
* A mutable reference is required so that unifying equality can unify the key with a key entry
|
* A mutable reference is required so that unifying equality can unify the key with a key entry
|
||||||
* in the HAMT
|
* in the HAMT
|
||||||
*/
|
*/
|
||||||
pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> {
|
pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
|
||||||
let mut stem = unsafe { *self.0 };
|
let mut stem = unsafe { *self.0 };
|
||||||
let mut mug = mug_u32(stack, *n)?;
|
let mut mug = mug_u32(stack, *n);
|
||||||
'lookup: loop {
|
'lookup: loop {
|
||||||
let chunk = mug & 0x1F; // 5 bits
|
let chunk = mug & 0x1F; // 5 bits
|
||||||
mug >>= 5;
|
mug >>= 5;
|
||||||
match stem.entry(chunk) {
|
match stem.entry(chunk) {
|
||||||
None => {
|
None => {
|
||||||
break Ok(None);
|
break None;
|
||||||
}
|
}
|
||||||
Some((Left(next_stem), _idx)) => {
|
Some((Left(next_stem), _idx)) => {
|
||||||
stem = next_stem;
|
stem = next_stem;
|
||||||
@ -322,11 +321,11 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
}
|
}
|
||||||
Some((Right(leaf), _idx)) => {
|
Some((Right(leaf), _idx)) => {
|
||||||
for pair in unsafe { leaf.to_mut_slice().iter_mut() } {
|
for pair in unsafe { leaf.to_mut_slice().iter_mut() } {
|
||||||
if unsafe { unifying_equality(stack, n, &mut pair.0)? } {
|
if unsafe { unifying_equality(stack, n, &mut pair.0) } {
|
||||||
break 'lookup Ok(Some(pair.1));
|
break 'lookup Some(pair.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break Ok(None);
|
break None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,11 +334,11 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
// XX a delete function requires a stack, do we need one?
|
// XX a delete function requires a stack, do we need one?
|
||||||
|
|
||||||
/// Make a new HAMT with the value inserted or replaced at the key.
|
/// Make a new HAMT with the value inserted or replaced at the key.
|
||||||
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<Hamt<T>> {
|
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> Hamt<T> {
|
||||||
let mut mug = mug_u32(stack, *n)?;
|
let mut mug = mug_u32(stack, *n);
|
||||||
let mut depth = 0u8;
|
let mut depth = 0u8;
|
||||||
let mut stem = unsafe { *self.0 };
|
let mut stem = unsafe { *self.0 };
|
||||||
let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) }?;
|
let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) };
|
||||||
let mut dest = stem_ret;
|
let mut dest = stem_ret;
|
||||||
unsafe {
|
unsafe {
|
||||||
'insert: loop {
|
'insert: loop {
|
||||||
@ -348,10 +347,10 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
match stem.entry(chunk) {
|
match stem.entry(chunk) {
|
||||||
// No entry found at mug chunk index; add Leaf to current Stem
|
// No entry found at mug chunk index; add Leaf to current Stem
|
||||||
None => {
|
None => {
|
||||||
let new_leaf_buffer = stack.struct_alloc(1)?;
|
let new_leaf_buffer = stack.struct_alloc(1);
|
||||||
*new_leaf_buffer = (*n, t);
|
*new_leaf_buffer = (*n, t);
|
||||||
let split = stem.hypothetical_index(chunk);
|
let split = stem.hypothetical_index(chunk);
|
||||||
let new_buffer = stack.struct_alloc(stem.size() + 1)?;
|
let new_buffer = stack.struct_alloc(stem.size() + 1);
|
||||||
if split > 0 {
|
if split > 0 {
|
||||||
copy_nonoverlapping(stem.buffer, new_buffer, split);
|
copy_nonoverlapping(stem.buffer, new_buffer, split);
|
||||||
}
|
}
|
||||||
@ -373,11 +372,11 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
typemap: stem.typemap & !chunk_to_bit(chunk),
|
typemap: stem.typemap & !chunk_to_bit(chunk),
|
||||||
buffer: new_buffer,
|
buffer: new_buffer,
|
||||||
};
|
};
|
||||||
break Ok(Hamt(stem_ret));
|
break Hamt(stem_ret);
|
||||||
}
|
}
|
||||||
// Stem found at mug chunk index; insert into found Stem
|
// Stem found at mug chunk index; insert into found Stem
|
||||||
Some((Left(next_stem), idx)) => {
|
Some((Left(next_stem), idx)) => {
|
||||||
let new_buffer = stack.struct_alloc(stem.size())?;
|
let new_buffer = stack.struct_alloc(stem.size());
|
||||||
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
||||||
*dest = Stem {
|
*dest = Stem {
|
||||||
bitmap: stem.bitmap,
|
bitmap: stem.bitmap,
|
||||||
@ -393,11 +392,11 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
Some((Right(leaf), idx)) => {
|
Some((Right(leaf), idx)) => {
|
||||||
// Override existing value for key, if one exists
|
// Override existing value for key, if one exists
|
||||||
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
|
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
|
||||||
if unifying_equality(stack, n, &mut pair.0)? {
|
if unifying_equality(stack, n, &mut pair.0) {
|
||||||
let new_leaf_buffer = stack.struct_alloc(leaf.len)?;
|
let new_leaf_buffer = stack.struct_alloc(leaf.len);
|
||||||
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
||||||
(*new_leaf_buffer.add(ldx)).1 = t;
|
(*new_leaf_buffer.add(ldx)).1 = t;
|
||||||
let new_buffer = stack.struct_alloc(stem.size())?;
|
let new_buffer = stack.struct_alloc(stem.size());
|
||||||
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
||||||
*new_buffer.add(idx) = Entry {
|
*new_buffer.add(idx) = Entry {
|
||||||
leaf: Leaf {
|
leaf: Leaf {
|
||||||
@ -410,16 +409,16 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
typemap: stem.typemap,
|
typemap: stem.typemap,
|
||||||
buffer: new_buffer,
|
buffer: new_buffer,
|
||||||
};
|
};
|
||||||
break 'insert Ok(Hamt(stem_ret));
|
break 'insert Hamt(stem_ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No existing pair in this Leaf matches the key, and we've maxxed out the
|
// No existing pair in this Leaf matches the key, and we've maxxed out the
|
||||||
// Hamt depth; add the the key-value pair to the list of pairs for this Leaf
|
// Hamt depth; add the the key-value pair to the list of pairs for this Leaf
|
||||||
if depth >= 5 {
|
if depth >= 5 {
|
||||||
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1)?;
|
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1);
|
||||||
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
|
||||||
*new_leaf_buffer.add(leaf.len) = (*n, t);
|
*new_leaf_buffer.add(leaf.len) = (*n, t);
|
||||||
let new_buffer = stack.struct_alloc(stem.size())?;
|
let new_buffer = stack.struct_alloc(stem.size());
|
||||||
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
||||||
*new_buffer.add(idx) = Entry {
|
*new_buffer.add(idx) = Entry {
|
||||||
leaf: Leaf {
|
leaf: Leaf {
|
||||||
@ -432,7 +431,7 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
typemap: stem.typemap,
|
typemap: stem.typemap,
|
||||||
buffer: new_buffer,
|
buffer: new_buffer,
|
||||||
};
|
};
|
||||||
break 'insert Ok(Hamt(stem_ret));
|
break 'insert Hamt(stem_ret);
|
||||||
// No existing pair in this Leaf matches the key, but we haven't maxxed out
|
// No existing pair in this Leaf matches the key, but we haven't maxxed out
|
||||||
// the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't
|
// the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't
|
||||||
// be making a linked list of pairs. Turn the Leaf into a Stem and insert
|
// be making a linked list of pairs. Turn the Leaf into a Stem and insert
|
||||||
@ -442,18 +441,18 @@ impl<T: Copy + Preserve> Hamt<T> {
|
|||||||
// Make a fake node pointing to the old leaf and "insert into it" the
|
// Make a fake node pointing to the old leaf and "insert into it" the
|
||||||
// next time around
|
// next time around
|
||||||
assert!(leaf.len == 1);
|
assert!(leaf.len == 1);
|
||||||
let fake_buffer = stack.struct_alloc(1)?;
|
let fake_buffer = stack.struct_alloc(1);
|
||||||
*fake_buffer = Entry { leaf };
|
*fake_buffer = Entry { leaf };
|
||||||
// Get the mug chunk for the Noun at the *next* level so that we can
|
// Get the mug chunk for the Noun at the *next* level so that we can
|
||||||
// build a fake stem for it
|
// build a fake stem for it
|
||||||
let fake_mug = mug_u32(stack, (*leaf.buffer).0)?;
|
let fake_mug = mug_u32(stack, (*leaf.buffer).0);
|
||||||
let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F;
|
let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F;
|
||||||
let next_stem = Stem {
|
let next_stem = Stem {
|
||||||
bitmap: chunk_to_bit(fake_chunk),
|
bitmap: chunk_to_bit(fake_chunk),
|
||||||
typemap: 0,
|
typemap: 0,
|
||||||
buffer: fake_buffer,
|
buffer: fake_buffer,
|
||||||
};
|
};
|
||||||
let new_buffer = stack.struct_alloc(stem.size())?;
|
let new_buffer = stack.struct_alloc(stem.size());
|
||||||
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
|
||||||
*dest = Stem {
|
*dest = Stem {
|
||||||
bitmap: stem.bitmap,
|
bitmap: stem.bitmap,
|
||||||
@ -518,13 +517,13 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
let res = if stack.is_in_frame(self.0) {
|
if stack.is_in_frame(self.0) {
|
||||||
let dest_stem = stack.struct_alloc_in_previous_frame(1)?;
|
let dest_stem = stack.struct_alloc_in_previous_frame(1);
|
||||||
copy_nonoverlapping(self.0, dest_stem, 1);
|
copy_nonoverlapping(self.0, dest_stem, 1);
|
||||||
self.0 = dest_stem;
|
self.0 = dest_stem;
|
||||||
if stack.is_in_frame((*dest_stem).buffer) {
|
if stack.is_in_frame((*dest_stem).buffer) {
|
||||||
let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size())?;
|
let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size());
|
||||||
copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size());
|
copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size());
|
||||||
(*dest_stem).buffer = dest_buffer;
|
(*dest_stem).buffer = dest_buffer;
|
||||||
// Here we're using the Rust stack since the array is a fixed
|
// Here we're using the Rust stack since the array is a fixed
|
||||||
@ -557,7 +556,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
|
|||||||
Some((Left(next_stem), idx)) => {
|
Some((Left(next_stem), idx)) => {
|
||||||
if stack.is_in_frame(next_stem.buffer) {
|
if stack.is_in_frame(next_stem.buffer) {
|
||||||
let dest_buffer =
|
let dest_buffer =
|
||||||
stack.struct_alloc_in_previous_frame(next_stem.size())?;
|
stack.struct_alloc_in_previous_frame(next_stem.size());
|
||||||
copy_nonoverlapping(
|
copy_nonoverlapping(
|
||||||
next_stem.buffer,
|
next_stem.buffer,
|
||||||
dest_buffer,
|
dest_buffer,
|
||||||
@ -583,15 +582,15 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
|
|||||||
Some((Right(leaf), idx)) => {
|
Some((Right(leaf), idx)) => {
|
||||||
if stack.is_in_frame(leaf.buffer) {
|
if stack.is_in_frame(leaf.buffer) {
|
||||||
let dest_buffer =
|
let dest_buffer =
|
||||||
stack.struct_alloc_in_previous_frame(leaf.len)?;
|
stack.struct_alloc_in_previous_frame(leaf.len);
|
||||||
copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len);
|
copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len);
|
||||||
let new_leaf = Leaf {
|
let new_leaf = Leaf {
|
||||||
len: leaf.len,
|
len: leaf.len,
|
||||||
buffer: dest_buffer,
|
buffer: dest_buffer,
|
||||||
};
|
};
|
||||||
for pair in new_leaf.to_mut_slice().iter_mut() {
|
for pair in new_leaf.to_mut_slice().iter_mut() {
|
||||||
pair.0.preserve(stack)?;
|
pair.0.preserve(stack);
|
||||||
pair.1.preserve(stack)?;
|
pair.1.preserve(stack);
|
||||||
}
|
}
|
||||||
*stem.buffer.add(idx) = Entry { leaf: new_leaf };
|
*stem.buffer.add(idx) = Entry { leaf: new_leaf };
|
||||||
}
|
}
|
||||||
@ -602,8 +601,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,10 +707,10 @@ mod test {
|
|||||||
let size = 1 << 27;
|
let size = 1 << 27;
|
||||||
let top_slots = 100;
|
let top_slots = 100;
|
||||||
let mut stack = NockStack::new(size, top_slots);
|
let mut stack = NockStack::new(size, top_slots);
|
||||||
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
|
let mut hamt = Hamt::<Noun>::new(&mut stack);
|
||||||
hamt = hamt.insert(&mut stack, &mut D(0), D(1)).unwrap();
|
hamt = hamt.insert(&mut stack, &mut D(0), D(1));
|
||||||
hamt = hamt.insert(&mut stack, &mut D(2), D(3)).unwrap();
|
hamt = hamt.insert(&mut stack, &mut D(2), D(3));
|
||||||
hamt = hamt.insert(&mut stack, &mut D(4), D(5)).unwrap();
|
hamt = hamt.insert(&mut stack, &mut D(4), D(5));
|
||||||
let mut iter = hamt.iter();
|
let mut iter = hamt.iter();
|
||||||
let three = cdr(&mut iter);
|
let three = cdr(&mut iter);
|
||||||
let one = cdr(&mut iter);
|
let one = cdr(&mut iter);
|
||||||
@ -730,10 +728,10 @@ mod test {
|
|||||||
let size = 1 << 27;
|
let size = 1 << 27;
|
||||||
let top_slots = 100;
|
let top_slots = 100;
|
||||||
let mut stack = NockStack::new(size, top_slots);
|
let mut stack = NockStack::new(size, top_slots);
|
||||||
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
|
let mut hamt = Hamt::<Noun>::new(&mut stack);
|
||||||
let mut hs = HashSet::new();
|
let mut hs = HashSet::new();
|
||||||
for n in 0..100 {
|
for n in 0..100 {
|
||||||
hamt = hamt.insert(&mut stack, &mut D(n), D(n)).unwrap();
|
hamt = hamt.insert(&mut stack, &mut D(n), D(n));
|
||||||
hs.insert((n, n));
|
hs.insert((n, n));
|
||||||
}
|
}
|
||||||
let mut iter = hamt.iter();
|
let mut iter = hamt.iter();
|
||||||
@ -748,21 +746,17 @@ mod test {
|
|||||||
let size = 1 << 27;
|
let size = 1 << 27;
|
||||||
let top_slots = 100;
|
let top_slots = 100;
|
||||||
let mut stack = NockStack::new(size, top_slots);
|
let mut stack = NockStack::new(size, top_slots);
|
||||||
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
|
let mut hamt = Hamt::<Noun>::new(&mut stack);
|
||||||
let mut n = D(0);
|
let mut n = D(0);
|
||||||
let t = D(1);
|
let t = D(1);
|
||||||
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
|
hamt = hamt.insert(&mut stack, &mut n, t);
|
||||||
let lu = hamt
|
let lu = hamt.lookup(&mut stack, &mut n);
|
||||||
.lookup(&mut stack, &mut n)
|
|
||||||
.expect("lookup failed due to OOM");
|
|
||||||
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
|
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
|
||||||
assert_eq!(lu_value, 1);
|
assert_eq!(lu_value, 1);
|
||||||
let mut n = D(2);
|
let mut n = D(2);
|
||||||
let t = D(3);
|
let t = D(3);
|
||||||
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
|
hamt = hamt.insert(&mut stack, &mut n, t);
|
||||||
let lu = hamt
|
let lu = hamt.lookup(&mut stack, &mut D(2));
|
||||||
.lookup(&mut stack, &mut D(2))
|
|
||||||
.expect("lookup failed due to OOM");
|
|
||||||
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
|
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
|
||||||
assert_eq!(lu_value, 3);
|
assert_eq!(lu_value, 3);
|
||||||
}
|
}
|
||||||
@ -772,38 +766,32 @@ mod test {
|
|||||||
let size = 1 << 27;
|
let size = 1 << 27;
|
||||||
let top_slots = 100;
|
let top_slots = 100;
|
||||||
let mut stack = NockStack::new(size, top_slots);
|
let mut stack = NockStack::new(size, top_slots);
|
||||||
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
|
let mut hamt = Hamt::<Noun>::new(&mut stack);
|
||||||
// 3-way collision
|
// 3-way collision
|
||||||
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
|
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
|
||||||
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
|
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
|
||||||
|
|
||||||
let mut n = D(0);
|
let mut n = D(0);
|
||||||
let t = D(0);
|
let t = D(0);
|
||||||
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
|
hamt = hamt.insert(&mut stack, &mut n, t);
|
||||||
|
|
||||||
let mut n = D(87699370);
|
let mut n = D(87699370);
|
||||||
let t = D(87699370);
|
let t = D(87699370);
|
||||||
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
|
hamt = hamt.insert(&mut stack, &mut n, t);
|
||||||
|
|
||||||
let mut n = D(317365951);
|
let mut n = D(317365951);
|
||||||
let t = D(317365951);
|
let t = D(317365951);
|
||||||
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
|
hamt = hamt.insert(&mut stack, &mut n, t);
|
||||||
|
|
||||||
let lu = hamt
|
let lu = hamt.lookup(&mut stack, &mut D(0));
|
||||||
.lookup(&mut stack, &mut D(0))
|
|
||||||
.expect("lookup failed due to OOM");
|
|
||||||
let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() };
|
let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() };
|
||||||
assert_eq!(lu_value, 0);
|
assert_eq!(lu_value, 0);
|
||||||
|
|
||||||
let lu = hamt
|
let lu = hamt.lookup(&mut stack, &mut D(87699370));
|
||||||
.lookup(&mut stack, &mut D(87699370))
|
|
||||||
.expect("lookup failed due to OOM");
|
|
||||||
let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() };
|
let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() };
|
||||||
assert_eq!(lu_value, 87699370);
|
assert_eq!(lu_value, 87699370);
|
||||||
|
|
||||||
let lu = hamt
|
let lu = hamt.lookup(&mut stack, &mut D(317365951));
|
||||||
.lookup(&mut stack, &mut D(317365951))
|
|
||||||
.expect("lookup failed due to OOM");
|
|
||||||
let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() };
|
let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() };
|
||||||
assert_eq!(lu_value, 317365951);
|
assert_eq!(lu_value, 317365951);
|
||||||
}
|
}
|
||||||
@ -813,13 +801,13 @@ mod test {
|
|||||||
let size = 1 << 27;
|
let size = 1 << 27;
|
||||||
let top_slots = 100;
|
let top_slots = 100;
|
||||||
let mut stack = NockStack::new(size, top_slots);
|
let mut stack = NockStack::new(size, top_slots);
|
||||||
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
|
let mut hamt = Hamt::<Noun>::new(&mut stack);
|
||||||
// 3-way collision
|
// 3-way collision
|
||||||
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
|
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
|
||||||
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
|
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
|
||||||
let mut hs = HashSet::new();
|
let mut hs = HashSet::new();
|
||||||
for x in &[0, 87699370, 317365951] {
|
for x in &[0, 87699370, 317365951] {
|
||||||
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)).unwrap();
|
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x));
|
||||||
hs.insert((*x, *x));
|
hs.insert((*x, *x));
|
||||||
}
|
}
|
||||||
for x in hamt.iter() {
|
for x in hamt.iter() {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,10 @@ pub mod tree;
|
|||||||
use crate::flog;
|
use crate::flog;
|
||||||
use crate::interpreter::{Context, Error, Mote};
|
use crate::interpreter::{Context, Error, Mote};
|
||||||
use crate::jets::bits::*;
|
use crate::jets::bits::*;
|
||||||
|
use crate::jets::cold::Cold;
|
||||||
use crate::jets::form::*;
|
use crate::jets::form::*;
|
||||||
use crate::jets::hash::*;
|
use crate::jets::hash::*;
|
||||||
|
use crate::jets::hot::{Hot, URBIT_HOT_STATE};
|
||||||
use crate::jets::list::*;
|
use crate::jets::list::*;
|
||||||
use crate::jets::lock::aes::*;
|
use crate::jets::lock::aes::*;
|
||||||
use crate::jets::lock::ed::*;
|
use crate::jets::lock::ed::*;
|
||||||
@ -32,36 +34,31 @@ use crate::jets::serial::*;
|
|||||||
use crate::jets::sort::*;
|
use crate::jets::sort::*;
|
||||||
|
|
||||||
use crate::jets::tree::*;
|
use crate::jets::tree::*;
|
||||||
use crate::mem::{AllocResult, NockStack, Preserve};
|
use crate::jets::warm::Warm;
|
||||||
|
use crate::mem::{NockStack, Preserve};
|
||||||
use crate::noun::{self, Noun, Slots, D};
|
use crate::noun::{self, Noun, Slots, D};
|
||||||
use sword_macros::tas;
|
use sword_macros::tas;
|
||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
/// Return Err if the computation crashed or should punt to Nock
|
/// Return Err if the computation crashed or should punt to Nock
|
||||||
pub type Result<T> = std::result::Result<T, JetErr>;
|
pub type Result = std::result::Result<Noun, JetErr>;
|
||||||
pub type Jet = fn(&mut Context, Noun) -> Result<Noun>;
|
pub type Jet = fn(&mut Context, Noun) -> Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only return a deterministic error if the Nock would have deterministically
|
* Only return a deterministic error if the Nock would have deterministically
|
||||||
* crashed.
|
* crashed.
|
||||||
*/
|
*/
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum JetErr {
|
pub enum JetErr {
|
||||||
Punt, // Retry with the raw nock
|
Punt, // Retry with the raw nock
|
||||||
Fail(Error), // Error; do not retry
|
Fail(Error), // Error; do not retry
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::mem::AllocationError> for JetErr {
|
|
||||||
fn from(_err: crate::mem::AllocationError) -> Self {
|
|
||||||
JetErr::Fail(Error::NonDeterministic(Mote::Meme, D(0)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Preserve for JetErr {
|
impl Preserve for JetErr {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
match self {
|
match self {
|
||||||
JetErr::Punt => Ok(()),
|
JetErr::Punt => {}
|
||||||
JetErr::Fail(ref mut err) => err.preserve(stack),
|
JetErr::Fail(ref mut err) => err.preserve(stack),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +232,7 @@ pub mod util {
|
|||||||
bits_to_word(checked_left_shift(bloq, step)?)
|
bits_to_word(checked_left_shift(bloq, step)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slot(noun: Noun, axis: u64) -> Result<Noun> {
|
pub fn slot(noun: Noun, axis: u64) -> Result {
|
||||||
noun.slot(axis).map_err(|_e| BAIL_EXIT)
|
noun.slot(axis).map_err(|_e| BAIL_EXIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +288,7 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> {
|
pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> {
|
||||||
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)])?;
|
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)]);
|
||||||
interpret(context, core, formula).map_err(JetErr::Fail)
|
interpret(context, core, formula).map_err(JetErr::Fail)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,44 +296,41 @@ pub mod util {
|
|||||||
let core: Noun = T(
|
let core: Noun = T(
|
||||||
&mut context.stack,
|
&mut context.stack,
|
||||||
&[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()],
|
&[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()],
|
||||||
)?;
|
);
|
||||||
kick(context, core, D(2))
|
kick(context, core, D(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::hamt::Hamt;
|
use crate::hamt::Hamt;
|
||||||
use crate::interpreter::Slogger;
|
use crate::interpreter::Slogger;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Noun, D, T};
|
use crate::noun::{Atom, Noun, D, T};
|
||||||
use crate::unifying_equality::test::unifying_equality;
|
use crate::unifying_equality::unifying_equality;
|
||||||
use assert_no_alloc::assert_no_alloc;
|
use assert_no_alloc::assert_no_alloc;
|
||||||
use ibig::UBig;
|
use ibig::UBig;
|
||||||
|
|
||||||
struct TestSlogger {}
|
struct TestSlogger {}
|
||||||
|
|
||||||
impl Slogger for TestSlogger {
|
impl Slogger for TestSlogger {
|
||||||
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) -> AllocResult<()> {
|
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) {
|
||||||
eprintln!("Jet slogged.");
|
eprintln!("Jet slogged.");
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) -> AllocResult<()> {
|
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) {
|
||||||
eprintln!("Jet flogged.");
|
eprintln!("Jet flogged.");
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_context() -> Result<Context> {
|
pub fn init_context() -> Context {
|
||||||
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
||||||
let cold = cold::Cold::new(&mut stack)?;
|
let cold = Cold::new(&mut stack);
|
||||||
let warm = warm::Warm::new(&mut stack)?;
|
let warm = Warm::new(&mut stack);
|
||||||
let hot = hot::Hot::init(&mut stack, hot::URBIT_HOT_STATE)?;
|
let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
|
||||||
let cache = Hamt::<Noun>::new(&mut stack)?;
|
let cache = Hamt::<Noun>::new(&mut stack);
|
||||||
let slogger = std::boxed::Box::pin(TestSlogger {});
|
let slogger = std::boxed::Box::pin(TestSlogger {});
|
||||||
|
|
||||||
Ok(Context {
|
Context {
|
||||||
stack,
|
stack,
|
||||||
slogger,
|
slogger,
|
||||||
cold,
|
cold,
|
||||||
@ -345,12 +339,12 @@ pub mod util {
|
|||||||
cache,
|
cache,
|
||||||
scry_stack: D(0),
|
scry_stack: D(0),
|
||||||
trace_info: None,
|
trace_info: None,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn A(stack: &mut NockStack, ubig: &UBig) -> AllocResult<Noun> {
|
pub fn A(stack: &mut NockStack, ubig: &UBig) -> Noun {
|
||||||
Ok(Atom::from_ubig(stack, ubig)?.as_noun())
|
Atom::from_ubig(stack, ubig).as_noun()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
|
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
|
||||||
@ -358,92 +352,28 @@ pub mod util {
|
|||||||
assert!(eq, "got: {}, need: {}", a, b);
|
assert!(eq, "got: {}, need: {}", a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_jet(
|
pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
|
||||||
context: &mut Context,
|
|
||||||
jet: Jet,
|
|
||||||
sam: Noun,
|
|
||||||
res: Noun,
|
|
||||||
) -> AllocResult<()> {
|
|
||||||
assert_jet_door(context, jet, sam, D(0), res)
|
assert_jet_door(context, jet, sam, D(0), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AssertJetFn = fn(
|
pub fn assert_jet_door(context: &mut Context, jet: Jet, sam: Noun, pay: Noun, res: Noun) {
|
||||||
&mut Context,
|
let sam = T(&mut context.stack, &[D(0), sam, pay]);
|
||||||
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
|
|
||||||
Noun,
|
|
||||||
Noun,
|
|
||||||
);
|
|
||||||
pub fn assert_jet_panicky(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
|
|
||||||
assert_jet(context, jet, sam, res).expect("assert_jet failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assert_jet_door(
|
|
||||||
context: &mut Context,
|
|
||||||
jet: Jet,
|
|
||||||
sam: Noun,
|
|
||||||
pay: Noun,
|
|
||||||
res: Noun,
|
|
||||||
) -> AllocResult<()> {
|
|
||||||
let sam = T(&mut context.stack, &[D(0), sam, pay])?;
|
|
||||||
let jet_res = assert_no_alloc(|| jet(context, sam).unwrap());
|
let jet_res = assert_no_alloc(|| jet(context, sam).unwrap());
|
||||||
assert_noun_eq(&mut context.stack, jet_res, res);
|
assert_noun_eq(&mut context.stack, jet_res, res);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AssertJetDoorFn = fn(
|
pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
|
||||||
&mut Context,
|
let res = A(&mut context.stack, &res);
|
||||||
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
|
assert_jet(context, jet, sam, res);
|
||||||
Noun,
|
|
||||||
Noun,
|
|
||||||
Noun,
|
|
||||||
);
|
|
||||||
pub fn assert_jet_door_panicky(
|
|
||||||
context: &mut Context,
|
|
||||||
jet: Jet,
|
|
||||||
sam: Noun,
|
|
||||||
pay: Noun,
|
|
||||||
res: Noun,
|
|
||||||
) {
|
|
||||||
assert_jet_door(context, jet, sam, pay, res).expect("assert_jet_door failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_jet_ubig(
|
pub fn assert_nary_jet_ubig(context: &mut Context, jet: Jet, sam: &[Noun], res: UBig) {
|
||||||
context: &mut Context,
|
let sam = T(&mut context.stack, sam);
|
||||||
jet: Jet,
|
assert_jet_ubig(context, jet, sam, res);
|
||||||
sam: Noun,
|
|
||||||
res: UBig,
|
|
||||||
) -> AllocResult<()> {
|
|
||||||
let res = A(&mut context.stack, &res)?;
|
|
||||||
assert_jet(context, jet, sam, res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AssertJetUBigFn = fn(
|
pub fn assert_jet_err(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
|
||||||
&mut Context,
|
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
|
||||||
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
|
|
||||||
Noun,
|
|
||||||
UBig,
|
|
||||||
);
|
|
||||||
pub fn assert_jet_ubig_panicky(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
|
|
||||||
assert_jet_ubig(context, jet, sam, res).expect("assert_jet_ubig failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assert_nary_jet_ubig(
|
|
||||||
context: &mut Context,
|
|
||||||
jet: Jet,
|
|
||||||
sam: &[Noun],
|
|
||||||
res: UBig,
|
|
||||||
) -> AllocResult<()> {
|
|
||||||
let sam = T(&mut context.stack, sam)?;
|
|
||||||
assert_jet_ubig(context, jet, sam, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assert_jet_err(
|
|
||||||
context: &mut Context,
|
|
||||||
jet: Jet,
|
|
||||||
sam: Noun,
|
|
||||||
err: JetErr,
|
|
||||||
) -> AllocResult<()> {
|
|
||||||
let sam = T(&mut context.stack, &[D(0), sam, D(0)])?;
|
|
||||||
let jet_res = jet(context, sam);
|
let jet_res = jet(context, sam);
|
||||||
assert!(
|
assert!(
|
||||||
jet_res.is_err(),
|
jet_res.is_err(),
|
||||||
@ -453,10 +383,10 @@ pub mod util {
|
|||||||
&jet_res
|
&jet_res
|
||||||
);
|
);
|
||||||
let jet_err = jet_res.unwrap_err();
|
let jet_err = jet_res.unwrap_err();
|
||||||
match (jet_err.clone(), err.clone()) {
|
match (jet_err, err) {
|
||||||
(JetErr::Punt, JetErr::Punt) => {}
|
(JetErr::Punt, JetErr::Punt) => {}
|
||||||
(JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => {
|
(JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => {
|
||||||
match (actual_err.clone(), expected_err.clone()) {
|
match (actual_err, expected_err) {
|
||||||
(Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected))
|
(Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected))
|
||||||
| (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected))
|
| (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected))
|
||||||
| (
|
| (
|
||||||
@ -485,22 +415,11 @@ pub mod util {
|
|||||||
sam, err, jet_err
|
sam, err, jet_err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type AssertJetErrFn = fn(
|
|
||||||
&mut Context,
|
|
||||||
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
|
|
||||||
Noun,
|
|
||||||
JetErr,
|
|
||||||
);
|
|
||||||
pub fn assert_jet_err_panicky(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
|
|
||||||
assert_jet_err(context, jet, sam, err).expect("assert_jet failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) {
|
pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) {
|
||||||
let sam = T(&mut context.stack, &[D(0), sam, D(0)]).unwrap();
|
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
|
||||||
let res = assert_no_alloc(|| jet(context, sam).unwrap());
|
let res = assert_no_alloc(|| jet(context, sam).unwrap());
|
||||||
assert!(res.is_atom(), "jet result not atom");
|
assert!(res.is_atom(), "jet result not atom");
|
||||||
let res_siz = res.atom().unwrap().size();
|
let res_siz = res.atom().unwrap().size();
|
||||||
@ -514,7 +433,7 @@ pub mod util {
|
|||||||
res: UBig,
|
res: UBig,
|
||||||
) {
|
) {
|
||||||
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
||||||
assert_nary_jet_ubig(context, jet, &sam, res).unwrap();
|
assert_nary_jet_ubig(context, jet, &sam, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_common_jet_noun(
|
pub fn assert_common_jet_noun(
|
||||||
@ -524,8 +443,8 @@ pub mod util {
|
|||||||
res: Noun,
|
res: Noun,
|
||||||
) {
|
) {
|
||||||
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
||||||
let sam = T(&mut context.stack, &sam).unwrap();
|
let sam = T(&mut context.stack, &sam);
|
||||||
assert_jet(context, jet, sam, res).unwrap();
|
assert_jet(context, jet, sam, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_common_jet_err(
|
pub fn assert_common_jet_err(
|
||||||
@ -535,8 +454,8 @@ pub mod util {
|
|||||||
err: JetErr,
|
err: JetErr,
|
||||||
) {
|
) {
|
||||||
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
||||||
let sam = T(&mut context.stack, &sam).unwrap();
|
let sam = T(&mut context.stack, &sam);
|
||||||
assert_jet_err(context, jet, sam, err).unwrap();
|
assert_jet_err(context, jet, sam, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_common_jet_size(
|
pub fn assert_common_jet_size(
|
||||||
@ -546,7 +465,7 @@ pub mod util {
|
|||||||
siz: usize,
|
siz: usize,
|
||||||
) {
|
) {
|
||||||
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
|
||||||
let sam = T(&mut context.stack, &sam).unwrap();
|
let sam = T(&mut context.stack, &sam);
|
||||||
assert_jet_size(context, jet, sam, siz)
|
assert_jet_size(context, jet, sam, siz)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@ crate::gdb!();
|
|||||||
* Bit arithmetic
|
* Bit arithmetic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
||||||
Ok(util::bex(&mut context.stack, arg)?.as_noun())
|
Ok(util::bex(&mut context.stack, arg).as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_can(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(arg, 2)?)?;
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
let original_list = slot(arg, 3)?;
|
let original_list = slot(arg, 3)?;
|
||||||
@ -27,7 +27,7 @@ pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
util::can(&mut context.stack, bloq, original_list)
|
util::can(&mut context.stack, bloq, original_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(arg, 2)?)?;
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
let a = slot(arg, 6)?.as_atom()?;
|
let a = slot(arg, 6)?.as_atom()?;
|
||||||
@ -41,7 +41,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len);
|
||||||
chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?;
|
chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?;
|
||||||
chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?;
|
chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?;
|
||||||
Ok(new_indirect.normalize_as_atom().as_noun())
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
@ -49,7 +49,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(arg, 2)?)?;
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
let start = slot(arg, 12)?.as_direct()?.data() as usize;
|
let start = slot(arg, 12)?.as_direct()?.data() as usize;
|
||||||
@ -62,14 +62,14 @@ pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
let new_indirect = unsafe {
|
let new_indirect = unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?);
|
||||||
chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?;
|
chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?;
|
||||||
new_indirect.normalize_as_atom()
|
new_indirect.normalize_as_atom()
|
||||||
};
|
};
|
||||||
Ok(new_indirect.as_noun())
|
Ok(new_indirect.as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sew(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(sam, 2)?)?;
|
let bloq = bloq(slot(sam, 2)?)?;
|
||||||
let e = slot(sam, 7)?.as_atom()?;
|
let e = slot(sam, 7)?.as_atom()?;
|
||||||
@ -90,12 +90,12 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut dest_indirect, dest) =
|
let (mut dest_indirect, dest) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?);
|
||||||
|
|
||||||
chop(bloq, 0, len_e, 0, dest, e.as_bitslice())?;
|
chop(bloq, 0, len_e, 0, dest, e.as_bitslice())?;
|
||||||
|
|
||||||
let (_, lead) =
|
let (_, lead) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
|
||||||
|
|
||||||
chop(bloq, 0, min(step, len_d), 0, lead, donor.as_bitslice())?;
|
chop(bloq, 0, min(step, len_d), 0, lead, donor.as_bitslice())?;
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_end(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let (bloq, step) = bite(slot(arg, 2)?)?;
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
let a = slot(arg, 3)?.as_atom()?;
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
@ -116,14 +116,14 @@ pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
|
||||||
chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?;
|
chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?;
|
||||||
Ok(new_indirect.normalize_as_atom().as_noun())
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let (bloq, step) = bite(slot(arg, 2)?)?;
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
let a = slot(arg, 3)?.as_atom()?;
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
@ -131,7 +131,7 @@ pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
util::lsh(&mut context.stack, bloq, step, a)
|
util::lsh(&mut context.stack, bloq, step, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(arg, 2)?)?;
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
let a = slot(arg, 3)?.as_atom()?;
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
@ -139,14 +139,14 @@ pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
Ok(D(util::met(bloq, a) as u64))
|
Ok(D(util::met(bloq, a) as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let bloq = bloq(slot(arg, 2)?)?;
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
let original_list = slot(arg, 3)?;
|
let original_list = slot(arg, 3)?;
|
||||||
Ok(util::rap(&mut context.stack, bloq, original_list)?.as_noun())
|
Ok(util::rap(&mut context.stack, bloq, original_list)?.as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let (bloq, step) = bite(slot(arg, 2)?)?;
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
let original_list = slot(arg, 3)?;
|
let original_list = slot(arg, 3)?;
|
||||||
@ -169,7 +169,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?)?;
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?);
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let mut list = original_list;
|
let mut list = original_list;
|
||||||
loop {
|
loop {
|
||||||
@ -189,7 +189,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data();
|
let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data();
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
let src = dat.as_bitslice();
|
let src = dat.as_bitslice();
|
||||||
let (mut output, dest) =
|
let (mut output, dest) =
|
||||||
unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize)? };
|
unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize) };
|
||||||
|
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
let total_len = len << boz;
|
let total_len = len << boz;
|
||||||
@ -219,14 +219,14 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
Ok(unsafe { output.normalize_as_atom() }.as_noun())
|
Ok(unsafe { output.normalize_as_atom() }.as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let (bloq, step) = bite(slot(arg, 2)?)?;
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
let atom = slot(arg, 3)?.as_atom()?;
|
let atom = slot(arg, 3)?.as_atom()?;
|
||||||
util::rip(&mut context.stack, bloq, step, atom)
|
util::rip(&mut context.stack, bloq, step, atom)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let (bloq, step) = bite(slot(arg, 2)?)?;
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
let a = slot(arg, 3)?.as_atom()?;
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
@ -238,13 +238,13 @@ pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
|
||||||
chop(bloq, step, len - step, 0, dest, a.as_bitslice())?;
|
chop(bloq, step, len - step, 0, dest, a.as_bitslice())?;
|
||||||
Ok(atom.normalize_as_atom().as_noun())
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let a = slot(sam, 1)?.as_atom()?;
|
let a = slot(sam, 1)?.as_atom()?;
|
||||||
Ok(D(util::met(0, a) as u64))
|
Ok(D(util::met(0, a) as u64))
|
||||||
@ -254,15 +254,15 @@ pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
* Bit logic
|
* Bit logic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn jet_con(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_con(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
Ok(util::con(&mut context.stack, a, b)?.as_noun())
|
Ok(util::con(&mut context.stack, a, b).as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
@ -270,7 +270,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let new_size = cmp::max(a.size(), b.size());
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
|
||||||
let a_bit = a.as_bitslice();
|
let a_bit = a.as_bitslice();
|
||||||
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
*dest &= b.as_bitslice();
|
*dest &= b.as_bitslice();
|
||||||
@ -278,7 +278,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
@ -286,7 +286,7 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let new_size = cmp::max(a.size(), b.size());
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
|
||||||
let a_bit = a.as_bitslice();
|
let a_bit = a.as_bitslice();
|
||||||
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
*dest ^= b.as_bitslice();
|
*dest ^= b.as_bitslice();
|
||||||
@ -297,26 +297,25 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
pub mod util {
|
pub mod util {
|
||||||
use crate::jets::util::*;
|
use crate::jets::util::*;
|
||||||
use crate::jets::{JetErr, Result};
|
use crate::jets::{JetErr, Result};
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
/// Binary exponent
|
/// Binary exponent
|
||||||
pub fn bex(stack: &mut NockStack, arg: usize) -> AllocResult<Atom> {
|
pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = if arg < 63 {
|
if arg < 63 {
|
||||||
DirectAtom::new_unchecked(1 << arg).as_atom()
|
DirectAtom::new_unchecked(1 << arg).as_atom()
|
||||||
} else {
|
} else {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
|
||||||
dest.set(arg, true);
|
dest.set(arg, true);
|
||||||
atom.normalize_as_atom()
|
atom.normalize_as_atom()
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result<Noun> {
|
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result {
|
||||||
let len = met(bloq, a);
|
let len = met(bloq, a);
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(D(0));
|
return Ok(D(0));
|
||||||
@ -324,13 +323,13 @@ pub mod util {
|
|||||||
|
|
||||||
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
|
||||||
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
|
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
|
||||||
Ok(atom.normalize_as_atom().as_noun())
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result<Noun> {
|
pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result {
|
||||||
let mut len = 0usize;
|
let mut len = 0usize;
|
||||||
let mut list = original_list;
|
let mut list = original_list;
|
||||||
loop {
|
loop {
|
||||||
@ -351,7 +350,7 @@ pub mod util {
|
|||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?;
|
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let mut list = original_list;
|
let mut list = original_list;
|
||||||
loop {
|
loop {
|
||||||
@ -385,32 +384,32 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result<Noun> {
|
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result {
|
||||||
let len = (met(bloq, atom) + step - 1) / step;
|
let len = (met(bloq, atom) + step - 1) / step;
|
||||||
let mut list = D(0);
|
let mut list = D(0);
|
||||||
for i in (0..len).rev() {
|
for i in (0..len).rev() {
|
||||||
let new_atom = unsafe {
|
let new_atom = unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq)?;
|
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq);
|
||||||
chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?;
|
chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?;
|
||||||
new_indirect.normalize_as_atom()
|
new_indirect.normalize_as_atom()
|
||||||
};
|
};
|
||||||
list = Cell::new(stack, new_atom.as_noun(), list)?.as_noun();
|
list = Cell::new(stack, new_atom.as_noun(), list).as_noun();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(list)
|
Ok(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binary OR
|
/// Binary OR
|
||||||
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> {
|
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
|
||||||
let new_size = cmp::max(a.size(), b.size());
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size)?;
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
|
||||||
let a_bit = a.as_bitslice();
|
let a_bit = a.as_bitslice();
|
||||||
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
*dest |= b.as_bitslice();
|
*dest |= b.as_bitslice();
|
||||||
Ok(atom.normalize_as_atom())
|
atom.normalize_as_atom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,11 +432,11 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
Ok(Atom::new(stack, 0)?)
|
Ok(Atom::new(stack, 0))
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut new_indirect, new_slice) =
|
let (mut new_indirect, new_slice) =
|
||||||
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?;
|
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let mut list = original_list;
|
let mut list = original_list;
|
||||||
|
|
||||||
@ -476,7 +475,6 @@ pub mod util {
|
|||||||
let s = &mut init_stack();
|
let s = &mut init_stack();
|
||||||
|
|
||||||
let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210))
|
let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210))
|
||||||
.unwrap()
|
|
||||||
.as_atom()
|
.as_atom()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(met(0, a), 128);
|
assert_eq!(met(0, a), 128);
|
||||||
@ -507,15 +505,8 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::*;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Noun, D};
|
use crate::noun::{Noun, D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
|
|
||||||
|
|
||||||
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
||||||
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
||||||
@ -547,7 +538,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bex() {
|
fn test_bex() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet(c, jet_bex, D(0), D(1));
|
assert_jet(c, jet_bex, D(0), D(1));
|
||||||
assert_jet(c, jet_bex, D(5), D(32));
|
assert_jet(c, jet_bex, D(5), D(32));
|
||||||
@ -562,7 +553,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_can() {
|
fn test_can() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
||||||
let bloq0 = D(0);
|
let bloq0 = D(0);
|
||||||
@ -607,7 +598,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cat() {
|
fn test_cat() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
||||||
let bloq0 = D(0);
|
let bloq0 = D(0);
|
||||||
@ -639,7 +630,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cut() {
|
fn test_cut() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let run = T(&mut c.stack, &[D(0), D(0)]);
|
let run = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
@ -662,7 +653,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_end() {
|
fn test_end() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a24]);
|
let sam = T(&mut c.stack, &[a0, a24]);
|
||||||
@ -685,7 +676,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lsh() {
|
fn test_lsh() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (_, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
let (_, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
||||||
assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86));
|
assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86));
|
||||||
@ -718,7 +709,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_met() {
|
fn test_met() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a0]);
|
let sam = T(&mut c.stack, &[a0, a0]);
|
||||||
@ -733,7 +724,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rap() {
|
fn test_rap() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let bloq0 = D(0);
|
let bloq0 = D(0);
|
||||||
let bloq2 = D(2);
|
let bloq2 = D(2);
|
||||||
@ -763,7 +754,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rep() {
|
fn test_rep() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
@ -776,7 +767,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rev() {
|
fn test_rev() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (_a0, a24, _a63, a96, _a128) = atoms(&mut c.stack);
|
let (_a0, a24, _a63, a96, _a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[D(0), D(60), a24]);
|
let sam = T(&mut c.stack, &[D(0), D(60), a24]);
|
||||||
@ -791,7 +782,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rip() {
|
fn test_rip() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
@ -814,7 +805,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rsh() {
|
fn test_rsh() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a24]);
|
let sam = T(&mut c.stack, &[a0, a24]);
|
||||||
@ -840,7 +831,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sew() {
|
fn test_sew() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
|
|
||||||
// 0xfaceb00c15deadbeef123456
|
// 0xfaceb00c15deadbeef123456
|
||||||
@ -885,7 +876,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_con() {
|
fn test_con() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a0]);
|
let sam = T(&mut c.stack, &[a0, a0]);
|
||||||
@ -906,7 +897,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dis() {
|
fn test_dis() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a0]);
|
let sam = T(&mut c.stack, &[a0, a0]);
|
||||||
@ -926,7 +917,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mix() {
|
fn test_mix() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let sam = T(&mut c.stack, &[a0, a0]);
|
let sam = T(&mut c.stack, &[a0, a0]);
|
||||||
@ -948,7 +939,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_xeb() {
|
fn test_xeb() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
assert_jet(c, jet_xeb, a0, D(0));
|
assert_jet(c, jet_xeb, a0, D(0));
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ use crate::noun::Noun;
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result {
|
||||||
let aura = slot(subject, 12)?.as_direct()?;
|
let aura = slot(subject, 12)?.as_direct()?;
|
||||||
let atom = slot(subject, 13)?.as_atom()?;
|
let atom = slot(subject, 13)?.as_atom()?;
|
||||||
util::scow(&mut context.stack, aura, atom)
|
util::scow(&mut context.stack, aura, atom)
|
||||||
@ -17,7 +17,7 @@ pub mod util {
|
|||||||
use crate::jets;
|
use crate::jets;
|
||||||
use crate::jets::JetErr;
|
use crate::jets::JetErr;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Cell, DirectAtom, Noun, D, T};
|
use crate::noun::{Atom, Cell, DirectAtom, D, T};
|
||||||
use num_traits::identities::Zero;
|
use num_traits::identities::Zero;
|
||||||
use sword_macros::tas;
|
use sword_macros::tas;
|
||||||
|
|
||||||
@ -25,11 +25,11 @@ pub mod util {
|
|||||||
stack: &mut NockStack,
|
stack: &mut NockStack,
|
||||||
aura: DirectAtom, // XX: technically this should be Atom?
|
aura: DirectAtom, // XX: technically this should be Atom?
|
||||||
atom: Atom,
|
atom: Atom,
|
||||||
) -> jets::Result<Noun> {
|
) -> jets::Result {
|
||||||
match aura.data() {
|
match aura.data() {
|
||||||
tas!(b"ud") => {
|
tas!(b"ud") => {
|
||||||
if atom.as_bitslice().first_one().is_none() {
|
if atom.as_bitslice().first_one().is_none() {
|
||||||
return Ok(T(stack, &[D(b'0' as u64), D(0)])?);
|
return Ok(T(stack, &[D(b'0' as u64), D(0)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut root = D(0);
|
let mut root = D(0);
|
||||||
@ -38,15 +38,15 @@ pub mod util {
|
|||||||
let mut n = atom.as_direct()?.data();
|
let mut n = atom.as_direct()?.data();
|
||||||
|
|
||||||
while n != 0 {
|
while n != 0 {
|
||||||
root = T(stack, &[D(b'0' as u64 + (n % 10)), root])?;
|
root = T(stack, &[D(b'0' as u64 + (n % 10)), root]);
|
||||||
n /= 10;
|
n /= 10;
|
||||||
lent += 1;
|
lent += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut n = atom.as_indirect()?.as_ubig(stack)?;
|
let mut n = atom.as_indirect()?.as_ubig(stack);
|
||||||
|
|
||||||
while !n.is_zero() {
|
while !n.is_zero() {
|
||||||
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root])?;
|
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root]);
|
||||||
n /= 10u64;
|
n /= 10u64;
|
||||||
lent += 1;
|
lent += 1;
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ pub mod util {
|
|||||||
|
|
||||||
while lent > 2 {
|
while lent > 2 {
|
||||||
if lent % 3 == 0 {
|
if lent % 3 == 0 {
|
||||||
let (cell, memory) = Cell::new_raw_mut(stack)?;
|
let (cell, memory) = Cell::new_raw_mut(stack);
|
||||||
(*memory).head = D(b'.' as u64);
|
(*memory).head = D(b'.' as u64);
|
||||||
(*memory).tail = list.tail();
|
(*memory).tail = list.tail();
|
||||||
(*(list.to_raw_pointer_mut())).tail = cell.as_noun();
|
(*(list.to_raw_pointer_mut())).tail = cell.as_noun();
|
||||||
@ -79,18 +79,11 @@ pub mod util {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
|
||||||
use crate::jets::JetErr;
|
use crate::jets::JetErr;
|
||||||
use crate::noun::{Noun, D};
|
use crate::noun::{Noun, D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
use sword_macros::tas;
|
use sword_macros::tas;
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
|
|
||||||
|
|
||||||
// Rust can't handle implicit conversions from u8 to u64
|
// Rust can't handle implicit conversions from u8 to u64
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
@ -100,7 +93,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scow() {
|
fn test_scow() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let aura = D(tas!(b"ud"));
|
let aura = D(tas!(b"ud"));
|
||||||
let sam = T(&mut c.stack, &[aura, D(0)]);
|
let sam = T(&mut c.stack, &[aura, D(0)]);
|
||||||
|
@ -8,22 +8,18 @@ use crate::noun::Noun;
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
Ok(mug(&mut context.stack, arg)?.as_noun())
|
Ok(mug(&mut context.stack, arg).as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, init_context, A};
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Noun, D};
|
use crate::noun::{Noun, D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
|
|
||||||
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
||||||
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
||||||
@ -51,7 +47,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mug() {
|
fn test_mug() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
|
|
||||||
assert_jet(c, jet_mug, a0, D(0x79ff04e8));
|
assert_jet(c, jet_mug, a0, D(0x79ff04e8));
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::jets::*;
|
use crate::jets::*;
|
||||||
use crate::mem::AllocResult;
|
|
||||||
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T};
|
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T};
|
||||||
use either::Either::{self, Left, Right};
|
use either::Either::{self, Left, Right};
|
||||||
use std::ptr::{copy_nonoverlapping, null_mut};
|
use std::ptr::{copy_nonoverlapping, null_mut};
|
||||||
@ -1505,7 +1504,7 @@ pub const URBIT_HOT_STATE: &[HotEntry] = &[
|
|||||||
pub struct Hot(*mut HotMem);
|
pub struct Hot(*mut HotMem);
|
||||||
|
|
||||||
impl Hot {
|
impl Hot {
|
||||||
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> AllocResult<Self> {
|
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut next = Hot(null_mut());
|
let mut next = Hot(null_mut());
|
||||||
for (htap, axe, jet) in constant_hot_state {
|
for (htap, axe, jet) in constant_hot_state {
|
||||||
@ -1513,10 +1512,10 @@ impl Hot {
|
|||||||
for i in *htap {
|
for i in *htap {
|
||||||
match i {
|
match i {
|
||||||
Left(tas) => {
|
Left(tas) => {
|
||||||
let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)?
|
let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)
|
||||||
.normalize_as_atom()
|
.normalize_as_atom()
|
||||||
.as_noun();
|
.as_noun();
|
||||||
a_path = T(stack, &[chum, a_path])?;
|
a_path = T(stack, &[chum, a_path]);
|
||||||
}
|
}
|
||||||
Right((tas, ver)) => {
|
Right((tas, ver)) => {
|
||||||
let chum = T(
|
let chum = T(
|
||||||
@ -1525,13 +1524,13 @@ impl Hot {
|
|||||||
DirectAtom::new_panic(*tas).as_atom().as_noun(),
|
DirectAtom::new_panic(*tas).as_atom().as_noun(),
|
||||||
DirectAtom::new_panic(*ver).as_atom().as_noun(),
|
DirectAtom::new_panic(*ver).as_atom().as_noun(),
|
||||||
],
|
],
|
||||||
)?;
|
);
|
||||||
a_path = T(stack, &[chum, a_path])?;
|
a_path = T(stack, &[chum, a_path]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let axis = DirectAtom::new_panic(*axe).as_atom();
|
let axis = DirectAtom::new_panic(*axe).as_atom();
|
||||||
let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1)?;
|
let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1);
|
||||||
*hot_mem_ptr = HotMem {
|
*hot_mem_ptr = HotMem {
|
||||||
a_path,
|
a_path,
|
||||||
axis,
|
axis,
|
||||||
@ -1540,7 +1539,7 @@ impl Hot {
|
|||||||
};
|
};
|
||||||
next = Hot(hot_mem_ptr);
|
next = Hot(hot_mem_ptr);
|
||||||
}
|
}
|
||||||
Ok(next)
|
next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1567,17 +1566,16 @@ struct HotMem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for Hot {
|
impl Preserve for Hot {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
let mut it = self;
|
let mut it = self;
|
||||||
while !it.0.is_null() && stack.is_in_frame(it.0) {
|
while !it.0.is_null() && stack.is_in_frame(it.0) {
|
||||||
let dest_mem = stack.struct_alloc_in_previous_frame(1)?;
|
let dest_mem = stack.struct_alloc_in_previous_frame(1);
|
||||||
copy_nonoverlapping(it.0, dest_mem, 1);
|
copy_nonoverlapping(it.0, dest_mem, 1);
|
||||||
it.0 = dest_mem;
|
it.0 = dest_mem;
|
||||||
(*it.0).a_path.preserve(stack)?;
|
(*it.0).a_path.preserve(stack);
|
||||||
(*it.0).axis.preserve(stack)?;
|
(*it.0).axis.preserve(stack);
|
||||||
it = &mut (*it.0).next;
|
it = &mut (*it.0).next;
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||||
|
@ -8,27 +8,27 @@ use crate::site::{site_slam, Site};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
util::flop(&mut context.stack, sam)
|
util::flop(&mut context.stack, sam)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let list = slot(subject, 6)?;
|
let list = slot(subject, 6)?;
|
||||||
util::lent(list).map(|x| D(x as u64))
|
util::lent(list).map(|x| D(x as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sample = slot(subject, 6)?;
|
let sample = slot(subject, 6)?;
|
||||||
let mut list = slot(sample, 2)?;
|
let mut list = slot(sample, 2)?;
|
||||||
let mut gate = slot(sample, 3)?;
|
let mut gate = slot(sample, 3)?;
|
||||||
let mut prod = slot(gate, 13)?;
|
let mut prod = slot(gate, 13)?;
|
||||||
|
|
||||||
let site = Site::new(context, &mut gate)?;
|
let site = Site::new(context, &mut gate);
|
||||||
loop {
|
loop {
|
||||||
if let Ok(list_cell) = list.as_cell() {
|
if let Ok(list_cell) = list.as_cell() {
|
||||||
list = list_cell.tail();
|
list = list_cell.tail();
|
||||||
let sam = T(&mut context.stack, &[list_cell.head(), prod])?;
|
let sam = T(&mut context.stack, &[list_cell.head(), prod]);
|
||||||
prod = site_slam(context, &site, sam)?;
|
prod = site_slam(context, &site, sam)?;
|
||||||
} else {
|
} else {
|
||||||
if unsafe { !list.raw_equals(D(0)) } {
|
if unsafe { !list.raw_equals(D(0)) } {
|
||||||
@ -39,7 +39,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let index = slot(sam, 2)?;
|
let index = slot(sam, 2)?;
|
||||||
let list = slot(sam, 3)?;
|
let list = slot(sam, 3)?;
|
||||||
@ -47,12 +47,12 @@ pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
util::snag(list, index)
|
util::snag(list, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result {
|
||||||
let list = slot(subject, 6)?;
|
let list = slot(subject, 6)?;
|
||||||
util::snip(&mut context.stack, list)
|
util::snip(&mut context.stack, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sample = slot(subject, 6)?;
|
let sample = slot(subject, 6)?;
|
||||||
let mut list = slot(sample, 2)?;
|
let mut list = slot(sample, 2)?;
|
||||||
let mut gate = slot(sample, 3)?;
|
let mut gate = slot(sample, 3)?;
|
||||||
@ -61,12 +61,12 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
// Since the gate doesn't change, we can do a single jet check and use that through the whole
|
// Since the gate doesn't change, we can do a single jet check and use that through the whole
|
||||||
// loop
|
// loop
|
||||||
let site = Site::new(context, &mut gate)?;
|
let site = Site::new(context, &mut gate);
|
||||||
loop {
|
loop {
|
||||||
if let Ok(list_cell) = list.as_cell() {
|
if let Ok(list_cell) = list.as_cell() {
|
||||||
list = list_cell.tail();
|
list = list_cell.tail();
|
||||||
unsafe {
|
unsafe {
|
||||||
let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack)?;
|
let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack);
|
||||||
(*new_mem).head = site_slam(context, &site, list_cell.head())?;
|
(*new_mem).head = site_slam(context, &site, list_cell.head())?;
|
||||||
*dest = new_cell.as_noun();
|
*dest = new_cell.as_noun();
|
||||||
dest = &mut (*new_mem).tail;
|
dest = &mut (*new_mem).tail;
|
||||||
@ -83,7 +83,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result {
|
||||||
let list = slot(subject, 6)?;
|
let list = slot(subject, 6)?;
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ pub mod util {
|
|||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
/// Reverse order of list
|
/// Reverse order of list
|
||||||
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result<Noun> {
|
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result {
|
||||||
let mut list = noun;
|
let mut list = noun;
|
||||||
let mut tsil = D(0);
|
let mut tsil = D(0);
|
||||||
loop {
|
loop {
|
||||||
@ -107,7 +107,7 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cell = list.as_cell()?;
|
let cell = list.as_cell()?;
|
||||||
tsil = T(stack, &[cell.head(), tsil])?;
|
tsil = T(stack, &[cell.head(), tsil]);
|
||||||
list = cell.tail();
|
list = cell.tail();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ pub mod util {
|
|||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snag(tape: Noun, index: Noun) -> Result<Noun> {
|
pub fn snag(tape: Noun, index: Noun) -> Result {
|
||||||
let mut list = tape;
|
let mut list = tape;
|
||||||
let mut idx = index.as_atom()?.as_u64()? as usize;
|
let mut idx = index.as_atom()?.as_u64()? as usize;
|
||||||
loop {
|
loop {
|
||||||
@ -149,7 +149,7 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result<Noun> {
|
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result {
|
||||||
let mut ret = D(0);
|
let mut ret = D(0);
|
||||||
let mut dest = &mut ret as *mut Noun;
|
let mut dest = &mut ret as *mut Noun;
|
||||||
let mut list = tape;
|
let mut list = tape;
|
||||||
@ -170,7 +170,7 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let (new_cell, new_mem) = Cell::new_raw_mut(stack)?;
|
let (new_cell, new_mem) = Cell::new_raw_mut(stack);
|
||||||
(*new_mem).head = cell.head();
|
(*new_mem).head = cell.head();
|
||||||
*dest = new_cell.as_noun();
|
*dest = new_cell.as_noun();
|
||||||
dest = &mut (*new_mem).tail;
|
dest = &mut (*new_mem).tail;
|
||||||
@ -181,7 +181,7 @@ pub mod util {
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result<Noun> {
|
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut res: Noun = D(0);
|
let mut res: Noun = D(0);
|
||||||
let mut dest = &mut res as *mut Noun;
|
let mut dest = &mut res as *mut Noun;
|
||||||
@ -196,7 +196,7 @@ pub mod util {
|
|||||||
let i = it.head();
|
let i = it.head();
|
||||||
sublist = it.tail();
|
sublist = it.tail();
|
||||||
|
|
||||||
let (new_cell, new_memory) = Cell::new_raw_mut(stack)?;
|
let (new_cell, new_memory) = Cell::new_raw_mut(stack);
|
||||||
(*new_memory).head = i;
|
(*new_memory).head = i;
|
||||||
*dest = new_cell.as_noun();
|
*dest = new_cell.as_noun();
|
||||||
dest = &mut (*new_memory).tail;
|
dest = &mut (*new_memory).tail;
|
||||||
@ -212,19 +212,13 @@ pub mod util {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context};
|
||||||
use crate::jets::util::BAIL_EXIT;
|
use crate::jets::util::BAIL_EXIT;
|
||||||
use crate::noun::D;
|
use crate::noun::{D, T};
|
||||||
// Override T with the panicky variants
|
|
||||||
use crate::test_fns::T;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flop() {
|
fn test_flop() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
||||||
let res = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]);
|
let res = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]);
|
||||||
@ -261,7 +255,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lent() {
|
fn test_lent() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet(c, jet_lent, D(0), D(0));
|
assert_jet(c, jet_lent, D(0), D(0));
|
||||||
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
||||||
@ -275,7 +269,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_snag() {
|
fn test_snag() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
||||||
let sam = T(&mut c.stack, &[D(1), list1]);
|
let sam = T(&mut c.stack, &[D(1), list1]);
|
||||||
assert_jet(c, jet_snag, sam, D(2));
|
assert_jet(c, jet_snag, sam, D(2));
|
||||||
@ -293,7 +287,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_snip() {
|
fn test_snip() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
||||||
assert_jet(c, jet_snip, sam, D(0));
|
assert_jet(c, jet_snip, sam, D(0));
|
||||||
@ -319,7 +313,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_zing() {
|
fn test_zing() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let list_0 = T(&mut c.stack, &[D(0), D(0), D(0), D(0)]);
|
let list_0 = T(&mut c.stack, &[D(0), D(0), D(0), D(0)]);
|
||||||
let list_1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
let list_1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
|
||||||
|
@ -11,7 +11,7 @@ crate::gdb!();
|
|||||||
// have fixed maximum key sizes, therefore we must punt if the key is
|
// have fixed maximum key sizes, therefore we must punt if the key is
|
||||||
// too large.
|
// too large.
|
||||||
|
|
||||||
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let txt = slot(subject, 6)?.as_atom()?;
|
let txt = slot(subject, 6)?.as_atom()?;
|
||||||
let key = slot(subject, 60)?.as_atom()?;
|
let key = slot(subject, 60)?.as_atom()?;
|
||||||
@ -27,7 +27,7 @@ pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let iv = slot(subject, 12)?.as_atom()?;
|
let iv = slot(subject, 12)?.as_atom()?;
|
||||||
let len = slot(subject, 26)?.as_atom()?;
|
let len = slot(subject, 26)?.as_atom()?;
|
||||||
@ -45,7 +45,7 @@ pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let txt = slot(subject, 6)?.as_atom()?;
|
let txt = slot(subject, 6)?.as_atom()?;
|
||||||
let key = slot(subject, 60)?.as_atom()?;
|
let key = slot(subject, 60)?.as_atom()?;
|
||||||
@ -61,7 +61,7 @@ pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let iv = slot(subject, 12)?.as_atom()?;
|
let iv = slot(subject, 12)?.as_atom()?;
|
||||||
let len = slot(subject, 26)?.as_atom()?;
|
let len = slot(subject, 26)?.as_atom()?;
|
||||||
@ -79,7 +79,7 @@ pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let txt = slot(subject, 6)?.as_atom()?;
|
let txt = slot(subject, 6)?.as_atom()?;
|
||||||
let key = slot(subject, 60)?.as_atom()?;
|
let key = slot(subject, 60)?.as_atom()?;
|
||||||
@ -95,7 +95,7 @@ pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let iv = slot(subject, 12)?.as_atom()?;
|
let iv = slot(subject, 12)?.as_atom()?;
|
||||||
let len = slot(subject, 26)?.as_atom()?;
|
let len = slot(subject, 26)?.as_atom()?;
|
||||||
@ -142,7 +142,7 @@ mod util {
|
|||||||
let length = list::util::lent(ads)?;
|
let length = list::util::lent(ads)?;
|
||||||
|
|
||||||
let siv_data: &mut [AcAesSivData] = unsafe {
|
let siv_data: &mut [AcAesSivData] = unsafe {
|
||||||
let ptr = stack.struct_alloc::<AcAesSivData>(length)?;
|
let ptr = stack.struct_alloc::<AcAesSivData>(length);
|
||||||
std::slice::from_raw_parts_mut(ptr, length)
|
std::slice::from_raw_parts_mut(ptr, length)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ mod util {
|
|||||||
let bytes = head.as_bytes();
|
let bytes = head.as_bytes();
|
||||||
let len = met(3, head);
|
let len = met(3, head);
|
||||||
|
|
||||||
let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len())?;
|
let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len());
|
||||||
buffer[0..len].copy_from_slice(&(bytes[0..len]));
|
buffer[0..len].copy_from_slice(&(bytes[0..len]));
|
||||||
|
|
||||||
item.length = bytes.len();
|
item.length = bytes.len();
|
||||||
@ -171,7 +171,7 @@ mod util {
|
|||||||
key: &mut [u8; N],
|
key: &mut [u8; N],
|
||||||
ads: Noun,
|
ads: Noun,
|
||||||
txt: Atom,
|
txt: Atom,
|
||||||
) -> Result<Noun> {
|
) -> Result {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ac_siv_data = _allocate_ads(stack, ads)?;
|
let ac_siv_data = _allocate_ads(stack, ads)?;
|
||||||
let siv_data: &mut [&mut [u8]] = std::slice::from_raw_parts_mut(
|
let siv_data: &mut [&mut [u8]] = std::slice::from_raw_parts_mut(
|
||||||
@ -181,19 +181,19 @@ mod util {
|
|||||||
|
|
||||||
let txt_len = met(3, txt);
|
let txt_len = met(3, txt);
|
||||||
|
|
||||||
let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack)?;
|
let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack);
|
||||||
|
|
||||||
// We match on length here and elsewhere where a similar pattern is followed
|
// We match on length here and elsewhere where a similar pattern is followed
|
||||||
// to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes.
|
// to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes.
|
||||||
match txt_len {
|
match txt_len {
|
||||||
0 => {
|
0 => {
|
||||||
ac_aes_siv_en::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
|
ac_aes_siv_en::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
|
||||||
Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)])?)
|
Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)]))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
|
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
|
||||||
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
|
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
|
||||||
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
|
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
|
||||||
ac_aes_siv_en::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
|
ac_aes_siv_en::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
|
||||||
Ok(T(
|
Ok(T(
|
||||||
stack,
|
stack,
|
||||||
@ -202,7 +202,7 @@ mod util {
|
|||||||
D(txt_len as u64),
|
D(txt_len as u64),
|
||||||
out_atom.normalize_as_atom().as_noun(),
|
out_atom.normalize_as_atom().as_noun(),
|
||||||
],
|
],
|
||||||
)?)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ mod util {
|
|||||||
iv: Atom,
|
iv: Atom,
|
||||||
len: Atom,
|
len: Atom,
|
||||||
txt: Atom,
|
txt: Atom,
|
||||||
) -> Result<Noun> {
|
) -> Result {
|
||||||
unsafe {
|
unsafe {
|
||||||
let txt_len = match len.as_direct() {
|
let txt_len = match len.as_direct() {
|
||||||
Ok(direct) => direct.data() as usize,
|
Ok(direct) => direct.data() as usize,
|
||||||
@ -231,20 +231,20 @@ mod util {
|
|||||||
ac_siv_data.len(),
|
ac_siv_data.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
|
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
|
||||||
|
|
||||||
match txt_len {
|
match txt_len {
|
||||||
0 => {
|
0 => {
|
||||||
ac_aes_siv_de::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
|
ac_aes_siv_de::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
|
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
|
||||||
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
|
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
|
||||||
ac_aes_siv_de::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
|
ac_aes_siv_de::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()])?)
|
Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,34 +252,33 @@ mod util {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_noun_eq, init_context, A};
|
||||||
use crate::jets::Jet;
|
use crate::jets::Jet;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Cell, D, T};
|
use crate::noun::{Cell, D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
|
|
||||||
|
|
||||||
pub fn assert_jet_in_door(
|
pub fn assert_jet_in_door(
|
||||||
c: &mut Context,
|
c: &mut Context,
|
||||||
jet: Jet,
|
jet: Jet,
|
||||||
sam: &[fn(&mut NockStack) -> Noun], // regular sample
|
sam: &[fn(&mut NockStack) -> Noun], // regular sample
|
||||||
ctx: &[fn(&mut NockStack) -> AllocResult<Noun>], // door sample as context
|
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
|
||||||
res: Noun,
|
res: Noun,
|
||||||
) {
|
) {
|
||||||
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect();
|
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect();
|
||||||
let ctx: Vec<Noun> = ctx.iter().flat_map(|f| f(&mut c.stack)).collect();
|
let ctx: Vec<Noun> = ctx.iter().map(|f| f(&mut c.stack)).collect();
|
||||||
let sam = if sam.len() > 1 {
|
let sam = if sam.len() > 1 {
|
||||||
T(&mut c.stack, &sam).expect("T alloc failed in assert_jet_in_door")
|
T(&mut c.stack, &sam)
|
||||||
} else {
|
} else {
|
||||||
sam[0]
|
sam[0]
|
||||||
};
|
};
|
||||||
let ctx = if ctx.len() > 1 {
|
let ctx = if ctx.len() > 1 {
|
||||||
T(&mut c.stack, &ctx).expect("2nd T alloc failed in assert_jet_in_door")
|
T(&mut c.stack, &ctx)
|
||||||
} else {
|
} else {
|
||||||
ctx[0]
|
ctx[0]
|
||||||
};
|
};
|
||||||
let pay = Cell::new(&mut c.stack, sam, ctx).expect("Cell alloc failed in assert_jet_in_door").as_noun();
|
let pay = Cell::new(&mut c.stack, sam, ctx).as_noun();
|
||||||
let sbj = Cell::new(&mut c.stack, D(0), pay).expect("2nd Cell alloc failed").as_noun();
|
let sbj = Cell::new(&mut c.stack, D(0), pay).as_noun();
|
||||||
// std::io::stderr().flush().unwrap();
|
// std::io::stderr().flush().unwrap();
|
||||||
let jet_res = jet(c, sbj).unwrap();
|
let jet_res = jet(c, sbj).unwrap();
|
||||||
// std::io::stderr().flush().unwrap();
|
// std::io::stderr().flush().unwrap();
|
||||||
@ -288,7 +287,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_siva_en() {
|
pub fn test_siva_en() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
/*
|
/*
|
||||||
> (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
> (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
||||||
[p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0]
|
[p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0]
|
||||||
@ -296,44 +295,44 @@ mod tests {
|
|||||||
fn sample(_s: &mut NockStack) -> Noun {
|
fn sample(_s: &mut NockStack) -> Noun {
|
||||||
D(0)
|
D(0)
|
||||||
}
|
}
|
||||||
fn context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn context(s: &mut NockStack) -> Noun {
|
||||||
let sample = T(s, &[D(0), D(0)])?;
|
let sample = T(s, &[D(0), D(0)]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
|
|
||||||
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77)).unwrap();
|
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77));
|
||||||
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
|
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
|
||||||
assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res);
|
assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res);
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
|
A(s, &ubig!(0x112233445566778899aabbccddee))
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(
|
let key = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
|
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
|
||||||
)?;
|
);
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
|
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
|
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
|
||||||
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
|
let res = T(&mut c.stack, &[iv, len, cyp]);
|
||||||
assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_sivb_en() {
|
pub fn test_sivb_en() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
> (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
> (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
||||||
@ -342,41 +341,41 @@ mod tests {
|
|||||||
fn sample(_s: &mut NockStack) -> Noun {
|
fn sample(_s: &mut NockStack) -> Noun {
|
||||||
D(0)
|
D(0)
|
||||||
}
|
}
|
||||||
fn context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn context(s: &mut NockStack) -> Noun {
|
||||||
let sample = T(s, &[D(0), D(0)])?;
|
let sample = T(s, &[D(0), D(0)]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
|
|
||||||
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd)).unwrap();
|
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd));
|
||||||
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
|
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
|
||||||
assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res);
|
assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res);
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
|
A(s, &ubig!(0x112233445566778899aabbccddee))
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
|
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
|
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
|
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c));
|
||||||
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
|
let res = T(&mut c.stack, &[iv, len, cyp]);
|
||||||
assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_sivc_en() {
|
pub fn test_sivc_en() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
> (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
> (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0)
|
||||||
@ -385,122 +384,122 @@ mod tests {
|
|||||||
fn sample(_s: &mut NockStack) -> Noun {
|
fn sample(_s: &mut NockStack) -> Noun {
|
||||||
D(0)
|
D(0)
|
||||||
}
|
}
|
||||||
fn context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn context(s: &mut NockStack) -> Noun {
|
||||||
let sample = T(s, &[D(0), D(0)])?;
|
let sample = T(s, &[D(0), D(0)]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
|
|
||||||
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519)).unwrap();
|
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519));
|
||||||
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
|
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
|
||||||
assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res);
|
assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res);
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
|
A(s, &ubig!(0x112233445566778899aabbccddee))
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
|
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
|
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
|
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0));
|
||||||
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
|
let res = T(&mut c.stack, &[iv, len, cyp]);
|
||||||
assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_siva_de() {
|
pub fn test_siva_de() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
|
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
|
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
|
||||||
T(s, &[iv, len, cyp]).unwrap()
|
T(s, &[iv, len, cyp])
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(
|
let key = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
|
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
|
||||||
)?;
|
);
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
|
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
|
||||||
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
|
let res = T(&mut c.stack, &[D(0), txt]);
|
||||||
assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_sivb_de() {
|
pub fn test_sivb_de() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
|
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
|
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c));
|
||||||
T(s, &[iv, len, cyp]).unwrap()
|
T(s, &[iv, len, cyp])
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
|
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
|
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
|
||||||
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
|
let res = T(&mut c.stack, &[D(0), txt]);
|
||||||
assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_sivc_de() {
|
pub fn test_sivc_de() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
/* RFC 5297
|
/* RFC 5297
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
|
||||||
*/
|
*/
|
||||||
fn gate_sample(s: &mut NockStack) -> Noun {
|
fn gate_sample(s: &mut NockStack) -> Noun {
|
||||||
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
|
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
|
||||||
let len = D(14);
|
let len = D(14);
|
||||||
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
|
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0));
|
||||||
T(s, &[iv, len, cyp]).unwrap()
|
T(s, &[iv, len, cyp])
|
||||||
}
|
}
|
||||||
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
|
fn gate_context(s: &mut NockStack) -> Noun {
|
||||||
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
|
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
|
||||||
let a = A(
|
let a = A(
|
||||||
s,
|
s,
|
||||||
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
|
||||||
)?;
|
);
|
||||||
let vec = T(s, &[a, D(0)])?;
|
let vec = T(s, &[a, D(0)]);
|
||||||
let sample = T(s, &[key, vec])?;
|
let sample = T(s, &[key, vec]);
|
||||||
T(s, &[D(0), sample, D(0)])
|
T(s, &[D(0), sample, D(0)])
|
||||||
}
|
}
|
||||||
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
|
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
|
||||||
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
|
let res = T(&mut c.stack, &[D(0), txt]);
|
||||||
assert_jet_in_door(c, jet_sivc_de, &[gate_sample], &[gate_context], res);
|
assert_jet_in_door(c, jet_sivc_de, &[gate_sample], &[gate_context], res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use sword_crypto::ed25519::{ac_ed_puck, ac_ed_shar, ac_ed_sign, ac_ed_veri};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sed = slot(subject, 6)?.as_atom()?;
|
let sed = slot(subject, 6)?.as_atom()?;
|
||||||
|
|
||||||
@ -21,14 +21,14 @@ pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let sed_bytes = &mut [0u8; 32];
|
let sed_bytes = &mut [0u8; 32];
|
||||||
sed_bytes[0..sed_len].copy_from_slice(&(sed.as_bytes())[0..sed_len]);
|
sed_bytes[0..sed_len].copy_from_slice(&(sed.as_bytes())[0..sed_len]);
|
||||||
|
|
||||||
let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?;
|
let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
|
||||||
ac_ed_puck(sed_bytes, pub_key);
|
ac_ed_puck(sed_bytes, pub_key);
|
||||||
|
|
||||||
Ok(pub_ida.normalize_as_atom().as_noun())
|
Ok(pub_ida.normalize_as_atom().as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let pub_key = slot(subject, 12)?.as_atom()?;
|
let pub_key = slot(subject, 12)?.as_atom()?;
|
||||||
let sec_key = slot(subject, 13)?.as_atom()?;
|
let sec_key = slot(subject, 13)?.as_atom()?;
|
||||||
@ -53,14 +53,14 @@ pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
public[0..pub_bytes.len()].copy_from_slice(pub_bytes);
|
public[0..pub_bytes.len()].copy_from_slice(pub_bytes);
|
||||||
secret[0..sec_bytes.len()].copy_from_slice(sec_bytes);
|
secret[0..sec_bytes.len()].copy_from_slice(sec_bytes);
|
||||||
|
|
||||||
let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?;
|
let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
|
||||||
ac_ed_shar(public, secret, shar);
|
ac_ed_shar(public, secret, shar);
|
||||||
|
|
||||||
Ok(shar_ida.normalize_as_atom().as_noun())
|
Ok(shar_ida.normalize_as_atom().as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let msg = slot(subject, 12)?.as_atom()?;
|
let msg = slot(subject, 12)?.as_atom()?;
|
||||||
let sed = slot(subject, 13)?.as_atom()?;
|
let sed = slot(subject, 13)?.as_atom()?;
|
||||||
@ -74,11 +74,11 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let seed = &mut [0u8; 32];
|
let seed = &mut [0u8; 32];
|
||||||
seed[0..sed_len].copy_from_slice(sed_bytes);
|
seed[0..sed_len].copy_from_slice(sed_bytes);
|
||||||
|
|
||||||
let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack)?;
|
let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack);
|
||||||
|
|
||||||
let msg_len = met(3, msg);
|
let msg_len = met(3, msg);
|
||||||
if msg_len > 0 {
|
if msg_len > 0 {
|
||||||
let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len)?;
|
let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len);
|
||||||
message.copy_from_slice(&msg.as_bytes()[0..msg_len]);
|
message.copy_from_slice(&msg.as_bytes()[0..msg_len]);
|
||||||
ac_ed_sign(message, seed, sig);
|
ac_ed_sign(message, seed, sig);
|
||||||
} else {
|
} else {
|
||||||
@ -90,7 +90,7 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let sig = slot(subject, 12)?.as_atom()?;
|
let sig = slot(subject, 12)?.as_atom()?;
|
||||||
let msg = slot(subject, 26)?.as_atom()?;
|
let msg = slot(subject, 26)?.as_atom()?;
|
||||||
let puk = slot(subject, 27)?.as_atom()?;
|
let puk = slot(subject, 27)?.as_atom()?;
|
||||||
@ -120,68 +120,64 @@ pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
|
||||||
use crate::noun::{D, T};
|
use crate::noun::{D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
|
|
||||||
// XX: Should use the test vectors from Section 7.1 of RFC 8032:
|
// XX: Should use the test vectors from Section 7.1 of RFC 8032:
|
||||||
// https://tools.ietf.org/html/rfc8032#section-7.1
|
// https://tools.ietf.org/html/rfc8032#section-7.1
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_puck() {
|
fn test_puck() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = A(&mut c.stack, &ubig!(_0x0)).unwrap();
|
let sam = A(&mut c.stack, &ubig!(_0x0));
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b),
|
&ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_puck, sam, ret);
|
assert_jet(c, jet_puck, sam, ret);
|
||||||
|
|
||||||
let sam = A(
|
let sam = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d),
|
&ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d),
|
||||||
).unwrap();
|
);
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7),
|
&ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_puck, sam, ret);
|
assert_jet(c, jet_puck, sam, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shar() {
|
fn test_shar() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
let ret = A(&mut c.stack, &ubig!(_0x0)).unwrap();
|
let ret = A(&mut c.stack, &ubig!(_0x0));
|
||||||
assert_jet(c, jet_shar, sam, ret);
|
assert_jet(c, jet_shar, sam, ret);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(234), D(234)]).unwrap();
|
let sam = T(&mut c.stack, &[D(234), D(234)]);
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5),
|
&ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shar, sam, ret);
|
assert_jet(c, jet_shar, sam, ret);
|
||||||
|
|
||||||
let sam = A(
|
let sam = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b),
|
&ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet_err(c, jet_shar, sam, BAIL_EXIT);
|
assert_jet_err(c, jet_shar, sam, BAIL_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sign() {
|
fn test_sign() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803)).unwrap();
|
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803));
|
||||||
assert_jet(c, jet_sign, sam, ret);
|
assert_jet(c, jet_sign, sam, ret);
|
||||||
|
|
||||||
let message = D(0x72);
|
let message = D(0x72);
|
||||||
@ -191,18 +187,16 @@ mod tests {
|
|||||||
let sed_bytes = sed_ubig.to_be_bytes();
|
let sed_bytes = sed_ubig.to_be_bytes();
|
||||||
let seed =
|
let seed =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[message, seed]).unwrap();
|
let sam = T(&mut c.stack, &[message, seed]);
|
||||||
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00)).unwrap();
|
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00));
|
||||||
assert_jet(c, jet_sign, sam, ret);
|
assert_jet(c, jet_sign, sam, ret);
|
||||||
|
|
||||||
let msg_ubig = ubig!(_0xaf82);
|
let msg_ubig = ubig!(_0xaf82);
|
||||||
let msg_bytes = msg_ubig.to_be_bytes();
|
let msg_bytes = msg_ubig.to_be_bytes();
|
||||||
let message =
|
let message =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let sed_ubig =
|
let sed_ubig =
|
||||||
@ -210,28 +204,26 @@ mod tests {
|
|||||||
let sed_bytes = sed_ubig.to_be_bytes();
|
let sed_bytes = sed_ubig.to_be_bytes();
|
||||||
let seed =
|
let seed =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[message, seed]).unwrap();
|
let sam = T(&mut c.stack, &[message, seed]);
|
||||||
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a)).unwrap();
|
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a));
|
||||||
assert_jet(c, jet_sign, sam, ret);
|
assert_jet(c, jet_sign, sam, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_veri() {
|
fn test_veri() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]);
|
||||||
assert_jet(c, jet_veri, sam, NO);
|
assert_jet(c, jet_veri, sam, NO);
|
||||||
|
|
||||||
let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00);
|
let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00);
|
||||||
let sig_bytes = sig_ubig.to_be_bytes();
|
let sig_bytes = sig_ubig.to_be_bytes();
|
||||||
let signature =
|
let signature =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let message = D(0x72);
|
let message = D(0x72);
|
||||||
@ -241,24 +233,21 @@ mod tests {
|
|||||||
let pub_bytes = pub_ubig.to_be_bytes();
|
let pub_bytes = pub_ubig.to_be_bytes();
|
||||||
let public_key =
|
let public_key =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
|
let sam = T(&mut c.stack, &[signature, message, public_key]);
|
||||||
assert_jet(c, jet_veri, sam, YES);
|
assert_jet(c, jet_veri, sam, YES);
|
||||||
|
|
||||||
let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a);
|
let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a);
|
||||||
let sig_bytes = sig_ubig.to_be_bytes();
|
let sig_bytes = sig_ubig.to_be_bytes();
|
||||||
let signature =
|
let signature =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let msg_ubig = ubig!(0xaf82);
|
let msg_ubig = ubig!(0xaf82);
|
||||||
let msg_bytes = msg_ubig.to_be_bytes();
|
let msg_bytes = msg_ubig.to_be_bytes();
|
||||||
let message =
|
let message =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let pub_ubig =
|
let pub_ubig =
|
||||||
@ -266,10 +255,9 @@ mod tests {
|
|||||||
let pub_bytes = pub_ubig.to_be_bytes();
|
let pub_bytes = pub_ubig.to_be_bytes();
|
||||||
let public_key =
|
let public_key =
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
|
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
|
||||||
.unwrap()
|
|
||||||
.as_noun();
|
.as_noun();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
|
let sam = T(&mut c.stack, &[signature, message, public_key]);
|
||||||
assert_jet(c, jet_veri, sam, YES);
|
assert_jet(c, jet_veri, sam, YES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,23 @@ use sword_crypto::sha::{ac_sha1, ac_shal, ac_shas, ac_shay};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let sal = slot(sam, 2)?.as_atom()?;
|
let sal = slot(sam, 2)?.as_atom()?;
|
||||||
let ruz = slot(sam, 3)?.as_atom()?;
|
let ruz = slot(sam, 3)?.as_atom()?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
|
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
|
||||||
|
|
||||||
let sal_bytes = &(sal.as_bytes())[0..met(3, sal)]; // drop trailing zeros
|
let sal_bytes = &(sal.as_bytes())[0..met(3, sal)]; // drop trailing zeros
|
||||||
let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len())?;
|
let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len());
|
||||||
salt.copy_from_slice(sal_bytes);
|
salt.copy_from_slice(sal_bytes);
|
||||||
|
|
||||||
let msg_len = met(3, ruz);
|
let msg_len = met(3, ruz);
|
||||||
if msg_len > 0 {
|
if msg_len > 0 {
|
||||||
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
||||||
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?;
|
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
|
||||||
msg.copy_from_slice(msg_bytes);
|
msg.copy_from_slice(msg_bytes);
|
||||||
ac_shas(msg, salt, out);
|
ac_shas(msg, salt, out);
|
||||||
} else {
|
} else {
|
||||||
@ -34,18 +34,18 @@ pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let ruz = sam.as_atom()?;
|
let ruz = sam.as_atom()?;
|
||||||
let msg_len = met(3, ruz);
|
let msg_len = met(3, ruz);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
|
let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
|
||||||
|
|
||||||
if msg_len > 0 {
|
if msg_len > 0 {
|
||||||
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
||||||
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?;
|
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
|
||||||
msg.copy_from_slice(msg_bytes);
|
msg.copy_from_slice(msg_bytes);
|
||||||
ac_shay(msg, out);
|
ac_shay(msg, out);
|
||||||
} else {
|
} else {
|
||||||
@ -56,7 +56,7 @@ pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let len = slot(sam, 2)?.as_atom()?;
|
let len = slot(sam, 2)?.as_atom()?;
|
||||||
@ -69,16 +69,16 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let msg_len = met(3, ruz);
|
let msg_len = met(3, ruz);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
|
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
ac_shay(&mut [], out);
|
ac_shay(&mut [], out);
|
||||||
} else if msg_len >= length {
|
} else if msg_len >= length {
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
||||||
ac_shay(msg, out);
|
ac_shay(msg, out);
|
||||||
} else {
|
} else {
|
||||||
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg[0..msg_len].copy_from_slice(msg_bytes);
|
msg[0..msg_len].copy_from_slice(msg_bytes);
|
||||||
ac_shay(msg, out);
|
ac_shay(msg, out);
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let len = slot(sam, 2)?.as_atom()?;
|
let len = slot(sam, 2)?.as_atom()?;
|
||||||
@ -100,16 +100,16 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let msg_len = met(3, ruz);
|
let msg_len = met(3, ruz);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64)?;
|
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64);
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
ac_shal(&mut [], out);
|
ac_shal(&mut [], out);
|
||||||
} else if msg_len >= length {
|
} else if msg_len >= length {
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
||||||
ac_shal(msg, out);
|
ac_shal(msg, out);
|
||||||
} else {
|
} else {
|
||||||
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg[0..msg_len].copy_from_slice(msg_bytes);
|
msg[0..msg_len].copy_from_slice(msg_bytes);
|
||||||
ac_shal(msg, out);
|
ac_shal(msg, out);
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let len = slot(sam, 2)?.as_atom()?;
|
let len = slot(sam, 2)?.as_atom()?;
|
||||||
@ -131,16 +131,16 @@ pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let msg_len = met(3, ruz);
|
let msg_len = met(3, ruz);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20)?;
|
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20);
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
ac_sha1(&mut [], out);
|
ac_sha1(&mut [], out);
|
||||||
} else if msg_len >= length {
|
} else if msg_len >= length {
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
|
||||||
ac_sha1(msg, out);
|
ac_sha1(msg, out);
|
||||||
} else {
|
} else {
|
||||||
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
|
||||||
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
|
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
|
||||||
msg[0..msg_len].copy_from_slice(msg_bytes);
|
msg[0..msg_len].copy_from_slice(msg_bytes);
|
||||||
ac_sha1(msg, out);
|
ac_sha1(msg, out);
|
||||||
}
|
}
|
||||||
@ -158,242 +158,242 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shas() {
|
fn test_shas() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shas,
|
jet_shas,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60),
|
ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shas,
|
jet_shas,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc),
|
ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(2), D(2)]).unwrap();
|
let sam = T(&mut c.stack, &[D(2), D(2)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shas,
|
jet_shas,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x4cf01fe7cc56ef70d17735322488de0d31857afcfe451e199abe6295f78f5328),
|
ubig!(_0x4cf01fe7cc56ef70d17735322488de0d31857afcfe451e199abe6295f78f5328),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let a = A(
|
let a = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
let b = A(
|
let b = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
||||||
).unwrap();
|
);
|
||||||
let sam = T(&mut c.stack, &[a, b]).unwrap();
|
let sam = T(&mut c.stack, &[a, b]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shas,
|
jet_shas,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0xf7569a89650553ef13f9a8f0bb751fd42b70a4821be6bc1cbe197af33ce4843c),
|
ubig!(_0xf7569a89650553ef13f9a8f0bb751fd42b70a4821be6bc1cbe197af33ce4843c),
|
||||||
).unwrap();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shax() {
|
fn test_shax() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shax,
|
jet_shax,
|
||||||
D(0), // ''
|
D(0), // ''
|
||||||
ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shax,
|
jet_shax,
|
||||||
D(7303014), // 'foo'
|
D(7303014), // 'foo'
|
||||||
ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
|
ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let a = A(
|
let a = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
|
&ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shax,
|
jet_shax,
|
||||||
a,
|
a,
|
||||||
ubig!(_0x9ee26e46c2028aa4a9c463aa722b82ed8bf6e185c3e5a5a69814a2c78fe8adc7),
|
ubig!(_0x9ee26e46c2028aa4a9c463aa722b82ed8bf6e185c3e5a5a69814a2c78fe8adc7),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shax,
|
jet_shax,
|
||||||
D(123456789),
|
D(123456789),
|
||||||
ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let a = A(
|
let a = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shax,
|
jet_shax,
|
||||||
a,
|
a,
|
||||||
ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9),
|
ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9),
|
||||||
).unwrap();
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shay() {
|
fn test_shay() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shay, sam, ret).unwrap();
|
assert_jet(c, jet_shay, sam, ret);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e),
|
&ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shay, sam, ret).unwrap();
|
assert_jet(c, jet_shay, sam, ret);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(1)]);
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shay, sam, ret).unwrap();
|
assert_jet(c, jet_shay, sam, ret);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(478560413032)]).unwrap(); // [1 'hello']
|
let sam = T(&mut c.stack, &[D(1), D(478560413032)]); // [1 'hello']
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa),
|
&ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shay, sam, ret).unwrap();
|
assert_jet(c, jet_shay, sam, ret);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(2), D(478560413032)]).unwrap(); // [2 'hello']
|
let sam = T(&mut c.stack, &[D(2), D(478560413032)]); // [2 'hello']
|
||||||
let ret = A(
|
let ret = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37),
|
&ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37),
|
||||||
).unwrap();
|
);
|
||||||
assert_jet(c, jet_shay, sam, ret).unwrap();
|
assert_jet(c, jet_shay, sam, ret);
|
||||||
|
|
||||||
let big = DIRECT_MAX + 1;
|
let big = DIRECT_MAX + 1;
|
||||||
let ida = unsafe {
|
let ida = unsafe {
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8).unwrap()
|
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8)
|
||||||
};
|
};
|
||||||
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
|
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
|
||||||
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
|
||||||
|
|
||||||
let big: u128 = (DIRECT_MAX as u128) << 64;
|
let big: u128 = (DIRECT_MAX as u128) << 64;
|
||||||
let ida = unsafe {
|
let ida = unsafe {
|
||||||
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8).unwrap()
|
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8)
|
||||||
};
|
};
|
||||||
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
|
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
|
||||||
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shal() {
|
fn test_shal() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shal,
|
jet_shal,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
|
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shal,
|
jet_shal,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8)
|
ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8)
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(1)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_shal,
|
jet_shal,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
|
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let wid = A(
|
let wid = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
let dat = A(
|
let dat = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
||||||
).unwrap();
|
);
|
||||||
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
|
let sam = T(&mut c.stack, &[wid, dat]);
|
||||||
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
|
||||||
|
|
||||||
let wid = A(
|
let wid = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[wid, D(1)]);
|
||||||
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha1() {
|
fn test_sha1() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(0)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_sha1,
|
jet_sha1,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
|
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
|
let sam = T(&mut c.stack, &[D(1), D(0)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_sha1,
|
jet_sha1,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f),
|
ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[D(0), D(1)]);
|
||||||
assert_jet_ubig(
|
assert_jet_ubig(
|
||||||
c,
|
c,
|
||||||
jet_sha1,
|
jet_sha1,
|
||||||
sam,
|
sam,
|
||||||
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
|
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let wid = A(
|
let wid = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
let dat = A(
|
let dat = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
|
||||||
).unwrap();
|
);
|
||||||
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
|
let sam = T(&mut c.stack, &[wid, dat]);
|
||||||
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
|
||||||
|
|
||||||
let wid = A(
|
let wid = A(
|
||||||
&mut c.stack,
|
&mut c.stack,
|
||||||
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
|
||||||
).unwrap();
|
);
|
||||||
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
|
let sam = T(&mut c.stack, &[wid, D(1)]);
|
||||||
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap();
|
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use sword_macros::tas;
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result {
|
||||||
let rff = slot(subject, 6)?;
|
let rff = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
|
|
||||||
@ -25,19 +25,19 @@ pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = 141 + tas!(b"crop") + (flag << 8);
|
let fun = 141 + tas!(b"crop") + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result {
|
||||||
// axe must be Atom, though we use it as Noun
|
// axe must be Atom, though we use it as Noun
|
||||||
let axe = slot(subject, 6)?.as_atom()?;
|
let axe = slot(subject, 6)?.as_atom()?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
@ -55,19 +55,19 @@ pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = 141 + tas!(b"fish") + (flag << 8);
|
let fun = 141 + tas!(b"fish") + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
|
||||||
let rff = slot(subject, 6)?;
|
let rff = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
|
|
||||||
@ -84,19 +84,19 @@ pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = 141 + tas!(b"fuse") + (flag << 8);
|
let fun = 141 + tas!(b"fuse") + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
|
||||||
let gol = slot(subject, 12)?;
|
let gol = slot(subject, 12)?;
|
||||||
let gen = slot(subject, 13)?;
|
let gen = slot(subject, 13)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
@ -106,19 +106,19 @@ pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
let fun = 141 + tas!(b"mint");
|
let fun = 141 + tas!(b"mint");
|
||||||
let vet = slot(van, 59).map_or(NONE, |x| x);
|
let vet = slot(van, 59).map_or(NONE, |x| x);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
|
||||||
let gol = slot(subject, 12)?;
|
let gol = slot(subject, 12)?;
|
||||||
let dox = slot(subject, 26)?;
|
let dox = slot(subject, 26)?;
|
||||||
let gen = slot(subject, 27)?;
|
let gen = slot(subject, 27)?;
|
||||||
@ -137,19 +137,19 @@ pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = 141 + tas!(b"mull") + (flag << 8);
|
let fun = 141 + tas!(b"mull") + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
|
||||||
let nest_in_core = slot(subject, 3)?;
|
let nest_in_core = slot(subject, 3)?;
|
||||||
|
|
||||||
let seg = slot(nest_in_core, 12)?;
|
let seg = slot(nest_in_core, 12)?;
|
||||||
@ -172,23 +172,23 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = (141 + tas!(b"dext")) + (flag << 8);
|
let fun = (141 + tas!(b"dext")) + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) }
|
if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) }
|
||||||
|| unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) }
|
|| unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) }
|
||||||
{
|
{
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
}
|
}
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
|
||||||
let leg = slot(subject, 6)?;
|
let leg = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
|
|
||||||
@ -205,13 +205,13 @@ pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
1
|
1
|
||||||
};
|
};
|
||||||
let fun = 141 + tas!(b"rest") + (flag << 8);
|
let fun = 141 + tas!(b"rest") + (flag << 8);
|
||||||
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat])?;
|
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat]);
|
||||||
|
|
||||||
match context.cache.lookup(&mut context.stack, &mut key)? {
|
match context.cache.lookup(&mut context.stack, &mut key) {
|
||||||
Some(pro) => Ok(pro),
|
Some(pro) => Ok(pro),
|
||||||
None => {
|
None => {
|
||||||
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
let pro = interpret(context, subject, slot(subject, 2)?)?;
|
||||||
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
|
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
|
||||||
Ok(pro)
|
Ok(pro)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,14 +22,14 @@ use ibig::UBig;
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_add(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_add(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
Ok(util::add(&mut context.stack, a, b)?.as_noun())
|
Ok(util::add(&mut context.stack, a, b).as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
if let Ok(atom) = arg.as_atom() {
|
if let Ok(atom) = arg.as_atom() {
|
||||||
match atom.as_either() {
|
match atom.as_either() {
|
||||||
@ -48,7 +48,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
Some(first_one) => {
|
Some(first_one) => {
|
||||||
let (mut new_indirect, new_slice) = unsafe {
|
let (mut new_indirect, new_slice) = unsafe {
|
||||||
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())?
|
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())
|
||||||
};
|
};
|
||||||
if first_one > 0 {
|
if first_one > 0 {
|
||||||
new_slice[..first_one].fill(true);
|
new_slice[..first_one].fill(true);
|
||||||
@ -67,7 +67,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_div(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -78,14 +78,14 @@ pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun())
|
Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun())
|
||||||
} else {
|
} else {
|
||||||
let a_big = a.as_ubig(stack)?;
|
let a_big = a.as_ubig(stack);
|
||||||
let b_big = b.as_ubig(stack)?;
|
let b_big = b.as_ubig(stack);
|
||||||
let res = UBig::div_stack(stack, a_big, b_big)?;
|
let res = UBig::div_stack(stack, a_big, b_big);
|
||||||
Ok(Atom::from_ubig(stack, &res)?.as_noun())
|
Ok(Atom::from_ubig(stack, &res).as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -103,54 +103,54 @@ pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (div, rem) = a.as_ubig(stack)?.div_rem(b.as_ubig(stack)?);
|
let (div, rem) = a.as_ubig(stack).div_rem(b.as_ubig(stack));
|
||||||
(
|
(
|
||||||
Atom::from_ubig(stack, &div)?.as_noun(),
|
Atom::from_ubig(stack, &div).as_noun(),
|
||||||
Atom::from_ubig(stack, &rem)?.as_noun(),
|
Atom::from_ubig(stack, &rem).as_noun(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(T(stack, &[div, rem])?)
|
Ok(T(stack, &[div, rem]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_gte(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_gte(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
Ok(util::gte(stack, a, b)?)
|
Ok(util::gte(stack, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_gth(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_gth(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
Ok(util::gth(stack, a, b)?)
|
Ok(util::gth(stack, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_lte(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_lte(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
Ok(util::lte(stack, a, b)?)
|
Ok(util::lte(stack, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_lth(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_lth(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
Ok(util::lth(stack, a, b)?)
|
Ok(util::lth(stack, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_max(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -166,14 +166,14 @@ pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
a.as_noun()
|
a.as_noun()
|
||||||
} else if a.bit_size() < b.bit_size() {
|
} else if a.bit_size() < b.bit_size() {
|
||||||
b.as_noun()
|
b.as_noun()
|
||||||
} else if a.as_ubig(stack)? >= b.as_ubig(stack)? {
|
} else if a.as_ubig(stack) >= b.as_ubig(stack) {
|
||||||
a.as_noun()
|
a.as_noun()
|
||||||
} else {
|
} else {
|
||||||
b.as_noun()
|
b.as_noun()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_min(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -189,14 +189,14 @@ pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
a.as_noun()
|
a.as_noun()
|
||||||
} else if a.bit_size() > b.bit_size() {
|
} else if a.bit_size() > b.bit_size() {
|
||||||
b.as_noun()
|
b.as_noun()
|
||||||
} else if a.as_ubig(stack)? <= b.as_ubig(stack)? {
|
} else if a.as_ubig(stack) <= b.as_ubig(stack) {
|
||||||
a.as_noun()
|
a.as_noun()
|
||||||
} else {
|
} else {
|
||||||
b.as_noun()
|
b.as_noun()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -207,12 +207,12 @@ pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun())
|
Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun())
|
||||||
} else {
|
} else {
|
||||||
let res = a.as_ubig(stack)? % b.as_ubig(stack)?;
|
let res = a.as_ubig(stack) % b.as_ubig(stack);
|
||||||
Ok(Atom::from_ubig(stack, &res)?.as_noun())
|
Ok(Atom::from_ubig(stack, &res).as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mul(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -221,26 +221,26 @@ pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
let res = a.data() as u128 * b.data() as u128;
|
let res = a.data() as u128 * b.data() as u128;
|
||||||
if res < DIRECT_MAX as u128 {
|
if res < DIRECT_MAX as u128 {
|
||||||
Ok(Atom::new(stack, res as u64)?.as_noun())
|
Ok(Atom::new(stack, res as u64).as_noun())
|
||||||
} else {
|
} else {
|
||||||
Ok(unsafe {
|
Ok(unsafe {
|
||||||
IndirectAtom::new_raw_bytes(
|
IndirectAtom::new_raw_bytes(
|
||||||
stack,
|
stack,
|
||||||
if res < u64::MAX as u128 { 8 } else { 16 },
|
if res < u64::MAX as u128 { 8 } else { 16 },
|
||||||
&res as *const u128 as *const u8,
|
&res as *const u128 as *const u8,
|
||||||
)?
|
)
|
||||||
}
|
}
|
||||||
.as_noun())
|
.as_noun())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let a_big = a.as_ubig(stack)?;
|
let a_big = a.as_ubig(stack);
|
||||||
let b_big = b.as_ubig(stack)?;
|
let b_big = b.as_ubig(stack);
|
||||||
let res = UBig::mul_stack(stack, a_big, b_big)?;
|
let res = UBig::mul_stack(stack, a_big, b_big);
|
||||||
Ok(Atom::from_ubig(stack, &res)?.as_noun())
|
Ok(Atom::from_ubig(stack, &res).as_noun())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sub(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
@ -249,115 +249,108 @@ pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Error, Noun, Result, NO, YES};
|
use crate::noun::{Atom, Error, Noun, Result, NO, YES};
|
||||||
use ibig::UBig;
|
use ibig::UBig;
|
||||||
|
|
||||||
/// Addition
|
/// Addition
|
||||||
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> {
|
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
|
||||||
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
Atom::new(stack, a.data() + b.data())
|
Atom::new(stack, a.data() + b.data())
|
||||||
} else {
|
} else {
|
||||||
let a_big = a.as_ubig(stack)?;
|
let a_big = a.as_ubig(stack);
|
||||||
let b_big = b.as_ubig(stack)?;
|
let b_big = b.as_ubig(stack);
|
||||||
let res = UBig::add_stack(stack, a_big, b_big)?;
|
let res = UBig::add_stack(stack, a_big, b_big);
|
||||||
Atom::from_ubig(stack, &res)
|
Atom::from_ubig(stack, &res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Greater than or equal to (boolean)
|
/// Greater than or equal to (boolean)
|
||||||
pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
|
pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
|
||||||
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
a.data() >= b.data()
|
a.data() >= b.data()
|
||||||
} else if a.bit_size() > b.bit_size() {
|
} else if a.bit_size() > b.bit_size() {
|
||||||
true
|
true
|
||||||
} else if a.bit_size() < b.bit_size() {
|
} else if a.bit_size() < b.bit_size() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
a.as_ubig(stack)? >= b.as_ubig(stack)?
|
a.as_ubig(stack) >= b.as_ubig(stack)
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Greater than or equal to
|
/// Greater than or equal to
|
||||||
pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
|
pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
|
||||||
if gte_b(stack, a, b)? {
|
if gte_b(stack, a, b) {
|
||||||
Ok(YES)
|
YES
|
||||||
} else {
|
} else {
|
||||||
Ok(NO)
|
NO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Greater than (boolean)
|
/// Greater than (boolean)
|
||||||
pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
|
pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
|
||||||
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
a.data() > b.data()
|
a.data() > b.data()
|
||||||
} else if a.bit_size() > b.bit_size() {
|
} else if a.bit_size() > b.bit_size() {
|
||||||
true
|
true
|
||||||
} else if a.bit_size() < b.bit_size() {
|
} else if a.bit_size() < b.bit_size() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
a.as_ubig(stack)? > b.as_ubig(stack)?
|
a.as_ubig(stack) > b.as_ubig(stack)
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Greater than
|
/// Greater than
|
||||||
pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
|
pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
|
||||||
let res = if gth_b(stack, a, b)? {
|
if gth_b(stack, a, b) {
|
||||||
YES
|
YES
|
||||||
} else {
|
} else {
|
||||||
NO
|
NO
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Less than or equal to (boolean)
|
/// Less than or equal to (boolean)
|
||||||
pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
|
pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
|
||||||
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
a.data() <= b.data()
|
a.data() <= b.data()
|
||||||
} else if a.bit_size() < b.bit_size() {
|
} else if a.bit_size() < b.bit_size() {
|
||||||
true
|
true
|
||||||
} else if a.bit_size() > b.bit_size() {
|
} else if a.bit_size() > b.bit_size() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
a.as_ubig(stack)? <= b.as_ubig(stack)?
|
a.as_ubig(stack) <= b.as_ubig(stack)
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Less than or equal to
|
/// Less than or equal to
|
||||||
pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
|
pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
|
||||||
let res = if lte_b(stack, a, b)? {
|
if lte_b(stack, a, b) {
|
||||||
YES
|
YES
|
||||||
} else {
|
} else {
|
||||||
NO
|
NO
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Less than (boolean)
|
/// Less than (boolean)
|
||||||
pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
|
pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
|
||||||
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
a.data() < b.data()
|
a.data() < b.data()
|
||||||
} else if a.bit_size() > b.bit_size() {
|
} else if a.bit_size() > b.bit_size() {
|
||||||
false
|
false
|
||||||
} else if a.bit_size() < b.bit_size() {
|
} else if a.bit_size() < b.bit_size() {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
a.as_ubig(stack)? < b.as_ubig(stack)?
|
a.as_ubig(stack) < b.as_ubig(stack)
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Less than
|
/// Less than
|
||||||
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
|
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
|
||||||
let res = if lth_b(stack, a, b)? {
|
if lth_b(stack, a, b) {
|
||||||
YES
|
YES
|
||||||
} else {
|
} else {
|
||||||
NO
|
NO
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtraction
|
/// Subtraction
|
||||||
@ -369,19 +362,19 @@ pub mod util {
|
|||||||
if a_small < b_small {
|
if a_small < b_small {
|
||||||
Err(Error::NotRepresentable)
|
Err(Error::NotRepresentable)
|
||||||
} else {
|
} else {
|
||||||
Ok(Atom::new(stack, a_small - b_small)?)
|
Ok(Atom::new(stack, a_small - b_small))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let a_big = a.as_ubig(stack)?;
|
let a_big = a.as_ubig(stack);
|
||||||
let b_big = b.as_ubig(stack)?;
|
let b_big = b.as_ubig(stack);
|
||||||
|
|
||||||
if a_big < b_big {
|
if a_big < b_big {
|
||||||
Err(Error::NotRepresentable)
|
Err(Error::NotRepresentable)
|
||||||
} else {
|
} else {
|
||||||
let a_big = a.as_ubig(stack)?;
|
let a_big = a.as_ubig(stack);
|
||||||
let b_big = b.as_ubig(stack)?;
|
let b_big = b.as_ubig(stack);
|
||||||
let res = UBig::sub_stack(stack, a_big, b_big);
|
let res = UBig::sub_stack(stack, a_big, b_big);
|
||||||
Ok(Atom::from_ubig(stack, &res)?)
|
Ok(Atom::from_ubig(stack, &res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,17 +385,8 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::*;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Noun, D, NO, YES};
|
use crate::noun::{Noun, D, NO, T, YES};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
|
|
||||||
|
|
||||||
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
||||||
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
||||||
@ -445,7 +429,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add() {
|
fn test_add() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
@ -464,7 +448,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dec() {
|
fn test_dec() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
let s = &mut c.stack;
|
let s = &mut c.stack;
|
||||||
|
|
||||||
let (a0, _a24, a63, _a96, a128) = atoms(s);
|
let (a0, _a24, a63, _a96, a128) = atoms(s);
|
||||||
@ -475,7 +459,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_div() {
|
fn test_div() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0));
|
assert_common_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0));
|
||||||
assert_common_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018));
|
assert_common_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018));
|
||||||
@ -498,7 +482,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dvr() {
|
fn test_dvr() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
|
||||||
let a264 = atom_264(&mut c.stack);
|
let a264 = atom_264(&mut c.stack);
|
||||||
@ -544,7 +528,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gte() {
|
fn test_gte() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_96], YES);
|
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_96], YES);
|
||||||
assert_common_jet_noun(c, jet_gte, &[atom_96, atom_63], YES);
|
assert_common_jet_noun(c, jet_gte, &[atom_96, atom_63], YES);
|
||||||
@ -558,7 +542,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gth() {
|
fn test_gth() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_96], YES);
|
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_96], YES);
|
||||||
assert_common_jet_noun(c, jet_gth, &[atom_96, atom_63], YES);
|
assert_common_jet_noun(c, jet_gth, &[atom_96, atom_63], YES);
|
||||||
@ -572,7 +556,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lte() {
|
fn test_lte() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_96], NO);
|
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_96], NO);
|
||||||
assert_common_jet_noun(c, jet_lte, &[atom_96, atom_63], NO);
|
assert_common_jet_noun(c, jet_lte, &[atom_96, atom_63], NO);
|
||||||
@ -586,7 +570,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lth() {
|
fn test_lth() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_96], NO);
|
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_96], NO);
|
||||||
assert_common_jet_noun(c, jet_lth, &[atom_96, atom_63], NO);
|
assert_common_jet_noun(c, jet_lth, &[atom_96, atom_63], NO);
|
||||||
@ -600,7 +584,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_max() {
|
fn test_max() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
@ -646,7 +630,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_min() {
|
fn test_min() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
@ -687,7 +671,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mod() {
|
fn test_mod() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
@ -707,7 +691,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mul() {
|
fn test_mul() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
@ -732,7 +716,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sub() {
|
fn test_sub() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet(
|
assert_common_jet(
|
||||||
c,
|
c,
|
||||||
|
@ -7,7 +7,7 @@ use crate::noun::{Noun, D, NO, T};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
// mink sample = [nock scry_namespace]
|
// mink sample = [nock scry_namespace]
|
||||||
// = [[subject formula] scry_namespace]
|
// = [[subject formula] scry_namespace]
|
||||||
@ -19,18 +19,18 @@ pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
Ok(util::mink(context, v_subject, v_formula, scry_handler)?)
|
Ok(util::mink(context, v_subject, v_formula, scry_handler)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result {
|
||||||
jet_mure(context, subject)
|
jet_mure(context, subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mule(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mule(context: &mut Context, subject: Noun) -> Result {
|
||||||
jet_mute(context, subject)
|
jet_mute(context, subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mure(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tap = slot(subject, 6)?;
|
let tap = slot(subject, 6)?;
|
||||||
let fol = util::slam_gate_fol(&mut context.stack)?;
|
let fol = util::slam_gate_fol(&mut context.stack);
|
||||||
let scry = util::pass_thru_scry(&mut context.stack)?;
|
let scry = util::pass_thru_scry(&mut context.stack);
|
||||||
|
|
||||||
match util::mink(context, tap, fol, scry) {
|
match util::mink(context, tap, fol, scry) {
|
||||||
Ok(tone) => {
|
Ok(tone) => {
|
||||||
@ -44,10 +44,10 @@ pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mute(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tap = slot(subject, 6)?;
|
let tap = slot(subject, 6)?;
|
||||||
let fol = util::slam_gate_fol(&mut context.stack)?;
|
let fol = util::slam_gate_fol(&mut context.stack);
|
||||||
let scry = util::pass_thru_scry(&mut context.stack)?;
|
let scry = util::pass_thru_scry(&mut context.stack);
|
||||||
|
|
||||||
let tone = util::mink(context, tap, fol, scry);
|
let tone = util::mink(context, tap, fol, scry);
|
||||||
|
|
||||||
@ -59,11 +59,9 @@ pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
// XX: Need to check that result is actually of type path
|
// XX: Need to check that result is actually of type path
|
||||||
// return [[%leaf "mute.hunk"] ~] if not
|
// return [[%leaf "mute.hunk"] ~] if not
|
||||||
let bon = util::smyt(&mut context.stack, toon.tail())?;
|
let bon = util::smyt(&mut context.stack, toon.tail())?;
|
||||||
Ok(T(&mut context.stack, &[NO, bon, D(0)])?)
|
Ok(T(&mut context.stack, &[NO, bon, D(0)]))
|
||||||
}
|
|
||||||
x if unsafe { x.raw_equals(D(2)) } => {
|
|
||||||
Ok(T(&mut context.stack, &[NO, toon.tail()])?)
|
|
||||||
}
|
}
|
||||||
|
x if unsafe { x.raw_equals(D(2)) } => Ok(T(&mut context.stack, &[NO, toon.tail()])),
|
||||||
_ => panic!("serf: mook: invalid toon"),
|
_ => panic!("serf: mook: invalid toon"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +75,7 @@ pub mod util {
|
|||||||
use crate::jets;
|
use crate::jets;
|
||||||
use crate::jets::bits::util::rip;
|
use crate::jets::bits::util::rip;
|
||||||
use crate::jets::form::util::scow;
|
use crate::jets::form::util::scow;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{tape, Cell, Noun, D, T};
|
use crate::noun::{tape, Cell, Noun, D, T};
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
use std::result;
|
use std::result;
|
||||||
@ -87,37 +85,37 @@ pub mod util {
|
|||||||
pub const ROSE: Noun = D(tas!(b"rose"));
|
pub const ROSE: Noun = D(tas!(b"rose"));
|
||||||
|
|
||||||
/// The classic "slam gate" formula.
|
/// The classic "slam gate" formula.
|
||||||
pub fn slam_gate_fol(stack: &mut NockStack) -> AllocResult<Noun> {
|
pub fn slam_gate_fol(stack: &mut NockStack) -> Noun {
|
||||||
T(stack, &[D(9), D(2), D(0), D(1)])
|
T(stack, &[D(9), D(2), D(0), D(1)])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The classic "pass-through" scry handler.
|
/// The classic "pass-through" scry handler.
|
||||||
pub fn pass_thru_scry(stack: &mut NockStack) -> AllocResult<Noun> {
|
pub fn pass_thru_scry(stack: &mut NockStack) -> Noun {
|
||||||
// .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
|
// .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
|
||||||
// [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0]
|
// [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0]
|
||||||
let sig = T(stack, &[D(1), D(0)])?;
|
let sig = T(stack, &[D(1), D(0)]);
|
||||||
let sam = T(stack, &[D(0), D(6)])?;
|
let sam = T(stack, &[D(0), D(6)]);
|
||||||
let hed = T(stack, &[D(0), D(2)])?;
|
let hed = T(stack, &[D(0), D(2)]);
|
||||||
let tel = T(stack, &[D(0), D(3)])?;
|
let tel = T(stack, &[D(0), D(3)]);
|
||||||
let zap = T(stack, &[D(0), D(0)])?;
|
let zap = T(stack, &[D(0), D(0)]);
|
||||||
|
|
||||||
let cry = T(stack, &[D(12), hed, tel])?;
|
let cry = T(stack, &[D(12), hed, tel]);
|
||||||
let fol = T(stack, &[D(1), cry])?;
|
let fol = T(stack, &[D(1), cry]);
|
||||||
let res = T(stack, &[D(2), sam, fol])?;
|
let res = T(stack, &[D(2), sam, fol]);
|
||||||
let uno = T(stack, &[sig, res])?;
|
let uno = T(stack, &[sig, res]);
|
||||||
let dos = T(stack, &[sig, uno])?;
|
let dos = T(stack, &[sig, uno]);
|
||||||
|
|
||||||
let gat = T(stack, &[zap, D(0)])?;
|
let gat = T(stack, &[zap, D(0)]);
|
||||||
|
|
||||||
T(stack, &[dos, gat])
|
T(stack, &[dos, gat])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The "always-fail" scry
|
/// The "always-fail" scry
|
||||||
pub fn null_scry(stack: &mut NockStack) -> AllocResult<Noun> {
|
pub fn null_scry(stack: &mut NockStack) -> Noun {
|
||||||
// .* 0 != => ~ |=(^ ~)
|
// .* 0 != => ~ |=(^ ~)
|
||||||
// [[1 0] [0 0] 0]
|
// [[1 0] [0 0] 0]
|
||||||
let sig = T(stack, &[D(1), D(0)])?;
|
let sig = T(stack, &[D(1), D(0)]);
|
||||||
let zap = T(stack, &[D(0), D(0)])?;
|
let zap = T(stack, &[D(0), D(0)]);
|
||||||
|
|
||||||
T(stack, &[sig, zap, D(0)])
|
T(stack, &[sig, zap, D(0)])
|
||||||
}
|
}
|
||||||
@ -151,25 +149,25 @@ pub mod util {
|
|||||||
let cache_snapshot = context.cache;
|
let cache_snapshot = context.cache;
|
||||||
let scry_snapshot = context.scry_stack;
|
let scry_snapshot = context.scry_stack;
|
||||||
|
|
||||||
context.cache = Hamt::<Noun>::new(&mut context.stack)?;
|
context.cache = Hamt::<Noun>::new(&mut context.stack);
|
||||||
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack])?;
|
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
|
||||||
|
|
||||||
match interpret(context, subject, formula) {
|
match interpret(context, subject, formula) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
context.cache = cache_snapshot;
|
context.cache = cache_snapshot;
|
||||||
context.scry_stack = scry_snapshot;
|
context.scry_stack = scry_snapshot;
|
||||||
Ok(T(&mut context.stack, &[D(0), res])?)
|
Ok(T(&mut context.stack, &[D(0), res]))
|
||||||
}
|
}
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
Error::ScryBlocked(path) => {
|
Error::ScryBlocked(path) => {
|
||||||
context.cache = cache_snapshot;
|
context.cache = cache_snapshot;
|
||||||
context.scry_stack = scry_snapshot;
|
context.scry_stack = scry_snapshot;
|
||||||
Ok(T(&mut context.stack, &[D(1), path])?)
|
Ok(T(&mut context.stack, &[D(1), path]))
|
||||||
}
|
}
|
||||||
Error::Deterministic(_, trace) => {
|
Error::Deterministic(_, trace) => {
|
||||||
context.cache = cache_snapshot;
|
context.cache = cache_snapshot;
|
||||||
context.scry_stack = scry_snapshot;
|
context.scry_stack = scry_snapshot;
|
||||||
Ok(T(&mut context.stack, &[D(2), trace])?)
|
Ok(T(&mut context.stack, &[D(2), trace]))
|
||||||
}
|
}
|
||||||
Error::ScryCrashed(trace) => {
|
Error::ScryCrashed(trace) => {
|
||||||
context.cache = cache_snapshot;
|
context.cache = cache_snapshot;
|
||||||
@ -199,7 +197,7 @@ pub mod util {
|
|||||||
context.cache = cache_snapshot;
|
context.cache = cache_snapshot;
|
||||||
context.scry_stack = scry_snapshot;
|
context.scry_stack = scry_snapshot;
|
||||||
Err(err)
|
Err(err)
|
||||||
} // TODO: Implement the rest of the error handling
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,8 +232,8 @@ pub mod util {
|
|||||||
tas!(b"hunk") => match dat.as_either_atom_cell() {
|
tas!(b"hunk") => match dat.as_either_atom_cell() {
|
||||||
Left(_) => {
|
Left(_) => {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let tape = tape(stack, "mook.hunk")?;
|
let tape = tape(stack, "mook.hunk");
|
||||||
T(stack, &[LEAF, tape])?
|
T(stack, &[LEAF, tape])
|
||||||
}
|
}
|
||||||
Right(cell) => {
|
Right(cell) => {
|
||||||
// XX: need to check that this is actually a path
|
// XX: need to check that this is actually a path
|
||||||
@ -248,11 +246,11 @@ pub mod util {
|
|||||||
Left(atom) => {
|
Left(atom) => {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let tape = rip(stack, 3, 1, atom)?;
|
let tape = rip(stack, 3, 1, atom)?;
|
||||||
T(stack, &[LEAF, tape])?
|
T(stack, &[LEAF, tape])
|
||||||
}
|
}
|
||||||
Right(cell) => {
|
Right(cell) => {
|
||||||
'tank: {
|
'tank: {
|
||||||
let scry = null_scry(&mut context.stack)?;
|
let scry = null_scry(&mut context.stack);
|
||||||
// if +mink didn't crash...
|
// if +mink didn't crash...
|
||||||
if let Ok(tone) = mink(context, dat, cell.head(), scry) {
|
if let Ok(tone) = mink(context, dat, cell.head(), scry) {
|
||||||
if let Some(tonc) = tone.cell() {
|
if let Some(tonc) = tone.cell() {
|
||||||
@ -272,8 +270,8 @@ pub mod util {
|
|||||||
// This code only called when the break statement
|
// This code only called when the break statement
|
||||||
// above doesn't trigger
|
// above doesn't trigger
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let tape = tape(stack, "####")?;
|
let tape = tape(stack, "####");
|
||||||
T(stack, &[LEAF, tape])?
|
T(stack, &[LEAF, tape])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -285,8 +283,8 @@ pub mod util {
|
|||||||
let pstr = pint.head().as_cell()?;
|
let pstr = pint.head().as_cell()?;
|
||||||
let pend = pint.tail().as_cell()?;
|
let pend = pint.tail().as_cell()?;
|
||||||
|
|
||||||
let colo = T(stack, &[D(b':' as u64), D(0)])?;
|
let colo = T(stack, &[D(b':' as u64), D(0)]);
|
||||||
let trel = T(stack, &[colo, D(0), D(0)])?;
|
let trel = T(stack, &[colo, D(0), D(0)]);
|
||||||
|
|
||||||
let smyt = smyt(stack, spot.head())?;
|
let smyt = smyt(stack, spot.head())?;
|
||||||
|
|
||||||
@ -304,7 +302,7 @@ pub mod util {
|
|||||||
list = list.tail().as_cell()?;
|
list = list.tail().as_cell()?;
|
||||||
}
|
}
|
||||||
// "{end_col}]>"
|
// "{end_col}]>"
|
||||||
let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)])?;
|
let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)]);
|
||||||
(*list.tail_as_mut()) = p4;
|
(*list.tail_as_mut()) = p4;
|
||||||
|
|
||||||
list = end_lin.as_cell()?;
|
list = end_lin.as_cell()?;
|
||||||
@ -315,7 +313,7 @@ pub mod util {
|
|||||||
list = list.tail().as_cell()?;
|
list = list.tail().as_cell()?;
|
||||||
}
|
}
|
||||||
// "{end_lin} {end_col}]>"
|
// "{end_lin} {end_col}]>"
|
||||||
let p3 = T(stack, &[D(b' ' as u64), end_col])?;
|
let p3 = T(stack, &[D(b' ' as u64), end_col]);
|
||||||
(*list.tail_as_mut()) = p3;
|
(*list.tail_as_mut()) = p3;
|
||||||
|
|
||||||
list = str_col.as_cell()?;
|
list = str_col.as_cell()?;
|
||||||
@ -329,7 +327,7 @@ pub mod util {
|
|||||||
let p2 = T(
|
let p2 = T(
|
||||||
stack,
|
stack,
|
||||||
&[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin],
|
&[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin],
|
||||||
)?;
|
);
|
||||||
(*list.tail_as_mut()) = p2;
|
(*list.tail_as_mut()) = p2;
|
||||||
|
|
||||||
list = str_lin.as_cell()?;
|
list = str_lin.as_cell()?;
|
||||||
@ -340,14 +338,14 @@ pub mod util {
|
|||||||
list = list.tail().as_cell()?;
|
list = list.tail().as_cell()?;
|
||||||
}
|
}
|
||||||
// "{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
// "{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
||||||
let p1 = T(stack, &[D(b' ' as u64), str_col])?;
|
let p1 = T(stack, &[D(b' ' as u64), str_col]);
|
||||||
(*list.tail_as_mut()) = p1;
|
(*list.tail_as_mut()) = p1;
|
||||||
|
|
||||||
// "<[{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
// "<[{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
||||||
let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin])?;
|
let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]);
|
||||||
let finn = T(stack, &[LEAF, tape])?;
|
let finn = T(stack, &[LEAF, tape]);
|
||||||
|
|
||||||
T(stack, &[ROSE, trel, smyt, finn, D(0)])?
|
T(stack, &[ROSE, trel, smyt, finn, D(0)])
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
@ -362,16 +360,16 @@ pub mod util {
|
|||||||
D(tas!(b".")),
|
D(tas!(b".")),
|
||||||
tape,
|
tape,
|
||||||
],
|
],
|
||||||
)?
|
)
|
||||||
} // XX: TODO
|
} // XX: TODO
|
||||||
// %hand
|
// %hand
|
||||||
// %lose
|
// %lose
|
||||||
};
|
};
|
||||||
|
|
||||||
if flop {
|
if flop {
|
||||||
res = T(&mut context.stack, &[tank, res])?;
|
res = T(&mut context.stack, &[tank, res]);
|
||||||
} else {
|
} else {
|
||||||
let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack)?;
|
let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack);
|
||||||
(*new_memory).head = tank;
|
(*new_memory).head = tank;
|
||||||
*dest = new_cell.as_noun();
|
*dest = new_cell.as_noun();
|
||||||
dest = &mut (*new_memory).tail;
|
dest = &mut (*new_memory).tail;
|
||||||
@ -381,23 +379,23 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*dest = D(0);
|
*dest = D(0);
|
||||||
let toon = Cell::new(&mut context.stack, D(2), res)?;
|
let toon = Cell::new(&mut context.stack, D(2), res);
|
||||||
Ok(toon)
|
Ok(toon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> {
|
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result {
|
||||||
let lash = D(tas!(b"/"));
|
let lash = D(tas!(b"/"));
|
||||||
let zero = D(0);
|
let zero = D(0);
|
||||||
let sep = T(stack, &[lash, zero])?;
|
let sep = T(stack, &[lash, zero]);
|
||||||
|
|
||||||
let trel = T(stack, &[sep, sep, zero])?;
|
let trel = T(stack, &[sep, sep, zero]);
|
||||||
let tank = smyt_help(stack, path)?;
|
let tank = smyt_help(stack, path)?;
|
||||||
|
|
||||||
Ok(T(stack, &[ROSE, trel, tank])?)
|
Ok(T(stack, &[ROSE, trel, tank]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> {
|
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result {
|
||||||
// XX: switch to using Cell:new_raw_mut
|
// XX: switch to using Cell:new_raw_mut
|
||||||
if unsafe { path.raw_equals(D(0)) } {
|
if unsafe { path.raw_equals(D(0)) } {
|
||||||
return Ok(D(0));
|
return Ok(D(0));
|
||||||
@ -406,23 +404,18 @@ pub mod util {
|
|||||||
let cell = path.as_cell()?;
|
let cell = path.as_cell()?;
|
||||||
let tail = smyt_help(stack, cell.tail())?;
|
let tail = smyt_help(stack, cell.tail())?;
|
||||||
let trip = rip(stack, 3, 1, cell.head().as_atom()?)?;
|
let trip = rip(stack, 3, 1, cell.head().as_atom()?)?;
|
||||||
let head = T(stack, &[LEAF, trip])?;
|
let head = T(stack, &[LEAF, trip]);
|
||||||
|
|
||||||
Ok(T(stack, &[head, tail])?)
|
Ok(T(stack, &[head, tail]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, init_context};
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::D;
|
use crate::noun::{D, T};
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::T;
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init() {
|
fn init() {
|
||||||
@ -438,7 +431,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mink_success() {
|
fn test_mink_success() {
|
||||||
let context = &mut init_context().unwrap();
|
let context = &mut init_context();
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
|
|
||||||
let subj = D(0);
|
let subj = D(0);
|
||||||
@ -452,7 +445,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mink_zapzap() {
|
fn test_mink_zapzap() {
|
||||||
let context = &mut init_context().unwrap();
|
let context = &mut init_context();
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
|
|
||||||
let subj = D(0);
|
let subj = D(0);
|
||||||
@ -466,7 +459,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mink_trace() {
|
fn test_mink_trace() {
|
||||||
let context = &mut init_context().unwrap();
|
let context = &mut init_context();
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let subj = D(0);
|
let subj = D(0);
|
||||||
let scry = D(0);
|
let scry = D(0);
|
||||||
|
@ -13,7 +13,7 @@ crate::gdb!();
|
|||||||
//
|
//
|
||||||
// Text conversion
|
// Text conversion
|
||||||
//
|
//
|
||||||
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?.as_atom()?;
|
let sam = slot(subject, 6)?.as_atom()?;
|
||||||
let chars = met(3, sam);
|
let chars = met(3, sam);
|
||||||
if chars == 0 {
|
if chars == 0 {
|
||||||
@ -27,7 +27,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
for byte in bytes {
|
for byte in bytes {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (it, it_mem) = Cell::new_raw_mut(&mut context.stack)?;
|
let (it, it_mem) = Cell::new_raw_mut(&mut context.stack);
|
||||||
|
|
||||||
// safe because a byte can't overflow a direct atom
|
// safe because a byte can't overflow a direct atom
|
||||||
(*it_mem).head = D((*byte) as u64);
|
(*it_mem).head = D((*byte) as u64);
|
||||||
@ -44,7 +44,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
// Tracing
|
// Tracing
|
||||||
//
|
//
|
||||||
|
|
||||||
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let zyc = slot(sam, 2)?;
|
let zyc = slot(sam, 2)?;
|
||||||
let naz = slot(sam, 3)?;
|
let naz = slot(sam, 3)?;
|
||||||
@ -56,7 +56,7 @@ pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
// Combinators
|
// Combinators
|
||||||
//
|
//
|
||||||
|
|
||||||
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let vex = slot(sam, 2)?.as_cell()?;
|
let vex = slot(sam, 2)?.as_cell()?;
|
||||||
let sab = slot(sam, 3)?;
|
let sab = slot(sam, 3)?;
|
||||||
@ -81,25 +81,25 @@ pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let yur = util::last(p_vex, p_yit)?;
|
let yur = util::last(p_vex, p_yit)?;
|
||||||
|
|
||||||
if unsafe { q_yit.raw_equals(D(0)) } {
|
if unsafe { q_yit.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, q_vex])?)
|
Ok(T(&mut context.stack, &[yur, q_vex]))
|
||||||
} else {
|
} else {
|
||||||
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
||||||
let puq_yit = uq_yit.head();
|
let puq_yit = uq_yit.head();
|
||||||
let quq_yit = uq_yit.tail();
|
let quq_yit = uq_yit.tail();
|
||||||
|
|
||||||
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?;
|
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
|
||||||
let vux = slam(context, raq, arg)?;
|
let vux = slam(context, raq, arg)?;
|
||||||
|
|
||||||
if unsafe { vux.raw_equals(D(0)) } {
|
if unsafe { vux.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, q_vex])?)
|
Ok(T(&mut context.stack, &[yur, q_vex]))
|
||||||
} else {
|
} else {
|
||||||
let q_vux = vux.as_cell()?.tail();
|
let q_vux = vux.as_cell()?.tail();
|
||||||
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit])?)
|
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let vex = slot(sam, 2)?.as_cell()?;
|
let vex = slot(sam, 2)?.as_cell()?;
|
||||||
let sab = slot(sam, 3)?;
|
let sab = slot(sam, 3)?;
|
||||||
@ -124,19 +124,19 @@ pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let yur = util::last(p_vex, p_yit)?;
|
let yur = util::last(p_vex, p_yit)?;
|
||||||
|
|
||||||
if unsafe { q_yit.raw_equals(D(0)) } {
|
if unsafe { q_yit.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, D(0)])?)
|
Ok(T(&mut context.stack, &[yur, D(0)]))
|
||||||
} else {
|
} else {
|
||||||
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
||||||
let puq_yit = uq_yit.head();
|
let puq_yit = uq_yit.head();
|
||||||
let quq_yit = uq_yit.tail();
|
let quq_yit = uq_yit.tail();
|
||||||
|
|
||||||
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?;
|
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
|
||||||
let vux = slam(context, raq, arg)?;
|
let vux = slam(context, raq, arg)?;
|
||||||
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit])?)
|
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let vex = slot(sam, 2)?.as_cell()?;
|
let vex = slot(sam, 2)?.as_cell()?;
|
||||||
let sab = slot(sam, 3)?;
|
let sab = slot(sam, 3)?;
|
||||||
@ -161,7 +161,7 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let yur = util::last(p_vex, p_yit)?;
|
let yur = util::last(p_vex, p_yit)?;
|
||||||
|
|
||||||
if unsafe { q_yit.raw_equals(D(0)) } {
|
if unsafe { q_yit.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, D(0)])?)
|
Ok(T(&mut context.stack, &[yur, D(0)]))
|
||||||
} else {
|
} else {
|
||||||
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
||||||
let quq_yit = uq_yit.tail();
|
let quq_yit = uq_yit.tail();
|
||||||
@ -173,19 +173,19 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let goy = util::last(yur, p_wam)?;
|
let goy = util::last(yur, p_wam)?;
|
||||||
|
|
||||||
if unsafe { q_wam.raw_equals(D(0)) } {
|
if unsafe { q_wam.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[goy, D(0)])?)
|
Ok(T(&mut context.stack, &[goy, D(0)]))
|
||||||
} else {
|
} else {
|
||||||
let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
|
let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
|
||||||
let puq_wam = uq_wam.head();
|
let puq_wam = uq_wam.head();
|
||||||
let quq_wam = uq_wam.tail();
|
let quq_wam = uq_wam.tail();
|
||||||
|
|
||||||
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam])?;
|
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam]);
|
||||||
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam])?)
|
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let vex = slot(sam, 2)?.as_cell()?;
|
let vex = slot(sam, 2)?.as_cell()?;
|
||||||
let sab = slot(sam, 3)?;
|
let sab = slot(sam, 3)?;
|
||||||
@ -207,10 +207,10 @@ pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
// XX: Why don't we just return yit? When would p_vex ever be the later of the two?
|
// XX: Why don't we just return yit? When would p_vex ever be the later of the two?
|
||||||
let arg = util::last(p_vex, p_yit)?;
|
let arg = util::last(p_vex, p_yit)?;
|
||||||
Ok(T(&mut context.stack, &[arg, q_yit])?)
|
Ok(T(&mut context.stack, &[arg, q_yit]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result {
|
||||||
let vex = slot(subject, 12)?.as_cell()?;
|
let vex = slot(subject, 12)?.as_cell()?;
|
||||||
let sab = slot(subject, 13)?;
|
let sab = slot(subject, 13)?;
|
||||||
let p_vex = vex.head();
|
let p_vex = vex.head();
|
||||||
@ -230,19 +230,19 @@ pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let yur = util::last(p_vex, p_yit)?;
|
let yur = util::last(p_vex, p_yit)?;
|
||||||
|
|
||||||
if unsafe { q_yit.raw_equals(D(0)) } {
|
if unsafe { q_yit.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, D(0)])?)
|
Ok(T(&mut context.stack, &[yur, D(0)]))
|
||||||
} else {
|
} else {
|
||||||
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
||||||
let puq_yit = uq_yit.head();
|
let puq_yit = uq_yit.head();
|
||||||
let quq_yit = uq_yit.tail();
|
let quq_yit = uq_yit.tail();
|
||||||
|
|
||||||
let inner = T(&mut context.stack, &[puq_vex, puq_yit])?;
|
let inner = T(&mut context.stack, &[puq_vex, puq_yit]);
|
||||||
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit])?)
|
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
|
||||||
let vex = slot(subject, 12)?.as_cell()?;
|
let vex = slot(subject, 12)?.as_cell()?;
|
||||||
let sab = slot(subject, 13)?;
|
let sab = slot(subject, 13)?;
|
||||||
|
|
||||||
@ -255,10 +255,10 @@ pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
let roq = kick(context, sab, D(2))?.as_cell()?;
|
let roq = kick(context, sab, D(2))?.as_cell()?;
|
||||||
let yur = util::last(p_vex, roq.head())?;
|
let yur = util::last(p_vex, roq.head())?;
|
||||||
Ok(T(&mut context.stack, &[yur, roq.tail()])?)
|
Ok(T(&mut context.stack, &[yur, roq.tail()]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let vex = slot(sam, 2)?.as_cell()?;
|
let vex = slot(sam, 2)?.as_cell()?;
|
||||||
let sab = slot(sam, 3)?;
|
let sab = slot(sam, 3)?;
|
||||||
@ -281,12 +281,12 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let yur = util::last(p_vex, p_yit)?;
|
let yur = util::last(p_vex, p_yit)?;
|
||||||
|
|
||||||
if unsafe { q_yit.raw_equals(D(0)) } {
|
if unsafe { q_yit.raw_equals(D(0)) } {
|
||||||
Ok(T(&mut context.stack, &[yur, D(0)])?)
|
Ok(T(&mut context.stack, &[yur, D(0)]))
|
||||||
} else {
|
} else {
|
||||||
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
|
||||||
let quq_yit = uq_yit.tail();
|
let quq_yit = uq_yit.tail();
|
||||||
|
|
||||||
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit])?)
|
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
// Rule Builders
|
// Rule Builders
|
||||||
//
|
//
|
||||||
|
|
||||||
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let cus = slot(van, 12)?;
|
let cus = slot(van, 12)?;
|
||||||
@ -309,11 +309,11 @@ pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
} else {
|
} else {
|
||||||
let quq_vex = q_vex.as_cell()?.tail().as_cell()?.tail();
|
let quq_vex = q_vex.as_cell()?.tail().as_cell()?.tail();
|
||||||
|
|
||||||
Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex])?)
|
Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let poq = slot(van, 12)?;
|
let poq = slot(van, 12)?;
|
||||||
@ -331,11 +331,11 @@ pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let quq_vex = uq_vex.tail();
|
let quq_vex = uq_vex.tail();
|
||||||
|
|
||||||
let wag = slam(context, poq, puq_vex)?;
|
let wag = slam(context, poq, puq_vex)?;
|
||||||
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
|
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let huf = slot(van, 6)?;
|
let huf = slot(van, 6)?;
|
||||||
@ -343,10 +343,10 @@ pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
Ok(T(
|
Ok(T(
|
||||||
&mut context.stack,
|
&mut context.stack,
|
||||||
&[tub.as_cell()?.head(), D(0), huf, tub],
|
&[tub.as_cell()?.head(), D(0), huf, tub],
|
||||||
)?)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let hez = slot(van, 12)?;
|
let hez = slot(van, 12)?;
|
||||||
@ -368,14 +368,14 @@ pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let quq_vex = uq_vex.tail();
|
let quq_vex = uq_vex.tail();
|
||||||
let pquq_vex = quq_vex.as_cell()?.head();
|
let pquq_vex = quq_vex.as_cell()?.head();
|
||||||
|
|
||||||
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex])?;
|
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex]);
|
||||||
let gud = T(&mut context.stack, &[inner_gud, puq_vex])?;
|
let gud = T(&mut context.stack, &[inner_gud, puq_vex]);
|
||||||
let wag = slam(context, hez, gud)?;
|
let wag = slam(context, hez, gud)?;
|
||||||
|
|
||||||
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
|
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_just(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let daf = slot(van, 6)?;
|
let daf = slot(van, 6)?;
|
||||||
@ -390,7 +390,7 @@ pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let mut bud = slot(van, 6)?;
|
let mut bud = slot(van, 6)?;
|
||||||
@ -413,7 +413,7 @@ pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
util::fail(context, p_tub)
|
util::fail(context, p_tub)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?.as_cell()?;
|
let tub = slot(subject, 6)?.as_cell()?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let zep = slot(van, 6)?.as_cell()?;
|
let zep = slot(van, 6)?.as_cell()?;
|
||||||
@ -442,7 +442,7 @@ pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?;
|
let tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let gob = slot(van, 12)?;
|
let gob = slot(van, 12)?;
|
||||||
@ -459,12 +459,12 @@ pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let puq_vex = uq_vex.head();
|
let puq_vex = uq_vex.head();
|
||||||
let quq_vex = uq_vex.tail();
|
let quq_vex = uq_vex.tail();
|
||||||
|
|
||||||
let wag = T(&mut context.stack, &[gob, puq_vex])?;
|
let wag = T(&mut context.stack, &[gob, puq_vex]);
|
||||||
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
|
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
|
||||||
let tub = slot(subject, 6)?.as_cell()?;
|
let tub = slot(subject, 6)?.as_cell()?;
|
||||||
let con = slot(subject, 7)?;
|
let con = slot(subject, 7)?;
|
||||||
let mut hel = slot(con, 2)?;
|
let mut hel = slot(con, 2)?;
|
||||||
@ -505,8 +505,8 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
|
|
||||||
match (hpn_hel.as_either(), tpn_hel.as_either()) {
|
match (hpn_hel.as_either(), tpn_hel.as_either()) {
|
||||||
(Left(_), Left(_)) => {
|
(Left(_), Left(_)) => {
|
||||||
gte_b(&mut context.stack, iq_tub, hpn_hel)?
|
gte_b(&mut context.stack, iq_tub, hpn_hel)
|
||||||
&& lte_b(&mut context.stack, iq_tub, tpn_hel)?
|
&& lte_b(&mut context.stack, iq_tub, tpn_hel)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// XX: Fixes jet mismatch in Vere
|
// XX: Fixes jet mismatch in Vere
|
||||||
@ -525,7 +525,7 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
Right(cell) => cell.head().as_atom()?,
|
Right(cell) => cell.head().as_atom()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if lth_b(&mut context.stack, iq_tub, wor)? {
|
if lth_b(&mut context.stack, iq_tub, wor) {
|
||||||
hel = l_hel;
|
hel = l_hel;
|
||||||
} else {
|
} else {
|
||||||
hel = r_hel;
|
hel = r_hel;
|
||||||
@ -542,9 +542,9 @@ struct StirPair {
|
|||||||
pub res: Noun, // p.u.q.edge
|
pub res: Noun, // p.u.q.edge
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = context.with_stack_frame(0, |context| {
|
context.with_stack_frame(0, |context| {
|
||||||
let mut tub = slot(subject, 6)?;
|
let mut tub = slot(subject, 6)?;
|
||||||
let van = slot(subject, 7)?;
|
let van = slot(subject, 7)?;
|
||||||
let rud = slot(van, 12)?;
|
let rud = slot(van, 12)?;
|
||||||
@ -565,7 +565,7 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let puq_vex = slot(q_vex, 6)?;
|
let puq_vex = slot(q_vex, 6)?;
|
||||||
let quq_vex = slot(q_vex, 7)?;
|
let quq_vex = slot(q_vex, 7)?;
|
||||||
|
|
||||||
*(context.stack.push::<StirPair>()?) = StirPair {
|
*(context.stack.push::<StirPair>()) = StirPair {
|
||||||
har: p_vex,
|
har: p_vex,
|
||||||
res: puq_vex,
|
res: puq_vex,
|
||||||
};
|
};
|
||||||
@ -586,15 +586,14 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
while !context.stack.stack_is_empty() {
|
while !context.stack.stack_is_empty() {
|
||||||
let par_u = *(context.stack.top::<StirPair>());
|
let par_u = *(context.stack.top::<StirPair>());
|
||||||
p_wag = util::last(par_u.har, p_wag)?;
|
p_wag = util::last(par_u.har, p_wag)?;
|
||||||
let sam = T(&mut context.stack, &[par_u.res, puq_wag])?;
|
let sam = T(&mut context.stack, &[par_u.res, puq_wag]);
|
||||||
puq_wag = slam(context, raq, sam)?;
|
puq_wag = slam(context, raq, sam)?;
|
||||||
context.stack.pop::<StirPair>();
|
context.stack.pop::<StirPair>();
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag])?;
|
let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag]);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})?;
|
})
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +603,7 @@ pub mod util {
|
|||||||
use crate::noun::{Noun, D, T};
|
use crate::noun::{Noun, D, T};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
pub fn last(zyc: Noun, naz: Noun) -> Result<Noun> {
|
pub fn last(zyc: Noun, naz: Noun) -> Result {
|
||||||
let zyl = zyc.as_cell()?;
|
let zyl = zyc.as_cell()?;
|
||||||
let nal = naz.as_cell()?;
|
let nal = naz.as_cell()?;
|
||||||
|
|
||||||
@ -627,7 +626,7 @@ pub mod util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
|
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
|
||||||
pub fn next(context: &mut Context, tub: Noun) -> Result<Noun> {
|
pub fn next(context: &mut Context, tub: Noun) -> Result {
|
||||||
let p_tub = tub.as_cell()?.head();
|
let p_tub = tub.as_cell()?.head();
|
||||||
let q_tub = tub.as_cell()?.tail();
|
let q_tub = tub.as_cell()?.tail();
|
||||||
|
|
||||||
@ -639,25 +638,25 @@ pub mod util {
|
|||||||
let tq_tub = q_tub.as_cell()?.tail();
|
let tq_tub = q_tub.as_cell()?.tail();
|
||||||
|
|
||||||
let zac = lust(context, iq_tub, p_tub)?;
|
let zac = lust(context, iq_tub, p_tub)?;
|
||||||
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub])?)
|
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
|
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
|
||||||
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result<Noun> {
|
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result {
|
||||||
let p_naz = naz.as_cell()?.head().as_atom()?;
|
let p_naz = naz.as_cell()?.head().as_atom()?;
|
||||||
let q_naz = naz.as_cell()?.tail().as_atom()?;
|
let q_naz = naz.as_cell()?.tail().as_atom()?;
|
||||||
|
|
||||||
if unsafe { weq.raw_equals(D(10)) } {
|
if unsafe { weq.raw_equals(D(10)) } {
|
||||||
let arg = inc(&mut context.stack, p_naz)?.as_noun();
|
let arg = inc(&mut context.stack, p_naz).as_noun();
|
||||||
Ok(T(&mut context.stack, &[arg, D(1)])?)
|
Ok(T(&mut context.stack, &[arg, D(1)]))
|
||||||
} else {
|
} else {
|
||||||
let arg = inc(&mut context.stack, q_naz)?.as_noun();
|
let arg = inc(&mut context.stack, q_naz).as_noun();
|
||||||
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg])?)
|
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fail(context: &mut Context, hair: Noun) -> Result<Noun> {
|
pub fn fail(context: &mut Context, hair: Noun) -> Result {
|
||||||
Ok(T(&mut context.stack, &[hair, D(0)])?)
|
Ok(T(&mut context.stack, &[hair, D(0)]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,13 +664,9 @@ pub mod util {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::*;
|
||||||
use crate::noun::D;
|
use crate::noun::{D, T};
|
||||||
use crate::serialization::cue;
|
use crate::serialization::cue;
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override T and A with the panicky variants
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_door: AssertJetDoorFn = assert_jet_door_panicky;
|
|
||||||
|
|
||||||
// XX: need unit tests for:
|
// XX: need unit tests for:
|
||||||
// +last
|
// +last
|
||||||
@ -688,7 +683,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_easy() {
|
fn test_easy() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
// ((easy 'a') [[1 1] "abc"])
|
// ((easy 'a') [[1 1] "abc"])
|
||||||
// [[1 1] "abc"]
|
// [[1 1] "abc"]
|
||||||
|
@ -6,27 +6,23 @@ use crate::serialization::{cue, jam};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_cue(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cue(context: &mut Context, subject: Noun) -> Result {
|
||||||
Ok(cue(&mut context.stack, slot(subject, 6)?.as_atom()?)?)
|
Ok(cue(&mut context.stack, slot(subject, 6)?.as_atom()?)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_jam(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_jam(context: &mut Context, subject: Noun) -> Result {
|
||||||
Ok(jam(&mut context.stack, slot(subject, 6)?)?.as_noun())
|
Ok(jam(&mut context.stack, slot(subject, 6)?).as_noun())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::*;
|
||||||
use crate::noun::D;
|
use crate::noun::{D, T};
|
||||||
// Override T with the panicky variant
|
|
||||||
use crate::test_fns::T;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_jam() {
|
fn test_jam() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet(c, jet_jam, D(0x0), D(0x2));
|
assert_jet(c, jet_jam, D(0x0), D(0x2));
|
||||||
assert_jet(c, jet_jam, D(0x1), D(0xc));
|
assert_jet(c, jet_jam, D(0x1), D(0xc));
|
||||||
@ -38,7 +34,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cue() {
|
fn test_cue() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet(c, jet_cue, D(0x2), D(0x0));
|
assert_jet(c, jet_cue, D(0x2), D(0x0));
|
||||||
assert_jet(c, jet_cue, D(0xc), D(0x1));
|
assert_jet(c, jet_cue, D(0xc), D(0x1));
|
||||||
|
@ -9,100 +9,95 @@ use std::cmp::Ordering;
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
|
pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result {
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let a = slot(sam, 2)?;
|
let a = slot(sam, 2)?;
|
||||||
let b = slot(sam, 3)?;
|
let b = slot(sam, 3)?;
|
||||||
|
|
||||||
Ok(util::dor(&mut context.stack, a, b)?)
|
Ok(util::dor(&mut context.stack, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
|
pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
|
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let a = slot(sam, 2)?;
|
let a = slot(sam, 2)?;
|
||||||
let b = slot(sam, 3)?;
|
let b = slot(sam, 3)?;
|
||||||
|
|
||||||
let c = mug(stack, a)?;
|
let c = mug(stack, a);
|
||||||
let d = mug(stack, b)?;
|
let d = mug(stack, b);
|
||||||
|
|
||||||
match c.data().cmp(&d.data()) {
|
match c.data().cmp(&d.data()) {
|
||||||
Ordering::Greater => Ok(NO),
|
Ordering::Greater => Ok(NO),
|
||||||
Ordering::Less => Ok(YES),
|
Ordering::Less => Ok(YES),
|
||||||
Ordering::Equal => Ok(util::dor(stack, a, b)?),
|
Ordering::Equal => Ok(util::dor(stack, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
|
pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
|
|
||||||
let sam = slot(subject, 6)?;
|
let sam = slot(subject, 6)?;
|
||||||
let a = slot(sam, 2)?;
|
let a = slot(sam, 2)?;
|
||||||
let b = slot(sam, 3)?;
|
let b = slot(sam, 3)?;
|
||||||
|
|
||||||
let c = mug(stack, a)?;
|
let c = mug(stack, a);
|
||||||
let d = mug(stack, b)?;
|
let d = mug(stack, b);
|
||||||
|
|
||||||
let e = mug(stack, c.as_noun())?;
|
let e = mug(stack, c.as_noun());
|
||||||
let f = mug(stack, d.as_noun())?;
|
let f = mug(stack, d.as_noun());
|
||||||
|
|
||||||
match e.data().cmp(&f.data()) {
|
match e.data().cmp(&f.data()) {
|
||||||
Ordering::Greater => Ok(NO),
|
Ordering::Greater => Ok(NO),
|
||||||
Ordering::Less => Ok(YES),
|
Ordering::Less => Ok(YES),
|
||||||
Ordering::Equal => Ok(util::dor(stack, a, b)?),
|
Ordering::Equal => Ok(util::dor(stack, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
use crate::jets::math::util::lth;
|
use crate::jets::math::util::lth;
|
||||||
use crate::jets::util::slot;
|
use crate::jets::util::slot;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Noun, NO, YES};
|
use crate::noun::{Noun, NO, YES};
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
|
||||||
pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> AllocResult<Noun> {
|
pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> Noun {
|
||||||
let res = if unsafe { a.raw_equals(b) } {
|
if unsafe { a.raw_equals(b) } {
|
||||||
YES
|
YES
|
||||||
} else {
|
} else {
|
||||||
match (a.as_either_atom_cell(), b.as_either_atom_cell()) {
|
match (a.as_either_atom_cell(), b.as_either_atom_cell()) {
|
||||||
(Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b)?,
|
(Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b),
|
||||||
(Left(_), Right(_)) => YES,
|
(Left(_), Right(_)) => YES,
|
||||||
(Right(_), Left(_)) => NO,
|
(Right(_), Left(_)) => NO,
|
||||||
(Right(cell_a), Right(cell_b)) => {
|
(Right(cell_a), Right(cell_b)) => {
|
||||||
let a_head = match slot(cell_a.as_noun(), 2) {
|
let a_head = match slot(cell_a.as_noun(), 2) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(_) => return Ok(NO),
|
Err(_) => return NO,
|
||||||
};
|
};
|
||||||
let b_head = slot(cell_b.as_noun(), 2).unwrap();
|
let b_head = slot(cell_b.as_noun(), 2).unwrap();
|
||||||
let a_tail = slot(cell_a.as_noun(), 3).unwrap();
|
let a_tail = slot(cell_a.as_noun(), 3).unwrap();
|
||||||
let b_tail = slot(cell_b.as_noun(), 3).unwrap();
|
let b_tail = slot(cell_b.as_noun(), 3).unwrap();
|
||||||
if unsafe { a_head.raw_equals(b_head) } {
|
if unsafe { a_head.raw_equals(b_head) } {
|
||||||
dor(stack, a_tail, b_tail)?
|
dor(stack, a_tail, b_tail)
|
||||||
} else {
|
} else {
|
||||||
dor(stack, a_head, b_head)?
|
dor(stack, a_head, b_head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::*;
|
use crate::jets::util::test::{assert_jet, init_context, A};
|
||||||
use crate::noun::D;
|
use crate::noun::{D, T};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override with the panicky variant
|
|
||||||
use crate::test_fns::{A, T};
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dor() {
|
fn test_dor() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
||||||
assert_jet(c, jet_dor, sam, YES);
|
assert_jet(c, jet_dor, sam, YES);
|
||||||
@ -118,7 +113,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gor() {
|
fn test_gor() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
||||||
assert_jet(c, jet_gor, sam, YES);
|
assert_jet(c, jet_gor, sam, YES);
|
||||||
@ -130,7 +125,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mor() {
|
fn test_mor() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
let sam = T(&mut c.stack, &[D(1), D(1)]);
|
||||||
assert_jet(c, jet_mor, sam, YES);
|
assert_jet(c, jet_mor, sam, YES);
|
||||||
|
@ -8,7 +8,7 @@ use crate::noun::{IndirectAtom, Noun, D};
|
|||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let tom = arg.as_atom()?;
|
let tom = arg.as_atom()?;
|
||||||
let met = met(0, tom);
|
let met = met(0, tom);
|
||||||
@ -24,7 +24,7 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let tom = slot(subject, 6)?.as_atom()?;
|
let tom = slot(subject, 6)?.as_atom()?;
|
||||||
let met = met(0, tom);
|
let met = met(0, tom);
|
||||||
@ -35,7 +35,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let out_bits = met - 1;
|
let out_bits = met - 1;
|
||||||
let out_words = (out_bits + 63) >> 6;
|
let out_words = (out_bits + 63) >> 6;
|
||||||
let (mut indirect_out, out_bs) =
|
let (mut indirect_out, out_bs) =
|
||||||
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? };
|
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
|
||||||
out_bs.set(met - 2, true); // Set MSB
|
out_bs.set(met - 2, true); // Set MSB
|
||||||
if met > 2 {
|
if met > 2 {
|
||||||
out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]);
|
out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]);
|
||||||
@ -44,7 +44,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
|
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
|
||||||
let stack = &mut context.stack;
|
let stack = &mut context.stack;
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
@ -67,7 +67,7 @@ pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
|
|||||||
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
|
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
|
||||||
|
|
||||||
let (mut indirect_out, out_bs) =
|
let (mut indirect_out, out_bs) =
|
||||||
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? };
|
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
|
||||||
|
|
||||||
out_bs[0..b_bits - 1].copy_from_bitslice(&b.as_bitslice()[0..b_bits - 1]);
|
out_bs[0..b_bits - 1].copy_from_bitslice(&b.as_bitslice()[0..b_bits - 1]);
|
||||||
out_bs[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]);
|
out_bs[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]);
|
||||||
@ -82,13 +82,6 @@ mod tests {
|
|||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Noun, D, DIRECT_MAX};
|
use crate::noun::{Noun, D, DIRECT_MAX};
|
||||||
use ibig::ubig;
|
use ibig::ubig;
|
||||||
// Override with the panicky variant
|
|
||||||
use crate::test_fns::A;
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet: AssertJetFn = assert_jet_panicky;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
|
|
||||||
|
|
||||||
fn atom_0(_stack: &mut NockStack) -> Noun {
|
fn atom_0(_stack: &mut NockStack) -> Noun {
|
||||||
D(0x0)
|
D(0x0)
|
||||||
@ -132,7 +125,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cap() {
|
fn test_cap() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_jet_err(c, jet_cap, D(0), BAIL_EXIT);
|
assert_jet_err(c, jet_cap, D(0), BAIL_EXIT);
|
||||||
assert_jet_err(c, jet_cap, D(1), BAIL_EXIT);
|
assert_jet_err(c, jet_cap, D(1), BAIL_EXIT);
|
||||||
@ -148,7 +141,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mas() {
|
fn test_mas() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
let a63 = atom_63(&mut c.stack);
|
let a63 = atom_63(&mut c.stack);
|
||||||
let a64 = atom_64(&mut c.stack);
|
let a64 = atom_64(&mut c.stack);
|
||||||
let a65 = atom_65(&mut c.stack);
|
let a65 = atom_65(&mut c.stack);
|
||||||
@ -180,7 +173,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_peg() {
|
fn test_peg() {
|
||||||
let c = &mut init_context().unwrap();
|
let c = &mut init_context();
|
||||||
|
|
||||||
assert_common_jet_err(c, jet_peg, &[atom_0, atom_1], BAIL_EXIT);
|
assert_common_jet_err(c, jet_peg, &[atom_0, atom_1], BAIL_EXIT);
|
||||||
assert_common_jet_err(c, jet_peg, &[atom_1, atom_0], BAIL_EXIT);
|
assert_common_jet_err(c, jet_peg, &[atom_1, atom_0], BAIL_EXIT);
|
||||||
|
@ -2,7 +2,7 @@ use crate::hamt::Hamt;
|
|||||||
use crate::jets::cold::{Batteries, Cold};
|
use crate::jets::cold::{Batteries, Cold};
|
||||||
use crate::jets::hot::Hot;
|
use crate::jets::hot::Hot;
|
||||||
use crate::jets::Jet;
|
use crate::jets::Jet;
|
||||||
use crate::mem::{AllocResult, NockStack, Preserve};
|
use crate::mem::{NockStack, Preserve};
|
||||||
use crate::noun::{Noun, Slots};
|
use crate::noun::{Noun, Slots};
|
||||||
use std::ptr::{copy_nonoverlapping, null_mut};
|
use std::ptr::{copy_nonoverlapping, null_mut};
|
||||||
|
|
||||||
@ -14,8 +14,8 @@ impl Preserve for Warm {
|
|||||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||||
self.0.assert_in_stack(stack);
|
self.0.assert_in_stack(stack);
|
||||||
}
|
}
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
self.0.preserve(stack)
|
self.0.preserve(stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,17 +47,16 @@ impl Preserve for WarmEntry {
|
|||||||
cursor = (*cursor.0).next;
|
cursor = (*cursor.0).next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
// TODO: Should this panic? What is this?
|
|
||||||
if self.0.is_null() {
|
if self.0.is_null() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
let mut ptr: *mut *mut WarmEntryMem = &mut self.0;
|
let mut ptr: *mut *mut WarmEntryMem = &mut self.0;
|
||||||
loop {
|
loop {
|
||||||
if stack.is_in_frame(*ptr) {
|
if stack.is_in_frame(*ptr) {
|
||||||
(**ptr).batteries.preserve(stack)?;
|
(**ptr).batteries.preserve(stack);
|
||||||
(**ptr).path.preserve(stack)?;
|
(**ptr).path.preserve(stack);
|
||||||
let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1)?;
|
let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1);
|
||||||
copy_nonoverlapping(*ptr, dest_mem, 1);
|
copy_nonoverlapping(*ptr, dest_mem, 1);
|
||||||
*ptr = dest_mem;
|
*ptr = dest_mem;
|
||||||
ptr = &mut ((*dest_mem).next.0);
|
ptr = &mut ((*dest_mem).next.0);
|
||||||
@ -68,7 +67,6 @@ impl Preserve for WarmEntry {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +86,8 @@ impl Iterator for WarmEntry {
|
|||||||
|
|
||||||
impl Warm {
|
impl Warm {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
|
pub fn new(stack: &mut NockStack) -> Self {
|
||||||
Ok(Warm(Hamt::new(stack)?))
|
Warm(Hamt::new(stack))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(
|
fn insert(
|
||||||
@ -99,32 +97,31 @@ impl Warm {
|
|||||||
path: Noun,
|
path: Noun,
|
||||||
batteries: Batteries,
|
batteries: Batteries,
|
||||||
jet: Jet,
|
jet: Jet,
|
||||||
) -> AllocResult<()> {
|
) {
|
||||||
let current_warm_entry = self.0.lookup(stack, formula)?.unwrap_or(WARM_ENTRY_NIL);
|
let current_warm_entry = self.0.lookup(stack, formula).unwrap_or(WARM_ENTRY_NIL);
|
||||||
unsafe {
|
unsafe {
|
||||||
let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1)?;
|
let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1);
|
||||||
*warm_entry_mem_ptr = WarmEntryMem {
|
*warm_entry_mem_ptr = WarmEntryMem {
|
||||||
batteries,
|
batteries,
|
||||||
jet,
|
jet,
|
||||||
path,
|
path,
|
||||||
next: current_warm_entry,
|
next: current_warm_entry,
|
||||||
};
|
};
|
||||||
self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr))?;
|
self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr));
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> AllocResult<Self> {
|
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> Self {
|
||||||
let mut warm = Self::new(stack)?;
|
let mut warm = Self::new(stack);
|
||||||
for (mut path, axis, jet) in *hot {
|
for (mut path, axis, jet) in *hot {
|
||||||
let batteries_list = cold.find(stack, &mut path)?;
|
let batteries_list = cold.find(stack, &mut path);
|
||||||
for batteries in batteries_list {
|
for batteries in batteries_list {
|
||||||
let mut batteries_tmp = batteries;
|
let mut batteries_tmp = batteries;
|
||||||
let (battery, _parent_axis) = batteries_tmp
|
let (battery, _parent_axis) = batteries_tmp
|
||||||
.next()
|
.next()
|
||||||
.expect("IMPOSSIBLE: empty battery entry in cold state");
|
.expect("IMPOSSIBLE: empty battery entry in cold state");
|
||||||
if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } {
|
if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } {
|
||||||
warm.insert(stack, &mut formula, path, batteries, jet)?;
|
warm.insert(stack, &mut formula, path, batteries, jet);
|
||||||
} else {
|
} else {
|
||||||
// XX: need NockStack allocated string interpolation
|
// XX: need NockStack allocated string interpolation
|
||||||
// eprintln!("Bad axis {} into formula {:?}", axis, battery);
|
// eprintln!("Bad axis {} into formula {:?}", axis, battery);
|
||||||
@ -132,7 +129,7 @@ impl Warm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(warm)
|
warm
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk through the linked list of WarmEntry objects and do a partial check
|
/// Walk through the linked list of WarmEntry objects and do a partial check
|
||||||
@ -143,17 +140,13 @@ impl Warm {
|
|||||||
stack: &mut NockStack,
|
stack: &mut NockStack,
|
||||||
s: &mut Noun,
|
s: &mut Noun,
|
||||||
f: &mut Noun,
|
f: &mut Noun,
|
||||||
) -> AllocResult<Option<(Jet, Noun)>> {
|
) -> Option<(Jet, Noun)> {
|
||||||
let warm_it = self.0.lookup(stack, f)?;
|
let warm_it = self.0.lookup(stack, f)?;
|
||||||
if let Some(warm_entry) = warm_it {
|
for (path, batteries, jet) in warm_it {
|
||||||
unsafe {
|
if batteries.matches(stack, *s) {
|
||||||
let jet = (*warm_entry.0).jet;
|
return Some((jet, path));
|
||||||
let path = (*warm_entry.0).path;
|
|
||||||
if (*warm_entry.0).batteries.matches(stack, *s)? {
|
|
||||||
return Ok(Some((jet, path)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,15 @@ extern crate lazy_static;
|
|||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
//pub mod bytecode;
|
|
||||||
pub mod flog;
|
pub mod flog;
|
||||||
pub mod hamt;
|
pub mod hamt;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
pub mod jets;
|
pub mod jets;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod mug;
|
pub mod mug;
|
||||||
pub mod newt;
|
|
||||||
pub mod noun;
|
pub mod noun;
|
||||||
pub mod serialization;
|
pub mod serialization;
|
||||||
pub mod site;
|
pub mod site;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod test_fns;
|
|
||||||
|
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub mod unifying_equality;
|
pub mod unifying_equality;
|
||||||
|
|
||||||
@ -78,10 +71,10 @@ mod tests {
|
|||||||
use crate::noun::*;
|
use crate::noun::*;
|
||||||
use crate::serialization::jam;
|
use crate::serialization::jam;
|
||||||
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
||||||
let head = Atom::new(&mut stack, 0).unwrap().as_noun();
|
let head = Atom::new(&mut stack, 0).as_noun();
|
||||||
let tail = Atom::new(&mut stack, 1).unwrap().as_noun();
|
let tail = Atom::new(&mut stack, 1).as_noun();
|
||||||
let cell = Cell::new(&mut stack, head, tail).unwrap().as_noun();
|
let cell = Cell::new(&mut stack, head, tail).as_noun();
|
||||||
let res = jam(&mut stack, cell).unwrap().as_direct().unwrap().data();
|
let res = jam(&mut stack, cell).as_direct().unwrap().data();
|
||||||
assert_eq!(res, 201);
|
assert_eq!(res, 201);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use either::Either::{self, Left, Right};
|
|||||||
use ibig::Stack;
|
use ibig::Stack;
|
||||||
use memmap::MmapMut;
|
use memmap::MmapMut;
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
|
use std::panic::panic_any;
|
||||||
use std::ptr::copy_nonoverlapping;
|
use std::ptr::copy_nonoverlapping;
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -65,8 +66,6 @@ impl From<AllocationError> for std::io::Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum NewStackError {
|
pub enum NewStackError {
|
||||||
#[error("stack too small")]
|
#[error("stack too small")]
|
||||||
@ -185,9 +184,11 @@ impl NockStack {
|
|||||||
* top_slots is how many slots to allocate to the top stack frame.
|
* top_slots is how many slots to allocate to the top stack frame.
|
||||||
*/
|
*/
|
||||||
pub fn new(size: usize, top_slots: usize) -> NockStack {
|
pub fn new(size: usize, top_slots: usize) -> NockStack {
|
||||||
Self::new_(size, top_slots)
|
let result = Self::new_(size, top_slots);
|
||||||
.expect("Error making new NockStack")
|
match result {
|
||||||
.0
|
Ok((stack, _)) => stack,
|
||||||
|
Err(e) => std::panic::panic_any(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_(size: usize, top_slots: usize) -> Result<(NockStack, usize), NewStackError> {
|
pub fn new_(size: usize, top_slots: usize) -> Result<(NockStack, usize), NewStackError> {
|
||||||
@ -294,10 +295,10 @@ impl NockStack {
|
|||||||
// Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false)
|
// Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false)
|
||||||
// Types of size: word (words: usize)
|
// Types of size: word (words: usize)
|
||||||
/// Check if an allocation or pointer retrieval indicates an invalid request or an invalid state
|
/// Check if an allocation or pointer retrieval indicates an invalid request or an invalid state
|
||||||
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> AllocResult<()> {
|
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) {
|
||||||
let _memory_state = self.memory_state(Some(words));
|
let _memory_state = self.memory_state(Some(words));
|
||||||
if self.pc && !alloc.alloc_type.allowed_when_pc() {
|
if self.pc && !alloc.alloc_type.allowed_when_pc() {
|
||||||
return Err(self.cannot_alloc_in_pc(Some(words)));
|
panic_any(self.cannot_alloc_in_pc(Some(words)));
|
||||||
}
|
}
|
||||||
// When self.pc is true
|
// When self.pc is true
|
||||||
// west:
|
// west:
|
||||||
@ -409,30 +410,24 @@ impl NockStack {
|
|||||||
};
|
};
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Increasing => {
|
Direction::Increasing => {
|
||||||
if target_point <= limit_point {
|
if !(target_point <= limit_point) {
|
||||||
Ok(())
|
panic_any(self.out_of_memory(alloc, Some(words)))
|
||||||
} else {
|
|
||||||
Err(self.out_of_memory(alloc, Some(words)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Direction::Decreasing => {
|
Direction::Decreasing => {
|
||||||
if target_point >= limit_point {
|
if !(target_point >= limit_point) {
|
||||||
Ok(())
|
panic_any(self.out_of_memory(alloc, Some(words)))
|
||||||
} else {
|
|
||||||
Err(self.out_of_memory(alloc, Some(words)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO this check is imprecise and should take into account the size of the pointer!
|
// TODO this check is imprecise and should take into account the size of the pointer!
|
||||||
Direction::IncreasingDeref => {
|
Direction::IncreasingDeref => {
|
||||||
if target_point < limit_point {
|
if !(target_point < limit_point) {
|
||||||
Ok(())
|
panic_any(self.out_of_memory(alloc, Some(words)))
|
||||||
} else {
|
|
||||||
Err(self.out_of_memory(alloc, Some(words)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) -> AllocResult<()> {
|
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) {
|
||||||
let alloc = self.get_alloc_config(alloc_type);
|
let alloc = self.get_alloc_config(alloc_type);
|
||||||
self.alloc_would_oom_(alloc, words)
|
self.alloc_would_oom_(alloc, words)
|
||||||
}
|
}
|
||||||
@ -443,7 +438,7 @@ impl NockStack {
|
|||||||
* "popping" the top frame.
|
* "popping" the top frame.
|
||||||
*/
|
*/
|
||||||
// Pop analogue, doesn't need OOM check.
|
// Pop analogue, doesn't need OOM check.
|
||||||
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) -> AllocResult<()> {
|
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) {
|
||||||
// Assert that we are at the top
|
// Assert that we are at the top
|
||||||
assert!((*self.prev_frame_pointer_pointer()).is_null());
|
assert!((*self.prev_frame_pointer_pointer()).is_null());
|
||||||
assert!((*self.prev_stack_pointer_pointer()).is_null());
|
assert!((*self.prev_stack_pointer_pointer()).is_null());
|
||||||
@ -459,7 +454,7 @@ impl NockStack {
|
|||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
byte_size,
|
byte_size,
|
||||||
)?;
|
);
|
||||||
// new top frame will be east
|
// new top frame will be east
|
||||||
let new_frame_pointer = self.start.add(self.size).sub(size) as *mut u64;
|
let new_frame_pointer = self.start.add(self.size).sub(size) as *mut u64;
|
||||||
*new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64;
|
*new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64;
|
||||||
@ -481,7 +476,7 @@ impl NockStack {
|
|||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
byte_size,
|
byte_size,
|
||||||
)?;
|
);
|
||||||
let new_frame_pointer = self.start.add(size) as *mut u64;
|
let new_frame_pointer = self.start.add(size) as *mut u64;
|
||||||
*new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64;
|
*new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64;
|
||||||
*new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64;
|
*new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64;
|
||||||
@ -492,7 +487,6 @@ impl NockStack {
|
|||||||
self.pc = false;
|
self.pc = false;
|
||||||
assert!(self.is_west());
|
assert!(self.is_west());
|
||||||
};
|
};
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the NockStack. The top frame is west as in the initial creation of the NockStack.
|
/// Resets the NockStack. The top frame is west as in the initial creation of the NockStack.
|
||||||
@ -615,32 +609,32 @@ impl NockStack {
|
|||||||
/** Mutable pointer to a slot in a stack frame: east stack */
|
/** Mutable pointer to a slot in a stack frame: east stack */
|
||||||
// TODO: slot_pointer_east_: Needs a simple bounds check
|
// TODO: slot_pointer_east_: Needs a simple bounds check
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
unsafe fn slot_pointer_east_(&self, slot: usize) -> AllocResult<*mut u64> {
|
unsafe fn slot_pointer_east_(&self, slot: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::East,
|
orientation: ArenaOrientation::East,
|
||||||
alloc_type: AllocationType::SlotPointer,
|
alloc_type: AllocationType::SlotPointer,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
slot,
|
slot,
|
||||||
)?;
|
);
|
||||||
Ok(self.frame_pointer.add(slot))
|
self.frame_pointer.add(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mutable pointer to a slot in a stack frame: west stack */
|
/** Mutable pointer to a slot in a stack frame: west stack */
|
||||||
// TODO: slot_pointer_west_: Needs a simple bounds check
|
// TODO: slot_pointer_west_: Needs a simple bounds check
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
||||||
unsafe fn slot_pointer_west_(&self, slot: usize) -> AllocResult<*mut u64> {
|
unsafe fn slot_pointer_west_(&self, slot: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::West,
|
orientation: ArenaOrientation::West,
|
||||||
alloc_type: AllocationType::SlotPointer,
|
alloc_type: AllocationType::SlotPointer,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
slot,
|
slot,
|
||||||
)?;
|
);
|
||||||
Ok(self.frame_pointer.sub(slot + 1))
|
self.frame_pointer.sub(slot + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mutable pointer to a slot in a stack frame: east stack */
|
/** Mutable pointer to a slot in a stack frame: east stack */
|
||||||
@ -659,7 +653,7 @@ impl NockStack {
|
|||||||
/// Mutable pointer to a slot in a stack frame
|
/// Mutable pointer to a slot in a stack frame
|
||||||
/// Panics on out-of-bounds conditions
|
/// Panics on out-of-bounds conditions
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
unsafe fn slot_pointer_(&self, slot: usize) -> AllocResult<*mut u64> {
|
unsafe fn slot_pointer_(&self, slot: usize) -> *mut u64 {
|
||||||
if self.is_west() {
|
if self.is_west() {
|
||||||
self.slot_pointer_west_(slot)
|
self.slot_pointer_west_(slot)
|
||||||
} else {
|
} else {
|
||||||
@ -742,38 +736,38 @@ impl NockStack {
|
|||||||
* allocation pointer is returned as the pointer to the newly allocated memory. */
|
* allocation pointer is returned as the pointer to the newly allocated memory. */
|
||||||
|
|
||||||
/** Bump the alloc pointer for a west frame to make space for an allocation */
|
/** Bump the alloc pointer for a west frame to make space for an allocation */
|
||||||
unsafe fn raw_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_west(&mut self, words: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
|
self.alloc_would_oom(AllocationType::Alloc, words);
|
||||||
if self.pc {
|
if self.pc {
|
||||||
panic!("Allocation during cleanup phase is prohibited.");
|
panic!("Allocation during cleanup phase is prohibited.");
|
||||||
}
|
}
|
||||||
self.alloc_pointer = self.alloc_pointer.sub(words);
|
self.alloc_pointer = self.alloc_pointer.sub(words);
|
||||||
Ok(self.alloc_pointer)
|
self.alloc_pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Bump the alloc pointer for an east frame to make space for an allocation */
|
/** Bump the alloc pointer for an east frame to make space for an allocation */
|
||||||
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_east(&mut self, words: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
|
self.alloc_would_oom(AllocationType::Alloc, words);
|
||||||
if self.pc {
|
if self.pc {
|
||||||
panic!("Allocation during cleanup phase is prohibited.");
|
panic!("Allocation during cleanup phase is prohibited.");
|
||||||
}
|
}
|
||||||
let alloc = self.alloc_pointer;
|
let alloc = self.alloc_pointer;
|
||||||
self.alloc_pointer = self.alloc_pointer.add(words);
|
self.alloc_pointer = self.alloc_pointer.add(words);
|
||||||
Ok(alloc)
|
alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for an indirect pointer in a west frame */
|
/** Allocate space for an indirect pointer in a west frame */
|
||||||
unsafe fn indirect_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn indirect_alloc_west(&mut self, words: usize) -> *mut u64 {
|
||||||
self.raw_alloc_west(words + 2)
|
self.raw_alloc_west(words + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for an indirect pointer in an east frame */
|
/** Allocate space for an indirect pointer in an east frame */
|
||||||
unsafe fn indirect_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn indirect_alloc_east(&mut self, words: usize) -> *mut u64 {
|
||||||
self.raw_alloc_east(words + 2)
|
self.raw_alloc_east(words + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for an indirect pointer in a stack frame */
|
/** Allocate space for an indirect pointer in a stack frame */
|
||||||
unsafe fn indirect_alloc(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn indirect_alloc(&mut self, words: usize) -> *mut u64 {
|
||||||
if self.is_west() {
|
if self.is_west() {
|
||||||
self.indirect_alloc_west(words)
|
self.indirect_alloc_west(words)
|
||||||
} else {
|
} else {
|
||||||
@ -782,19 +776,19 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for a struct in a west frame */
|
/** Allocate space for a struct in a west frame */
|
||||||
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> AllocResult<*mut T> {
|
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> *mut T {
|
||||||
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count)?;
|
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count);
|
||||||
Ok(eigen_pointer as *mut T)
|
eigen_pointer as *mut T
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for a struct in an east frame */
|
/** Allocate space for a struct in an east frame */
|
||||||
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> AllocResult<*mut T> {
|
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> *mut T {
|
||||||
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count)?;
|
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count);
|
||||||
Ok(eigen_pointer as *mut T)
|
eigen_pointer as *mut T
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for a struct in a stack frame */
|
/** Allocate space for a struct in a stack frame */
|
||||||
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> AllocResult<*mut T> {
|
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> *mut T {
|
||||||
if self.is_west() {
|
if self.is_west() {
|
||||||
self.struct_alloc_west::<T>(count)
|
self.struct_alloc_west::<T>(count)
|
||||||
} else {
|
} else {
|
||||||
@ -802,40 +796,40 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::West,
|
orientation: ArenaOrientation::West,
|
||||||
alloc_type: AllocationType::AllocPreviousFrame,
|
alloc_type: AllocationType::AllocPreviousFrame,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
words,
|
words,
|
||||||
)?;
|
);
|
||||||
// note that the allocation is on the east frame, and thus resembles raw_alloc_east
|
// note that the allocation is on the east frame, and thus resembles raw_alloc_east
|
||||||
let alloc = *self.prev_alloc_pointer_pointer();
|
let alloc = *self.prev_alloc_pointer_pointer();
|
||||||
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words);
|
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words);
|
||||||
Ok(alloc)
|
alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> *mut u64 {
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::East,
|
orientation: ArenaOrientation::East,
|
||||||
alloc_type: AllocationType::AllocPreviousFrame,
|
alloc_type: AllocationType::AllocPreviousFrame,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
words,
|
words,
|
||||||
)?;
|
);
|
||||||
// note that the allocation is on the west frame, and thus resembles raw_alloc_west
|
// note that the allocation is on the west frame, and thus resembles raw_alloc_west
|
||||||
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words);
|
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words);
|
||||||
Ok(*(self.prev_alloc_pointer_pointer()))
|
*(self.prev_alloc_pointer_pointer())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the
|
/** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the
|
||||||
* stack frame is in cleanup phase, which is the only time we should be allocating in a previous
|
* stack frame is in cleanup phase, which is the only time we should be allocating in a previous
|
||||||
* frame. */
|
* frame. */
|
||||||
unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
|
||||||
self.pre_copy()?;
|
self.pre_copy();
|
||||||
if self.is_west() {
|
if self.is_west() {
|
||||||
self.raw_alloc_in_previous_frame_west(words)
|
self.raw_alloc_in_previous_frame_west(words)
|
||||||
} else {
|
} else {
|
||||||
@ -844,21 +838,18 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Allocates space in the previous frame for some number of T's. */
|
/** Allocates space in the previous frame for some number of T's. */
|
||||||
pub unsafe fn struct_alloc_in_previous_frame<T>(
|
pub unsafe fn struct_alloc_in_previous_frame<T>(&mut self, count: usize) -> *mut T {
|
||||||
&mut self,
|
let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count);
|
||||||
count: usize,
|
res as *mut T
|
||||||
) -> AllocResult<*mut T> {
|
|
||||||
let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count)?;
|
|
||||||
Ok(res as *mut T)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for an indirect atom in the previous stack frame. */
|
/** Allocate space for an indirect atom in the previous stack frame. */
|
||||||
unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
|
||||||
self.raw_alloc_in_previous_frame(words + 2)
|
self.raw_alloc_in_previous_frame(words + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocate space for an alloc::Layout in a stack frame */
|
/** Allocate space for an alloc::Layout in a stack frame */
|
||||||
unsafe fn layout_alloc(&mut self, layout: Layout) -> AllocResult<*mut u64> {
|
unsafe fn layout_alloc(&mut self, layout: Layout) -> *mut u64 {
|
||||||
assert!(layout.align() <= 64, "layout alignment must be <= 64");
|
assert!(layout.align() <= 64, "layout alignment must be <= 64");
|
||||||
if self.is_west() {
|
if self.is_west() {
|
||||||
self.raw_alloc_west((layout.size() + 7) >> 3)
|
self.raw_alloc_west((layout.size() + 7) >> 3)
|
||||||
@ -896,15 +887,14 @@ impl NockStack {
|
|||||||
* lightweight stack (push(), pop(), top()) are the same regardless of whether
|
* lightweight stack (push(), pop(), top()) are the same regardless of whether
|
||||||
* or not pre_copy() has been called.
|
* or not pre_copy() has been called.
|
||||||
* */
|
* */
|
||||||
unsafe fn pre_copy(&mut self) -> AllocResult<()> {
|
unsafe fn pre_copy(&mut self) {
|
||||||
// pre_copy is intended to be idempotent, so we don't need to do anything if it's already been called
|
// pre_copy is intended to be idempotent, so we don't need to do anything if it's already been called
|
||||||
if !self.pc {
|
if !self.pc {
|
||||||
let is_west = self.is_west();
|
let is_west = self.is_west();
|
||||||
let words = if is_west { RESERVED + 1 } else { RESERVED };
|
let words = if is_west { RESERVED + 1 } else { RESERVED };
|
||||||
// TODO: pre_copy: Treating pre_copy like a FramePush for OOM checking purposes
|
// TODO: pre_copy: Treating pre_copy like a FramePush for OOM checking purposes
|
||||||
// Is this correct?
|
// Is this correct?
|
||||||
let () =
|
let () = self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words);
|
||||||
self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words)?;
|
|
||||||
*(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME));
|
*(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME));
|
||||||
*(self.free_slot(STACK)) = *(self.slot_pointer(STACK));
|
*(self.free_slot(STACK)) = *(self.slot_pointer(STACK));
|
||||||
*(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC));
|
*(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC));
|
||||||
@ -916,22 +906,21 @@ impl NockStack {
|
|||||||
self.stack_pointer = self.alloc_pointer.add(words);
|
self.stack_pointer = self.alloc_pointer.add(words);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn copy(&mut self, noun: &mut Noun) -> AllocResult<()> {
|
unsafe fn copy(&mut self, noun: &mut Noun) {
|
||||||
assert_acyclic!(*noun);
|
assert_acyclic!(*noun);
|
||||||
assert_no_forwarding_pointers!(*noun);
|
assert_no_forwarding_pointers!(*noun);
|
||||||
assert_no_junior_pointers!(self, *noun);
|
assert_no_junior_pointers!(self, *noun);
|
||||||
|
|
||||||
self.pre_copy()?;
|
self.pre_copy();
|
||||||
assert!(self.stack_is_empty());
|
assert!(self.stack_is_empty());
|
||||||
let noun_ptr = noun as *mut Noun;
|
let noun_ptr = noun as *mut Noun;
|
||||||
// Add two slots to the lightweight stack
|
// Add two slots to the lightweight stack
|
||||||
// Set the first new slot to the noun to be copied
|
// Set the first new slot to the noun to be copied
|
||||||
*(self.push::<Noun>()?) = *noun;
|
*(self.push::<Noun>()) = *noun;
|
||||||
// Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change
|
// Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change
|
||||||
*(self.push::<*mut Noun>()?) = noun_ptr;
|
*(self.push::<*mut Noun>()) = noun_ptr;
|
||||||
loop {
|
loop {
|
||||||
if self.stack_is_empty() {
|
if self.stack_is_empty() {
|
||||||
break;
|
break;
|
||||||
@ -965,7 +954,7 @@ impl NockStack {
|
|||||||
Either::Left(mut indirect) => {
|
Either::Left(mut indirect) => {
|
||||||
// Make space for the atom
|
// Make space for the atom
|
||||||
let alloc =
|
let alloc =
|
||||||
self.indirect_alloc_in_previous_frame(indirect.size())?;
|
self.indirect_alloc_in_previous_frame(indirect.size());
|
||||||
|
|
||||||
// Indirect atoms can be copied directly
|
// Indirect atoms can be copied directly
|
||||||
copy_nonoverlapping(
|
copy_nonoverlapping(
|
||||||
@ -984,16 +973,16 @@ impl NockStack {
|
|||||||
Either::Right(mut cell) => {
|
Either::Right(mut cell) => {
|
||||||
// Make space for the cell
|
// Make space for the cell
|
||||||
let alloc =
|
let alloc =
|
||||||
self.struct_alloc_in_previous_frame::<CellMemory>(1)?;
|
self.struct_alloc_in_previous_frame::<CellMemory>(1);
|
||||||
|
|
||||||
// Copy the cell metadata
|
// Copy the cell metadata
|
||||||
(*alloc).metadata = (*cell.to_raw_pointer()).metadata;
|
(*alloc).metadata = (*cell.to_raw_pointer()).metadata;
|
||||||
|
|
||||||
// Push the tail and the head to the work stack
|
// Push the tail and the head to the work stack
|
||||||
*(self.push::<Noun>()?) = cell.tail();
|
*(self.push::<Noun>()) = cell.tail();
|
||||||
*(self.push::<*mut Noun>()?) = &mut (*alloc).tail;
|
*(self.push::<*mut Noun>()) = &mut (*alloc).tail;
|
||||||
*(self.push::<Noun>()?) = cell.head();
|
*(self.push::<Noun>()) = cell.head();
|
||||||
*(self.push::<*mut Noun>()?) = &mut (*alloc).head;
|
*(self.push::<*mut Noun>()) = &mut (*alloc).head;
|
||||||
|
|
||||||
// Set the forwarding pointer
|
// Set the forwarding pointer
|
||||||
cell.set_forwarding_pointer(alloc);
|
cell.set_forwarding_pointer(alloc);
|
||||||
@ -1015,7 +1004,6 @@ impl NockStack {
|
|||||||
assert_acyclic!(*noun);
|
assert_acyclic!(*noun);
|
||||||
assert_no_forwarding_pointers!(*noun);
|
assert_no_forwarding_pointers!(*noun);
|
||||||
assert_no_junior_pointers!(self, *noun);
|
assert_no_junior_pointers!(self, *noun);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't need an OOM check, just an assertion. We expect it to panic.
|
// Doesn't need an OOM check, just an assertion. We expect it to panic.
|
||||||
@ -1103,7 +1091,7 @@ impl NockStack {
|
|||||||
self.pc = false;
|
self.pc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) -> AllocResult<()> {
|
pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) {
|
||||||
x.preserve(self)
|
x.preserve(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,12 +1104,12 @@ impl NockStack {
|
|||||||
|
|
||||||
/** Push a frame onto the stack with 0 or more local variable slots. */
|
/** Push a frame onto the stack with 0 or more local variable slots. */
|
||||||
/// This computation for num_locals is done in the east/west variants, but roughly speaking it's the input n words + 3 for prev frame alloc/stack/frame pointers
|
/// This computation for num_locals is done in the east/west variants, but roughly speaking it's the input n words + 3 for prev frame alloc/stack/frame pointers
|
||||||
pub fn frame_push(&mut self, num_locals: usize) -> AllocResult<()> {
|
pub fn frame_push(&mut self, num_locals: usize) {
|
||||||
if self.pc {
|
if self.pc {
|
||||||
panic!("frame_push during cleanup phase is prohibited.");
|
panic!("frame_push during cleanup phase is prohibited.");
|
||||||
}
|
}
|
||||||
let words = num_locals + RESERVED;
|
let words = num_locals + RESERVED;
|
||||||
let () = self.alloc_would_oom(AllocationType::FramePush, words)?;
|
self.alloc_would_oom(AllocationType::FramePush, words);
|
||||||
|
|
||||||
let current_frame_pointer = self.frame_pointer;
|
let current_frame_pointer = self.frame_pointer;
|
||||||
let current_stack_pointer = self.stack_pointer;
|
let current_stack_pointer = self.stack_pointer;
|
||||||
@ -1138,7 +1126,6 @@ impl NockStack {
|
|||||||
*(self.slot_pointer(STACK)) = current_stack_pointer as u64;
|
*(self.slot_pointer(STACK)) = current_stack_pointer as u64;
|
||||||
*(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64;
|
*(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64;
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Run a closure inside a frame, popping regardless of the value returned by the closure.
|
/** Run a closure inside a frame, popping regardless of the value returned by the closure.
|
||||||
@ -1146,16 +1133,16 @@ impl NockStack {
|
|||||||
*
|
*
|
||||||
* Note that results allocated on the stack *must* be `preserve()`d by the closure.
|
* Note that results allocated on the stack *must* be `preserve()`d by the closure.
|
||||||
*/
|
*/
|
||||||
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> AllocResult<O>
|
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> O
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut NockStack) -> O,
|
F: FnOnce(&mut NockStack) -> O,
|
||||||
O: Preserve,
|
O: Preserve,
|
||||||
{
|
{
|
||||||
self.frame_push(num_locals)?;
|
self.frame_push(num_locals);
|
||||||
let mut ret = f(self);
|
let mut ret = f(self);
|
||||||
ret.preserve(self)?;
|
ret.preserve(self);
|
||||||
self.frame_pop();
|
self.frame_pop();
|
||||||
Ok(ret)
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lightweight stack.
|
/** Lightweight stack.
|
||||||
@ -1182,7 +1169,7 @@ impl NockStack {
|
|||||||
* this violates the _east/_west naming convention somewhat, since e.g.
|
* this violates the _east/_west naming convention somewhat, since e.g.
|
||||||
* a west frame when pc == false has a west-oriented lightweight stack,
|
* a west frame when pc == false has a west-oriented lightweight stack,
|
||||||
* but when pc == true it becomes east-oriented.*/
|
* but when pc == true it becomes east-oriented.*/
|
||||||
pub unsafe fn push<T>(&mut self) -> AllocResult<*mut T> {
|
pub unsafe fn push<T>(&mut self) -> *mut T {
|
||||||
if self.is_west() && !self.pc || !self.is_west() && self.pc {
|
if self.is_west() && !self.pc || !self.is_west() && self.pc {
|
||||||
self.push_west::<T>()
|
self.push_west::<T>()
|
||||||
} else {
|
} else {
|
||||||
@ -1191,16 +1178,16 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Push onto a west-oriented lightweight stack, moving the stack_pointer.
|
/// Push onto a west-oriented lightweight stack, moving the stack_pointer.
|
||||||
unsafe fn push_west<T>(&mut self) -> AllocResult<*mut T> {
|
unsafe fn push_west<T>(&mut self) -> *mut T {
|
||||||
let words = word_size_of::<T>();
|
let words = word_size_of::<T>();
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::West,
|
orientation: ArenaOrientation::West,
|
||||||
alloc_type: AllocationType::Push,
|
alloc_type: AllocationType::Push,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
words,
|
words,
|
||||||
)?;
|
);
|
||||||
let ap = if self.pc {
|
let ap = if self.pc {
|
||||||
*(self.prev_alloc_pointer_pointer())
|
*(self.prev_alloc_pointer_pointer())
|
||||||
} else {
|
} else {
|
||||||
@ -1219,21 +1206,21 @@ impl NockStack {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.stack_pointer = new_sp;
|
self.stack_pointer = new_sp;
|
||||||
Ok(alloc as *mut T)
|
alloc as *mut T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push onto an east-oriented ligthweight stack, moving the stack_pointer
|
/// Push onto an east-oriented ligthweight stack, moving the stack_pointer
|
||||||
unsafe fn push_east<T>(&mut self) -> AllocResult<*mut T> {
|
unsafe fn push_east<T>(&mut self) -> *mut T {
|
||||||
let words = word_size_of::<T>();
|
let words = word_size_of::<T>();
|
||||||
let () = self.alloc_would_oom_(
|
self.alloc_would_oom_(
|
||||||
Allocation {
|
Allocation {
|
||||||
orientation: ArenaOrientation::East,
|
orientation: ArenaOrientation::East,
|
||||||
alloc_type: AllocationType::Push,
|
alloc_type: AllocationType::Push,
|
||||||
pc: self.pc,
|
pc: self.pc,
|
||||||
},
|
},
|
||||||
words,
|
words,
|
||||||
)?;
|
);
|
||||||
let ap = if self.pc {
|
let ap = if self.pc {
|
||||||
*(self.prev_alloc_pointer_pointer())
|
*(self.prev_alloc_pointer_pointer())
|
||||||
} else {
|
} else {
|
||||||
@ -1251,7 +1238,7 @@ impl NockStack {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.stack_pointer = alloc;
|
self.stack_pointer = alloc;
|
||||||
Ok(alloc as *mut T)
|
alloc as *mut T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,15 +1472,15 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NounAllocator for NockStack {
|
impl NounAllocator for NockStack {
|
||||||
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64> {
|
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
|
||||||
self.indirect_alloc(words)
|
self.indirect_alloc(words)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory> {
|
unsafe fn alloc_cell(&mut self) -> *mut CellMemory {
|
||||||
self.struct_alloc::<CellMemory>(1)
|
self.struct_alloc::<CellMemory>(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T> {
|
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T {
|
||||||
self.struct_alloc::<T>(count)
|
self.struct_alloc::<T>(count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1501,17 +1488,16 @@ impl NounAllocator for NockStack {
|
|||||||
/// Immutable, acyclic objects which may be copied up the stack
|
/// Immutable, acyclic objects which may be copied up the stack
|
||||||
pub trait Preserve {
|
pub trait Preserve {
|
||||||
/// Ensure an object will not be invalidated by popping the NockStack
|
/// Ensure an object will not be invalidated by popping the NockStack
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()>;
|
unsafe fn preserve(&mut self, stack: &mut NockStack);
|
||||||
unsafe fn assert_in_stack(&self, stack: &NockStack);
|
unsafe fn assert_in_stack(&self, stack: &NockStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for IndirectAtom {
|
impl Preserve for IndirectAtom {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
let size = indirect_raw_size(*self);
|
let size = indirect_raw_size(*self);
|
||||||
let buf = stack.struct_alloc_in_previous_frame::<u64>(size)?;
|
let buf = stack.struct_alloc_in_previous_frame::<u64>(size);
|
||||||
copy_nonoverlapping(self.to_raw_pointer(), buf, size);
|
copy_nonoverlapping(self.to_raw_pointer(), buf, size);
|
||||||
*self = IndirectAtom::from_raw_pointer(buf);
|
*self = IndirectAtom::from_raw_pointer(buf);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||||
stack.assert_noun_in(self.as_atom().as_noun());
|
stack.assert_noun_in(self.as_atom().as_noun());
|
||||||
@ -1519,15 +1505,14 @@ impl Preserve for IndirectAtom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for Atom {
|
impl Preserve for Atom {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Left(_direct) => {}
|
Left(_direct) => {}
|
||||||
Right(mut indirect) => {
|
Right(mut indirect) => {
|
||||||
indirect.preserve(stack)?;
|
indirect.preserve(stack);
|
||||||
*self = indirect.as_atom();
|
*self = indirect.as_atom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||||
stack.assert_noun_in(self.as_noun());
|
stack.assert_noun_in(self.as_noun());
|
||||||
@ -1535,7 +1520,7 @@ impl Preserve for Atom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for Noun {
|
impl Preserve for Noun {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
stack.copy(self)
|
stack.copy(self)
|
||||||
}
|
}
|
||||||
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
unsafe fn assert_in_stack(&self, stack: &NockStack) {
|
||||||
@ -1544,14 +1529,13 @@ impl Preserve for Noun {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Stack for NockStack {
|
impl Stack for NockStack {
|
||||||
type AllocError = AllocationError;
|
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64 {
|
||||||
unsafe fn alloc_layout(&mut self, layout: Layout) -> AllocResult<*mut u64> {
|
|
||||||
self.layout_alloc(layout)
|
self.layout_alloc(layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
|
impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
|
||||||
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, stack: &mut NockStack) {
|
||||||
match self.as_mut() {
|
match self.as_mut() {
|
||||||
Ok(t_ref) => t_ref.preserve(stack),
|
Ok(t_ref) => t_ref.preserve(stack),
|
||||||
Err(e_ref) => e_ref.preserve(stack),
|
Err(e_ref) => e_ref.preserve(stack),
|
||||||
@ -1567,25 +1551,25 @@ impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for bool {
|
impl Preserve for bool {
|
||||||
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, _: &mut NockStack) {}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for u32 {
|
impl Preserve for u32 {
|
||||||
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, _: &mut NockStack) {}
|
||||||
Ok(())
|
|
||||||
}
|
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preserve for usize {
|
||||||
|
unsafe fn preserve(&mut self, _: &mut NockStack) {}
|
||||||
|
|
||||||
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preserve for AllocationError {
|
impl Preserve for AllocationError {
|
||||||
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
|
unsafe fn preserve(&mut self, _: &mut NockStack) {}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
unsafe fn assert_in_stack(&self, _: &NockStack) {}
|
||||||
}
|
}
|
||||||
@ -1593,6 +1577,7 @@ impl Preserve for AllocationError {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::cold::test::{make_noun_list, make_test_stack};
|
use crate::jets::cold::test::{make_noun_list, make_test_stack};
|
||||||
@ -1613,9 +1598,9 @@ mod test {
|
|||||||
let vec = Vec::from_iter(0..item_count);
|
let vec = Vec::from_iter(0..item_count);
|
||||||
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
|
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
|
||||||
let slice = vec.as_slice();
|
let slice = vec.as_slice();
|
||||||
let noun_list = make_noun_list(&mut stack, slice)?;
|
let noun_list = make_noun_list(&mut stack, slice);
|
||||||
assert!(!noun_list.0.is_null());
|
assert!(!noun_list.0.is_null());
|
||||||
let noun = noun_list.into_noun(&mut stack)?;
|
let noun = noun_list.into_noun(&mut stack);
|
||||||
let new_noun_list: NounList =
|
let new_noun_list: NounList =
|
||||||
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?;
|
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?;
|
||||||
let mut tracking_item_count = 0;
|
let mut tracking_item_count = 0;
|
||||||
@ -1642,9 +1627,9 @@ mod test {
|
|||||||
const FAILS: u64 = 73;
|
const FAILS: u64 = 73;
|
||||||
const STACK_SIZE: usize = 512;
|
const STACK_SIZE: usize = 512;
|
||||||
|
|
||||||
let should_fail_to_alloc = test_noun_list_alloc_fn(STACK_SIZE, FAILS);
|
let should_fail_to_alloc = catch_unwind(|| test_noun_list_alloc_fn(STACK_SIZE, FAILS));
|
||||||
assert!(should_fail_to_alloc
|
assert!(should_fail_to_alloc
|
||||||
.map_err(|err| err.is_alloc_error())
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
.unwrap_err());
|
.unwrap_err());
|
||||||
let should_succeed = test_noun_list_alloc_fn(STACK_SIZE, PASSES);
|
let should_succeed = test_noun_list_alloc_fn(STACK_SIZE, PASSES);
|
||||||
assert!(should_succeed.is_ok());
|
assert!(should_succeed.is_ok());
|
||||||
@ -1654,32 +1639,36 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_frame_push() {
|
fn test_frame_push() {
|
||||||
// fails at 100, passes at 99, top_slots default to 100?
|
// fails at 100, passes at 99, top_slots default to 100?
|
||||||
const PASSES: usize = 502;
|
const PASSES: usize = 503;
|
||||||
const FAILS: usize = 503;
|
const FAILS: usize = 504;
|
||||||
const STACK_SIZE: usize = 512;
|
const STACK_SIZE: usize = 512;
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
let frame_push_res = stack.frame_push(FAILS);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(FAILS)));
|
||||||
assert!(frame_push_res.is_err());
|
assert!(frame_push_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err());
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
let frame_push_res = stack.frame_push(PASSES);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(PASSES)));
|
||||||
assert!(frame_push_res.is_ok());
|
assert!(frame_push_res.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
// cargo test -p sword test_stack_push -- --nocapture
|
// cargo test -p sword test_stack_push -- --nocapture
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stack_push() {
|
fn test_stack_push() {
|
||||||
const PASSES: usize = 505;
|
const PASSES: usize = 506;
|
||||||
const STACK_SIZE: usize = 512;
|
const STACK_SIZE: usize = 512;
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
// Fails at 102, probably because top_slots is 100?
|
// Fails at 102, probably because top_slots is 100?
|
||||||
while counter < PASSES {
|
while counter < PASSES {
|
||||||
let push_res = unsafe { stack.push::<u64>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
|
||||||
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
let push_res = unsafe { stack.push::<u64>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
|
||||||
assert!(push_res.is_err());
|
assert!(push_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
// cargo test -p sword test_frame_and_stack_push -- --nocapture
|
// cargo test -p sword test_frame_and_stack_push -- --nocapture
|
||||||
@ -1690,27 +1679,31 @@ mod test {
|
|||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
while counter < SUCCESS_PUSHES {
|
while counter < SUCCESS_PUSHES {
|
||||||
let frame_push_res = stack.frame_push(1);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
|
||||||
assert!(
|
assert!(
|
||||||
frame_push_res.is_ok(),
|
frame_push_res.is_ok(),
|
||||||
"Failed to frame_push, counter: {}",
|
"Failed to frame_push, counter: {}",
|
||||||
counter
|
counter
|
||||||
);
|
);
|
||||||
let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
|
||||||
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
let frame_push_res = stack.frame_push(1);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
|
||||||
assert!(frame_push_res.is_err());
|
assert!(frame_push_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err());
|
||||||
// a single stack u64 push won't cause an error but a frame push will
|
// a single stack u64 push won't cause an error but a frame push will
|
||||||
let push_res = unsafe { stack.push::<u64>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
|
||||||
assert!(push_res.is_ok());
|
assert!(push_res.is_ok());
|
||||||
// pushing an array of 1 u64 will NOT cause an error
|
// pushing an array of 1 u64 will NOT cause an error
|
||||||
let push_res = unsafe { stack.push::<[u64; 1]>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 1]>() }));
|
||||||
assert!(push_res.is_ok());
|
assert!(push_res.is_ok());
|
||||||
// pushing an array of 2 u64s WILL cause an error
|
// pushing an array of 2 u64s WILL cause an error
|
||||||
let push_res = unsafe { stack.push::<[u64; 2]>() };
|
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 2]>() }));
|
||||||
assert!(push_res.is_err());
|
assert!(push_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
// cargo test -p sword test_slot_pointer -- --nocapture
|
// cargo test -p sword test_slot_pointer -- --nocapture
|
||||||
@ -1721,12 +1714,13 @@ mod test {
|
|||||||
const SLOT_POINTERS: usize = 32;
|
const SLOT_POINTERS: usize = 32;
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
// let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
|
// let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
|
||||||
let frame_push_res = stack.frame_push(SLOT_POINTERS);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(SLOT_POINTERS)));
|
||||||
assert!(frame_push_res.is_ok());
|
assert!(frame_push_res.is_ok());
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
while counter < SLOT_POINTERS + RESERVED {
|
while counter < SLOT_POINTERS + RESERVED {
|
||||||
println!("counter: {counter}");
|
println!("counter: {counter}");
|
||||||
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) };
|
let slot_pointer_res =
|
||||||
|
catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
|
||||||
assert!(
|
assert!(
|
||||||
slot_pointer_res.is_ok(),
|
slot_pointer_res.is_ok(),
|
||||||
"Failed to slot_pointer, counter: {}",
|
"Failed to slot_pointer, counter: {}",
|
||||||
@ -1734,8 +1728,11 @@ mod test {
|
|||||||
);
|
);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) };
|
let slot_pointer_res =
|
||||||
assert!(slot_pointer_res.is_err())
|
catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
|
||||||
|
assert!(slot_pointer_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err())
|
||||||
}
|
}
|
||||||
|
|
||||||
// cargo test -p sword test_prev_alloc -- --nocapture
|
// cargo test -p sword test_prev_alloc -- --nocapture
|
||||||
@ -1743,18 +1740,20 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_prev_alloc() {
|
fn test_prev_alloc() {
|
||||||
const STACK_SIZE: usize = 512;
|
const STACK_SIZE: usize = 512;
|
||||||
const SUCCESS_ALLOCS: usize = 502;
|
const SUCCESS_ALLOCS: usize = 503;
|
||||||
let mut stack = make_test_stack(STACK_SIZE);
|
let mut stack = make_test_stack(STACK_SIZE);
|
||||||
println!("\n############## frame push \n");
|
println!("\n############## frame push \n");
|
||||||
let frame_push_res = stack.frame_push(0);
|
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(0)));
|
||||||
assert!(frame_push_res.is_ok());
|
assert!(frame_push_res.is_ok());
|
||||||
let pre_copy_res = unsafe { stack.pre_copy() };
|
let pre_copy_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.pre_copy() }));
|
||||||
assert!(pre_copy_res.is_ok());
|
assert!(pre_copy_res.is_ok());
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
|
|
||||||
while counter < SUCCESS_ALLOCS {
|
while counter < SUCCESS_ALLOCS {
|
||||||
println!("counter: {counter}");
|
println!("counter: {counter}");
|
||||||
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) };
|
let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
|
||||||
|
stack.raw_alloc_in_previous_frame(1)
|
||||||
|
}));
|
||||||
assert!(
|
assert!(
|
||||||
prev_alloc_res.is_ok(),
|
prev_alloc_res.is_ok(),
|
||||||
"Failed to prev_alloc, counter: {}",
|
"Failed to prev_alloc, counter: {}",
|
||||||
@ -1763,11 +1762,14 @@ mod test {
|
|||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
println!("### This next raw_alloc_in_previous_frame should fail ###\n");
|
println!("### This next raw_alloc_in_previous_frame should fail ###\n");
|
||||||
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) };
|
let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
|
||||||
|
stack.raw_alloc_in_previous_frame(1)
|
||||||
|
}));
|
||||||
assert!(
|
assert!(
|
||||||
prev_alloc_res.is_err(),
|
|
||||||
"Didn't get expected alloc error, res: {:#?}",
|
|
||||||
prev_alloc_res
|
prev_alloc_res
|
||||||
|
.map_err(|err| err.is::<AllocationError>())
|
||||||
|
.unwrap_err(),
|
||||||
|
"Didn't get expected alloc error",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use crate::assert_acyclic;
|
||||||
|
use crate::assert_no_forwarding_pointers;
|
||||||
|
use crate::assert_no_junior_pointers;
|
||||||
use crate::mem::*;
|
use crate::mem::*;
|
||||||
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
||||||
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
|
|
||||||
use either::Either::*;
|
use either::Either::*;
|
||||||
use murmur3::murmur3_32_of_slice;
|
use murmur3::murmur3_32_of_slice;
|
||||||
|
|
||||||
@ -126,67 +128,74 @@ pub fn mug_u32_one(noun: Noun) -> Option<u32> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> AllocResult<u32> {
|
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
||||||
if let Some(mug) = get_mug(noun) {
|
if let Some(mug) = get_mug(noun) {
|
||||||
return Ok(mug);
|
return mug;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_acyclic!(noun);
|
assert_acyclic!(noun);
|
||||||
assert_no_forwarding_pointers!(noun);
|
assert_no_forwarding_pointers!(noun);
|
||||||
assert_no_junior_pointers!(stack, noun);
|
assert_no_junior_pointers!(stack, noun);
|
||||||
|
|
||||||
|
stack.frame_push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
stack.with_frame(0, |stack| {
|
*(stack.push()) = noun;
|
||||||
*(stack.push()?) = noun;
|
}
|
||||||
loop {
|
loop {
|
||||||
if stack.stack_is_empty() {
|
if stack.stack_is_empty() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
let noun: Noun = *(stack.top());
|
let noun: Noun = unsafe { *(stack.top()) };
|
||||||
match noun.as_either_direct_allocated() {
|
match noun.as_either_direct_allocated() {
|
||||||
Left(_direct) => {
|
Left(_direct) => {
|
||||||
|
unsafe {
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} // no point in calculating a direct mug here as we wont cache it
|
||||||
|
Right(allocated) => match allocated.get_cached_mug() {
|
||||||
|
Some(_mug) => {
|
||||||
|
unsafe {
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
None => match allocated.as_either() {
|
||||||
|
Left(indirect) => unsafe {
|
||||||
|
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
|
||||||
stack.pop::<Noun>();
|
stack.pop::<Noun>();
|
||||||
continue;
|
continue;
|
||||||
} // no point in calculating a direct mug here as we wont cache it
|
},
|
||||||
Right(allocated) => match allocated.get_cached_mug() {
|
Right(cell) => unsafe {
|
||||||
Some(_mug) => {
|
match (get_mug(cell.head()), get_mug(cell.tail())) {
|
||||||
stack.pop::<Noun>();
|
(Some(head_mug), Some(tail_mug)) => {
|
||||||
continue;
|
set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug));
|
||||||
}
|
|
||||||
None => match allocated.as_either() {
|
|
||||||
Left(indirect) => {
|
|
||||||
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
|
|
||||||
stack.pop::<Noun>();
|
stack.pop::<Noun>();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Right(cell) => match (get_mug(cell.head()), get_mug(cell.tail())) {
|
_ => {
|
||||||
(Some(head_mug), Some(tail_mug)) => {
|
*(stack.push()) = cell.tail();
|
||||||
set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug));
|
*(stack.push()) = cell.head();
|
||||||
stack.pop::<Noun>();
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
*(stack.push()?) = cell.tail();
|
|
||||||
*(stack.push()?) = cell.head();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
assert_acyclic!(noun);
|
|
||||||
assert_no_forwarding_pointers!(noun);
|
|
||||||
assert_no_junior_pointers!(stack, noun);
|
|
||||||
|
|
||||||
// TODO: Purge this expect.
|
|
||||||
Ok(get_mug(noun).expect("Noun should have a mug once it is mugged."))
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
|
unsafe {
|
||||||
|
stack.frame_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_acyclic!(noun);
|
||||||
|
assert_no_forwarding_pointers!(noun);
|
||||||
|
assert_no_junior_pointers!(stack, noun);
|
||||||
|
|
||||||
|
get_mug(noun).expect("Noun should have a mug once it is mugged.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mug(stack: &mut NockStack, noun: Noun) -> AllocResult<DirectAtom> {
|
pub fn mug(stack: &mut NockStack, noun: Noun) -> DirectAtom {
|
||||||
Ok(unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun)? as u64) })
|
unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun) as u64) }
|
||||||
}
|
}
|
||||||
|
@ -1,307 +0,0 @@
|
|||||||
use crate::interpreter::Slogger;
|
|
||||||
/** Newt: IPC to the king
|
|
||||||
*
|
|
||||||
* This manages an IPC connection to the king over stdin and stdout. The protocol is jammed nouns,
|
|
||||||
* with the following schema:
|
|
||||||
*
|
|
||||||
* |%
|
|
||||||
* :: +writ: from king to serf
|
|
||||||
* ::
|
|
||||||
* +$ writ
|
|
||||||
* $% $: %live
|
|
||||||
* $% [%cram eve=@]
|
|
||||||
* [%exit cod=@]
|
|
||||||
* [%save eve=@]
|
|
||||||
* [%meld ~]
|
|
||||||
* [%pack ~]
|
|
||||||
* == ==
|
|
||||||
* [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [%beam @tas beam]))
|
|
||||||
* [%play eve=@ lit=(list ?((pair @da ovum) *))]
|
|
||||||
* [%work mil=@ job=(pair @da ovum)]
|
|
||||||
* ==
|
|
||||||
* :: +plea: from serf to king
|
|
||||||
* ::
|
|
||||||
* +$ plea
|
|
||||||
* $% [%live ~]
|
|
||||||
* [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@]
|
|
||||||
* [%slog pri=@ tank]
|
|
||||||
* [%flog cord]
|
|
||||||
* $: %peek
|
|
||||||
* $% [%done dat=(unit (cask))]
|
|
||||||
* [%bail dud=goof]
|
|
||||||
* == ==
|
|
||||||
* $: %play
|
|
||||||
* $% [%done mug=@]
|
|
||||||
* [%bail eve=@ mug=@ dud=goof]
|
|
||||||
* == ==
|
|
||||||
* $: %work
|
|
||||||
* $% [%done eve=@ mug=@ fec=(list ovum)]
|
|
||||||
* [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)]
|
|
||||||
* [%bail lud=(list goof)]
|
|
||||||
* == ==
|
|
||||||
* ==
|
|
||||||
* --
|
|
||||||
*
|
|
||||||
* NB: stdin and stdout are generally buffered, and there's no officially supported way to work
|
|
||||||
* around that: https://github.com/rust-lang/rust/issues/58326.
|
|
||||||
*
|
|
||||||
* We use stdin and stdout with File::from_raw_fd(0) and File::from_raw_fd(1), which seems to get
|
|
||||||
* around this. We tested that using io::Stdout requires flushing while this doesn't, but we
|
|
||||||
* haven't tested the same for stdin.
|
|
||||||
*
|
|
||||||
* It's important to not use io::Stdin and io::Stdout directly. All printfs should use stderr.
|
|
||||||
*/
|
|
||||||
use crate::mem::{AllocResult, NockStack};
|
|
||||||
use crate::noun::{IndirectAtom, Noun, D, T};
|
|
||||||
use crate::serialization::{cue, jam};
|
|
||||||
use either::Either;
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::os::unix::prelude::FromRawFd;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::ptr::copy_nonoverlapping;
|
|
||||||
use std::slice::from_raw_parts_mut;
|
|
||||||
use sword_macros::tas;
|
|
||||||
|
|
||||||
crate::gdb!();
|
|
||||||
|
|
||||||
pub struct Newt {
|
|
||||||
input: std::fs::File,
|
|
||||||
output: std::fs::File,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Newt {
|
|
||||||
pub fn new_from_files(input: std::fs::File, output: std::fs::File) -> Newt {
|
|
||||||
Newt { input, output }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new() -> Newt {
|
|
||||||
Newt {
|
|
||||||
input: unsafe { std::fs::File::from_raw_fd(0) },
|
|
||||||
output: unsafe { std::fs::File::from_raw_fd(1) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_mock() -> Newt {
|
|
||||||
Newt {
|
|
||||||
input: std::fs::File::open("/dev/null").expect("newt: could not open /dev/null"),
|
|
||||||
output: std::fs::File::options()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.open("/dev/null")
|
|
||||||
.expect("newt: could not open /dev/null"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write a noun to the newt.
|
|
||||||
*
|
|
||||||
* NB: we write 64-bit words, while vere writes bytes. The extra zero bytes shouldn't be a
|
|
||||||
* problem.
|
|
||||||
*/
|
|
||||||
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) -> AllocResult<()> {
|
|
||||||
let atom = jam(stack, noun)?;
|
|
||||||
let size = atom.size() << 3;
|
|
||||||
// XX: checked add?
|
|
||||||
let buf = unsafe { from_raw_parts_mut(stack.struct_alloc::<u8>(size + 5)?, size + 5) };
|
|
||||||
buf[0] = 0u8;
|
|
||||||
buf[1] = size as u8;
|
|
||||||
buf[2] = (size >> 8) as u8;
|
|
||||||
buf[3] = (size >> 16) as u8;
|
|
||||||
buf[4] = (size >> 24) as u8;
|
|
||||||
match atom.as_either() {
|
|
||||||
Either::Left(direct) => unsafe {
|
|
||||||
copy_nonoverlapping(
|
|
||||||
&direct.data() as *const u64 as *const u8,
|
|
||||||
buf.as_mut_ptr().add(5),
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
Either::Right(indirect) => unsafe {
|
|
||||||
// REVIEW: is this safe/the right way to do this?
|
|
||||||
copy_nonoverlapping(
|
|
||||||
indirect.data_pointer() as *const u8,
|
|
||||||
buf.as_mut_ptr().add(5),
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
self.output.write_all(buf).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %ripe, the first event.
|
|
||||||
*
|
|
||||||
* eve = event number
|
|
||||||
* mug = mug of Arvo after above event
|
|
||||||
*/
|
|
||||||
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) -> AllocResult<()> {
|
|
||||||
let version = T(
|
|
||||||
stack,
|
|
||||||
&[
|
|
||||||
D(1), // newt protocol
|
|
||||||
D(139), // hoon kelvin
|
|
||||||
D(4), // nock kelvin
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
let ripe = T(stack, &[D(tas!(b"ripe")), version, D(eve), D(mug)])?;
|
|
||||||
self.write_noun(stack, ripe)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %live, acknowledging. */
|
|
||||||
pub fn live(&mut self, stack: &mut NockStack) -> AllocResult<()> {
|
|
||||||
let live = T(stack, &[D(tas!(b"live")), D(0)])?;
|
|
||||||
self.write_noun(stack, live)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %peek %done, successfully scried. */
|
|
||||||
pub fn peek_done(&mut self, stack: &mut NockStack, dat: Noun) -> AllocResult<()> {
|
|
||||||
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"done")), dat])?;
|
|
||||||
self.write_noun(stack, peek)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %peek %bail, unsuccessfully scried.
|
|
||||||
*
|
|
||||||
* dud = goof
|
|
||||||
*/
|
|
||||||
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) -> AllocResult<()> {
|
|
||||||
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud])?;
|
|
||||||
self.write_noun(stack, peek)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %play %done, successfully replayed events.
|
|
||||||
*
|
|
||||||
* mug = mug of Arvo after full replay
|
|
||||||
*/
|
|
||||||
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) -> AllocResult<()> {
|
|
||||||
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)])?;
|
|
||||||
self.write_noun(stack, play)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %play %bail, failed to replay events.
|
|
||||||
*
|
|
||||||
* eve = last good event number
|
|
||||||
* mug = mug of Arvo after above event
|
|
||||||
* dud = goof when trying next event
|
|
||||||
*/
|
|
||||||
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) -> AllocResult<()> {
|
|
||||||
let play = T(
|
|
||||||
stack,
|
|
||||||
&[D(tas!(b"play")), D(tas!(b"bail")), D(eve), D(mug), dud],
|
|
||||||
)?;
|
|
||||||
self.write_noun(stack, play)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %work %done, successfully ran event.
|
|
||||||
*
|
|
||||||
* eve = new event number
|
|
||||||
* mug = mug of Arvo after above event
|
|
||||||
* fec = list of effects
|
|
||||||
*/
|
|
||||||
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) -> AllocResult<()> {
|
|
||||||
let work = T(
|
|
||||||
stack,
|
|
||||||
&[D(tas!(b"work")), D(tas!(b"done")), D(eve), D(mug), fec],
|
|
||||||
)?;
|
|
||||||
self.write_noun(stack, work)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %work %swap, successfully replaced failed event.
|
|
||||||
*
|
|
||||||
* eve = new event number
|
|
||||||
* mug = mug of Arvo after above event
|
|
||||||
* job = event performed instead of the one given to serf by king
|
|
||||||
* fec = list of effects
|
|
||||||
*/
|
|
||||||
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) -> AllocResult<()> {
|
|
||||||
let work = T(
|
|
||||||
stack,
|
|
||||||
&[D(tas!(b"work")), D(tas!(b"swap")), D(eve), D(mug), job, fec],
|
|
||||||
)?;
|
|
||||||
self.write_noun(stack, work)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn slogger(&self) -> Result<Pin<Box<dyn Slogger + Unpin>>, std::io::Error> {
|
|
||||||
let input = self.input.try_clone()?;
|
|
||||||
let output = self.output.try_clone()?;
|
|
||||||
Ok(std::boxed::Box::pin(NewtSlogger(Newt { input, output })))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send %work %bail, failed to run event.
|
|
||||||
*
|
|
||||||
* lud = list of goof
|
|
||||||
*/
|
|
||||||
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) -> AllocResult<()> {
|
|
||||||
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud])?;
|
|
||||||
self.write_noun(stack, work)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fetch next message. */
|
|
||||||
pub fn next(&mut self, stack: &mut NockStack) -> AllocResult<Option<Noun>> {
|
|
||||||
let mut header: Vec<u8> = vec![0; 5];
|
|
||||||
if let Err(err) = self.input.read_exact(&mut header) {
|
|
||||||
if err.kind() == std::io::ErrorKind::UnexpectedEof {
|
|
||||||
return Ok(None);
|
|
||||||
} else {
|
|
||||||
panic!("Newt::next: Error reading header: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let byte_len = u32::from_le_bytes([header[1], header[2], header[3], header[4]]) as usize;
|
|
||||||
|
|
||||||
let atom = unsafe {
|
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bytes(stack, byte_len)?;
|
|
||||||
if let Err(err) = self.input.read_exact(dest) {
|
|
||||||
if err.kind() == std::io::ErrorKind::UnexpectedEof {
|
|
||||||
return Ok(None);
|
|
||||||
} else {
|
|
||||||
panic!("Newt::next: Error reading body: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
atom.normalize_as_atom()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(cue(stack, atom).expect("Newt::next: bad jammed noun")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Slogger for Newt {
|
|
||||||
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
|
|
||||||
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank])?;
|
|
||||||
self.write_noun(stack, slog)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
|
|
||||||
let flog = T(stack, &[D(tas!(b"flog")), cord])?;
|
|
||||||
self.write_noun(stack, flog)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Newt {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NewtSlogger(Newt);
|
|
||||||
|
|
||||||
impl Slogger for NewtSlogger {
|
|
||||||
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
|
|
||||||
self.0.slog(stack, pri, tank)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
|
|
||||||
self.0.flog(stack, cord)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
use crate::mem::{word_size_of, AllocResult, NockStack};
|
use crate::mem::{word_size_of, NockStack};
|
||||||
use bitvec::prelude::{BitSlice, Lsb0};
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
use either::{Either, Left, Right};
|
use either::{Either, Left, Right};
|
||||||
use ibig::{Stack, UBig};
|
use ibig::{Stack, UBig};
|
||||||
@ -155,7 +155,7 @@ fn is_cell(noun: u64) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A noun-related error. */
|
/** A noun-related error. */
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/** Expected type [`Allocated`]. */
|
/** Expected type [`Allocated`]. */
|
||||||
NotAllocated,
|
NotAllocated,
|
||||||
@ -169,7 +169,6 @@ pub enum Error {
|
|||||||
NotIndirectAtom,
|
NotIndirectAtom,
|
||||||
/** The value can't be represented by the given type. */
|
/** The value can't be represented by the given type. */
|
||||||
NotRepresentable,
|
NotRepresentable,
|
||||||
AllocationError(crate::mem::AllocationError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl error::Error for Error {}
|
||||||
@ -183,17 +182,10 @@ impl std::fmt::Display for Error {
|
|||||||
Error::NotDirectAtom => f.write_str("not a direct atom"),
|
Error::NotDirectAtom => f.write_str("not a direct atom"),
|
||||||
Error::NotIndirectAtom => f.write_str("not an indirect atom"),
|
Error::NotIndirectAtom => f.write_str("not an indirect atom"),
|
||||||
Error::NotRepresentable => f.write_str("unrepresentable value"),
|
Error::NotRepresentable => f.write_str("unrepresentable value"),
|
||||||
Error::AllocationError(_) => f.write_str("allocation error"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::mem::AllocationError> for Error {
|
|
||||||
fn from(allocation_error: crate::mem::AllocationError) -> Self {
|
|
||||||
Error::AllocationError(allocation_error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Error> for () {
|
impl From<Error> for () {
|
||||||
fn from(_: Error) -> Self {}
|
fn from(_: Error) -> Self {}
|
||||||
}
|
}
|
||||||
@ -308,18 +300,18 @@ pub const fn D(n: u64) -> Noun {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Noun> {
|
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
|
||||||
Ok(Cell::new_tuple(allocator, tup)?.as_noun())
|
Cell::new_tuple(allocator, tup).as_noun()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create $tape Noun from ASCII string
|
/// Create $tape Noun from ASCII string
|
||||||
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> AllocResult<Noun> {
|
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> Noun {
|
||||||
// XX: Needs unit tests
|
// XX: Needs unit tests
|
||||||
let mut res = D(0);
|
let mut res = D(0);
|
||||||
for c in text.bytes().rev() {
|
for c in text.bytes().rev() {
|
||||||
res = T(allocator, &[D(c as u64), res])?
|
res = T(allocator, &[D(c as u64), res])
|
||||||
}
|
}
|
||||||
Ok(res)
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An indirect atom.
|
/** An indirect atom.
|
||||||
@ -380,10 +372,10 @@ impl IndirectAtom {
|
|||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
data: *const u64,
|
data: *const u64,
|
||||||
) -> AllocResult<Self> {
|
) -> Self {
|
||||||
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size)?;
|
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size);
|
||||||
ptr::copy_nonoverlapping(data, buffer, size);
|
ptr::copy_nonoverlapping(data, buffer, size);
|
||||||
Ok(*(indirect.normalize()))
|
*(indirect.normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make an indirect atom by copying from other memory.
|
/** Make an indirect atom by copying from other memory.
|
||||||
@ -394,16 +386,13 @@ impl IndirectAtom {
|
|||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
) -> AllocResult<Self> {
|
) -> Self {
|
||||||
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size)?;
|
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size);
|
||||||
ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size);
|
ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size);
|
||||||
Ok(*(indirect.normalize()))
|
*(indirect.normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(
|
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(allocator: &mut A, data: &[u8]) -> Self {
|
||||||
allocator: &mut A,
|
|
||||||
data: &[u8],
|
|
||||||
) -> AllocResult<Self> {
|
|
||||||
IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr())
|
IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,12 +403,12 @@ impl IndirectAtom {
|
|||||||
pub unsafe fn new_raw_mut<A: NounAllocator>(
|
pub unsafe fn new_raw_mut<A: NounAllocator>(
|
||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> AllocResult<(Self, *mut u64)> {
|
) -> (Self, *mut u64) {
|
||||||
debug_assert!(size > 0);
|
debug_assert!(size > 0);
|
||||||
let buffer = allocator.alloc_indirect(size)?;
|
let buffer = allocator.alloc_indirect(size);
|
||||||
*buffer = 0;
|
*buffer = 0;
|
||||||
*buffer.add(1) = size as u64;
|
*buffer.add(1) = size as u64;
|
||||||
Ok((Self::from_raw_pointer(buffer), buffer.add(2)))
|
(Self::from_raw_pointer(buffer), buffer.add(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make an indirect atom that can be written into, and zero the whole data buffer.
|
/** Make an indirect atom that can be written into, and zero the whole data buffer.
|
||||||
@ -429,10 +418,10 @@ impl IndirectAtom {
|
|||||||
pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>(
|
pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>(
|
||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> AllocResult<(Self, *mut u64)> {
|
) -> (Self, *mut u64) {
|
||||||
let allocation = Self::new_raw_mut(allocator, size)?;
|
let allocation = Self::new_raw_mut(allocator, size);
|
||||||
ptr::write_bytes(allocation.1, 0, size);
|
ptr::write_bytes(allocation.1, 0, size);
|
||||||
Ok(allocation)
|
allocation
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make an indirect atom that can be written into as a bitslice. The constraints of
|
/** Make an indirect atom that can be written into as a bitslice. The constraints of
|
||||||
@ -441,12 +430,12 @@ impl IndirectAtom {
|
|||||||
pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>(
|
pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>(
|
||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> AllocResult<(Self, &'a mut BitSlice<u64, Lsb0>)> {
|
) -> (Self, &'a mut BitSlice<u64, Lsb0>) {
|
||||||
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size)?;
|
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size);
|
||||||
Ok((
|
(
|
||||||
noun,
|
noun,
|
||||||
BitSlice::from_slice_mut(from_raw_parts_mut(ptr, size)),
|
BitSlice::from_slice_mut(from_raw_parts_mut(ptr, size)),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make an indirect atom that can be written into as a slice of bytes. The constraints of
|
/** Make an indirect atom that can be written into as a slice of bytes. The constraints of
|
||||||
@ -457,19 +446,19 @@ impl IndirectAtom {
|
|||||||
pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>(
|
pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>(
|
||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> AllocResult<(Self, &'a mut [u8])> {
|
) -> (Self, &'a mut [u8]) {
|
||||||
let word_size = (size + 7) >> 3;
|
let word_size = (size + 7) >> 3;
|
||||||
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
|
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
|
||||||
Ok((noun, from_raw_parts_mut(ptr as *mut u8, size)))
|
(noun, from_raw_parts_mut(ptr as *mut u8, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an indirect atom backed by a fixed-size array
|
/// Create an indirect atom backed by a fixed-size array
|
||||||
pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>(
|
pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>(
|
||||||
allocator: &mut A,
|
allocator: &mut A,
|
||||||
) -> AllocResult<(Self, &'a mut [u8; N])> {
|
) -> (Self, &'a mut [u8; N]) {
|
||||||
let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3;
|
let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3;
|
||||||
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
|
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
|
||||||
Ok((noun, &mut *(ptr as *mut [u8; N])))
|
(noun, &mut *(ptr as *mut [u8; N]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Size of an indirect atom in 64-bit words */
|
/** Size of an indirect atom in 64-bit words */
|
||||||
@ -519,7 +508,7 @@ impl IndirectAtom {
|
|||||||
BitSlice::from_slice_mut(self.as_mut_slice())
|
BitSlice::from_slice_mut(self.as_mut_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
|
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> UBig {
|
||||||
UBig::from_le_bytes_stack(stack, self.as_bytes())
|
UBig::from_le_bytes_stack(stack, self.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,34 +638,32 @@ impl Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> AllocResult<Cell> {
|
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> Cell {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (cell, memory) = Self::new_raw_mut(allocator)?;
|
let (cell, memory) = Self::new_raw_mut(allocator);
|
||||||
(*memory).head = head;
|
(*memory).head = head;
|
||||||
(*memory).tail = tail;
|
(*memory).tail = tail;
|
||||||
Ok(cell)
|
cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Cell> {
|
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Cell {
|
||||||
if tup.len() < 2 {
|
if tup.len() < 2 {
|
||||||
panic!("Cannot create tuple with fewer than 2 elements");
|
panic!("Cannot create tuple with fewer than 2 elements");
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = tup.len();
|
let len = tup.len();
|
||||||
let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1])?;
|
let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1]);
|
||||||
for i in (0..len - 2).rev() {
|
for i in (0..len - 2).rev() {
|
||||||
cell = Cell::new(allocator, tup[i], cell.as_noun())?;
|
cell = Cell::new(allocator, tup[i], cell.as_noun());
|
||||||
}
|
}
|
||||||
Ok(cell)
|
cell
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn new_raw_mut<A: NounAllocator>(
|
pub unsafe fn new_raw_mut<A: NounAllocator>(allocator: &mut A) -> (Cell, *mut CellMemory) {
|
||||||
allocator: &mut A,
|
let memory = allocator.alloc_cell();
|
||||||
) -> AllocResult<(Cell, *mut CellMemory)> {
|
|
||||||
let memory = allocator.alloc_cell()?;
|
|
||||||
(*memory).metadata = 0;
|
(*memory).metadata = 0;
|
||||||
Ok((Self::from_raw_pointer(memory), memory))
|
(Self::from_raw_pointer(memory), memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn head(&self) -> Noun {
|
pub fn head(&self) -> Noun {
|
||||||
@ -761,21 +748,20 @@ pub union Atom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Atom {
|
impl Atom {
|
||||||
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> AllocResult<Atom> {
|
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> Atom {
|
||||||
let res = if value <= DIRECT_MAX {
|
if value <= DIRECT_MAX {
|
||||||
unsafe { DirectAtom::new_unchecked(value).as_atom() }
|
unsafe { DirectAtom::new_unchecked(value).as_atom() }
|
||||||
} else {
|
} else {
|
||||||
unsafe { IndirectAtom::new_raw(allocator, 1, &value)?.as_atom() }
|
unsafe { IndirectAtom::new_raw(allocator, 1, &value).as_atom() }
|
||||||
};
|
}
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// to_le_bytes and new_raw are copies. We should be able to do this completely without copies
|
// to_le_bytes and new_raw are copies. We should be able to do this completely without copies
|
||||||
// if we integrate with ibig properly.
|
// if we integrate with ibig properly.
|
||||||
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> AllocResult<Atom> {
|
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> Atom {
|
||||||
let bit_size = big.bit_len();
|
let bit_size = big.bit_len();
|
||||||
let buffer = big.to_le_bytes_stack();
|
let buffer = big.to_le_bytes_stack();
|
||||||
let atom = if bit_size < 64 {
|
if bit_size < 64 {
|
||||||
let mut value = 0u64;
|
let mut value = 0u64;
|
||||||
for i in (0..bit_size).step_by(8) {
|
for i in (0..bit_size).step_by(8) {
|
||||||
value |= (buffer[i / 8] as u64) << i;
|
value |= (buffer[i / 8] as u64) << i;
|
||||||
@ -783,9 +769,8 @@ impl Atom {
|
|||||||
unsafe { DirectAtom::new_unchecked(value).as_atom() }
|
unsafe { DirectAtom::new_unchecked(value).as_atom() }
|
||||||
} else {
|
} else {
|
||||||
let byte_size = (big.bit_len() + 7) >> 3;
|
let byte_size = (big.bit_len() + 7) >> 3;
|
||||||
unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr())?.as_atom() }
|
unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr()).as_atom() }
|
||||||
};
|
}
|
||||||
Ok(atom)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_direct(&self) -> bool {
|
pub fn is_direct(&self) -> bool {
|
||||||
@ -882,13 +867,12 @@ impl Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
|
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> UBig {
|
||||||
let ubig = if self.is_indirect() {
|
if self.is_indirect() {
|
||||||
unsafe { self.indirect.as_ubig(stack)? }
|
unsafe { self.indirect.as_ubig(stack) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { self.direct.as_ubig(stack) }
|
unsafe { self.direct.as_ubig(stack) }
|
||||||
};
|
}
|
||||||
Ok(ubig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn direct(&self) -> Option<DirectAtom> {
|
pub fn direct(&self) -> Option<DirectAtom> {
|
||||||
@ -1314,13 +1298,13 @@ pub trait NounAllocator: Sized {
|
|||||||
*
|
*
|
||||||
* This should allocate *two more* `u64`s than `words` to make space for the size and metadata
|
* This should allocate *two more* `u64`s than `words` to make space for the size and metadata
|
||||||
*/
|
*/
|
||||||
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64>;
|
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64;
|
||||||
|
|
||||||
/** Allocate memory for a cell */
|
/** Allocate memory for a cell */
|
||||||
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory>;
|
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
|
||||||
|
|
||||||
/** Allocate space for a struct in a stack frame */
|
/** Allocate space for a struct in a stack frame */
|
||||||
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T>;
|
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::hamt::MutHamt;
|
use crate::hamt::MutHamt;
|
||||||
use crate::interpreter::Error::{self, *};
|
use crate::interpreter::Error::{self, *};
|
||||||
use crate::interpreter::Mote::*;
|
use crate::interpreter::Mote::*;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
||||||
use bitvec::prelude::{BitSlice, Lsb0};
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
use either::Either::{Left, Right};
|
use either::Either::{Left, Right};
|
||||||
@ -103,13 +103,13 @@ enum CueStackEntry {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// A Result containing either the deserialized Noun or an Error
|
/// A Result containing either the deserialized Noun or an Error
|
||||||
pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Result<Noun, Error> {
|
pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Result<Noun, Error> {
|
||||||
let backref_map = MutHamt::<Noun>::new(stack)?;
|
let backref_map = MutHamt::<Noun>::new(stack);
|
||||||
let mut result = D(0);
|
let mut result = D(0);
|
||||||
let mut cursor = 0;
|
let mut cursor = 0;
|
||||||
|
|
||||||
let res = unsafe {
|
unsafe {
|
||||||
stack.with_frame(0, |stack: &mut NockStack| {
|
stack.with_frame(0, |stack: &mut NockStack| {
|
||||||
*(stack.push::<CueStackEntry>()?) =
|
*(stack.push::<CueStackEntry>()) =
|
||||||
CueStackEntry::DestinationPointer(&mut result as *mut Noun);
|
CueStackEntry::DestinationPointer(&mut result as *mut Noun);
|
||||||
loop {
|
loop {
|
||||||
if stack.stack_is_empty() {
|
if stack.stack_is_empty() {
|
||||||
@ -125,43 +125,42 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Resu
|
|||||||
// 11 tag: backref
|
// 11 tag: backref
|
||||||
if next_bit(&mut cursor, buffer) {
|
if next_bit(&mut cursor, buffer) {
|
||||||
let mut backref_noun =
|
let mut backref_noun =
|
||||||
Atom::new(stack, rub_backref(&mut cursor, buffer)?)?.as_noun();
|
Atom::new(stack, rub_backref(&mut cursor, buffer)?).as_noun();
|
||||||
*dest_ptr = backref_map
|
*dest_ptr = backref_map
|
||||||
.lookup(stack, &mut backref_noun)?
|
.lookup(stack, &mut backref_noun)
|
||||||
.ok_or(Deterministic(Exit, D(0)))?;
|
.ok_or(Deterministic(Exit, D(0)))?;
|
||||||
} else {
|
} else {
|
||||||
// 10 tag: cell
|
// 10 tag: cell
|
||||||
let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack)?;
|
let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack);
|
||||||
*dest_ptr = cell.as_noun();
|
*dest_ptr = cell.as_noun();
|
||||||
let mut backref_atom =
|
let mut backref_atom =
|
||||||
Atom::new(stack, (cursor - 2) as u64)?.as_noun();
|
Atom::new(stack, (cursor - 2) as u64).as_noun();
|
||||||
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?;
|
backref_map.insert(stack, &mut backref_atom, *dest_ptr);
|
||||||
*(stack.push()?) = CueStackEntry::BackRef(
|
*(stack.push()) = CueStackEntry::BackRef(
|
||||||
cursor as u64 - 2,
|
cursor as u64 - 2,
|
||||||
dest_ptr as *const Noun,
|
dest_ptr as *const Noun,
|
||||||
);
|
);
|
||||||
*(stack.push()?) =
|
*(stack.push()) =
|
||||||
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail);
|
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail);
|
||||||
*(stack.push()?) =
|
*(stack.push()) =
|
||||||
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head);
|
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 0 tag: atom
|
// 0 tag: atom
|
||||||
let backref: u64 = (cursor - 1) as u64;
|
let backref: u64 = (cursor - 1) as u64;
|
||||||
*dest_ptr = rub_atom(stack, &mut cursor, buffer)?.as_noun();
|
*dest_ptr = rub_atom(stack, &mut cursor, buffer)?.as_noun();
|
||||||
let mut backref_atom = Atom::new(stack, backref)?.as_noun();
|
let mut backref_atom = Atom::new(stack, backref).as_noun();
|
||||||
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?;
|
backref_map.insert(stack, &mut backref_atom, *dest_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CueStackEntry::BackRef(backref, noun_ptr) => {
|
CueStackEntry::BackRef(backref, noun_ptr) => {
|
||||||
let mut backref_atom = Atom::new(stack, backref)?.as_noun();
|
let mut backref_atom = Atom::new(stack, backref).as_noun();
|
||||||
backref_map.insert(stack, &mut backref_atom, *noun_ptr)?
|
backref_map.insert(stack, &mut backref_atom, *noun_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})?
|
})
|
||||||
};
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize a noun from an Atom
|
/// Deserialize a noun from an Atom
|
||||||
@ -236,7 +235,7 @@ fn rub_atom(
|
|||||||
} else {
|
} else {
|
||||||
// Need an indirect atom
|
// Need an indirect atom
|
||||||
let wordsize = (size + 63) >> 6;
|
let wordsize = (size + 63) >> 6;
|
||||||
let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize)? };
|
let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize) };
|
||||||
slice[0..bits.len()].copy_from_bitslice(bits);
|
slice[0..bits.len()].copy_from_bitslice(bits);
|
||||||
debug_assert!(atom.size() > 0);
|
debug_assert!(atom.size() > 0);
|
||||||
unsafe { Ok(atom.normalize_as_atom()) }
|
unsafe { Ok(atom.normalize_as_atom()) }
|
||||||
@ -273,71 +272,79 @@ struct JamState<'a> {
|
|||||||
/// Corresponds to ++jam in the hoon stdlib.
|
/// Corresponds to ++jam in the hoon stdlib.
|
||||||
///
|
///
|
||||||
/// Implements a compact encoding scheme for nouns, with backreferences for shared structures.
|
/// Implements a compact encoding scheme for nouns, with backreferences for shared structures.
|
||||||
pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult<Atom> {
|
pub fn jam(stack: &mut NockStack, noun: Noun) -> Atom {
|
||||||
let backref_map = MutHamt::new(stack)?;
|
let backref_map = MutHamt::new(stack);
|
||||||
let size = 8;
|
let size = 8;
|
||||||
let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size)? };
|
let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size) };
|
||||||
let mut state = JamState {
|
let mut state = JamState {
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
size,
|
size,
|
||||||
atom,
|
atom,
|
||||||
slice,
|
slice,
|
||||||
};
|
};
|
||||||
|
stack.frame_push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
stack.with_frame(0, |stack| {
|
*(stack.push::<Noun>()) = noun;
|
||||||
*(stack.push::<Noun>()?) = noun;
|
};
|
||||||
'jam: loop {
|
'jam: loop {
|
||||||
if stack.stack_is_empty() {
|
if stack.stack_is_empty() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
let mut noun = *(stack.top::<Noun>());
|
let mut noun = unsafe { *(stack.top::<Noun>()) };
|
||||||
if let Some(backref) = backref_map.lookup(stack, &mut noun)? {
|
if let Some(backref) = backref_map.lookup(stack, &mut noun) {
|
||||||
match noun.as_either_atom_cell() {
|
match noun.as_either_atom_cell() {
|
||||||
Left(atom) => {
|
Left(atom) => {
|
||||||
let atom_size = met0_usize(atom);
|
let atom_size = met0_usize(atom);
|
||||||
let backref_size = met0_u64_to_usize(backref);
|
let backref_size = met0_u64_to_usize(backref);
|
||||||
if atom_size <= backref_size {
|
if atom_size <= backref_size {
|
||||||
jam_atom(stack, &mut state, atom)?;
|
jam_atom(stack, &mut state, atom);
|
||||||
} else {
|
} else {
|
||||||
jam_backref(stack, &mut state, backref)?;
|
jam_backref(stack, &mut state, backref);
|
||||||
}
|
|
||||||
}
|
|
||||||
Right(_cell) => {
|
|
||||||
jam_backref(stack, &mut state, backref)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stack.pop::<Noun>();
|
|
||||||
continue 'jam;
|
|
||||||
};
|
|
||||||
backref_map.insert(stack, &mut noun, state.cursor as u64)?;
|
|
||||||
match noun.as_either_atom_cell() {
|
|
||||||
Left(atom) => {
|
|
||||||
jam_atom(stack, &mut state, atom)?;
|
|
||||||
stack.pop::<Noun>();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Right(cell) => {
|
|
||||||
jam_cell(stack, &mut state)?;
|
|
||||||
stack.pop::<Noun>();
|
|
||||||
*(stack.push::<Noun>()?) = cell.tail();
|
|
||||||
*(stack.push::<Noun>()?) = cell.head();
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Right(_cell) => {
|
||||||
|
jam_backref(stack, &mut state, backref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
};
|
||||||
|
continue 'jam;
|
||||||
|
};
|
||||||
|
backref_map.insert(stack, &mut noun, state.cursor as u64);
|
||||||
|
match noun.as_either_atom_cell() {
|
||||||
|
Left(atom) => {
|
||||||
|
jam_atom(stack, &mut state, atom);
|
||||||
|
unsafe {
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Right(cell) => {
|
||||||
|
jam_cell(stack, &mut state);
|
||||||
|
unsafe {
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
*(stack.push::<Noun>()) = cell.tail();
|
||||||
|
*(stack.push::<Noun>()) = cell.head();
|
||||||
|
};
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = state.atom.normalize_as_atom();
|
}
|
||||||
Ok(result)
|
}
|
||||||
})?
|
unsafe {
|
||||||
|
let mut result = state.atom.normalize_as_atom();
|
||||||
|
stack.preserve(&mut result);
|
||||||
|
stack.frame_pop();
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize an atom into the jam state
|
/// Serialize an atom into the jam state
|
||||||
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<()> {
|
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) {
|
||||||
loop {
|
loop {
|
||||||
if state.cursor + 1 > state.slice.len() {
|
if state.cursor + 1 > state.slice.len() {
|
||||||
double_atom_size(traversal, state)?;
|
double_atom_size(traversal, state);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -345,20 +352,19 @@ fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Allo
|
|||||||
state.slice.set(state.cursor, false); // 0 tag for atom
|
state.slice.set(state.cursor, false); // 0 tag for atom
|
||||||
state.cursor += 1;
|
state.cursor += 1;
|
||||||
loop {
|
loop {
|
||||||
if let Ok(()) = mat(traversal, state, atom)? {
|
if let Ok(()) = mat(traversal, state, atom) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
double_atom_size(traversal, state)?;
|
double_atom_size(traversal, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize a cell into the jam state
|
/// Serialize a cell into the jam state
|
||||||
fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> {
|
fn jam_cell(traversal: &mut NockStack, state: &mut JamState) {
|
||||||
loop {
|
loop {
|
||||||
if state.cursor + 2 > state.slice.len() {
|
if state.cursor + 2 > state.slice.len() {
|
||||||
double_atom_size(traversal, state)?;
|
double_atom_size(traversal, state);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -366,14 +372,13 @@ fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()>
|
|||||||
state.slice.set(state.cursor, true); // 1 bit
|
state.slice.set(state.cursor, true); // 1 bit
|
||||||
state.slice.set(state.cursor + 1, false); // 0 bit, forming 10 tag for cell
|
state.slice.set(state.cursor + 1, false); // 0 bit, forming 10 tag for cell
|
||||||
state.cursor += 2;
|
state.cursor += 2;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize a backreference into the jam state
|
/// Serialize a backreference into the jam state
|
||||||
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) -> AllocResult<()> {
|
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) {
|
||||||
loop {
|
loop {
|
||||||
if state.cursor + 2 > state.slice.len() {
|
if state.cursor + 2 > state.slice.len() {
|
||||||
double_atom_size(traversal, state)?;
|
double_atom_size(traversal, state);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -381,46 +386,44 @@ fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) ->
|
|||||||
state.slice.set(state.cursor, true); // 1 bit
|
state.slice.set(state.cursor, true); // 1 bit
|
||||||
state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref
|
state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref
|
||||||
state.cursor += 2;
|
state.cursor += 2;
|
||||||
let backref_atom = Atom::new(traversal, backref)?;
|
let backref_atom = Atom::new(traversal, backref);
|
||||||
loop {
|
loop {
|
||||||
if let Ok(()) = mat(traversal, state, backref_atom)? {
|
if let Ok(()) = mat(traversal, state, backref_atom) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
double_atom_size(traversal, state)?;
|
double_atom_size(traversal, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Double the size of the atom in the jam state
|
/// Double the size of the atom in the jam state
|
||||||
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> {
|
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) {
|
||||||
let new_size = state.size + state.size;
|
let new_size = state.size + state.size;
|
||||||
let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size)? };
|
let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size) };
|
||||||
new_slice[0..state.cursor].copy_from_bitslice(&state.slice[0..state.cursor]);
|
new_slice[0..state.cursor].copy_from_bitslice(&state.slice[0..state.cursor]);
|
||||||
state.size = new_size;
|
state.size = new_size;
|
||||||
state.atom = new_atom;
|
state.atom = new_atom;
|
||||||
state.slice = new_slice;
|
state.slice = new_slice;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode an atom's size and value into the jam state
|
/// Encode an atom's size and value into the jam state
|
||||||
///
|
///
|
||||||
/// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())`
|
/// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())`
|
||||||
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<Result<(), ()>> {
|
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Result<(), ()> {
|
||||||
let b_atom_size = met0_usize(atom);
|
let b_atom_size = met0_usize(atom);
|
||||||
let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64)?;
|
let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64);
|
||||||
if b_atom_size == 0 {
|
if b_atom_size == 0 {
|
||||||
if state.cursor + 1 > state.slice.len() {
|
if state.cursor + 1 > state.slice.len() {
|
||||||
Ok(Err(()))
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
state.slice.set(state.cursor, true);
|
state.slice.set(state.cursor, true);
|
||||||
state.cursor += 1;
|
state.cursor += 1;
|
||||||
Ok(Ok(()))
|
Ok(())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let c_b_size = met0_usize(b_atom_size_atom);
|
let c_b_size = met0_usize(b_atom_size_atom);
|
||||||
if state.cursor + c_b_size + c_b_size + b_atom_size > state.slice.len() {
|
if state.cursor + c_b_size + c_b_size + b_atom_size > state.slice.len() {
|
||||||
Ok(Err(()))
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
state.slice[state.cursor..state.cursor + c_b_size].fill(false); // a 0 bit for each bit in the atom size
|
state.slice[state.cursor..state.cursor + c_b_size].fill(false); // a 0 bit for each bit in the atom size
|
||||||
state.slice.set(state.cursor + c_b_size, true); // a terminating 1 bit
|
state.slice.set(state.cursor + c_b_size, true); // a terminating 1 bit
|
||||||
@ -430,7 +433,7 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
|
|||||||
..state.cursor + c_b_size + c_b_size + b_atom_size]
|
..state.cursor + c_b_size + c_b_size + b_atom_size]
|
||||||
.copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]);
|
.copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]);
|
||||||
state.cursor += c_b_size + c_b_size + b_atom_size;
|
state.cursor += c_b_size + c_b_size + b_atom_size;
|
||||||
Ok(Ok(()))
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,12 +441,14 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::jets::util::test::assert_noun_eq;
|
use crate::jets::util::test::assert_noun_eq;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{Atom, Cell, Noun};
|
use crate::noun::{Atom, Cell, CellMemory, Noun};
|
||||||
fn setup_stack() -> NockStack {
|
fn setup_stack() -> NockStack {
|
||||||
NockStack::new(1 << 30, 0)
|
NockStack::new(1 << 30, 0)
|
||||||
}
|
}
|
||||||
@ -451,8 +456,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_atom() {
|
fn test_jam_cue_atom() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let atom = Atom::new(&mut stack, 42).unwrap();
|
let atom = Atom::new(&mut stack, 42);
|
||||||
let jammed = jam(&mut stack, atom.as_noun()).unwrap();
|
let jammed = jam(&mut stack, atom.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, atom.as_noun());
|
assert_noun_eq(&mut stack, cued, atom.as_noun());
|
||||||
}
|
}
|
||||||
@ -460,10 +465,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_cell() {
|
fn test_jam_cue_cell() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
|
let n1 = Atom::new(&mut stack, 1).as_noun();
|
||||||
let n2 = Atom::new(&mut stack, 2).unwrap().as_noun();
|
let n2 = Atom::new(&mut stack, 2).as_noun();
|
||||||
let cell = Cell::new(&mut stack, n1, n2).unwrap().as_noun();
|
let cell = Cell::new(&mut stack, n1, n2).as_noun();
|
||||||
let jammed = jam(&mut stack, cell).unwrap();
|
let jammed = jam(&mut stack, cell);
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, cell);
|
assert_noun_eq(&mut stack, cued, cell);
|
||||||
}
|
}
|
||||||
@ -471,12 +476,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_nested_cell() {
|
fn test_jam_cue_nested_cell() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let n3 = Atom::new(&mut stack, 3).unwrap().as_noun();
|
let n3 = Atom::new(&mut stack, 3).as_noun();
|
||||||
let n4 = Atom::new(&mut stack, 4).unwrap().as_noun();
|
let n4 = Atom::new(&mut stack, 4).as_noun();
|
||||||
let inner_cell = Cell::new(&mut stack, n3, n4).unwrap();
|
let inner_cell = Cell::new(&mut stack, n3, n4);
|
||||||
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
|
let n1 = Atom::new(&mut stack, 1).as_noun();
|
||||||
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun()).unwrap();
|
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun());
|
||||||
let jammed = jam(&mut stack, outer_cell.as_noun()).unwrap();
|
let jammed = jam(&mut stack, outer_cell.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, outer_cell.as_noun());
|
assert_noun_eq(&mut stack, cued, outer_cell.as_noun());
|
||||||
}
|
}
|
||||||
@ -484,9 +489,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_shared_structure() {
|
fn test_jam_cue_shared_structure() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let shared_atom = Atom::new(&mut stack, 42).unwrap();
|
let shared_atom = Atom::new(&mut stack, 42);
|
||||||
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun()).unwrap();
|
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun());
|
||||||
let jammed = jam(&mut stack, cell.as_noun()).unwrap();
|
let jammed = jam(&mut stack, cell.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, cell.as_noun());
|
assert_noun_eq(&mut stack, cued, cell.as_noun());
|
||||||
}
|
}
|
||||||
@ -494,8 +499,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_large_atom() {
|
fn test_jam_cue_large_atom() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let large_atom = Atom::new(&mut stack, u64::MAX).unwrap();
|
let large_atom = Atom::new(&mut stack, u64::MAX);
|
||||||
let jammed = jam(&mut stack, large_atom.as_noun()).unwrap();
|
let jammed = jam(&mut stack, large_atom.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, large_atom.as_noun());
|
assert_noun_eq(&mut stack, cued, large_atom.as_noun());
|
||||||
}
|
}
|
||||||
@ -503,8 +508,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_empty_atom() {
|
fn test_jam_cue_empty_atom() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let empty_atom = Atom::new(&mut stack, 0).unwrap();
|
let empty_atom = Atom::new(&mut stack, 0);
|
||||||
let jammed = jam(&mut stack, empty_atom.as_noun()).unwrap();
|
let jammed = jam(&mut stack, empty_atom.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, empty_atom.as_noun());
|
assert_noun_eq(&mut stack, cued, empty_atom.as_noun());
|
||||||
}
|
}
|
||||||
@ -512,12 +517,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_jam_cue_complex_structure() {
|
fn test_jam_cue_complex_structure() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let atom1 = Atom::new(&mut stack, 1).unwrap();
|
let atom1 = Atom::new(&mut stack, 1);
|
||||||
let atom2 = Atom::new(&mut stack, 2).unwrap();
|
let atom2 = Atom::new(&mut stack, 2);
|
||||||
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun()).unwrap();
|
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun());
|
||||||
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun()).unwrap();
|
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun());
|
||||||
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun()).unwrap();
|
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun());
|
||||||
let jammed = jam(&mut stack, cell3.as_noun()).unwrap();
|
let jammed = jam(&mut stack, cell3.as_noun());
|
||||||
let cued = cue(&mut stack, jammed).unwrap();
|
let cued = cue(&mut stack, jammed).unwrap();
|
||||||
assert_noun_eq(&mut stack, cued, cell3.as_noun());
|
assert_noun_eq(&mut stack, cued, cell3.as_noun());
|
||||||
}
|
}
|
||||||
@ -525,7 +530,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_cue_invalid_input() {
|
fn test_cue_invalid_input() {
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid tag
|
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid tag
|
||||||
let result = cue(&mut stack, invalid_atom);
|
let result = cue(&mut stack, invalid_atom);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
@ -538,15 +543,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let mut rng_clone = rng.clone();
|
let mut rng_clone = rng.clone();
|
||||||
let (original, total_size) =
|
let (original, total_size) = generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone);
|
||||||
generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone).unwrap();
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Total size of all generated nouns: {:.2} KB",
|
"Total size of all generated nouns: {:.2} KB",
|
||||||
total_size as f64 / 1024.0
|
total_size as f64 / 1024.0
|
||||||
);
|
);
|
||||||
println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0);
|
println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0);
|
||||||
let jammed = jam(&mut stack, original.clone()).unwrap();
|
let jammed = jam(&mut stack, original.clone());
|
||||||
println!(
|
println!(
|
||||||
"Jammed size: {:.2} KB",
|
"Jammed size: {:.2} KB",
|
||||||
jammed.as_noun().mass() as f64 / 1024.0
|
jammed.as_noun().mass() as f64 / 1024.0
|
||||||
@ -557,26 +561,7 @@ mod tests {
|
|||||||
assert_noun_eq(&mut stack, cued, original);
|
assert_noun_eq(&mut stack, cued, original);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noun_size(noun: Noun) -> usize {
|
fn generate_random_noun(stack: &mut NockStack, bits: usize, rng: &mut StdRng) -> (Noun, usize) {
|
||||||
let mut size = 0;
|
|
||||||
let mut stack = vec![noun];
|
|
||||||
while let Some(top) = stack.pop() {
|
|
||||||
if let Ok(i) = top.as_indirect() {
|
|
||||||
size += i.raw_size();
|
|
||||||
} else if let Ok(c) = top.as_cell() {
|
|
||||||
size += (std::mem::size_of::<crate::noun::CellMemory>() + 7) << 3;
|
|
||||||
stack.push(c.tail());
|
|
||||||
stack.push(c.head());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_random_noun(
|
|
||||||
stack: &mut NockStack,
|
|
||||||
bits: usize,
|
|
||||||
rng: &mut StdRng,
|
|
||||||
) -> AllocResult<(Noun, usize)> {
|
|
||||||
const MAX_DEPTH: usize = 100; // Adjust this value as needed
|
const MAX_DEPTH: usize = 100; // Adjust this value as needed
|
||||||
fn inner(
|
fn inner(
|
||||||
stack: &mut NockStack,
|
stack: &mut NockStack,
|
||||||
@ -584,7 +569,7 @@ mod tests {
|
|||||||
rng: &mut StdRng,
|
rng: &mut StdRng,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
accumulated_size: usize,
|
accumulated_size: usize,
|
||||||
) -> AllocResult<(Noun, usize)> {
|
) -> (Noun, usize) {
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 {
|
if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 {
|
||||||
// println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0);
|
// println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0);
|
||||||
@ -593,51 +578,78 @@ mod tests {
|
|||||||
|
|
||||||
let result = if rng.gen_bool(0.5) || done {
|
let result = if rng.gen_bool(0.5) || done {
|
||||||
let value = rng.gen::<u64>();
|
let value = rng.gen::<u64>();
|
||||||
let atom = Atom::new(stack, value).unwrap();
|
let atom = Atom::new(stack, value);
|
||||||
let noun = atom.as_noun();
|
let noun = atom.as_noun();
|
||||||
(noun, accumulated_size + noun.mass())
|
(noun, accumulated_size + noun.mass())
|
||||||
} else {
|
} else {
|
||||||
let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size)?;
|
let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size);
|
||||||
let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size)?;
|
let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size);
|
||||||
|
|
||||||
let cell = Cell::new(stack, left, right).unwrap();
|
let cell = Cell::new(stack, left, right);
|
||||||
let noun = cell.as_noun();
|
let noun = cell.as_noun();
|
||||||
(noun, noun.mass())
|
(noun, noun.mass())
|
||||||
};
|
};
|
||||||
|
|
||||||
if noun_size(result.0) > stack.size() {
|
if space_needed_noun(result.0, stack) > stack.size() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Stack size exceeded with noun size {:.2} KB",
|
"Stack size exceeded with noun size {:.2} KB",
|
||||||
result.0.mass() as f64 / 1024.0
|
result.0.mass() as f64 / 1024.0
|
||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
let top_noun = *stack.top::<Noun>();
|
let top_noun = *stack.top::<Noun>();
|
||||||
Ok((top_noun, result.1))
|
(top_noun, result.1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(result)
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner(stack, bits, rng, 0, 0)
|
inner(stack, bits, rng, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn space_needed_noun(noun: Noun, stack: &mut NockStack) -> usize {
|
||||||
|
unsafe {
|
||||||
|
stack.with_frame(0, |stack| {
|
||||||
|
*(stack.push::<Noun>()) = noun;
|
||||||
|
let mut size = 0;
|
||||||
|
while !stack.stack_is_empty() {
|
||||||
|
let noun = *(stack.top::<Noun>());
|
||||||
|
stack.pop::<Noun>();
|
||||||
|
match noun.as_either_atom_cell() {
|
||||||
|
Left(atom) => match atom.as_either() {
|
||||||
|
Left(_) => {}
|
||||||
|
Right(indirect) => {
|
||||||
|
size += indirect.raw_size();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Right(cell) => {
|
||||||
|
size += size_of::<CellMemory>();
|
||||||
|
*(stack.push::<Noun>()) = cell.tail();
|
||||||
|
*(stack.push::<Noun>()) = cell.head();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_deeply_nested_noun(
|
fn generate_deeply_nested_noun(
|
||||||
stack: &mut NockStack,
|
stack: &mut NockStack,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
rng: &mut StdRng,
|
rng: &mut StdRng,
|
||||||
) -> AllocResult<(Noun, usize)> {
|
) -> (Noun, usize) {
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
let (noun, size) = generate_random_noun(stack, 100, rng)?;
|
let (noun, size) = generate_random_noun(stack, 100, rng);
|
||||||
Ok((noun, size))
|
(noun, size)
|
||||||
} else {
|
} else {
|
||||||
let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?;
|
let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
|
||||||
let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?;
|
let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
|
||||||
let cell = Cell::new(stack, left, right).unwrap();
|
let cell = Cell::new(stack, left, right);
|
||||||
let noun = cell.as_noun();
|
let noun = cell.as_noun();
|
||||||
let total_size = left_size + right_size + noun.mass();
|
let total_size = left_size + right_size + noun.mass();
|
||||||
|
|
||||||
if noun_size(noun) > stack.size() {
|
if { space_needed_noun(noun, stack) } > stack.size() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Stack size exceeded at depth {} with noun size {:.2} KB",
|
"Stack size exceeded at depth {} with noun size {:.2} KB",
|
||||||
depth,
|
depth,
|
||||||
@ -645,11 +657,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
let top_noun = *stack.top::<Noun>();
|
let top_noun = *stack.top::<Noun>();
|
||||||
Ok((top_noun, total_size))
|
(top_noun, total_size)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth);
|
// println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth);
|
||||||
Ok((noun, total_size))
|
(noun, total_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -659,7 +671,7 @@ mod tests {
|
|||||||
std::env::set_var("RUST_BACKTRACE", "full");
|
std::env::set_var("RUST_BACKTRACE", "full");
|
||||||
|
|
||||||
let mut stack = setup_stack();
|
let mut stack = setup_stack();
|
||||||
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid atom representation
|
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid atom representation
|
||||||
let result = cue(&mut stack, invalid_atom);
|
let result = cue(&mut stack, invalid_atom);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -668,6 +680,8 @@ mod tests {
|
|||||||
assert!(matches!(e, Error::Deterministic(_, _)));
|
assert!(matches!(e, Error::Deterministic(_, _)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ignore] // We will put this back when we have proper error catching
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cue_nondeterministic_error() {
|
fn test_cue_nondeterministic_error() {
|
||||||
let mut big_stack = NockStack::new(1 << 30, 0);
|
let mut big_stack = NockStack::new(1 << 30, 0);
|
||||||
@ -675,10 +689,10 @@ mod tests {
|
|||||||
let mut rng = StdRng::seed_from_u64(1);
|
let mut rng = StdRng::seed_from_u64(1);
|
||||||
|
|
||||||
// Create an atom with a very large value to potentially cause overflow
|
// Create an atom with a very large value to potentially cause overflow
|
||||||
let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng).unwrap();
|
let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng);
|
||||||
|
|
||||||
// Attempt to jam and then cue the large atom in the big stack
|
// Attempt to jam and then cue the large atom in the big stack
|
||||||
let jammed = jam(&mut big_stack, large_atom).unwrap();
|
let jammed = jam(&mut big_stack, large_atom);
|
||||||
|
|
||||||
// make a smaller stack to try to cause a nondeterministic error
|
// make a smaller stack to try to cause a nondeterministic error
|
||||||
// NOTE: if the stack is big enough to fit the jammed atom, cue panics
|
// NOTE: if the stack is big enough to fit the jammed atom, cue panics
|
||||||
@ -697,10 +711,7 @@ mod tests {
|
|||||||
println!("Result: {:?}", result);
|
println!("Result: {:?}", result);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
assert!(matches!(
|
assert!(matches!(e, Error::NonDeterministic(_, _)));
|
||||||
e,
|
|
||||||
Error::NonDeterministic(crate::interpreter::Mote::Meme, _)
|
|
||||||
));
|
|
||||||
println!("got expected error: {:?}", e);
|
println!("got expected error: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ use bitvec::slice::BitSlice;
|
|||||||
use crate::interpreter::{interpret, Context};
|
use crate::interpreter::{interpret, Context};
|
||||||
use crate::jets::util::slot;
|
use crate::jets::util::slot;
|
||||||
use crate::jets::{Jet, JetErr};
|
use crate::jets::{Jet, JetErr};
|
||||||
use crate::mem::AllocResult;
|
|
||||||
use crate::noun::{Noun, D, T};
|
use crate::noun::{Noun, D, T};
|
||||||
|
|
||||||
/// Return Err if the computation crashed or should punt to Nock
|
/// Return Err if the computation crashed or should punt to Nock
|
||||||
@ -20,13 +19,13 @@ pub struct Site {
|
|||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
/// Prepare a locally cached gate to call repeatedly.
|
/// Prepare a locally cached gate to call repeatedly.
|
||||||
pub fn new(ctx: &mut Context, core: &mut Noun) -> AllocResult<Site> {
|
pub fn new(ctx: &mut Context, core: &mut Noun) -> Site {
|
||||||
let mut battery = slot(*core, 2).unwrap();
|
let mut battery = slot(*core, 2).unwrap();
|
||||||
let context = slot(*core, 7).unwrap();
|
let context = slot(*core, 7).unwrap();
|
||||||
|
|
||||||
let warm_result = ctx
|
let warm_result = ctx
|
||||||
.warm
|
.warm
|
||||||
.find_jet(&mut ctx.stack, core, &mut battery)?
|
.find_jet(&mut ctx.stack, core, &mut battery)
|
||||||
.filter(|(_jet, mut path)| {
|
.filter(|(_jet, mut path)| {
|
||||||
// check that 7 is a prefix of the parent battery axis,
|
// check that 7 is a prefix of the parent battery axis,
|
||||||
// to ensure that the sample (axis 6) is not part of the jet match.
|
// to ensure that the sample (axis 6) is not part of the jet match.
|
||||||
@ -35,12 +34,10 @@ impl Site {
|
|||||||
// jet and we only actually match one of them, but we check all of them and run
|
// jet and we only actually match one of them, but we check all of them and run
|
||||||
// unjetted if any have an axis outside 7.
|
// unjetted if any have an axis outside 7.
|
||||||
let axis_7_bits: &BitSlice<u64, Lsb0> = BitSlice::from_element(&7u64);
|
let axis_7_bits: &BitSlice<u64, Lsb0> = BitSlice::from_element(&7u64);
|
||||||
// TODO: This panic is ugly but the code is awkward.
|
let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path);
|
||||||
let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path).ok().expect("OOM'd on ctx.cold.find in Site::new");
|
|
||||||
let mut ret = true;
|
let mut ret = true;
|
||||||
for mut batteries in batteries_list {
|
for mut batteries in batteries_list {
|
||||||
if let Some((_, parent_axis)) = batteries.next() {
|
if let Some((_battery, parent_axis)) = batteries.next() {
|
||||||
// let parent_axis = unsafe { (*battery.0).parent_axis };
|
|
||||||
let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3];
|
let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3];
|
||||||
if parent_axis_prefix_bits == axis_7_bits {
|
if parent_axis_prefix_bits == axis_7_bits {
|
||||||
continue;
|
continue;
|
||||||
@ -54,19 +51,19 @@ impl Site {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
});
|
});
|
||||||
Ok(Site {
|
Site {
|
||||||
battery,
|
battery,
|
||||||
context,
|
context,
|
||||||
jet: warm_result.map(|(jet, _)| jet),
|
jet: warm_result.map(|(jet, _)| jet),
|
||||||
path: warm_result.map(|(_, path)| path).unwrap_or(D(0)),
|
path: warm_result.map(|(_, path)| path).unwrap_or(D(0)),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Slam a cached call site.
|
/// Slam a cached call site.
|
||||||
pub fn site_slam(ctx: &mut Context, site: &Site, sample: Noun) -> Result {
|
pub fn site_slam(ctx: &mut Context, site: &Site, sample: Noun) -> Result {
|
||||||
let subject = T(&mut ctx.stack, &[site.battery, sample, site.context])?;
|
let subject = T(&mut ctx.stack, &[site.battery, sample, site.context]);
|
||||||
if site.jet.is_some() {
|
if site.jet.is_some() {
|
||||||
let jet = site.jet.unwrap();
|
let jet = site.jet.unwrap();
|
||||||
jet(ctx, subject)
|
jet(ctx, subject)
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
use crate::{mem::NockStack, noun::Noun};
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn T<A: crate::noun::NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
|
|
||||||
crate::noun::T(allocator, tup).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn A(stack: &mut NockStack, atom: &ibig::UBig) -> Noun {
|
|
||||||
crate::jets::util::test::A(stack, atom).unwrap()
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ use crate::flog;
|
|||||||
use crate::interpreter::Context;
|
use crate::interpreter::Context;
|
||||||
use crate::jets::bits::util::rap;
|
use crate::jets::bits::util::rap;
|
||||||
use crate::jets::form::util::scow;
|
use crate::jets::form::util::scow;
|
||||||
use crate::mem::{AllocResult, NockStack};
|
use crate::mem::NockStack;
|
||||||
use crate::mug::met3_usize;
|
use crate::mug::met3_usize;
|
||||||
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun};
|
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun};
|
||||||
use either::Either::*;
|
use either::Either::*;
|
||||||
@ -153,7 +153,7 @@ pub unsafe fn write_nock_trace(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pc = path_to_cord(stack, (*trace_stack).path)?;
|
let pc = path_to_cord(stack, (*trace_stack).path);
|
||||||
let pc_len = met3_usize(pc);
|
let pc_len = met3_usize(pc);
|
||||||
let pc_bytes = &pc.as_bytes()[0..pc_len];
|
let pc_bytes = &pc.as_bytes()[0..pc_len];
|
||||||
let pc_str = match std::str::from_utf8(pc_bytes) {
|
let pc_str = match std::str::from_utf8(pc_bytes) {
|
||||||
@ -185,7 +185,7 @@ pub unsafe fn write_nock_trace(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XX: Need Rust string interpolation helper that doesn't allocate
|
// XX: Need Rust string interpolation helper that doesn't allocate
|
||||||
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
|
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
|
||||||
let mut cursor = path;
|
let mut cursor = path;
|
||||||
let mut length = 0usize;
|
let mut length = 0usize;
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
|
|||||||
// reset cursor, then actually write the path
|
// reset cursor, then actually write the path
|
||||||
cursor = path;
|
cursor = path;
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length)? };
|
let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length) };
|
||||||
let slash = (b"/")[0];
|
let slash = (b"/")[0];
|
||||||
|
|
||||||
while let Ok(c) = cursor.as_cell() {
|
while let Ok(c) = cursor.as_cell() {
|
||||||
@ -254,5 +254,5 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
|
|||||||
cursor = c.tail();
|
cursor = c.tail();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(unsafe { deres.normalize_as_atom() })
|
unsafe { deres.normalize_as_atom() }
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::mem::{AllocResult, NockStack, ALLOC, FRAME, STACK};
|
use crate::mem::{NockStack, ALLOC, FRAME, STACK};
|
||||||
use crate::noun::Noun;
|
use crate::noun::Noun;
|
||||||
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
|
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
|
||||||
use either::Either::*;
|
use either::Either::*;
|
||||||
@ -20,22 +20,7 @@ macro_rules! assert_no_junior_pointers {
|
|||||||
( $x:expr, $y:expr ) => {};
|
( $x:expr, $y:expr ) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
||||||
pub(crate) mod test {
|
|
||||||
use crate::mem::NockStack;
|
|
||||||
use crate::noun::Noun;
|
|
||||||
|
|
||||||
/// Tests only, not part of the actual implementation. Use this outside of #[cfg(test)] and I will sic the linter on you.
|
|
||||||
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
|
||||||
super::unifying_equality(stack, a, b).expect("OOM error in test::unifying_equality")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn unifying_equality(
|
|
||||||
stack: &mut NockStack,
|
|
||||||
a: *mut Noun,
|
|
||||||
b: *mut Noun,
|
|
||||||
) -> AllocResult<bool> {
|
|
||||||
/* This version of unifying equality is not like that of vere.
|
/* This version of unifying equality is not like that of vere.
|
||||||
* Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug
|
* Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug
|
||||||
* equality) and then unifies the nouns at the top level if they are equal.
|
* equality) and then unifies the nouns at the top level if they are equal.
|
||||||
@ -68,109 +53,108 @@ pub unsafe fn unifying_equality(
|
|||||||
|
|
||||||
// If the nouns are already word-equal we have nothing to do
|
// If the nouns are already word-equal we have nothing to do
|
||||||
if (*a).raw_equals(*b) {
|
if (*a).raw_equals(*b) {
|
||||||
return Ok(true);
|
return true;
|
||||||
};
|
};
|
||||||
// If the nouns have cached mugs which are disequal we have nothing to do
|
// If the nouns have cached mugs which are disequal we have nothing to do
|
||||||
if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) {
|
if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) {
|
||||||
if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) {
|
if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) {
|
||||||
if a_mug != b_mug {
|
if a_mug != b_mug {
|
||||||
return Ok(false);
|
return false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
stack.with_frame(0, |stack| {
|
stack.frame_push(0);
|
||||||
*(stack.push::<(*mut Noun, *mut Noun)>()?) = (a, b);
|
*(stack.push::<(*mut Noun, *mut Noun)>()) = (a, b);
|
||||||
loop {
|
loop {
|
||||||
if stack.stack_is_empty() {
|
if stack.stack_is_empty() {
|
||||||
break;
|
break;
|
||||||
|
};
|
||||||
|
let (x, y): (*mut Noun, *mut Noun) = *(stack.top());
|
||||||
|
if (*x).raw_equals(*y) {
|
||||||
|
stack.pop::<(*mut Noun, *mut Noun)>();
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let (Ok(x_alloc), Ok(y_alloc)) = (
|
||||||
|
// equal direct atoms return true for raw_equals()
|
||||||
|
(*x).as_allocated(),
|
||||||
|
(*y).as_allocated(),
|
||||||
|
) {
|
||||||
|
if let (Some(x_mug), Some(y_mug)) = (x_alloc.get_cached_mug(), y_alloc.get_cached_mug())
|
||||||
|
{
|
||||||
|
if x_mug != y_mug {
|
||||||
|
break; // short-circuit, the mugs differ therefore the nouns must differ
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let (x, y): (*mut Noun, *mut Noun) = *(stack.top());
|
match (x_alloc.as_either(), y_alloc.as_either()) {
|
||||||
if (*x).raw_equals(*y) {
|
(Left(x_indirect), Left(y_indirect)) => {
|
||||||
stack.pop::<(*mut Noun, *mut Noun)>();
|
let x_as_ptr = x_indirect.to_raw_pointer();
|
||||||
continue;
|
let y_as_ptr = y_indirect.to_raw_pointer();
|
||||||
};
|
if x_indirect.size() == y_indirect.size()
|
||||||
if let (Ok(x_alloc), Ok(y_alloc)) = (
|
&& memcmp(
|
||||||
// equal direct atoms return true for raw_equals()
|
x_indirect.data_pointer() as *const c_void,
|
||||||
(*x).as_allocated(),
|
y_indirect.data_pointer() as *const c_void,
|
||||||
(*y).as_allocated(),
|
x_indirect.size() << 3,
|
||||||
) {
|
) == 0
|
||||||
if let (Some(x_mug), Some(y_mug)) =
|
{
|
||||||
(x_alloc.get_cached_mug(), y_alloc.get_cached_mug())
|
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
||||||
{
|
if x_as_ptr == junior {
|
||||||
if x_mug != y_mug {
|
*x = *y;
|
||||||
break; // short-circuit, the mugs differ therefore the nouns must differ
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match (x_alloc.as_either(), y_alloc.as_either()) {
|
|
||||||
(Left(x_indirect), Left(y_indirect)) => {
|
|
||||||
let x_as_ptr = x_indirect.to_raw_pointer();
|
|
||||||
let y_as_ptr = y_indirect.to_raw_pointer();
|
|
||||||
if x_indirect.size() == y_indirect.size()
|
|
||||||
&& memcmp(
|
|
||||||
x_indirect.data_pointer() as *const c_void,
|
|
||||||
y_indirect.data_pointer() as *const c_void,
|
|
||||||
x_indirect.size() << 3,
|
|
||||||
) == 0
|
|
||||||
{
|
|
||||||
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
|
||||||
if x_as_ptr == junior {
|
|
||||||
*x = *y;
|
|
||||||
} else {
|
|
||||||
*y = *x;
|
|
||||||
}
|
|
||||||
stack.pop::<(*mut Noun, *mut Noun)>();
|
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
*y = *x;
|
||||||
}
|
}
|
||||||
}
|
stack.pop::<(*mut Noun, *mut Noun)>();
|
||||||
(Right(x_cell), Right(y_cell)) => {
|
continue;
|
||||||
let x_as_ptr = x_cell.to_raw_pointer() as *const u64;
|
} else {
|
||||||
let y_as_ptr = y_cell.to_raw_pointer() as *const u64;
|
break;
|
||||||
if x_cell.head().raw_equals(y_cell.head())
|
|
||||||
&& x_cell.tail().raw_equals(y_cell.tail())
|
|
||||||
{
|
|
||||||
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
|
||||||
if x_as_ptr == junior {
|
|
||||||
*x = *y;
|
|
||||||
} else {
|
|
||||||
*y = *x;
|
|
||||||
}
|
|
||||||
stack.pop::<(*mut Noun, *mut Noun)>();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
/* THIS ISN'T AN INFINITE LOOP
|
|
||||||
* If we discover a disequality in either side, we will
|
|
||||||
* short-circuit the entire loop and reset the work stack.
|
|
||||||
*
|
|
||||||
* If both sides are equal, then we will discover pointer
|
|
||||||
* equality when we return and unify the cell.
|
|
||||||
*/
|
|
||||||
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
|
|
||||||
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
|
|
||||||
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
|
|
||||||
(x_cell.head_as_mut(), y_cell.head_as_mut());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(_, _) => {
|
|
||||||
break; // cells don't unify with atoms
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
(Right(x_cell), Right(y_cell)) => {
|
||||||
break; // direct atom not raw equal, so short circuit
|
let x_as_ptr = x_cell.to_raw_pointer() as *const u64;
|
||||||
|
let y_as_ptr = y_cell.to_raw_pointer() as *const u64;
|
||||||
|
if x_cell.head().raw_equals(y_cell.head())
|
||||||
|
&& x_cell.tail().raw_equals(y_cell.tail())
|
||||||
|
{
|
||||||
|
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
||||||
|
if x_as_ptr == junior {
|
||||||
|
*x = *y;
|
||||||
|
} else {
|
||||||
|
*y = *x;
|
||||||
|
}
|
||||||
|
stack.pop::<(*mut Noun, *mut Noun)>();
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
/* THIS ISN'T AN INFINITE LOOP
|
||||||
|
* If we discover a disequality in either side, we will
|
||||||
|
* short-circuit the entire loop and reset the work stack.
|
||||||
|
*
|
||||||
|
* If both sides are equal, then we will discover pointer
|
||||||
|
* equality when we return and unify the cell.
|
||||||
|
*/
|
||||||
|
*(stack.push::<(*mut Noun, *mut Noun)>()) =
|
||||||
|
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
|
||||||
|
*(stack.push::<(*mut Noun, *mut Noun)>()) =
|
||||||
|
(x_cell.head_as_mut(), y_cell.head_as_mut());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(_, _) => {
|
||||||
|
break; // cells don't unify with atoms
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
break; // direct atom not raw equal, so short circuit
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
stack.frame_pop();
|
||||||
|
|
||||||
assert_acyclic!(*a);
|
assert_acyclic!(*a);
|
||||||
assert_acyclic!(*b);
|
assert_acyclic!(*b);
|
||||||
assert_no_forwarding_pointers!(*a);
|
assert_no_forwarding_pointers!(*a);
|
||||||
assert_no_forwarding_pointers!(*b);
|
assert_no_forwarding_pointers!(*b);
|
||||||
assert_no_junior_pointers!(stack, *a);
|
assert_no_junior_pointers!(stack, *a);
|
||||||
assert_no_junior_pointers!(stack, *b);
|
assert_no_junior_pointers!(stack, *b);
|
||||||
|
|
||||||
Ok((*a).raw_equals(*b))
|
(*a).raw_equals(*b)
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn senior_pointer_first(
|
unsafe fn senior_pointer_first(
|
||||||
|
Loading…
Reference in New Issue
Block a user