hoon, jets: add +mas

This commit is contained in:
Alex Shelkovnykov 2023-08-29 16:46:12 -06:00
parent 15656c1fe2
commit a90b23d263
7 changed files with 138 additions and 69 deletions

View File

@ -147,6 +147,17 @@
* $(a (div a 2)) * $(a (div a 2))
== ==
:: ::
++ mas :: axis within head/tail
~/ %mas
|= a=@
~> %sham.%mas
^- @
?- a
?(%2 %3) 1
?(%0 %1) !!
* (add (mod a 2) (mul $(a (div a 2)) 2))
==
::
:: List logic :: List logic
:: ::
++ flop :: reverse ++ flop :: reverse

4
rust/ares/Cargo.lock generated
View File

@ -230,9 +230,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "funty" name = "funty"

View File

@ -12,7 +12,7 @@ ibig = { path = "../ibig-rs" }
[dependencies] [dependencies]
ares_macros = { path = "../ares_macros" } ares_macros = { path = "../ares_macros" }
bitvec = "1.0.0" bitvec = "1.0.0"
either = "1.6.1" either = "1.9.0"
libc = "0.2.126" libc = "0.2.126"
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" } murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
memmap = "0.7.0" memmap = "0.7.0"

View File

@ -9,6 +9,7 @@ use crate::mem::NockStack;
use crate::newt::Newt; use crate::newt::Newt;
use crate::noun::{self, Noun, Slots}; use crate::noun::{self, Noun, Slots};
use ares_macros::tas; use ares_macros::tas;
use std::cmp;
crate::gdb!(); crate::gdb!();
@ -70,6 +71,7 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
tas!(b"rev") => Some(jet_rev), tas!(b"rev") => Some(jet_rev),
// //
tas!(b"cap") => Some(jet_cap), tas!(b"cap") => Some(jet_cap),
tas!(b"mas") => Some(jet_mas),
// //
tas!(b"mink") => Some(jet_mink), tas!(b"mink") => Some(jet_mink),
_ => { _ => {
@ -91,8 +93,10 @@ pub fn get_jet_test_mode(_jet_name: Noun) -> bool {
pub mod util { pub mod util {
use super::*; use super::*;
use crate::noun::{Atom, Noun, D}; use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D};
use crate::noun::Error::NotRepresentable;
use bitvec::prelude::{BitSlice, Lsb0}; use bitvec::prelude::{BitSlice, Lsb0};
use ibig::UBig;
use std::result; use std::result;
pub fn slot(noun: Noun, axis: u64) -> Result { pub fn slot(noun: Noun, axis: u64) -> Result {
@ -151,6 +155,58 @@ pub mod util {
Ok(()) Ok(())
} }
/** Subtraction */
pub fn sub(stack: &mut NockStack, a: Atom, b: Atom) -> noun::Result<Atom> {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
let a_small = a.data();
let b_small = b.data();
if a_small < b_small {
Err(NotRepresentable)
} else {
Ok(Atom::new(stack, a_small - b_small))
}
} else {
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
if a_big < b_big {
Err(NotRepresentable)
} else {
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::sub_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res))
}
}
}
/** Binary exponent */
pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
unsafe {
if arg < 63 {
DirectAtom::new_unchecked(1 << arg).as_atom()
} else {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
dest.set(arg, true);
atom.normalize_as_atom()
}
}
}
/** Binary OR */
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
let new_size = cmp::max(a.size(), b.size());
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest |= b.as_bitslice();
atom.normalize_as_atom()
}
}
/** Measure the number of bloqs in an atom */ /** Measure the number of bloqs in an atom */
pub fn met(bloq: usize, a: Atom) -> usize { pub fn met(bloq: usize, a: Atom) -> usize {
if unsafe { a.as_noun().raw_equals(D(0)) } { if unsafe { a.as_noun().raw_equals(D(0)) } {

View File

@ -14,12 +14,12 @@
*/ */
use crate::jets; use crate::jets;
use crate::jets::JetErr::*; use crate::jets::JetErr::*;
use crate::jets::util::{bite, chop, met, slot}; use crate::jets::util::*;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::mug::mug; use crate::mug::mug;
use crate::newt::Newt; use crate::newt::Newt;
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES}; use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES};
use either::Either::*; use either::{Left, Right};
use ibig::ops::DivRem; use ibig::ops::DivRem;
use ibig::UBig; use ibig::UBig;
use std::cmp; use std::cmp;
@ -96,24 +96,7 @@ pub fn jet_sub(
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()?;
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { Ok(sub(stack, a, b)?.as_noun())
if a.data() < b.data() {
Err(Deterministic)
} else {
Ok(unsafe { DirectAtom::new_unchecked(a.data() - b.data()) }.as_noun())
}
} else {
let a_int = a.as_ubig(stack);
let b_int = b.as_ubig(stack);
if a_int < b_int {
Err(Deterministic)
} else {
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::sub_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res).as_noun())
}
}
} }
pub fn jet_mul( pub fn jet_mul(
@ -329,16 +312,7 @@ pub fn jet_bex(
subject: Noun, subject: Noun,
) -> jets::Result { ) -> jets::Result {
let arg = slot(subject, 6)?.as_direct()?.data() as usize; let arg = slot(subject, 6)?.as_direct()?.data() as usize;
Ok(bex(stack, arg).as_noun())
if arg < 63 {
Ok(unsafe { DirectAtom::new_unchecked(1 << arg) }.as_noun())
} else {
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
dest.set(arg, true);
Ok(atom.normalize_as_atom().as_noun())
}
}
} }
pub fn jet_lsh( pub fn jet_lsh(
@ -410,15 +384,7 @@ pub fn jet_con(
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()?;
let new_size = cmp::max(a.size(), b.size()); Ok(con(stack, a, b).as_noun())
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest |= b.as_bitslice();
Ok(atom.normalize_as_atom().as_noun())
}
} }
pub fn jet_dis( pub fn jet_dis(

View File

@ -2,7 +2,7 @@
*/ */
use crate::jets; use crate::jets;
use crate::jets::JetErr::*; use crate::jets::JetErr::*;
use crate::jets::util::{met, slot}; use crate::jets::util::*;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::newt::Newt; use crate::newt::Newt;
use crate::noun::{Noun, D}; use crate::noun::{Noun, D};
@ -12,7 +12,7 @@ crate::gdb!();
pub fn jet_cap( pub fn jet_cap(
_stack: &mut NockStack, _stack: &mut NockStack,
_newt: &mut Option<&mut Newt>, _newt: &mut Option<&mut Newt>,
subject: Noun, subject: Noun
) -> jets::Result { ) -> jets::Result {
let arg = slot(subject, 6)?; let arg = slot(subject, 6)?;
let tom = arg.as_atom()?; let tom = arg.as_atom()?;
@ -29,6 +29,26 @@ pub fn jet_cap(
} }
} }
pub fn jet_mas(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let met = met(0, tom);
if met < 2 {
Err(Deterministic)
} 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())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -51,4 +71,20 @@ mod tests {
assert_jet(s, jet_cap, D(7), D(3)); assert_jet(s, jet_cap, D(7), D(3));
assert_jet(s, jet_cap, D(8), D(2)); assert_jet(s, jet_cap, D(8), D(2));
} }
#[test]
fn test_mas() {
let s = &mut init_stack();
assert_jet_err(s, jet_mas, D(0), JetErr::Deterministic);
assert_jet_err(s, jet_mas, D(1), JetErr::Deterministic);
assert_jet(s, jet_mas, D(2), D(1));
assert_jet(s, jet_mas, D(3), D(1));
assert_jet(s, jet_mas, D(4), D(2));
assert_jet(s, jet_mas, D(5), D(3));
assert_jet(s, jet_mas, D(6), D(2));
assert_jet(s, jet_mas, D(7), D(3));
assert_jet(s, jet_mas, D(8), D(4));
}
} }

View File

@ -1,6 +1,6 @@
use crate::mem::{word_size_of, NockStack}; use crate::mem::{word_size_of, NockStack};
use bitvec::prelude::{BitSlice, Lsb0}; use bitvec::prelude::{BitSlice, Lsb0};
use either::Either; use either::{Either, Left, Right};
use ibig::{Stack, UBig}; use ibig::{Stack, UBig};
use intmap::IntMap; use intmap::IntMap;
use std::fmt; use std::fmt;
@ -61,8 +61,8 @@ pub fn acyclic_noun(noun: Noun) -> bool {
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool { fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
match noun.as_either_atom_cell() { match noun.as_either_atom_cell() {
Either::Left(_atom) => true, Left(_atom) => true,
Either::Right(cell) => { Right(cell) => {
if seen.get(cell.0).is_some() { if seen.get(cell.0).is_some() {
false false
} else { } else {
@ -669,9 +669,9 @@ impl Atom {
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> { pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
if self.is_indirect() { if self.is_indirect() {
unsafe { Either::Right(self.indirect) } unsafe { Right(self.indirect) }
} else { } else {
unsafe { Either::Left(self.direct) } unsafe { Left(self.direct) }
} }
} }
@ -717,22 +717,22 @@ impl Atom {
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
match self.as_either() { match self.as_either() {
Either::Left(_direct) => 1, Left(_direct) => 1,
Either::Right(indirect) => indirect.size(), Right(indirect) => indirect.size(),
} }
} }
pub fn bit_size(&self) -> usize { pub fn bit_size(&self) -> usize {
match self.as_either() { match self.as_either() {
Either::Left(direct) => direct.bit_size(), Left(direct) => direct.bit_size(),
Either::Right(indirect) => indirect.bit_size(), Right(indirect) => indirect.bit_size(),
} }
} }
pub fn data_pointer(&self) -> *const u64 { pub fn data_pointer(&self) -> *const u64 {
match self.as_either() { match self.as_either() {
Either::Left(_direct) => (self as *const Atom) as *const u64, Left(_direct) => (self as *const Atom) as *const u64,
Either::Right(indirect) => indirect.data_pointer(), Right(indirect) => indirect.data_pointer(),
} }
} }
@ -787,8 +787,8 @@ impl Allocated {
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> { pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
match self.as_either() { match self.as_either() {
Either::Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()), Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
Either::Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()), Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
} }
} }
@ -802,9 +802,9 @@ impl Allocated {
pub fn as_either(&self) -> Either<IndirectAtom, Cell> { pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
if self.is_indirect() { if self.is_indirect() {
unsafe { Either::Left(self.indirect) } unsafe { Left(self.indirect) }
} else { } else {
unsafe { Either::Right(self.cell) } unsafe { Right(self.cell) }
} }
} }
@ -905,17 +905,17 @@ impl Noun {
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> { pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
if self.is_cell() { if self.is_cell() {
unsafe { Either::Right(self.cell) } unsafe { Right(self.cell) }
} else { } else {
unsafe { Either::Left(self.atom) } unsafe { Left(self.atom) }
} }
} }
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> { pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
if self.is_direct() { if self.is_direct() {
unsafe { Either::Left(self.direct) } unsafe { Left(self.direct) }
} else { } else {
unsafe { Either::Right(self.allocated) } unsafe { Right(self.allocated) }
} }
} }
@ -1013,8 +1013,8 @@ impl Noun {
if allocated.get_metadata() & (1 << 32) == 0 { if allocated.get_metadata() & (1 << 32) == 0 {
allocated.set_metadata(allocated.get_metadata() | (1 << 32)); allocated.set_metadata(allocated.get_metadata() | (1 << 32));
match allocated.as_either() { match allocated.as_either() {
Either::Left(indirect) => indirect.size() + 2, Left(indirect) => indirect.size() + 2,
Either::Right(cell) => { Right(cell) => {
word_size_of::<CellMemory>() word_size_of::<CellMemory>()
+ cell.head().mass_wind(inside) + cell.head().mass_wind(inside)
+ cell.tail().mass_wind(inside) + cell.tail().mass_wind(inside)
@ -1036,7 +1036,7 @@ impl Noun {
if let Ok(allocated) = self.as_allocated() { if let Ok(allocated) = self.as_allocated() {
if inside(allocated.to_raw_pointer()) { if inside(allocated.to_raw_pointer()) {
allocated.set_metadata(allocated.get_metadata() & !(1 << 32)); allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
if let Either::Right(cell) = allocated.as_either() { if let Right(cell) = allocated.as_either() {
cell.head().mass_unwind(inside); cell.head().mass_unwind(inside);
cell.tail().mass_unwind(inside); cell.tail().mass_unwind(inside);
} }
@ -1077,8 +1077,8 @@ impl Slots for Noun {}
impl private::RawSlots for Noun { impl private::RawSlots for Noun {
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> { fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
match self.as_either_atom_cell() { match self.as_either_atom_cell() {
Either::Right(cell) => cell.raw_slot(axis), Right(cell) => cell.raw_slot(axis),
Either::Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
} }
} }
} }