Merge pull request #114 from urbit/msl/some-uts

Some `++ut` jets
This commit is contained in:
Edward Amsden 2023-11-15 06:25:42 -06:00 committed by GitHub
commit 66d51f555c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 238 additions and 12 deletions

View File

@ -6,6 +6,7 @@ pub mod bits;
pub mod form;
pub mod hash;
pub mod list;
pub mod lute;
pub mod math;
pub mod nock;
pub mod serial;

218
rust/ares/src/jets/lute.rs Normal file
View File

@ -0,0 +1,218 @@
/** ++ut jets (compiler backend and pretty-printer)
*/
use crate::interpreter::{interpret, Context};
use crate::jets::util::*;
use crate::jets::Result;
use crate::noun::{Noun, D, NO, NONE, T, YES};
use ares_macros::tas;
crate::gdb!();
pub fn jet_crop(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = 141 + tas!(b"crop") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_fish(context: &mut Context, subject: Noun) -> Result {
// axe must be Atom, though we use it as Noun
let axe = slot(subject, 6)?.as_atom()?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = 141 + tas!(b"fish") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = 141 + tas!(b"fuse") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?;
let gen = slot(subject, 13)?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let fun = 141 + tas!(b"mint");
let vet = slot(van, 59).map_or(NONE, |x| x);
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?;
let dox = slot(subject, 26)?;
let gen = slot(subject, 27)?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = 141 + tas!(b"mull") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_nest(context: &mut Context, subject: Noun) -> Result {
let nest_in_core = slot(subject, 3)?;
let seg = slot(nest_in_core, 12)?;
let reg = slot(nest_in_core, 26)?;
let nest_core = slot(nest_in_core, 7)?;
let rff = slot(nest_core, 13)?;
let van = slot(nest_core, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = (141 + tas!(b"dext")) + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) }
|| unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) }
{
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
}
Ok(pro)
}
}
}
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
let leg = slot(subject, 6)?;
let van = slot(subject, 7)?;
let bat = slot(van, 2)?;
let sut = slot(van, 6)?;
let flag = if let Ok(noun) = slot(van, 59) {
if unsafe { noun.raw_equals(D(0)) } {
0u64
} else {
1u64
}
} else {
1
};
let fun = 141 + tas!(b"rest") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat]);
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}

View File

@ -51,18 +51,19 @@ pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
Err(error) => match error {
Error::NonDeterministic(_) => Err(JetErr::Fail(error)),
Error::ScryCrashed(trace) => {
// When we enter a +mink call, we record what the scry handler stack looked like on
// entry. Each scry pulls the scry handler off the top of the scry handler stack and
// and calls interpret() with the remainder of the scry handler stack. When a scry
// succeeds, it replaces the scry handler it used at the top of the stack. However,
// it never does so when it fails. Therefore, we can tell which particular
// virtualization instance failed if the scry handler stack at the time of failure
// is identical to the scry handler stack on entry to the +mink call. Therefore,
// when a virtual nock call returns ScryCrashed, mink compares the root of the scry
// handler stack currently in the context object with the one that was on the stack
// when the mink call was initiated. If they match, it's this mink call that crashed
// so convert the Error::ScryCrashed into a Error::Deterministic. Otherwise, pass
// the Error::ScryCrashed up to the senior virtualizer.
// When we enter a +mink call, we record the state of the scry handler stack at the
// time (i.e. the Noun representing (list scry)). Each scry will pop the head off of
// this scry handler stack and calls interpret(), using the rest of the scry handler
// stack in the event that it scries again recursively. When a scry succeeds, it
// replaces the scry handler that it used by pushing it back onto the top of the
// scry handler stack. However, it never does so when it fails. Therefore, we can
// tell which particular virtualization instance failed by comparing the scry
// handler stack at the time of failure (i.e. the scry handler stack in the context
// after a failed scry) with the scry handler stack at the time of the virtualization
// call. Thus, whenever a virtualized interpret() call fails with a
// Error::ScryCrashed, jet_mink() compares the two scry handler stack Nouns> If they
// are identical, jet_mink() bails with Error::Deterministic. Otherwise, it forwards
// the Error::ScryCrashed to the senior virtualization call.
if unsafe { context.scry_stack.raw_equals(old_scry_stack) } {
Err(JetErr::Fail(Error::Deterministic(trace)))
} else {

View File

@ -1,4 +1,5 @@
use crate::mem::{word_size_of, NockStack};
use ares_macros::tas;
use bitvec::prelude::{BitSlice, Lsb0};
use either::{Either, Left, Right};
use ibig::{Stack, UBig};
@ -39,6 +40,7 @@ const FORWARDING_MASK: u64 = CELL_MASK;
/** Loobeans */
pub const YES: Noun = D(0);
pub const NO: Noun = D(1);
pub const NONE: Noun = unsafe { DirectAtom::new_unchecked(tas!(b"MORMAGIC")).as_noun() };
#[cfg(feature = "check_acyclic")]
#[macro_export]
@ -916,6 +918,10 @@ pub union Noun {
}
impl Noun {
pub fn is_none(self) -> bool {
unsafe { self.raw == u64::MAX }
}
pub fn is_direct(&self) -> bool {
unsafe { is_direct_atom(self.raw) }
}