mirror of
https://github.com/urbit/ares.git
synced 2024-11-23 00:25:49 +03:00
hoon, jets: add +mas
This commit is contained in:
parent
15656c1fe2
commit
a90b23d263
@ -147,6 +147,17 @@
|
||||
* $(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
|
||||
::
|
||||
++ flop :: reverse
|
||||
|
4
rust/ares/Cargo.lock
generated
4
rust/ares/Cargo.lock
generated
@ -230,9 +230,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
|
@ -12,7 +12,7 @@ ibig = { path = "../ibig-rs" }
|
||||
[dependencies]
|
||||
ares_macros = { path = "../ares_macros" }
|
||||
bitvec = "1.0.0"
|
||||
either = "1.6.1"
|
||||
either = "1.9.0"
|
||||
libc = "0.2.126"
|
||||
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
|
||||
memmap = "0.7.0"
|
||||
|
@ -9,6 +9,7 @@ use crate::mem::NockStack;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{self, Noun, Slots};
|
||||
use ares_macros::tas;
|
||||
use std::cmp;
|
||||
|
||||
crate::gdb!();
|
||||
|
||||
@ -70,6 +71,7 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
|
||||
tas!(b"rev") => Some(jet_rev),
|
||||
//
|
||||
tas!(b"cap") => Some(jet_cap),
|
||||
tas!(b"mas") => Some(jet_mas),
|
||||
//
|
||||
tas!(b"mink") => Some(jet_mink),
|
||||
_ => {
|
||||
@ -91,8 +93,10 @@ pub fn get_jet_test_mode(_jet_name: Noun) -> bool {
|
||||
|
||||
pub mod util {
|
||||
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 ibig::UBig;
|
||||
use std::result;
|
||||
|
||||
pub fn slot(noun: Noun, axis: u64) -> Result {
|
||||
@ -151,6 +155,58 @@ pub mod util {
|
||||
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 */
|
||||
pub fn met(bloq: usize, a: Atom) -> usize {
|
||||
if unsafe { a.as_noun().raw_equals(D(0)) } {
|
||||
|
@ -14,12 +14,12 @@
|
||||
*/
|
||||
use crate::jets;
|
||||
use crate::jets::JetErr::*;
|
||||
use crate::jets::util::{bite, chop, met, slot};
|
||||
use crate::jets::util::*;
|
||||
use crate::mem::NockStack;
|
||||
use crate::mug::mug;
|
||||
use crate::newt::Newt;
|
||||
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::UBig;
|
||||
use std::cmp;
|
||||
@ -96,24 +96,7 @@ pub fn jet_sub(
|
||||
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()) {
|
||||
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())
|
||||
}
|
||||
}
|
||||
Ok(sub(stack, a, b)?.as_noun())
|
||||
}
|
||||
|
||||
pub fn jet_mul(
|
||||
@ -329,16 +312,7 @@ pub fn jet_bex(
|
||||
subject: Noun,
|
||||
) -> jets::Result {
|
||||
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
Ok(bex(stack, arg).as_noun())
|
||||
}
|
||||
|
||||
pub fn jet_lsh(
|
||||
@ -410,15 +384,7 @@ pub fn jet_con(
|
||||
let a = slot(arg, 2)?.as_atom()?;
|
||||
let b = slot(arg, 3)?.as_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();
|
||||
Ok(atom.normalize_as_atom().as_noun())
|
||||
}
|
||||
Ok(con(stack, a, b).as_noun())
|
||||
}
|
||||
|
||||
pub fn jet_dis(
|
||||
|
@ -2,7 +2,7 @@
|
||||
*/
|
||||
use crate::jets;
|
||||
use crate::jets::JetErr::*;
|
||||
use crate::jets::util::{met, slot};
|
||||
use crate::jets::util::*;
|
||||
use crate::mem::NockStack;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{Noun, D};
|
||||
@ -12,7 +12,7 @@ crate::gdb!();
|
||||
pub fn jet_cap(
|
||||
_stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
subject: Noun
|
||||
) -> jets::Result {
|
||||
let arg = slot(subject, 6)?;
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -51,4 +71,20 @@ mod tests {
|
||||
assert_jet(s, jet_cap, D(7), D(3));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::mem::{word_size_of, NockStack};
|
||||
use bitvec::prelude::{BitSlice, Lsb0};
|
||||
use either::Either;
|
||||
use either::{Either, Left, Right};
|
||||
use ibig::{Stack, UBig};
|
||||
use intmap::IntMap;
|
||||
use std::fmt;
|
||||
@ -61,8 +61,8 @@ pub fn acyclic_noun(noun: Noun) -> bool {
|
||||
|
||||
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
||||
match noun.as_either_atom_cell() {
|
||||
Either::Left(_atom) => true,
|
||||
Either::Right(cell) => {
|
||||
Left(_atom) => true,
|
||||
Right(cell) => {
|
||||
if seen.get(cell.0).is_some() {
|
||||
false
|
||||
} else {
|
||||
@ -669,9 +669,9 @@ impl Atom {
|
||||
|
||||
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
|
||||
if self.is_indirect() {
|
||||
unsafe { Either::Right(self.indirect) }
|
||||
unsafe { Right(self.indirect) }
|
||||
} else {
|
||||
unsafe { Either::Left(self.direct) }
|
||||
unsafe { Left(self.direct) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,22 +717,22 @@ impl Atom {
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
match self.as_either() {
|
||||
Either::Left(_direct) => 1,
|
||||
Either::Right(indirect) => indirect.size(),
|
||||
Left(_direct) => 1,
|
||||
Right(indirect) => indirect.size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bit_size(&self) -> usize {
|
||||
match self.as_either() {
|
||||
Either::Left(direct) => direct.bit_size(),
|
||||
Either::Right(indirect) => indirect.bit_size(),
|
||||
Left(direct) => direct.bit_size(),
|
||||
Right(indirect) => indirect.bit_size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_pointer(&self) -> *const u64 {
|
||||
match self.as_either() {
|
||||
Either::Left(_direct) => (self as *const Atom) as *const u64,
|
||||
Either::Right(indirect) => indirect.data_pointer(),
|
||||
Left(_direct) => (self as *const Atom) as *const u64,
|
||||
Right(indirect) => indirect.data_pointer(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,8 +787,8 @@ impl Allocated {
|
||||
|
||||
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
|
||||
match self.as_either() {
|
||||
Either::Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
|
||||
Either::Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
|
||||
Left(indirect) => indirect.forwarding_pointer().map(|i| i.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> {
|
||||
if self.is_indirect() {
|
||||
unsafe { Either::Left(self.indirect) }
|
||||
unsafe { Left(self.indirect) }
|
||||
} 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> {
|
||||
if self.is_cell() {
|
||||
unsafe { Either::Right(self.cell) }
|
||||
unsafe { Right(self.cell) }
|
||||
} else {
|
||||
unsafe { Either::Left(self.atom) }
|
||||
unsafe { Left(self.atom) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
|
||||
if self.is_direct() {
|
||||
unsafe { Either::Left(self.direct) }
|
||||
unsafe { Left(self.direct) }
|
||||
} else {
|
||||
unsafe { Either::Right(self.allocated) }
|
||||
unsafe { Right(self.allocated) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,8 +1013,8 @@ impl Noun {
|
||||
if allocated.get_metadata() & (1 << 32) == 0 {
|
||||
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
|
||||
match allocated.as_either() {
|
||||
Either::Left(indirect) => indirect.size() + 2,
|
||||
Either::Right(cell) => {
|
||||
Left(indirect) => indirect.size() + 2,
|
||||
Right(cell) => {
|
||||
word_size_of::<CellMemory>()
|
||||
+ cell.head().mass_wind(inside)
|
||||
+ cell.tail().mass_wind(inside)
|
||||
@ -1036,7 +1036,7 @@ impl Noun {
|
||||
if let Ok(allocated) = self.as_allocated() {
|
||||
if inside(allocated.to_raw_pointer()) {
|
||||
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.tail().mass_unwind(inside);
|
||||
}
|
||||
@ -1077,8 +1077,8 @@ impl Slots for Noun {}
|
||||
impl private::RawSlots for Noun {
|
||||
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
|
||||
match self.as_either_atom_cell() {
|
||||
Either::Right(cell) => cell.raw_slot(axis),
|
||||
Either::Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
|
||||
Right(cell) => cell.raw_slot(axis),
|
||||
Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user