Merge pull request #117 from urbit/sigilante/jets-one

Jets for `min`, `max`, and `peg`
This commit is contained in:
Edward Amsden 2023-11-15 06:38:48 -06:00 committed by GitHub
commit 7a82b5d201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 428 additions and 138 deletions

View File

@ -147,6 +147,7 @@ pub mod util {
use std::result;
/**
* Address-based size checks.
* Currently, only addresses indexable by the first 48 bits are reachable by
* modern 64-bit CPUs.
*/
@ -159,7 +160,7 @@ pub mod util {
.ok_or(JetErr::Fail(Error::NonDeterministic(D(0))))
}
/// Performs addition that returns None on Noun size overflow
/// Performs subtraction that returns None on Noun size overflow
pub fn checked_sub(a: usize, b: usize) -> result::Result<usize, JetErr> {
a.checked_sub(b)
.ok_or(JetErr::Fail(Error::NonDeterministic(D(0))))
@ -339,5 +340,56 @@ pub mod util {
}
}
}
pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
let res = assert_no_alloc(|| jet(context, sam).unwrap());
assert!(res.is_atom(), "jet result not atom");
let res_siz = res.atom().unwrap().size();
assert!(siz == res_siz, "got: {}, need: {}", res_siz, siz);
}
pub fn assert_common_jet(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
res: UBig,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
assert_nary_jet_ubig(context, jet, &sam, res);
}
pub fn assert_common_jet_noun(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
res: Noun,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
assert_jet(context, jet, sam, res);
}
pub fn assert_common_jet_err(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
err: JetErr,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
assert_jet_err(context, jet, sam, err);
}
pub fn assert_common_jet_size(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
siz: usize,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
assert_jet_size(context, jet, sam, siz)
}
}
}

View File

@ -130,17 +130,7 @@ pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result {
let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?;
let len = util::met(bloq, a);
if len == 0 {
return Ok(D(0));
}
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun())
}
util::lsh(&mut context.stack, bloq, step, a)
}
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result {
@ -373,6 +363,20 @@ pub mod util {
}
}
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result {
let len = met(bloq, a);
if len == 0 {
return Ok(D(0));
}
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun())
}
}
/// Measure the number of bloqs in an atom
pub fn met(bloq: usize, a: Atom) -> usize {
if unsafe { a.as_noun().raw_equals(D(0)) } {
@ -458,7 +462,7 @@ pub mod util {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::{assert_jet, assert_jet_ubig, init_context, A};
use crate::jets::util::test::*;
use crate::mem::NockStack;
use crate::noun::{Noun, D, T};
use ibig::ubig;
@ -633,9 +637,8 @@ mod tests {
fn test_lsh() {
let c = &mut init_context();
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a24]);
assert_jet(c, jet_lsh, sam, D(0x10eca86));
let (_, a24, _a63, a96, a128) = atoms(&mut c.stack);
assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86));
let sam = T(&mut c.stack, &[D(3), a24]);
assert_jet(c, jet_lsh, sam, D(0x87654300));
let sam = T(&mut c.stack, &[D(7), a24]);

View File

@ -23,19 +23,10 @@ use ibig::UBig;
crate::gdb!();
pub fn jet_add(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Ok(Atom::new(stack, a.data() + b.data()).as_noun())
} else {
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::add_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res).as_noun())
}
Ok(util::add(&mut context.stack, a, b).as_noun())
}
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result {
@ -201,6 +192,52 @@ pub fn jet_lth(context: &mut Context, subject: Noun) -> Result {
Ok(util::lth(stack, a, b))
}
pub fn jet_max(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
if a.data() >= b.data() {
a.as_noun()
} else {
b.as_noun()
}
} else if a.bit_size() > b.bit_size() {
a.as_noun()
} else if a.bit_size() < b.bit_size() {
b.as_noun()
} else if a.as_ubig(stack) >= b.as_ubig(stack) {
a.as_noun()
} else {
b.as_noun()
})
}
pub fn jet_min(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
if a.data() <= b.data() {
a.as_noun()
} else {
b.as_noun()
}
} else if a.bit_size() < b.bit_size() {
a.as_noun()
} else if a.bit_size() > b.bit_size() {
b.as_noun()
} else if a.as_ubig(stack) <= b.as_ubig(stack) {
a.as_noun()
} else {
b.as_noun()
})
}
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
@ -258,6 +295,19 @@ pub mod util {
use crate::noun::{Atom, Error, Noun, Result, NO, YES};
use ibig::UBig;
/// Addition
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Atom::new(stack, a.data() + b.data())
} else {
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::add_stack(stack, a_big, b_big);
Atom::from_ubig(stack, &res)
}
}
/// Less than
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
if a.data() < b.data() {
@ -307,13 +357,11 @@ pub mod util {
mod tests {
use super::*;
use crate::interpreter::Error;
use crate::jets::util::test::{
assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_context, A,
};
use crate::jets::{Jet, JetErr};
use crate::jets::util::test::*;
use crate::jets::JetErr;
use crate::mem::NockStack;
use crate::noun::{Noun, D, NO, T, YES};
use ibig::{ubig, UBig};
use ibig::ubig;
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))
@ -354,55 +402,23 @@ mod tests {
A(stack, &ubig!(_0xdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540000ffdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540001ff))
}
fn assert_math_jet(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
res: UBig,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
assert_nary_jet_ubig(context, jet, &sam, res);
}
fn assert_math_jet_noun(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
res: Noun,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
assert_jet(context, jet, sam, res);
}
fn assert_math_jet_err(
context: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun],
err: JetErr,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam);
assert_jet_err(context, jet, sam, err);
}
#[test]
fn test_add() {
let c = &mut init_context();
assert_math_jet(
assert_common_jet(
c,
jet_add,
&[atom_128, atom_96],
ubig!(0xdeadbef00d03068514bb685765666666),
);
assert_math_jet(
assert_common_jet(
c,
jet_add,
&[atom_63, atom_96],
ubig!(0xfaceb00c95deadbeef123455),
);
assert_math_jet(c, jet_add, &[atom_63, atom_63], ubig!(0xfffffffffffffffe));
assert_common_jet(c, jet_add, &[atom_63, atom_63], ubig!(0xfffffffffffffffe));
}
#[test]
@ -420,12 +436,12 @@ mod tests {
fn test_div() {
let c = &mut init_context();
assert_math_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0));
assert_math_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018));
assert_math_jet(c, jet_div, &[atom_63, atom_96], ubig!(0));
assert_math_jet(c, jet_div, &[atom_63, atom_63], ubig!(1));
assert_math_jet(c, jet_div, &[atom_63, atom_24], ubig!(0xf2044dacfe));
assert_math_jet(
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_63, atom_96], ubig!(0));
assert_common_jet(c, jet_div, &[atom_63, atom_63], ubig!(1));
assert_common_jet(c, jet_div, &[atom_63, atom_24], ubig!(0xf2044dacfe));
assert_common_jet(
c,
jet_div,
&[atom_128, atom_24],
@ -434,14 +450,14 @@ mod tests {
let res = ubig!(
_0x00000000000001000000000000000000000000000000000000000000000000000000000000000001
);
assert_math_jet(c, jet_div, &[atom_528, atom_264], res);
assert_math_jet_err(
assert_common_jet(c, jet_div, &[atom_528, atom_264], res);
assert_common_jet_err(
c,
jet_div,
&[atom_63, atom_0],
JetErr::Fail(Error::Deterministic(D(0))),
);
assert_math_jet_err(
assert_common_jet_err(
c,
jet_div,
&[atom_0, atom_0],
@ -492,7 +508,7 @@ mod tests {
let res = T(&mut c.stack, &[res_a, res_b]);
assert_jet(c, jet_dvr, sam, res);
assert_math_jet_err(
assert_common_jet_err(
c,
jet_dvr,
&[atom_63, atom_0],
@ -504,81 +520,168 @@ mod tests {
fn test_gte() {
let c = &mut init_context();
assert_math_jet_noun(c, jet_gte, &[atom_128, atom_96], YES);
assert_math_jet_noun(c, jet_gte, &[atom_96, atom_63], YES);
assert_math_jet_noun(c, jet_gte, &[atom_63, atom_96], NO);
assert_math_jet_noun(c, jet_gte, &[atom_63, atom_63], YES);
assert_math_jet_noun(c, jet_gte, &[atom_63, atom_24], YES);
assert_math_jet_noun(c, jet_gte, &[atom_128, atom_24], YES);
assert_math_jet_noun(c, jet_gte, &[atom_128, atom_128_b], YES);
assert_math_jet_noun(c, jet_gte, &[atom_128_b, atom_128], NO);
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_63, atom_96], NO);
assert_common_jet_noun(c, jet_gte, &[atom_63, atom_63], YES);
assert_common_jet_noun(c, jet_gte, &[atom_63, atom_24], YES);
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_24], YES);
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_128_b], YES);
assert_common_jet_noun(c, jet_gte, &[atom_128_b, atom_128], NO);
}
#[test]
fn test_gth() {
let c = &mut init_context();
assert_math_jet_noun(c, jet_gth, &[atom_128, atom_96], YES);
assert_math_jet_noun(c, jet_gth, &[atom_96, atom_63], YES);
assert_math_jet_noun(c, jet_gth, &[atom_63, atom_96], NO);
assert_math_jet_noun(c, jet_gth, &[atom_63, atom_63], NO);
assert_math_jet_noun(c, jet_gth, &[atom_63, atom_24], YES);
assert_math_jet_noun(c, jet_gth, &[atom_128, atom_24], YES);
assert_math_jet_noun(c, jet_gth, &[atom_128, atom_128_b], YES);
assert_math_jet_noun(c, jet_gth, &[atom_128_b, atom_128], NO);
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_63, atom_96], NO);
assert_common_jet_noun(c, jet_gth, &[atom_63, atom_63], NO);
assert_common_jet_noun(c, jet_gth, &[atom_63, atom_24], YES);
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_24], YES);
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_128_b], YES);
assert_common_jet_noun(c, jet_gth, &[atom_128_b, atom_128], NO);
}
#[test]
fn test_lte() {
let c = &mut init_context();
assert_math_jet_noun(c, jet_lte, &[atom_128, atom_96], NO);
assert_math_jet_noun(c, jet_lte, &[atom_96, atom_63], NO);
assert_math_jet_noun(c, jet_lte, &[atom_63, atom_96], YES);
assert_math_jet_noun(c, jet_lte, &[atom_63, atom_63], YES);
assert_math_jet_noun(c, jet_lte, &[atom_63, atom_24], NO);
assert_math_jet_noun(c, jet_lte, &[atom_128, atom_24], NO);
assert_math_jet_noun(c, jet_lte, &[atom_128, atom_128_b], NO);
assert_math_jet_noun(c, jet_lte, &[atom_128_b, atom_128], YES);
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_63, atom_96], YES);
assert_common_jet_noun(c, jet_lte, &[atom_63, atom_63], YES);
assert_common_jet_noun(c, jet_lte, &[atom_63, atom_24], NO);
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_24], NO);
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_128_b], NO);
assert_common_jet_noun(c, jet_lte, &[atom_128_b, atom_128], YES);
}
#[test]
fn test_lth() {
let c = &mut init_context();
assert_math_jet_noun(c, jet_lth, &[atom_128, atom_96], NO);
assert_math_jet_noun(c, jet_lth, &[atom_96, atom_63], NO);
assert_math_jet_noun(c, jet_lth, &[atom_63, atom_96], YES);
assert_math_jet_noun(c, jet_lth, &[atom_63, atom_63], NO);
assert_math_jet_noun(c, jet_lth, &[atom_63, atom_24], NO);
assert_math_jet_noun(c, jet_lth, &[atom_128, atom_24], NO);
assert_math_jet_noun(c, jet_lth, &[atom_128, atom_128_b], NO);
assert_math_jet_noun(c, jet_lth, &[atom_128_b, atom_128], YES);
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_63, atom_96], YES);
assert_common_jet_noun(c, jet_lth, &[atom_63, atom_63], NO);
assert_common_jet_noun(c, jet_lth, &[atom_63, atom_24], NO);
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_24], NO);
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_128_b], NO);
assert_common_jet_noun(c, jet_lth, &[atom_128_b, atom_128], YES);
}
#[test]
fn test_max() {
let c = &mut init_context();
assert_common_jet(
c,
jet_max,
&[atom_128, atom_96],
ubig!(0xdeadbeef12345678fedcba9876543210),
);
assert_common_jet(
c,
jet_max,
&[atom_96, atom_63],
ubig!(0xfaceb00c15deadbeef123456),
);
assert_common_jet(
c,
jet_max,
&[atom_63, atom_96],
ubig!(0xfaceb00c15deadbeef123456),
);
assert_common_jet(c, jet_max, &[atom_63, atom_63], ubig!(0x7fffffffffffffff));
assert_common_jet(c, jet_max, &[atom_63, atom_24], ubig!(0x7fffffffffffffff));
assert_common_jet(
c,
jet_max,
&[atom_128, atom_24],
ubig!(0xdeadbeef12345678fedcba9876543210),
);
assert_common_jet(
c,
jet_max,
&[atom_128, atom_128_b],
ubig!(0xdeadbeef12345678fedcba9876543210),
);
assert_common_jet(
c,
jet_max,
&[atom_128_b, atom_128],
ubig!(0xdeadbeef12345678fedcba9876543210),
);
assert_common_jet(c, jet_max, &[atom_528, atom_264], ubig!(_0xdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540000ffdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540001ff));
assert_common_jet(c, jet_max, &[atom_264, atom_528], ubig!(_0xdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540000ffdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540001ff));
}
#[test]
fn test_min() {
let c = &mut init_context();
assert_common_jet(
c,
jet_min,
&[atom_128, atom_96],
ubig!(0xfaceb00c15deadbeef123456),
);
assert_common_jet(c, jet_min, &[atom_96, atom_63], ubig!(0x7fffffffffffffff));
assert_common_jet(c, jet_min, &[atom_63, atom_96], ubig!(0x7fffffffffffffff));
assert_common_jet(c, jet_min, &[atom_63, atom_63], ubig!(0x7fffffffffffffff));
assert_common_jet(c, jet_min, &[atom_63, atom_24], ubig!(0x876543));
assert_common_jet(c, jet_min, &[atom_128, atom_24], ubig!(0x876543));
assert_common_jet(
c,
jet_min,
&[atom_128, atom_128_b],
ubig!(0xdeadbeef12345678fedcba9876540000),
);
assert_common_jet(
c,
jet_min,
&[atom_128_b, atom_128],
ubig!(0xdeadbeef12345678fedcba9876540000),
);
assert_common_jet(
c,
jet_min,
&[atom_528, atom_264],
ubig!(_0xdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540000ff),
);
assert_common_jet(
c,
jet_min,
&[atom_264, atom_528],
ubig!(_0xdeadbeef12345678fedcba9876540000deadbeef12345678fedcba9876540000ff),
);
}
#[test]
fn test_mod() {
let c = &mut init_context();
assert_math_jet(
assert_common_jet(
c,
jet_mod,
&[atom_128, atom_96],
ubig!(0xcb0ce564ec598f658409d170),
);
assert_math_jet(c, jet_mod, &[atom_96, atom_63], ubig!(0x15deadc0e4af946e));
assert_math_jet(c, jet_mod, &[atom_63, atom_96], ubig!(0x7fffffffffffffff));
assert_math_jet(c, jet_mod, &[atom_63, atom_63], ubig!(0));
assert_math_jet(c, jet_mod, &[atom_63, atom_24], ubig!(0x798385));
assert_math_jet(c, jet_mod, &[atom_128, atom_24], ubig!(0x3b2013));
assert_math_jet(c, jet_mod, &[atom_528, atom_264], ubig!(0x100));
assert_math_jet_err(
assert_common_jet(c, jet_mod, &[atom_96, atom_63], ubig!(0x15deadc0e4af946e));
assert_common_jet(c, jet_mod, &[atom_63, atom_96], ubig!(0x7fffffffffffffff));
assert_common_jet(c, jet_mod, &[atom_63, atom_63], ubig!(0));
assert_common_jet(c, jet_mod, &[atom_63, atom_24], ubig!(0x798385));
assert_common_jet(c, jet_mod, &[atom_128, atom_24], ubig!(0x3b2013));
assert_common_jet(c, jet_mod, &[atom_528, atom_264], ubig!(0x100));
assert_common_jet_err(
c,
jet_mod,
&[atom_63, atom_0],
JetErr::Fail(Error::Deterministic(D(0))),
);
assert_math_jet_err(
assert_common_jet_err(
c,
jet_mod,
&[atom_0, atom_0],
@ -590,46 +693,46 @@ mod tests {
fn test_mul() {
let c = &mut init_context();
assert_math_jet(
assert_common_jet(
c,
jet_mul,
&[atom_128, atom_96],
ubig!(_0xda297567129704bf42e744f13ff0ea4fc4ac01215b708bc94f941160),
);
assert_math_jet(
assert_common_jet(
c,
jet_mul,
&[atom_63, atom_96],
ubig!(_0x7d6758060aef56de7cba6a1eea21524110edcbaa),
);
assert_math_jet(
assert_common_jet(
c,
jet_mul,
&[atom_63, atom_63],
ubig!(0x3fffffffffffffff0000000000000001),
);
assert_math_jet(c, jet_mul, &[atom_24, atom_24], ubig!(0x479bf4b7ef89));
assert_common_jet(c, jet_mul, &[atom_24, atom_24], ubig!(0x479bf4b7ef89));
}
#[test]
fn test_sub() {
let c = &mut init_context();
assert_math_jet(
assert_common_jet(
c,
jet_sub,
&[atom_128, atom_96],
ubig!(0xdeadbeee1765a66ce8fe0cd98741fdba),
);
assert_math_jet(
assert_common_jet(
c,
jet_sub,
&[atom_96, atom_63],
ubig!(0xfaceb00b95deadbeef123457),
);
assert_math_jet(c, jet_sub, &[atom_63, atom_63], ubig!(0));
assert_math_jet(c, jet_sub, &[atom_128, atom_128], ubig!(0));
assert_math_jet_err(
assert_common_jet(c, jet_sub, &[atom_63, atom_63], ubig!(0));
assert_common_jet(c, jet_sub, &[atom_128, atom_128], ubig!(0));
assert_common_jet_err(
c,
jet_sub,
&[atom_63, atom_96],

View File

@ -2,10 +2,9 @@
*/
use crate::interpreter::{Context, Error};
use crate::jets::bits::util::*;
use crate::jets::math::util::*;
use crate::jets::util::*;
use crate::jets::{JetErr, Result};
use crate::noun::{Noun, D};
use crate::noun::{IndirectAtom, Noun, D};
crate::gdb!();
@ -27,28 +26,104 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let tom = slot(subject, 6)?.as_atom()?;
let met = met(0, tom);
if met < 2 {
Err(JetErr::Fail(Error::Deterministic(D(0))))
} else {
let c = bex(stack, met - 1);
let d = bex(stack, met - 2);
let e = sub(stack, tom, c)?;
Ok(con(stack, e, d).as_noun())
let out_bits = met - 1;
let out_words = (out_bits + 63) >> 6;
let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
out_bs.set(met - 2, true); // Set MSB
if met > 2 {
out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]);
};
unsafe { Ok(indirect_out.normalize_as_atom().as_noun()) }
}
}
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
unsafe {
if a.as_noun().raw_equals(D(0)) {
return Err(JetErr::Fail(Error::Deterministic(D(0))));
};
if b.as_noun().raw_equals(D(0)) {
return Err(JetErr::Fail(Error::Deterministic(D(0))));
};
}
let a_bits = met(0, a);
let b_bits = met(0, b);
let out_bits = a_bits + b_bits - 1;
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
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]);
unsafe { Ok(indirect_out.normalize_as_atom().as_noun()) }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::interpreter::Error;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context};
use crate::jets::util::test::*;
use crate::jets::JetErr;
use crate::noun::D;
use crate::mem::NockStack;
use crate::noun::{Noun, D, DIRECT_MAX};
use ibig::ubig;
fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x0)
}
fn atom_1(_stack: &mut NockStack) -> Noun {
D(0x1)
}
fn atom_62(_stack: &mut NockStack) -> Noun {
D(0x3fffffffffffffff)
}
fn atom_63(_stack: &mut NockStack) -> Noun {
D(0x4000000000000000)
}
fn atom_64(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(_0x8000000000000000))
}
fn atom_65(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(_0x10000000000000000))
}
fn atom_66(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(_0x20000000000000000))
}
fn pos_2(_stack: &mut NockStack) -> Noun {
D(2)
}
fn pos_3(_stack: &mut NockStack) -> Noun {
D(3)
}
fn pos_4(_stack: &mut NockStack) -> Noun {
D(4)
}
#[test]
fn test_cap() {
@ -69,10 +144,16 @@ mod tests {
#[test]
fn test_mas() {
let c = &mut init_context();
let a63 = atom_63(&mut c.stack);
let a64 = atom_64(&mut c.stack);
let a65 = atom_65(&mut c.stack);
let a66 = atom_66(&mut c.stack);
// Test invalid input
assert_jet_err(c, jet_mas, D(0), JetErr::Fail(Error::Deterministic(D(0))));
assert_jet_err(c, jet_mas, D(1), JetErr::Fail(Error::Deterministic(D(0))));
// Test direct
assert_jet(c, jet_mas, D(2), D(1));
assert_jet(c, jet_mas, D(3), D(1));
assert_jet(c, jet_mas, D(4), D(2));
@ -80,5 +161,56 @@ mod tests {
assert_jet(c, jet_mas, D(6), D(2));
assert_jet(c, jet_mas, D(7), D(3));
assert_jet(c, jet_mas, D(8), D(4));
// Test indirect
assert_jet(c, jet_mas, a64, a63);
assert_jet(c, jet_mas, a65, a64);
assert_jet(c, jet_mas, a66, a65);
// Test allocation
assert_jet_size(c, jet_mas, D(2), 1_usize);
assert_jet_size(c, jet_mas, a65, 1_usize);
assert_jet_size(c, jet_mas, a66, 2_usize);
}
#[test]
fn test_peg() {
let c = &mut init_context();
assert_common_jet_err(
c,
jet_peg,
&[atom_0, atom_1],
JetErr::Fail(Error::Deterministic(D(0))),
);
assert_common_jet_err(
c,
jet_peg,
&[atom_1, atom_0],
JetErr::Fail(Error::Deterministic(D(0))),
);
// Test direct
assert_common_jet_noun(c, jet_peg, &[pos_2, pos_3], D(5));
assert_common_jet_noun(c, jet_peg, &[pos_4, pos_4], D(16));
// Test direct with overflow.
assert_common_jet_noun(c, jet_peg, &[atom_62, pos_3], D(DIRECT_MAX));
assert_common_jet(c, jet_peg, &[pos_2, atom_63], ubig!(0x8000000000000000));
// Test indirect.
assert_common_jet(c, jet_peg, &[atom_65, atom_1], ubig!(_0x10000000000000000));
assert_common_jet(c, jet_peg, &[atom_1, atom_65], ubig!(_0x10000000000000000));
assert_common_jet(
c,
jet_peg,
&[atom_65, atom_65],
ubig!(_0x100000000000000000000000000000000),
);
// Test allocation
assert_common_jet_size(c, jet_peg, &[atom_65, atom_1], 2_usize);
assert_common_jet_size(c, jet_peg, &[atom_1, atom_65], 2_usize);
assert_common_jet_size(c, jet_peg, &[atom_65, atom_65], 3_usize);
}
}