[ares] allow jets to fail

This commit is contained in:
Philip Monk 2023-02-13 16:55:27 -07:00
parent bb819abcc2
commit 9f3b4dd781
2 changed files with 43 additions and 18 deletions

View File

@ -632,7 +632,7 @@ fn match_pre_hint(stack: &mut NockStack, subject: Noun, cell: Cell) -> Result<No
tas!(b"sham") => {
let jet_formula = cell.tail().as_cell()?;
let jet = jets::get_jet(jet_formula.tail())?;
return Ok(jet(stack, subject));
return Ok(jet(stack, subject)?); // Punt all errors to Nock
}
_ => Err(()),
}

View File

@ -4,7 +4,29 @@ use crate::noun::{DirectAtom, IndirectAtom, Noun};
use ares_macros::tas;
use either::Either::*;
pub fn get_jet(jet_name: Noun) -> Result<fn(&mut NockStack, Noun) -> Noun, ()> {
/// Return Err if the computation crashed or should punt to Nock
pub type Jet = fn(&mut NockStack, Noun) -> Result<Noun, JetErr>;
/// Only return a deterministic error if the Nock would have deterministically crashed.
pub enum JetErr {
Punt, // Retry with the raw nock
Deterministic, // The Nock would have crashed
NonDeterministic, // Other error
}
impl From<()> for JetErr {
fn from(_: ()) -> Self {
JetErr::NonDeterministic
}
}
impl From<JetErr> for () {
fn from(_: JetErr) -> Self {}
}
use JetErr::*;
pub fn get_jet(jet_name: Noun) -> Result<Jet, ()> {
match jet_name.as_direct()?.data() {
tas!(b"dec") => Ok(jet_dec),
tas!(b"cut") => Ok(jet_cut),
@ -12,22 +34,22 @@ pub fn get_jet(jet_name: Noun) -> Result<fn(&mut NockStack, Noun) -> Noun, ()> {
}
}
fn jet_dec(stack: &mut NockStack, subject: Noun) -> Noun {
fn jet_dec(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
let arg = raw_slot(subject, 6);
if let Ok(atom) = arg.as_atom() {
match atom.as_either() {
Left(direct) => {
if direct.data() == 0 {
panic!("Decrementing 0");
Err(Deterministic)
} else {
unsafe { DirectAtom::new_unchecked(direct.data() - 1) }.as_noun()
Ok(unsafe { DirectAtom::new_unchecked(direct.data() - 1) }.as_noun())
}
}
Right(indirect) => {
let indirect_slice = indirect.as_bitslice();
match indirect_slice.first_one() {
None => {
panic!("Decrementing 0");
panic!("Decrementing 0 stored as an indirect atom");
}
Some(first_one) => {
let (mut new_indirect, new_slice) =
@ -39,27 +61,30 @@ fn jet_dec(stack: &mut NockStack, subject: Noun) -> Noun {
new_slice[first_one + 1..]
.copy_from_bitslice(&indirect_slice[first_one + 1..]);
let res = unsafe { new_indirect.normalize_as_atom() };
res.as_noun()
Ok(res.as_noun())
}
}
}
}
} else {
panic!("Argument to dec must be atom");
Err(Deterministic)
}
}
fn jet_cut(stack: &mut NockStack, subject: Noun) -> Noun {
fn jet_cut(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
let arg = raw_slot(subject, 6);
let bloq = raw_slot(arg, 2).as_direct().unwrap().data();
let start = raw_slot(arg, 12).as_direct().unwrap().data();
let run = raw_slot(arg, 13).as_direct().unwrap().data();
let atom = raw_slot(arg, 7).as_atom().unwrap();
let bloq = raw_slot(arg, 2).as_direct()?.data();
let start = raw_slot(arg, 12).as_direct()?.data();
let run = raw_slot(arg, 13).as_direct()?.data();
let atom = raw_slot(arg, 7).as_atom()?;
let slice = atom.as_bitslice();
let unit = 1 << bloq;
let new_indirect = unsafe {
let (mut new_indirect, new_slice) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, ((run * unit + 63) >> 6) as usize) };
IndirectAtom::new_raw_mut_bitslice(stack, ((run * unit + 63) >> 6) as usize);
new_slice[..(unit * run) as usize]
.copy_from_bitslice(&slice[(unit * start) as usize..(unit * (start + run)) as usize]);
unsafe { new_indirect.normalize_as_atom().as_noun() }
new_indirect.normalize_as_atom()
};
Ok(new_indirect.as_noun())
}