[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") => { tas!(b"sham") => {
let jet_formula = cell.tail().as_cell()?; let jet_formula = cell.tail().as_cell()?;
let jet = jets::get_jet(jet_formula.tail())?; let jet = jets::get_jet(jet_formula.tail())?;
return Ok(jet(stack, subject)); return Ok(jet(stack, subject)?); // Punt all errors to Nock
} }
_ => Err(()), _ => Err(()),
} }

View File

@ -4,7 +4,29 @@ use crate::noun::{DirectAtom, IndirectAtom, Noun};
use ares_macros::tas; use ares_macros::tas;
use either::Either::*; 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() { match jet_name.as_direct()?.data() {
tas!(b"dec") => Ok(jet_dec), tas!(b"dec") => Ok(jet_dec),
tas!(b"cut") => Ok(jet_cut), 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); let arg = raw_slot(subject, 6);
if let Ok(atom) = arg.as_atom() { if let Ok(atom) = arg.as_atom() {
match atom.as_either() { match atom.as_either() {
Left(direct) => { Left(direct) => {
if direct.data() == 0 { if direct.data() == 0 {
panic!("Decrementing 0"); Err(Deterministic)
} else { } else {
unsafe { DirectAtom::new_unchecked(direct.data() - 1) }.as_noun() Ok(unsafe { DirectAtom::new_unchecked(direct.data() - 1) }.as_noun())
} }
} }
Right(indirect) => { Right(indirect) => {
let indirect_slice = indirect.as_bitslice(); let indirect_slice = indirect.as_bitslice();
match indirect_slice.first_one() { match indirect_slice.first_one() {
None => { None => {
panic!("Decrementing 0"); panic!("Decrementing 0 stored as an indirect atom");
} }
Some(first_one) => { Some(first_one) => {
let (mut new_indirect, new_slice) = let (mut new_indirect, new_slice) =
@ -39,27 +61,30 @@ fn jet_dec(stack: &mut NockStack, subject: Noun) -> Noun {
new_slice[first_one + 1..] new_slice[first_one + 1..]
.copy_from_bitslice(&indirect_slice[first_one + 1..]); .copy_from_bitslice(&indirect_slice[first_one + 1..]);
let res = unsafe { new_indirect.normalize_as_atom() }; let res = unsafe { new_indirect.normalize_as_atom() };
res.as_noun() Ok(res.as_noun())
} }
} }
} }
} }
} else { } 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 arg = raw_slot(subject, 6);
let bloq = raw_slot(arg, 2).as_direct().unwrap().data(); let bloq = raw_slot(arg, 2).as_direct()?.data();
let start = raw_slot(arg, 12).as_direct().unwrap().data(); let start = raw_slot(arg, 12).as_direct()?.data();
let run = raw_slot(arg, 13).as_direct().unwrap().data(); let run = raw_slot(arg, 13).as_direct()?.data();
let atom = raw_slot(arg, 7).as_atom().unwrap(); let atom = raw_slot(arg, 7).as_atom()?;
let slice = atom.as_bitslice(); let slice = atom.as_bitslice();
let unit = 1 << bloq; let unit = 1 << bloq;
let (mut new_indirect, new_slice) = let new_indirect = unsafe {
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, ((run * unit + 63) >> 6) as usize) }; let (mut new_indirect, new_slice) =
new_slice[..(unit * run) as usize] IndirectAtom::new_raw_mut_bitslice(stack, ((run * unit + 63) >> 6) as usize);
.copy_from_bitslice(&slice[(unit * start) as usize..(unit * (start + run)) as usize]); new_slice[..(unit * run) as usize]
unsafe { new_indirect.normalize_as_atom().as_noun() } .copy_from_bitslice(&slice[(unit * start) as usize..(unit * (start + run)) as usize]);
new_indirect.normalize_as_atom()
};
Ok(new_indirect.as_noun())
} }