diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index c10fb84..58aaa98 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -13,6 +13,7 @@ use crate::newt::Newt; use crate::noun; use crate::noun::{Atom, Cell, IndirectAtom, Noun, Slots, D, T}; use crate::serf::TERMINATOR; +use ares_macros::tas; use assert_no_alloc::assert_no_alloc; use bitvec::prelude::{BitSlice, Lsb0}; use either::Either::*; @@ -215,6 +216,20 @@ struct Nock11S { tail: bool, } +#[derive(Copy, Clone)] +enum Todo12 { + ComputeReff, + ComputePath, + Scry, +} + +#[derive(Copy, Clone)] +struct Nock12 { + todo: Todo12, + reff: Noun, + path: Noun, +} + #[derive(Copy, Clone)] enum NockWork { Done, @@ -233,55 +248,39 @@ enum NockWork { Work10(Nock10), Work11D(Nock11D), Work11S(Nock11S), + Work12(Nock12), } -pub struct Context<'a> { - pub stack: &'a mut NockStack, +pub struct Context { + pub stack: NockStack, // For printing slogs; if None, print to stdout; Option slated to be removed - pub newt: Option<&'a mut Newt>, - // Per-event cache; option to share cache with virtualized events - pub cache: &'a mut Hamt, + pub newt: Newt, + pub cold: Cold, + pub warm: Warm, + pub hot: Hot, // XX: persistent memo cache - pub cold: &'a mut Cold, - pub warm: &'a mut Warm, - pub hot: &'a Hot, + // Per-event cache; option to share cache with virtualized events + pub cache: Hamt, + pub scry_stack: Noun, } -#[derive(Debug)] -pub enum Tone { - Blocked(Noun), - Error(NockErr, Noun), +#[derive(Clone, Copy, Debug)] +pub enum Error { + ScryBlocked(Noun), // path + ScryCrashed(Noun), // trace + Deterministic(Noun), // trace + NonDeterministic(Noun), // trace } -#[derive(Debug)] -pub enum NockErr { - Deterministic, - NonDeterministic, -} - -impl From for () { - fn from(_: NockErr) -> Self {} -} - -impl From for NockErr { +impl From for Error { fn from(_: noun::Error) -> Self { - NockErr::Deterministic + Error::Deterministic(D(0)) } } -impl From for NockErr { +impl From for Error { fn from(_: cold::Error) -> Self { - NockErr::Deterministic - } -} - -impl From for NockErr { - fn from(e: JetErr) -> Self { - match e { - JetErr::Deterministic => NockErr::Deterministic, - JetErr::NonDeterministic => NockErr::NonDeterministic, - JetErr::Punt => panic!("unhandled JetErr::Punt"), - } + Error::Deterministic(D(0)) } } @@ -293,7 +292,7 @@ fn debug_assertions(stack: &mut NockStack, noun: Noun) { } /** Interpret nock */ -pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result { +pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Result { let terminator = Arc::clone(&TERMINATOR); let orig_subject = subject; // for debugging let virtual_frame: *const u64 = context.stack.get_frame_pointer(); @@ -304,7 +303,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.frame_push(1); // Bottom of mean stack *(context.stack.local_noun_pointer(0)) = D(0); - *context.stack.push() = NockWork::Done; + *(context.stack.push()) = NockWork::Done; }; // DO NOT REMOVE THIS ASSERTION @@ -319,56 +318,61 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res // // (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use) let nock = assert_no_alloc(|| unsafe { - push_formula(context.stack, formula, true)?; + push_formula(&mut context.stack, formula, true)?; loop { let work: NockWork = *context.stack.top(); match work { NockWork::Done => { - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + let stack = &mut context.stack; - context.stack.preserve(context.cache); - context.stack.preserve(context.cold); - context.stack.preserve(context.warm); - context.stack.preserve(&mut res); - context.stack.frame_pop(); + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, res); + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); break Ok(res); } NockWork::Ret => { - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + let stack = &mut context.stack; - context.stack.preserve(context.cache); - context.stack.preserve(context.cold); - context.stack.preserve(context.warm); - context.stack.preserve(&mut res); - context.stack.frame_pop(); + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, res); + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); } NockWork::WorkCons(mut cons) => match cons.todo { TodoCons::ComputeHead => { cons.todo = TodoCons::ComputeTail; *context.stack.top() = NockWork::WorkCons(cons); - push_formula(context.stack, cons.head, false)?; + push_formula(&mut context.stack, cons.head, false)?; } TodoCons::ComputeTail => { cons.todo = TodoCons::Cons; cons.head = res; *context.stack.top() = NockWork::WorkCons(cons); - push_formula(context.stack, cons.tail, false)?; + push_formula(&mut context.stack, cons.tail, false)?; } TodoCons::Cons => { - res = T(context.stack, &[cons.head, res]); - context.stack.pop::(); + let stack = &mut context.stack; + res = T(stack, &[cons.head, res]); + stack.pop::(); } }, NockWork::Work0(zero) => { @@ -377,7 +381,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.pop::(); } else { // Axis invalid for input Noun - break Err(NockErr::Deterministic); + break Err(Error::Deterministic(D(0))); } } NockWork::Work1(once) => { @@ -386,65 +390,70 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res } NockWork::Work2(mut vale) => { if (*terminator).load(Ordering::Relaxed) { - break Err(NockErr::NonDeterministic); + break Err(Error::NonDeterministic(D(0))); } match vale.todo { Todo2::ComputeSubject => { vale.todo = Todo2::ComputeFormula; *context.stack.top() = NockWork::Work2(vale); - push_formula(context.stack, vale.subject, false)?; + push_formula(&mut context.stack, vale.subject, false)?; } Todo2::ComputeFormula => { vale.todo = Todo2::ComputeResult; vale.subject = res; *context.stack.top() = NockWork::Work2(vale); - push_formula(context.stack, vale.formula, false)?; + push_formula(&mut context.stack, vale.formula, false)?; } Todo2::ComputeResult => { - if let Some(jet) = - context - .warm - .find_jet(context.stack, &mut vale.subject, &mut res) - { - match jet(context, vale.subject) { - Ok(jet_res) => { - res = jet_res; - context.stack.pop::(); - continue; - } - Err(JetErr::Punt) => {} - Err(err) => { - break Err(err.into()); + if !cfg!(feature = "sham_hints") { + if let Some(jet) = context.warm.find_jet( + &mut context.stack, + &mut vale.subject, + &mut res, + ) { + match jet(context, vale.subject) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } } } }; + let stack = &mut context.stack; if vale.tail { - context.stack.pop::(); + stack.pop::(); subject = vale.subject; - push_formula(context.stack, res, true)?; + push_formula(stack, res, true)?; } else { vale.todo = Todo2::RestoreSubject; std::mem::swap(&mut vale.subject, &mut subject); - *context.stack.top() = NockWork::Work2(vale); + *stack.top() = NockWork::Work2(vale); - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); - mean_frame_push(context.stack, 0); - *context.stack.push() = NockWork::Ret; - push_formula(context.stack, res, true)?; + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, res, true)?; } } Todo2::RestoreSubject => { - subject = vale.subject; - context.stack.pop::(); + let stack = &mut context.stack; - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + subject = vale.subject; + stack.pop::(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); } } } @@ -452,7 +461,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo3::ComputeChild => { thee.todo = Todo3::ComputeType; *context.stack.top() = NockWork::Work3(thee); - push_formula(context.stack, thee.child, false)?; + push_formula(&mut context.stack, thee.child, false)?; } Todo3::ComputeType => { res = if res.is_cell() { D(0) } else { D(1) }; @@ -463,15 +472,15 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo4::ComputeChild => { four.todo = Todo4::Increment; *context.stack.top() = NockWork::Work4(four); - push_formula(context.stack, four.child, false)?; + push_formula(&mut context.stack, four.child, false)?; } Todo4::Increment => { if let Ok(atom) = res.as_atom() { - res = inc(context.stack, atom).as_noun(); + res = inc(&mut context.stack, atom).as_noun(); context.stack.pop::(); } else { // Cannot increment (Nock 4) a cell - break Err(NockErr::Deterministic); + break Err(Error::Deterministic(D(0))); } } }, @@ -479,44 +488,46 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo5::ComputeLeftChild => { five.todo = Todo5::ComputeRightChild; *context.stack.top() = NockWork::Work5(five); - push_formula(context.stack, five.left, false)?; + push_formula(&mut context.stack, five.left, false)?; } Todo5::ComputeRightChild => { five.todo = Todo5::TestEquals; five.left = res; *context.stack.top() = NockWork::Work5(five); - push_formula(context.stack, five.right, false)?; + push_formula(&mut context.stack, five.right, false)?; } Todo5::TestEquals => { + let stack = &mut context.stack; let saved_value_ptr = &mut five.left; - res = if unifying_equality(context.stack, &mut res, saved_value_ptr) { + res = if unifying_equality(stack, &mut res, saved_value_ptr) { D(0) } else { D(1) }; - context.stack.pop::(); + stack.pop::(); } }, NockWork::Work6(mut cond) => match cond.todo { Todo6::ComputeTest => { cond.todo = Todo6::ComputeBranch; *context.stack.top() = NockWork::Work6(cond); - push_formula(context.stack, cond.test, false)?; + push_formula(&mut context.stack, cond.test, false)?; } Todo6::ComputeBranch => { - context.stack.pop::(); + let stack = &mut context.stack; + stack.pop::(); if let Left(direct) = res.as_either_direct_allocated() { if direct.data() == 0 { - push_formula(context.stack, cond.zero, cond.tail)?; + push_formula(stack, cond.zero, cond.tail)?; } else if direct.data() == 1 { - push_formula(context.stack, cond.once, cond.tail)?; + push_formula(stack, cond.once, cond.tail)?; } else { // Test branch of Nock 6 must return 0 or 1 - break Err(NockErr::Deterministic); + break Err(Error::Deterministic(D(0))); } } else { // Test branch of Nock 6 must return a direct atom - break Err(NockErr::Deterministic); + break Err(Error::Deterministic(D(0))); } } }, @@ -524,19 +535,20 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo7::ComputeSubject => { pose.todo = Todo7::ComputeResult; *context.stack.top() = NockWork::Work7(pose); - push_formula(context.stack, pose.subject, false)?; + push_formula(&mut context.stack, pose.subject, false)?; } Todo7::ComputeResult => { + let stack = &mut context.stack; if pose.tail { - context.stack.pop::(); + stack.pop::(); subject = res; - push_formula(context.stack, pose.formula, true)?; + push_formula(stack, pose.formula, true)?; } else { pose.todo = Todo7::RestoreSubject; pose.subject = subject; - *context.stack.top() = NockWork::Work7(pose); + *stack.top() = NockWork::Work7(pose); subject = res; - push_formula(context.stack, pose.formula, false)?; + push_formula(stack, pose.formula, false)?; } } Todo7::RestoreSubject => { @@ -548,19 +560,20 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo8::ComputeSubject => { pins.todo = Todo8::ComputeResult; *context.stack.top() = NockWork::Work8(pins); - push_formula(context.stack, pins.pin, false)?; + push_formula(&mut context.stack, pins.pin, false)?; } Todo8::ComputeResult => { + let stack = &mut context.stack; if pins.tail { - subject = T(context.stack, &[res, subject]); - context.stack.pop::(); - push_formula(context.stack, pins.formula, true)?; + subject = T(stack, &[res, subject]); + stack.pop::(); + push_formula(stack, pins.formula, true)?; } else { pins.todo = Todo8::RestoreSubject; pins.pin = subject; - *context.stack.top() = NockWork::Work8(pins); - subject = T(context.stack, &[res, subject]); - push_formula(context.stack, pins.formula, false)?; + *stack.top() = NockWork::Work8(pins); + subject = T(stack, &[res, subject]); + push_formula(stack, pins.formula, false)?; } } Todo8::RestoreSubject => { @@ -570,63 +583,70 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res }, NockWork::Work9(mut kale) => { if (*terminator).load(Ordering::Relaxed) { - break Err(NockErr::NonDeterministic); + break Err(Error::NonDeterministic(D(0))); } match kale.todo { Todo9::ComputeCore => { kale.todo = Todo9::ComputeResult; *context.stack.top() = NockWork::Work9(kale); - push_formula(context.stack, kale.core, false)?; + push_formula(&mut context.stack, kale.core, false)?; } Todo9::ComputeResult => { if let Ok(mut formula) = res.slot_atom(kale.axis) { - if let Some(jet) = - context.warm.find_jet(context.stack, &mut res, &mut formula) - { - match jet(context, res) { - Ok(jet_res) => { - res = jet_res; - context.stack.pop::(); - continue; - } - Err(JetErr::Punt) => {} - Err(err) => { - break Err(err.into()); + if !cfg!(feature = "sham_hints") { + if let Some(jet) = context.warm.find_jet( + &mut context.stack, + &mut res, + &mut formula, + ) { + match jet(context, res) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } } } }; + let stack = &mut context.stack; if kale.tail { - context.stack.pop::(); + stack.pop::(); subject = res; - push_formula(context.stack, formula, true)?; + push_formula(stack, formula, true)?; } else { kale.todo = Todo9::RestoreSubject; kale.core = subject; - *context.stack.top() = NockWork::Work9(kale); + *stack.top() = NockWork::Work9(kale); - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); subject = res; - mean_frame_push(context.stack, 0); - *context.stack.push() = NockWork::Ret; - push_formula(context.stack, formula, true)?; + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, formula, true)?; } } else { // Axis into core must be atom - break Err(NockErr::Deterministic); + break Err(Error::Deterministic(D(0))); } } Todo9::RestoreSubject => { - subject = kale.core; - context.stack.pop::(); + let stack = &mut context.stack; - debug_assertions(context.stack, orig_subject); - debug_assertions(context.stack, subject); - debug_assertions(context.stack, res); + subject = kale.core; + stack.pop::(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); } } } @@ -635,16 +655,16 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Todo10::ComputeTree => { diet.todo = Todo10::ComputePatch; // should we compute patch then tree? *context.stack.top() = NockWork::Work10(diet); - push_formula(context.stack, diet.tree, false)?; + push_formula(&mut context.stack, diet.tree, false)?; } Todo10::ComputePatch => { diet.todo = Todo10::Edit; diet.tree = res; *context.stack.top() = NockWork::Work10(diet); - push_formula(context.stack, diet.patch, false)?; + push_formula(&mut context.stack, diet.patch, false)?; } Todo10::Edit => { - res = edit(context.stack, diet.axis.as_bitslice(), res, diet.tree); + res = edit(&mut context.stack, diet.axis.as_bitslice(), res, diet.tree); context.stack.pop::(); } } @@ -660,7 +680,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res Ok(None) => { dint.todo = Todo11D::ComputeResult; *context.stack.top() = NockWork::Work11D(dint); - push_formula(context.stack, dint.hint, false)?; + push_formula(&mut context.stack, dint.hint, false)?; } Err(err) => { break Err(err); @@ -687,7 +707,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res dint.hint = res; *context.stack.top() = NockWork::Work11D(dint); } - push_formula(context.stack, dint.body, dint.tail)?; + push_formula(&mut context.stack, dint.body, dint.tail)?; } Err(err) => { break Err(err); @@ -724,7 +744,7 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res sint.todo = Todo11S::Done; *context.stack.top() = NockWork::Work11S(sint); } - push_formula(context.stack, sint.body, sint.tail)?; + push_formula(&mut context.stack, sint.body, sint.tail)?; } Err(err) => { break Err(err); @@ -742,17 +762,94 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res context.stack.pop::(); } }, + NockWork::Work12(mut scry) => match scry.todo { + Todo12::ComputeReff => { + let stack = &mut context.stack; + scry.todo = Todo12::ComputePath; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.reff, false)?; + } + Todo12::ComputePath => { + let stack = &mut context.stack; + scry.todo = Todo12::Scry; + scry.reff = res; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.path, false)?; + } + Todo12::Scry => { + if let Some(cell) = context.scry_stack.cell() { + scry.path = res; + let scry_stack = context.scry_stack; + let scry_handler = cell.head(); + let scry_gate = scry_handler.as_cell()?; + let payload = T(&mut context.stack, &[scry.reff, res]); + let scry_core = T( + &mut context.stack, + &[ + scry_gate.head(), + payload, + scry_gate.tail().as_cell()?.tail(), + ], + ); + let scry_form = T(&mut context.stack, &[D(9), D(2), D(1), scry_core]); + + context.scry_stack = cell.tail(); + // Alternately, we could use scry_core as the subject and [9 2 0 1] as + // the formula. It's unclear if performance will be better with a purely + // static formula. + match interpret(context, D(0), scry_form) { + Ok(noun) => match noun.as_either_atom_cell() { + Left(atom) => { + if atom.as_noun().raw_equals(D(0)) { + break Err(Error::ScryBlocked(scry.path)); + } else { + break Err(Error::ScryCrashed(D(0))); + } + } + Right(cell) => match cell.tail().as_either_atom_cell() { + Left(_) => { + let stack = &mut context.stack; + let hunk = + T(stack, &[D(tas!(b"hunk")), scry.reff, scry.path]); + mean_push(stack, hunk); + break Err(Error::ScryCrashed(D(0))); + } + Right(cell) => { + res = cell.tail(); + context.scry_stack = scry_stack; + context.stack.pop::(); + } + }, + }, + Err(error) => match error { + Error::Deterministic(trace) | Error::ScryCrashed(trace) => { + break Err(Error::ScryCrashed(trace)); + } + Error::NonDeterministic(_) => { + break Err(error); + } + Error::ScryBlocked(_) => { + break Err(Error::NonDeterministic(D(0))); + } + }, + } + } else { + // No scry handler + break Err(Error::Deterministic(D(0))); + } + } + }, }; } }); match nock { Ok(res) => Ok(res), - Err(err) => Err(exit_early(context.stack, context.cache, virtual_frame, err)), + Err(err) => Err(exit(context, virtual_frame, err)), } } -fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), NockErr> { +fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), Error> { unsafe { if let Ok(formula_cell) = formula.as_cell() { // Formula @@ -772,7 +869,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), *stack.push() = NockWork::Work0(Nock0 { axis: axis_atom }); } else { // Axis for Nock 0 must be an atom - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } 1 => { @@ -790,7 +887,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Argument to Nock 2 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 3 => { @@ -814,7 +911,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Argument to Nock 5 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 6 => { @@ -829,11 +926,11 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Argument tail to Nock 6 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } else { // Argument to Nock 6 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } 7 => { @@ -846,7 +943,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Argument to Nock 7 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 8 => { @@ -859,7 +956,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Argument to Nock 8 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 9 => { @@ -873,11 +970,11 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Axis for Nock 9 must be an atom - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } else { // Argument to Nock 9 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 10 => { @@ -892,15 +989,15 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Axis for Nock 10 must be an atom - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } else { // Heah of argument to Nock 10 must be a cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } else { // Argument to Nock 10 must be a cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } 11 => { @@ -925,48 +1022,70 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(), }); } else { // Hint tag must be an atom - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } }; } else { // Argument for Nock 11 must be cell - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); }; } + 12 => { + if let Ok(arg_cell) = formula_cell.tail().as_cell() { + *stack.push() = NockWork::Work12(Nock12 { + todo: Todo12::ComputeReff, + reff: arg_cell.head(), + path: arg_cell.tail(), + }); + } else { + // Argument for Nock 12 must be cell + return Err(Error::Deterministic(D(0))); + } + } _ => { // Invalid formula opcode - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } } else { // Formula opcode must be direct atom - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } } } else { // Bad formula: atoms are not formulas - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } } Ok(()) } -pub fn exit_early( - stack: &mut NockStack, - cache: &mut Hamt, - virtual_frame: *const u64, - error: NockErr, -) -> Tone { +pub fn exit(context: &mut Context, virtual_frame: *const u64, error: Error) -> Error { unsafe { - let mut trace = *(stack.local_noun_pointer(0)); - while stack.get_frame_pointer() != virtual_frame { - stack.preserve(&mut trace); - stack.preserve(cache); - stack.frame_pop(); + let stack = &mut context.stack; + + let mut preserve = match error { + Error::ScryBlocked(path) => path, + Error::Deterministic(t) | Error::NonDeterministic(t) | Error::ScryCrashed(t) => { + // Return $tang of traces + let h = *(stack.local_noun_pointer(0)); + T(stack, &[h, t]) + } + }; + + while (stack).get_frame_pointer() != virtual_frame { + (stack).preserve(&mut preserve); + (stack).frame_pop(); + } + + match error { + Error::Deterministic(_) => Error::Deterministic(preserve), + Error::NonDeterministic(_) => Error::NonDeterministic(preserve), + Error::ScryCrashed(_) => Error::ScryCrashed(preserve), + Error::ScryBlocked(_) => error, } - Tone::Error(error, trace) } } @@ -1103,7 +1222,7 @@ mod hint { tag: Atom, hint: Noun, body: Noun, - ) -> Result, NockErr> { + ) -> Result, Error> { // XX: handle IndirectAtom tags match tag.as_direct()?.data() { tas!(b"sham") => { @@ -1136,29 +1255,32 @@ mod hint { "\rjet {} failed, raw: {:?}, jetted: {}", jet_name, nock_res, jet_res ); - let tape = tape(*stack, "jet mismatch"); - let mean = T(*stack, &[D(tas!(b"mean")), tape]); + let tape = tape(stack, "jet mismatch"); + let mean = T(stack, &[D(tas!(b"mean")), tape]); mean_push(stack, mean); - Err(NockErr::Deterministic) + Err(Error::Deterministic(D(0))) } else { Ok(Some(nock_res)) } } - Err(Tone::Error(err, _)) => { + Err(error) => { let stack = &mut context.stack; // XX: need string interpolation without allocation, then delete eprintln // let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, err, jet_res); eprintln!( "\rjet {} failed, raw: {:?}, jetted: {}", - jet_name, err, jet_res + jet_name, error, jet_res ); - let tape = tape(*stack, "jet mismatch"); - let mean = T(*stack, &[D(tas!(b"mean")), tape]); + let tape = tape(stack, "jet mismatch"); + let mean = T(stack, &[D(tas!(b"mean")), tape]); mean_push(stack, mean); - Err(err) - } - Err(Tone::Blocked(_)) => { - panic!("jet test mode: no scry handling") + + match error { + Error::NonDeterministic(_) => { + Err(Error::NonDeterministic(D(0))) + } + _ => Err(Error::Deterministic(D(0))), + } } } } else { @@ -1170,8 +1292,8 @@ mod hint { let stack = &mut context.stack; // XX: need string interpolation without allocation // let tape = tape(stack, "{} jet error in {}", err, jet_name); - let tape = tape(*stack, "jet error"); - let mean = T(*stack, &[D(tas!(b"mean")), tape]); + let tape = tape(stack, "jet error"); + let mean = T(stack, &[D(tas!(b"mean")), tape]); mean_push(stack, mean); Err(err.into()) } @@ -1185,7 +1307,7 @@ mod hint { } tas!(b"memo") => { let stack = &mut context.stack; - let mut key = Cell::new(*stack, subject, body).as_noun(); + let mut key = Cell::new(stack, subject, body).as_noun(); Ok(context.cache.lookup(stack, &mut key)) } _ => Ok(None), @@ -1199,45 +1321,50 @@ mod hint { tag: Atom, hint: Option<(Noun, Noun)>, _body: Noun, - ) -> Result, NockErr> { + ) -> Result, Error> { // XX: handle IndirectAtom tags match tag.as_direct()?.data() { tas!(b"slog") => { - let (_form, clue) = hint.ok_or(NockErr::Deterministic)?; + let stack = &mut context.stack; + let newt = &mut context.newt; + + let (_form, clue) = hint.ok_or(Error::Deterministic(D(0)))?; let slog_cell = clue.as_cell()?; let pri = slog_cell.head().as_direct()?.data(); let tank = slog_cell.tail(); - slog(context.stack, &mut context.newt, pri, tank); + newt.slog(stack, pri, tank); Ok(None) } tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { let terminator = Arc::clone(&TERMINATOR); if (*terminator).load(Ordering::Relaxed) { - return Err(NockErr::NonDeterministic); + return Err(Error::NonDeterministic(D(0))); } let stack = &mut context.stack; - let (_form, clue) = hint.ok_or(NockErr::Deterministic)?; - let noun = T(*stack, &[tag.as_noun(), clue]); + let (_form, clue) = hint.ok_or(Error::Deterministic(D(0)))?; + let noun = T(stack, &[tag.as_noun(), clue]); mean_push(stack, noun); Ok(None) } tas!(b"hela") => { - // XX: should this be virtualized? - // pretty sure we should be bailing on error - // might need to switch return type to Result, NockErr> + // XX: This only prints the trace down to the bottom of THIS + // interpret call. We'll need to recursively work down + // frames to get the stack trace all the way to the root. let mean = unsafe { *(context.stack.local_noun_pointer(0)) }; - let tone = Cell::new(context.stack, D(2), mean); + let tone = Cell::new(&mut context.stack, D(2), mean); match mook(context, tone, true) { Ok(toon) => { let stack = &mut context.stack; + let newt = &mut context.newt; + if unsafe { !toon.head().raw_equals(D(2)) } { - let tape = tape(*stack, "%hela failed: toon not %2"); - let mean = T(*stack, &[D(tas!(b"mean")), tape]); + let tape = tape(stack, "%hela failed: toon not %2"); + let mean = T(stack, &[D(tas!(b"mean")), tape]); mean_push(stack, mean); - return Err(NockErr::Deterministic); + return Err(Error::Deterministic(D(0))); } let mut list = toon.tail(); @@ -1247,7 +1374,7 @@ mod hint { } let cell = list.as_cell().unwrap(); - slog(stack, &mut context.newt, 0, cell.head()); + newt.slog(stack, 0, cell.head()); list = cell.tail(); } @@ -1256,8 +1383,8 @@ mod hint { } Err(err) => { let stack = &mut context.stack; - let tape = tape(*stack, "%hela failed: mook error"); - let mean = T(*stack, &[D(tas!(b"mean")), tape]); + let tape = tape(stack, "%hela failed: mook error"); + let mean = T(stack, &[D(tas!(b"mean")), tape]); mean_push(stack, mean); Err(err.into()) } @@ -1275,65 +1402,71 @@ mod hint { hint: Option, body: Noun, res: Noun, - ) -> Result, NockErr> { + ) -> Result, Error> { let stack = &mut context.stack; - let cache = &mut context.cache; let newt = &mut context.newt; + let cold = &mut context.cold; + let hot = &context.hot; + let cache = &mut context.cache; // XX: handle IndirectAtom tags match tag.as_direct()?.data() { tas!(b"memo") => { - let mut key = Cell::new(*stack, subject, body).as_noun(); - **cache = (*cache).insert(stack, &mut key, res); + let mut key = Cell::new(stack, subject, body).as_noun(); + context.cache = cache.insert(stack, &mut key, res); } tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { mean_pop(stack); } tas!(b"fast") => { - if let Some(clue) = hint { - let cold_res: cold::Result = { - let chum = clue.slot(2)?; - let parent_formula_op = clue.slot(12)?.as_atom()?.as_direct()?; - let parent_formula_ax = clue.slot(13)?.as_atom()?; + if !cfg!(feature = "sham_hints") { + if let Some(clue) = hint { + let cold_res: cold::Result = { + let chum = clue.slot(2)?; + let parent_formula_op = clue.slot(12)?.as_atom()?.as_direct()?; + let parent_formula_ax = clue.slot(13)?.as_atom()?; - if parent_formula_op.data() == 1 { - if parent_formula_ax.as_direct()?.data() == 0 { - context.cold.register(stack, res, parent_formula_ax, chum) + if parent_formula_op.data() == 1 { + if parent_formula_ax.as_direct()?.data() == 0 { + cold.register(stack, res, parent_formula_ax, chum) + } else { + // XX: Need better message in slog; need better slogging tools + // format!("invalid root parent axis: {} {}", chum, parent_formula_ax) + let tape = tape( + stack, + "serf: cold: register: invalid root parent axis", + ); + slog_leaf(stack, newt, tape); + Ok(false) + } } else { - // XX: Need better message in slog; need better slogging tools - // format!("invalid root parent axis: {} {}", chum, parent_formula_ax) - let tape = - tape(*stack, "serf: cold: register: invalid root parent axis"); - slog_leaf(stack, newt, tape); - Ok(false) + cold.register(stack, res, parent_formula_ax, chum) } - } else { - context.cold.register(stack, res, parent_formula_ax, chum) - } - }; + }; - match cold_res { - Ok(true) => *context.warm = Warm::init(stack, context.cold, context.hot), - Err(cold::Error::NoParent) => { - // XX: Need better message in slog; need better slogging tools - // format!("could not find parent battery at given axis: {} {}", chum, parent_formula_ax) - let tape = tape( - *stack, - "serf: cold: register: could not find parent battery at given axis", - ); - slog_leaf(stack, newt, tape); + match cold_res { + Ok(true) => context.warm = Warm::init(stack, cold, hot), + Err(cold::Error::NoParent) => { + // XX: Need better message in slog; need better slogging tools + // format!("could not find parent battery at given axis: {} {}", chum, parent_formula_ax) + let tape = tape( + stack, + "serf: cold: register: could not find parent battery at given axis", + ); + slog_leaf(stack, newt, tape); + } + Err(cold::Error::BadNock) => { + // XX: Need better message in slog; need better slogging tools + // format!("bad clue formula: {}", clue) + let tape = tape(stack, "serf: cold: register: bad clue formula"); + slog_leaf(stack, newt, tape); + } + _ => {} } - Err(cold::Error::BadNock) => { - // XX: Need better message in slog; need better slogging tools - // format!("bad clue formula: {}", clue) - let tape = tape(*stack, "serf: cold: register: bad clue formula"); - slog_leaf(stack, newt, tape); - } - _ => {} + } else { + let tape = tape(stack, "serf: cold: register: no clue for %fast"); + slog_leaf(stack, newt, tape); } - } else { - let tape = tape(*stack, "serf: cold: register: no clue for %fast"); - slog_leaf(stack, newt, tape); } } _ => {} @@ -1342,16 +1475,8 @@ mod hint { Ok(None) } - fn slog_leaf(stack: &mut NockStack, newt: &mut Option<&mut Newt>, tape: Noun) { + fn slog_leaf(stack: &mut NockStack, newt: &mut Newt, tape: Noun) { let tank = T(stack, &[LEAF, tape]); - slog(stack, newt, 0u64, tank); - } - - fn slog(stack: &mut NockStack, newt: &mut Option<&mut Newt>, pri: u64, tank: Noun) { - if newt.is_none() { - eprintln!("raw slog: {} {}", pri, tank); - } else { - newt.as_mut().unwrap().slog(stack, pri, tank); - } + newt.slog(stack, 0u64, tank); } } diff --git a/rust/ares/src/jets.rs b/rust/ares/src/jets.rs index d7e009c..b420a91 100644 --- a/rust/ares/src/jets.rs +++ b/rust/ares/src/jets.rs @@ -12,7 +12,7 @@ pub mod sort; pub mod text; pub mod tree; -use crate::interpreter::Context; +use crate::interpreter::{Context, Error}; use crate::jets::bits::*; use crate::jets::cold::Cold; use crate::jets::form::*; @@ -26,7 +26,8 @@ use crate::jets::text::*; use crate::jets::tree::*; use crate::jets::warm::Warm; use crate::mem::NockStack; -use crate::noun::{self, Noun, Slots}; +use crate::newt::Newt; +use crate::noun::{self, Noun, Slots, D}; use ares_macros::tas; use std::cmp; @@ -40,16 +41,15 @@ pub type Jet = fn(&mut Context, Noun) -> Result; * Only return a deterministic error if the Nock would have deterministically * crashed. */ -#[derive(Debug, PartialEq)] +#[derive(Clone, Copy, Debug)] pub enum JetErr { - Punt, // Retry with the raw nock - Deterministic, // The Nock would have crashed - NonDeterministic, // Other error + Punt, // Retry with the raw nock + Fail(Error), // Error; do not retry } impl From for JetErr { fn from(_err: noun::Error) -> Self { - Self::Deterministic + Self::Fail(Error::Deterministic(D(0))) } } @@ -57,6 +57,15 @@ impl From for () { fn from(_: JetErr) -> Self {} } +impl From for Error { + fn from(e: JetErr) -> Self { + match e { + JetErr::Fail(f) => f, + JetErr::Punt => panic!("unhandled JetErr::Punt"), + } + } +} + pub fn get_jet(jet_name: Noun) -> Option { match jet_name.as_direct().ok()?.data() { tas!(b"add") => Some(jet_add), @@ -139,12 +148,13 @@ pub mod util { pub fn checked_add(a: usize, b: usize) -> result::Result { a.checked_add(b) .filter(|x| x <= &MAX_BIT_LENGTH) - .ok_or(JetErr::NonDeterministic) + .ok_or(JetErr::Fail(Error::NonDeterministic(D(0)))) } /// Performs addition that returns None on Noun size overflow pub fn checked_sub(a: usize, b: usize) -> result::Result { - a.checked_sub(b).ok_or(JetErr::NonDeterministic) + a.checked_sub(b) + .ok_or(JetErr::Fail(Error::NonDeterministic(D(0)))) } pub fn checked_left_shift(bloq: usize, a: usize) -> result::Result { @@ -152,7 +162,7 @@ pub mod util { // Catch overflow if (res >> bloq) < a || res > MAX_BIT_LENGTH { - Err(JetErr::NonDeterministic) + Err(JetErr::Fail(Error::NonDeterministic(D(0)))) } else { Ok(res) } @@ -169,14 +179,15 @@ pub mod util { } pub fn slot(noun: Noun, axis: u64) -> Result { - noun.slot(axis).map_err(|_e| JetErr::Deterministic) + noun.slot(axis) + .map_err(|_e| JetErr::Fail(Error::Deterministic(D(0)))) } /// Extract a bloq and check that it's computable by the current system pub fn bloq(a: Noun) -> result::Result { let bloq = a.as_direct()?.data() as usize; if bloq >= 47 { - Err(JetErr::NonDeterministic) + Err(JetErr::Fail(Error::NonDeterministic(D(0)))) } else { Ok(bloq) } @@ -311,8 +322,23 @@ pub mod util { use assert_no_alloc::assert_no_alloc; use ibig::UBig; - pub fn init_stack() -> NockStack { - NockStack::new(8 << 10 << 10, 0) + pub fn init_context() -> Context { + let mut stack = NockStack::new(8 << 10 << 10, 0); + let newt = Newt::new_mock(); + let cold = Cold::new(&mut stack); + let warm = Warm::new(); + let hot = Hot::init(&mut stack); + let cache = Hamt::::new(); + + Context { + stack, + newt, + cold, + warm, + hot, + cache, + scry_stack: D(0), + } } #[allow(non_snake_case)] @@ -325,51 +351,25 @@ pub mod util { assert!(eq, "got: {}, need: {}", a, b); } - pub fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) { - // XX: consider making a mock context singleton that tests can use - let mut cache = Hamt::::new(); - let mut cold = Cold::new(stack); - let mut warm = Warm::new(); - let hot = Hot::init(stack); - let mut context = Context { - stack, - newt: None, - cache: &mut cache, - cold: &mut cold, - warm: &mut warm, - hot: &hot, - }; - let sam = T(context.stack, &[D(0), sam, D(0)]); - let jet_res = assert_no_alloc(|| jet(&mut context, sam).unwrap()); - assert_noun_eq(stack, jet_res, res); + pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) { + let sam = T(&mut context.stack, &[D(0), sam, D(0)]); + let jet_res = assert_no_alloc(|| jet(context, sam).unwrap()); + assert_noun_eq(&mut context.stack, jet_res, res); } - pub fn assert_jet_ubig(stack: &mut NockStack, jet: Jet, sam: Noun, res: UBig) { - let res = A(stack, &res); - assert_jet(stack, jet, sam, res); + pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) { + let res = A(&mut context.stack, &res); + assert_jet(context, jet, sam, res); } - pub fn assert_nary_jet_ubig(stack: &mut NockStack, jet: Jet, sam: &[Noun], res: UBig) { - let sam = T(stack, sam); - assert_jet_ubig(stack, jet, sam, res); + pub fn assert_nary_jet_ubig(context: &mut Context, jet: Jet, sam: &[Noun], res: UBig) { + let sam = T(&mut context.stack, sam); + assert_jet_ubig(context, jet, sam, res); } - pub fn assert_jet_err(stack: &mut NockStack, jet: Jet, sam: Noun, err: JetErr) { - // XX: consider making a mock context singleton that tests can use - let mut cache = Hamt::::new(); - let mut cold = Cold::new(stack); - let mut warm = Warm::new(); - let hot = Hot::init(stack); - let mut context = Context { - stack, - newt: None, - cache: &mut cache, - cold: &mut cold, - warm: &mut warm, - hot: &hot, - }; - let sam = T(context.stack, &[D(0), sam, D(0)]); - let jet_res = jet(&mut context, sam); + pub fn assert_jet_err(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) { + let sam = T(&mut context.stack, &[D(0), sam, D(0)]); + let jet_res = jet(context, sam); assert!( jet_res.is_err(), "with sample: {}, expected err: {:?}, got: {:?}", @@ -378,23 +378,51 @@ pub mod util { &jet_res ); let jet_err = jet_res.unwrap_err(); - assert_eq!( - jet_err, err, - "with sample: {}, expected err: {:?}, got: {:?}", - sam, err, jet_err - ); + match (jet_err, err) { + (JetErr::Punt, JetErr::Punt) => {} + (JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => { + match (actual_err, expected_err) { + (Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected)) + | (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected)) + | (Error::Deterministic(mut actual), Error::Deterministic(mut expected)) + | ( + Error::NonDeterministic(mut actual), + Error::NonDeterministic(mut expected), + ) => unsafe { + assert!(unifying_equality( + &mut context.stack, + &mut actual, + &mut expected + )); + }, + _ => { + panic!( + "with sample: {}, expected err: {:?}, got: {:?}", + sam, expected_err, actual_err + ); + } + } + } + _ => { + panic!( + "with sample: {}, expected err: {:?}, got: {:?}", + sam, err, jet_err + ); + } + } } } #[cfg(test)] mod tests { - use super::test::{init_stack, A}; + use super::test::{init_context, A}; use super::*; use ibig::ubig; #[test] fn test_met() { - let s = &mut init_stack(); + let c = &mut init_context(); + let s = &mut c.stack; let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210)) .as_atom() diff --git a/rust/ares/src/jets/bits.rs b/rust/ares/src/jets/bits.rs index a12be17..1bb0c46 100644 --- a/rust/ares/src/jets/bits.rs +++ b/rust/ares/src/jets/bits.rs @@ -1,9 +1,8 @@ /** Bit arithmetic & logic jets */ -use crate::interpreter::Context; +use crate::interpreter::{Context, Error}; use crate::jets::util::*; -use crate::jets::JetErr::*; -use crate::jets::Result; +use crate::jets::{JetErr, Result}; use crate::noun::{DirectAtom, IndirectAtom, Noun, D}; use std::cmp; @@ -15,7 +14,7 @@ crate::gdb!(); pub fn jet_bex(context: &mut Context, subject: Noun) -> Result { let arg = slot(subject, 6)?.as_direct()?.data() as usize; - Ok(bex(context.stack, arg).as_noun()) + Ok(bex(&mut context.stack, arg).as_noun()) } pub fn jet_can(context: &mut Context, subject: Noun) -> Result { @@ -43,7 +42,7 @@ pub fn jet_can(context: &mut Context, subject: Noun) -> Result { } else { unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?); let mut pos = 0; let mut list = original_list; loop { @@ -79,7 +78,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result { } else { unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, new_len); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len); chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?; chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?; Ok(new_indirect.normalize_as_atom().as_noun()) @@ -100,7 +99,7 @@ pub fn jet_cut(context: &mut Context, subject: Noun) -> Result { let new_indirect = unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, run)?); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?); chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?; new_indirect.normalize_as_atom() }; @@ -119,7 +118,7 @@ pub fn jet_end(context: &mut Context, subject: Noun) -> Result { } else { unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, step)?); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?); chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?; Ok(new_indirect.normalize_as_atom().as_noun()) } @@ -138,7 +137,7 @@ pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result { let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?; unsafe { - let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size); + let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size); chop(bloq, 0, len, step, dest, a.as_bitslice())?; Ok(atom.normalize_as_atom().as_noun()) } @@ -175,7 +174,7 @@ pub fn jet_rap(context: &mut Context, subject: Noun) -> Result { } else { unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?); let mut pos = 0; let mut list = original_list; @@ -221,7 +220,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result { } else { unsafe { let (mut new_indirect, new_slice) = - IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?); + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?); let mut pos = 0; let mut list = original_list; loop { @@ -246,7 +245,7 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result { let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data(); if boz >= 64 { - return Err(NonDeterministic); + return Err(JetErr::Fail(Error::Deterministic(D(0)))); } let boz = boz as usize; @@ -261,7 +260,9 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result { let mut output = if dat.is_direct() && bits < 64 { unsafe { DirectAtom::new_unchecked(0).as_atom() } } else { - unsafe { IndirectAtom::new_raw(context.stack, ((bits + 7) / 8) as usize, &0).as_atom() } + unsafe { + IndirectAtom::new_raw(&mut context.stack, ((bits + 7) / 8) as usize, &0).as_atom() + } }; let src = dat.as_bitslice(); @@ -281,7 +282,7 @@ pub fn jet_rip(context: &mut Context, subject: Noun) -> Result { let arg = slot(subject, 6)?; let (bloq, step) = bite(slot(arg, 2)?)?; let atom = slot(arg, 3)?.as_atom()?; - rip(context.stack, bloq, step, atom) + rip(&mut context.stack, bloq, step, atom) } pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result { @@ -296,7 +297,7 @@ pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result { let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?; unsafe { - let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size); + let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size); chop(bloq, step, len - step, 0, dest, a.as_bitslice())?; Ok(atom.normalize_as_atom().as_noun()) } @@ -311,7 +312,7 @@ pub fn jet_con(context: &mut Context, subject: Noun) -> Result { let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; - Ok(con(context.stack, a, b).as_noun()) + Ok(con(&mut context.stack, a, b).as_noun()) } pub fn jet_dis(context: &mut Context, subject: Noun) -> Result { @@ -322,7 +323,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result { let new_size = cmp::max(a.size(), b.size()); unsafe { - let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size); + let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size); let a_bit = a.as_bitslice(); dest[..a_bit.len()].copy_from_bitslice(a_bit); *dest &= b.as_bitslice(); @@ -338,7 +339,7 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result { let new_size = cmp::max(a.size(), b.size()); unsafe { - let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size); + let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size); let a_bit = a.as_bitslice(); dest[..a_bit.len()].copy_from_bitslice(a_bit); *dest ^= b.as_bitslice(); @@ -349,7 +350,7 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, assert_jet_ubig, init_stack, A}; + use crate::jets::util::test::{assert_jet, assert_jet_ubig, init_context, A}; use crate::mem::NockStack; use crate::noun::{Noun, D, T}; use ibig::ubig; @@ -384,12 +385,13 @@ mod tests { #[test] fn test_bex() { - let s = &mut init_stack(); - assert_jet(s, jet_bex, D(0), D(1)); - assert_jet(s, jet_bex, D(5), D(32)); - assert_jet(s, jet_bex, D(62), D(0x4000000000000000)); + let c = &mut init_context(); + + assert_jet(c, jet_bex, D(0), D(1)); + assert_jet(c, jet_bex, D(5), D(32)); + assert_jet(c, jet_bex, D(62), D(0x4000000000000000)); assert_jet_ubig( - s, + c, jet_bex, D(256), ubig!(_0x10000000000000000000000000000000000000000000000000000000000000000), @@ -398,218 +400,243 @@ mod tests { #[test] fn test_can() { - let s = &mut init_stack(); - let (a0, _a24, _a63, _a96, a128) = atoms(s); + let c = &mut init_context(); + + let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack); let bloq0 = D(0); let bloq3 = D(3); let bloq4 = D(4); - let sam = T(s, &[bloq0, D(0)]); - assert_jet(s, jet_can, sam, D(0)); - let sam = T(s, &[bloq3, D(0)]); - assert_jet(s, jet_can, sam, D(0)); - let run1 = T(s, &[D(0), a0]); - let run2 = T(s, &[D(1), a0]); - let run3 = T(s, &[D(2), a0]); - let sam = T(s, &[bloq0, run1, run2, run3, D(0)]); - assert_jet(s, jet_can, sam, D(0)); - let sam = T(s, &[bloq3, run1, run2, run3, D(0)]); - assert_jet(s, jet_can, sam, D(0)); - let run1 = T(s, &[D(1), a128]); - let run2 = T(s, &[D(3), a0]); - let sam = T(s, &[bloq3, run1, run2, D(0)]); - assert_jet(s, jet_can, sam, D(0x10)); - let run1 = T(s, &[D(3), a0]); - let run2 = T(s, &[D(1), a128]); - let sam = T(s, &[bloq3, run1, run2, D(0)]); - assert_jet(s, jet_can, sam, D(0x10000000)); - let run1 = T(s, &[D(8), D(0xfe)]); - let run2 = T(s, &[D(4), D(0xa)]); - let run3 = T(s, &[D(0), D(0xbbbb)]); - let run4 = T(s, &[D(1), D(0)]); - let run5 = T(s, &[D(1), D(0)]); - let run6 = T(s, &[D(1), D(1)]); - let run7 = T(s, &[D(1), D(1)]); - let sam = T(s, &[bloq0, run1, run2, run3, run4, run5, run6, run7, D(0)]); - assert_jet(s, jet_can, sam, D(0xcafe)); - let run1 = T(s, &[D(1), D(0xfe)]); - let run2 = T(s, &[D(1), D(0xca)]); - let sam = T(s, &[bloq4, run1, run2, D(0)]); - assert_jet(s, jet_can, sam, D(0xca00fe)); + let sam = T(&mut c.stack, &[bloq0, D(0)]); + assert_jet(c, jet_can, sam, D(0)); + let sam = T(&mut c.stack, &[bloq3, D(0)]); + assert_jet(c, jet_can, sam, D(0)); + let run1 = T(&mut c.stack, &[D(0), a0]); + let run2 = T(&mut c.stack, &[D(1), a0]); + let run3 = T(&mut c.stack, &[D(2), a0]); + let sam = T(&mut c.stack, &[bloq0, run1, run2, run3, D(0)]); + assert_jet(c, jet_can, sam, D(0)); + let sam = T(&mut c.stack, &[bloq3, run1, run2, run3, D(0)]); + assert_jet(c, jet_can, sam, D(0)); + let run1 = T(&mut c.stack, &[D(1), a128]); + let run2 = T(&mut c.stack, &[D(3), a0]); + let sam = T(&mut c.stack, &[bloq3, run1, run2, D(0)]); + assert_jet(c, jet_can, sam, D(0x10)); + let run1 = T(&mut c.stack, &[D(3), a0]); + let run2 = T(&mut c.stack, &[D(1), a128]); + let sam = T(&mut c.stack, &[bloq3, run1, run2, D(0)]); + assert_jet(c, jet_can, sam, D(0x10000000)); + let run1 = T(&mut c.stack, &[D(8), D(0xfe)]); + let run2 = T(&mut c.stack, &[D(4), D(0xa)]); + let run3 = T(&mut c.stack, &[D(0), D(0xbbbb)]); + let run4 = T(&mut c.stack, &[D(1), D(0)]); + let run5 = T(&mut c.stack, &[D(1), D(0)]); + let run6 = T(&mut c.stack, &[D(1), D(1)]); + let run7 = T(&mut c.stack, &[D(1), D(1)]); + let sam = T( + &mut c.stack, + &[bloq0, run1, run2, run3, run4, run5, run6, run7, D(0)], + ); + assert_jet(c, jet_can, sam, D(0xcafe)); + let run1 = T(&mut c.stack, &[D(1), D(0xfe)]); + let run2 = T(&mut c.stack, &[D(1), D(0xca)]); + let sam = T(&mut c.stack, &[bloq4, run1, run2, D(0)]); + assert_jet(c, jet_can, sam, D(0xca00fe)); } #[test] fn test_cat() { - let s = &mut init_stack(); - let (a0, a24, _a63, _a96, a128) = atoms(s); + let c = &mut init_context(); + + let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack); let bloq0 = D(0); let bloq3 = D(3); let bloq4 = D(4); - let sam = T(s, &[bloq0, a0, a0]); - assert_jet(s, jet_cat, sam, D(0)); - let sam = T(s, &[bloq3, a0, a0]); - assert_jet(s, jet_cat, sam, D(0)); - let sam = T(s, &[bloq0, a24, a128]); - let res = A(s, &ubig!(_0xdeadbeef12345678fedcba9876543210876543)); - assert_jet(s, jet_cat, sam, res); - let sam = T(s, &[bloq3, a24, a128]); - let res = A(s, &ubig!(_0xdeadbeef12345678fedcba9876543210876543)); - assert_jet(s, jet_cat, sam, res); - let sam = T(s, &[bloq4, a24, a128]); - let res = A(s, &ubig!(_0xdeadbeef12345678fedcba987654321000876543)); - assert_jet(s, jet_cat, sam, res); + let sam = T(&mut c.stack, &[bloq0, a0, a0]); + assert_jet(c, jet_cat, sam, D(0)); + let sam = T(&mut c.stack, &[bloq3, a0, a0]); + assert_jet(c, jet_cat, sam, D(0)); + let sam = T(&mut c.stack, &[bloq0, a24, a128]); + let res = A( + &mut c.stack, + &ubig!(_0xdeadbeef12345678fedcba9876543210876543), + ); + assert_jet(c, jet_cat, sam, res); + let sam = T(&mut c.stack, &[bloq3, a24, a128]); + let res = A( + &mut c.stack, + &ubig!(_0xdeadbeef12345678fedcba9876543210876543), + ); + assert_jet(c, jet_cat, sam, res); + let sam = T(&mut c.stack, &[bloq4, a24, a128]); + let res = A( + &mut c.stack, + &ubig!(_0xdeadbeef12345678fedcba987654321000876543), + ); + assert_jet(c, jet_cat, sam, res); } #[test] fn test_cut() { - let s = &mut init_stack(); - let (_a0, a24, _a63, a96, a128) = atoms(s); - let run = T(s, &[D(0), D(0)]); - let sam = T(s, &[D(0), run, a24]); - assert_jet(s, jet_cut, sam, D(0)); - let run = T(s, &[D(0), D(5)]); - let sam = T(s, &[D(0), run, a24]); - assert_jet(s, jet_cut, sam, D(0x3)); - let run = T(s, &[D(4), D(6)]); - let sam = T(s, &[D(3), run, a96]); - assert_jet(s, jet_cut, sam, D(0xb00c15deadbe)); - let run = T(s, &[D(4), D(1)]); - let sam = T(s, &[D(4), run, a24]); - assert_jet(s, jet_cut, sam, D(0)); - let run = T(s, &[D(2), D(10)]); - let sam = T(s, &[D(4), run, a128]); - let res = A(s, &ubig!(0xdeadbeef12345678fedcba98)); - assert_jet(s, jet_cut, sam, res); + let c = &mut init_context(); + + let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack); + let run = T(&mut c.stack, &[D(0), D(0)]); + let sam = T(&mut c.stack, &[D(0), run, a24]); + assert_jet(c, jet_cut, sam, D(0)); + let run = T(&mut c.stack, &[D(0), D(5)]); + let sam = T(&mut c.stack, &[D(0), run, a24]); + assert_jet(c, jet_cut, sam, D(0x3)); + let run = T(&mut c.stack, &[D(4), D(6)]); + let sam = T(&mut c.stack, &[D(3), run, a96]); + assert_jet(c, jet_cut, sam, D(0xb00c15deadbe)); + let run = T(&mut c.stack, &[D(4), D(1)]); + let sam = T(&mut c.stack, &[D(4), run, a24]); + assert_jet(c, jet_cut, sam, D(0)); + let run = T(&mut c.stack, &[D(2), D(10)]); + let sam = T(&mut c.stack, &[D(4), run, a128]); + let res = A(&mut c.stack, &ubig!(0xdeadbeef12345678fedcba98)); + assert_jet(c, jet_cut, sam, res); } #[test] fn test_end() { - let s = &mut init_stack(); - let (a0, a24, _a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a24]); - assert_jet(s, jet_end, sam, D(0x1)); - let sam = T(s, &[D(3), a24]); - assert_jet(s, jet_end, sam, D(0x43)); - let sam = T(s, &[D(7), a24]); - assert_jet(s, jet_end, sam, a24); - let sam = T(s, &[D(6), a128]); - let res = A(s, &ubig!(0xfedcba9876543210)); - assert_jet(s, jet_end, sam, res); + let c = &mut init_context(); - let bit = T(s, &[D(0), D(5)]); - let sam = T(s, &[bit, a24]); - assert_jet(s, jet_end, sam, D(0x3)); - let bit = T(s, &[D(4), D(6)]); - let sam = T(s, &[bit, a96]); - assert_jet(s, jet_end, sam, a96); + let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a24]); + assert_jet(c, jet_end, sam, D(0x1)); + let sam = T(&mut c.stack, &[D(3), a24]); + assert_jet(c, jet_end, sam, D(0x43)); + let sam = T(&mut c.stack, &[D(7), a24]); + assert_jet(c, jet_end, sam, a24); + let sam = T(&mut c.stack, &[D(6), a128]); + let res = A(&mut c.stack, &ubig!(0xfedcba9876543210)); + assert_jet(c, jet_end, sam, res); + + let bit = T(&mut c.stack, &[D(0), D(5)]); + let sam = T(&mut c.stack, &[bit, a24]); + assert_jet(c, jet_end, sam, D(0x3)); + let bit = T(&mut c.stack, &[D(4), D(6)]); + let sam = T(&mut c.stack, &[bit, a96]); + assert_jet(c, jet_end, sam, a96); } #[test] fn test_lsh() { - let s = &mut init_stack(); - let (a0, a24, _a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a24]); - assert_jet(s, jet_lsh, sam, D(0x10eca86)); - let sam = T(s, &[D(3), a24]); - assert_jet(s, jet_lsh, sam, D(0x87654300)); - let sam = T(s, &[D(7), a24]); - let res = A(s, &ubig!(_0x87654300000000000000000000000000000000)); - assert_jet(s, jet_lsh, sam, res); - let sam = T(s, &[D(6), a128]); + let c = &mut init_context(); + + let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a24]); + assert_jet(c, jet_lsh, sam, D(0x10eca86)); + let sam = T(&mut c.stack, &[D(3), a24]); + assert_jet(c, jet_lsh, sam, D(0x87654300)); + let sam = T(&mut c.stack, &[D(7), a24]); let res = A( - s, + &mut c.stack, + &ubig!(_0x87654300000000000000000000000000000000), + ); + assert_jet(c, jet_lsh, sam, res); + let sam = T(&mut c.stack, &[D(6), a128]); + let res = A( + &mut c.stack, &ubig!(_0xdeadbeef12345678fedcba98765432100000000000000000), ); - assert_jet(s, jet_lsh, sam, res); + assert_jet(c, jet_lsh, sam, res); - let bit = T(s, &[D(0), D(5)]); - let sam = T(s, &[bit, a24]); - assert_jet(s, jet_lsh, sam, D(0x10eca860)); - let bit = T(s, &[D(4), D(6)]); - let sam = T(s, &[bit, a96]); + let bit = T(&mut c.stack, &[D(0), D(5)]); + let sam = T(&mut c.stack, &[bit, a24]); + assert_jet(c, jet_lsh, sam, D(0x10eca860)); + let bit = T(&mut c.stack, &[D(4), D(6)]); + let sam = T(&mut c.stack, &[bit, a96]); let res = A( - s, + &mut c.stack, &ubig!(_0xfaceb00c15deadbeef123456000000000000000000000000), ); - assert_jet(s, jet_lsh, sam, res); + assert_jet(c, jet_lsh, sam, res); } #[test] fn test_met() { - let s = &mut init_stack(); - let (a0, a24, _a63, _a96, a128) = atoms(s); - let sam = T(s, &[a0, a0]); - assert_jet(s, jet_met, sam, D(0)); - let sam = T(s, &[a0, a24]); - assert_jet(s, jet_met, sam, D(24)); - let sam = T(s, &[D(3), a24]); - assert_jet(s, jet_met, sam, D(3)); - let sam = T(s, &[D(1), a128]); - assert_jet(s, jet_met, sam, D(64)); + let c = &mut init_context(); + + let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a0]); + assert_jet(c, jet_met, sam, D(0)); + let sam = T(&mut c.stack, &[a0, a24]); + assert_jet(c, jet_met, sam, D(24)); + let sam = T(&mut c.stack, &[D(3), a24]); + assert_jet(c, jet_met, sam, D(3)); + let sam = T(&mut c.stack, &[D(1), a128]); + assert_jet(c, jet_met, sam, D(64)); } #[test] fn test_rap() { - let s = &mut init_stack(); + let c = &mut init_context(); + let bloq0 = D(0); let bloq2 = D(2); let bloq3 = D(3); let empty_list = D(0); - let zero_list = T(s, &[D(0), D(0), D(0)]); - let test_list = T(s, &[D(0xe), D(0xf), D(0xa), D(0xc), D(0)]); - let wide_list = T(s, &[D(0xafe), D(0xc), D(0)]); - let sam = T(s, &[bloq0, empty_list]); - assert_jet(s, jet_rap, sam, D(0)); - let sam = T(s, &[bloq0, zero_list]); - assert_jet(s, jet_rap, sam, D(0)); - let sam = T(s, &[bloq3, zero_list]); - assert_jet(s, jet_rap, sam, D(0)); - let sam = T(s, &[bloq0, test_list]); - assert_jet(s, jet_rap, sam, D(0xcafe)); - let sam = T(s, &[bloq2, test_list]); - assert_jet(s, jet_rap, sam, D(0xcafe)); - let sam = T(s, &[bloq2, wide_list]); - assert_jet(s, jet_rap, sam, D(0xcafe)); - let sam = T(s, &[bloq3, test_list]); - let res = A(s, &ubig!(0xc0a0f0e)); - assert_jet(s, jet_rap, sam, res); - let sam = T(s, &[bloq3, wide_list]); - assert_jet(s, jet_rap, sam, D(0xc0afe)); + let zero_list = T(&mut c.stack, &[D(0), D(0), D(0)]); + let test_list = T(&mut c.stack, &[D(0xe), D(0xf), D(0xa), D(0xc), D(0)]); + let wide_list = T(&mut c.stack, &[D(0xafe), D(0xc), D(0)]); + let sam = T(&mut c.stack, &[bloq0, empty_list]); + assert_jet(c, jet_rap, sam, D(0)); + let sam = T(&mut c.stack, &[bloq0, zero_list]); + assert_jet(c, jet_rap, sam, D(0)); + let sam = T(&mut c.stack, &[bloq3, zero_list]); + assert_jet(c, jet_rap, sam, D(0)); + let sam = T(&mut c.stack, &[bloq0, test_list]); + assert_jet(c, jet_rap, sam, D(0xcafe)); + let sam = T(&mut c.stack, &[bloq2, test_list]); + assert_jet(c, jet_rap, sam, D(0xcafe)); + let sam = T(&mut c.stack, &[bloq2, wide_list]); + assert_jet(c, jet_rap, sam, D(0xcafe)); + let sam = T(&mut c.stack, &[bloq3, test_list]); + let res = A(&mut c.stack, &ubig!(0xc0a0f0e)); + assert_jet(c, jet_rap, sam, res); + let sam = T(&mut c.stack, &[bloq3, wide_list]); + assert_jet(c, jet_rap, sam, D(0xc0afe)); } #[test] fn test_rep() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - let sam = T(s, &[D(0), D(0)]); - assert_jet(s, jet_rep, sam, D(0)); - let bit = T(s, &[D(3), D(2)]); - let sam = T(s, &[bit, a0, a24, a63, a96, a128, D(0)]); - let res = A(s, &ubig!(0x32103456ffff65430000)); - assert_jet(s, jet_rep, sam, res); + let c = &mut init_context(); + + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[D(0), D(0)]); + assert_jet(c, jet_rep, sam, D(0)); + let bit = T(&mut c.stack, &[D(3), D(2)]); + let sam = T(&mut c.stack, &[bit, a0, a24, a63, a96, a128, D(0)]); + let res = A(&mut c.stack, &ubig!(0x32103456ffff65430000)); + assert_jet(c, jet_rep, sam, res); } #[test] fn test_rev() { - let s = &mut init_stack(); - let (_a0, a24, _a63, _a96, _a128) = atoms(s); - let sam = T(s, &[D(0), D(60), a24]); - assert_jet(s, jet_rev, sam, D(0xc2a6e1000000000)); + let c = &mut init_context(); + + let (_a0, a24, _a63, _a96, _a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[D(0), D(60), a24]); + assert_jet(c, jet_rev, sam, D(0xc2a6e1000000000)); let test = 0x1234567890123u64; - let sam = T(s, &[D(3), D(7), D(test)]); - assert_jet(s, jet_rev, sam, D(test.swap_bytes() >> 8)); + let sam = T(&mut c.stack, &[D(3), D(7), D(test)]); + assert_jet(c, jet_rev, sam, D(test.swap_bytes() >> 8)); } #[test] fn test_rip() { - let s = &mut init_stack(); - let (_a0, _a24, _a63, _a96, a128) = atoms(s); - let sam = T(s, &[D(0), D(0)]); - assert_jet(s, jet_rip, sam, D(0)); - let bit = T(s, &[D(1), D(2)]); - let sam = T(s, &[bit, a128]); + let c = &mut init_context(); + + let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[D(0), D(0)]); + assert_jet(c, jet_rip, sam, D(0)); + let bit = T(&mut c.stack, &[D(1), D(2)]); + let sam = T(&mut c.stack, &[bit, a128]); #[rustfmt::skip] let res = T( - s, + &mut c.stack, &[ D(0x0), D(0x1), D(0x2), D(0x3), D(0x4), D(0x5), D(0x6), D(0x7), D(0x8), D(0x9), D(0xa), D(0xb), D(0xc), D(0xd), D(0xe), D(0xf), @@ -618,33 +645,33 @@ mod tests { D(0x0), ], ); - - assert_jet(s, jet_rip, sam, res); + assert_jet(c, jet_rip, sam, res); } #[test] fn test_rsh() { - let s = &mut init_stack(); - let (a0, a24, _a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a24]); - assert_jet(s, jet_rsh, sam, D(0x43b2a1)); - let sam = T(s, &[D(3), a24]); - assert_jet(s, jet_rsh, sam, D(0x8765)); - let sam = T(s, &[D(7), a24]); - assert_jet(s, jet_rsh, sam, D(0)); - let sam = T(s, &[D(2), a128]); - let res = A(s, &ubig!(0xdeadbeef12345678fedcba987654321)); - assert_jet(s, jet_rsh, sam, res); - let sam = T(s, &[D(6), a128]); - let res = A(s, &ubig!(0xdeadbeef12345678)); - assert_jet(s, jet_rsh, sam, res); + let c = &mut init_context(); - let bit = T(s, &[D(0), D(5)]); - let sam = T(s, &[bit, a24]); - assert_jet(s, jet_rsh, sam, D(0x43b2a)); - let bit = T(s, &[D(4), D(6)]); - let sam = T(s, &[bit, a96]); - assert_jet(s, jet_rsh, sam, D(0)); + let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a24]); + assert_jet(c, jet_rsh, sam, D(0x43b2a1)); + let sam = T(&mut c.stack, &[D(3), a24]); + assert_jet(c, jet_rsh, sam, D(0x8765)); + let sam = T(&mut c.stack, &[D(7), a24]); + assert_jet(c, jet_rsh, sam, D(0)); + let sam = T(&mut c.stack, &[D(2), a128]); + let res = A(&mut c.stack, &ubig!(0xdeadbeef12345678fedcba987654321)); + assert_jet(c, jet_rsh, sam, res); + let sam = T(&mut c.stack, &[D(6), a128]); + let res = A(&mut c.stack, &ubig!(0xdeadbeef12345678)); + assert_jet(c, jet_rsh, sam, res); + + let bit = T(&mut c.stack, &[D(0), D(5)]); + let sam = T(&mut c.stack, &[bit, a24]); + assert_jet(c, jet_rsh, sam, D(0x43b2a)); + let bit = T(&mut c.stack, &[D(4), D(6)]); + let sam = T(&mut c.stack, &[bit, a96]); + assert_jet(c, jet_rsh, sam, D(0)); } /* @@ -653,61 +680,64 @@ mod tests { #[test] fn test_con() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a0]); - assert_jet(s, jet_con, sam, D(0)); - let sam = T(s, &[a24, a96]); - let res = A(s, &ubig!(0xfaceb00c15deadbeef977557)); - assert_jet(s, jet_con, sam, res); - let sam = T(s, &[a96, a128]); - let res = A(s, &ubig!(0xdeadbeeffafef67cffdebfbeff563656)); - assert_jet(s, jet_con, sam, res); - let sam = T(s, &[a24, a63]); - assert_jet(s, jet_con, sam, a63); - let sam = T(s, &[a0, a128]); - assert_jet(s, jet_con, sam, a128); - let sam = T(s, &[a128, a0]); - assert_jet(s, jet_con, sam, a128); + let c = &mut init_context(); + + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a0]); + assert_jet(c, jet_con, sam, D(0)); + let sam = T(&mut c.stack, &[a24, a96]); + let res = A(&mut c.stack, &ubig!(0xfaceb00c15deadbeef977557)); + assert_jet(c, jet_con, sam, res); + let sam = T(&mut c.stack, &[a96, a128]); + let res = A(&mut c.stack, &ubig!(0xdeadbeeffafef67cffdebfbeff563656)); + assert_jet(c, jet_con, sam, res); + let sam = T(&mut c.stack, &[a24, a63]); + assert_jet(c, jet_con, sam, a63); + let sam = T(&mut c.stack, &[a0, a128]); + assert_jet(c, jet_con, sam, a128); + let sam = T(&mut c.stack, &[a128, a0]); + assert_jet(c, jet_con, sam, a128); } #[test] fn test_dis() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a0]); - assert_jet(s, jet_dis, sam, D(0)); - let sam = T(s, &[a24, a96]); - assert_jet(s, jet_dis, sam, D(0x22442)); - let sam = T(s, &[a96, a128]); - let res = A(s, &ubig!(0x1204100814dca89866103010)); - assert_jet(s, jet_dis, sam, res); - let sam = T(s, &[a24, a63]); - assert_jet(s, jet_dis, sam, a24); - let sam = T(s, &[a0, a128]); - assert_jet(s, jet_dis, sam, a0); - let sam = T(s, &[a128, a0]); - assert_jet(s, jet_dis, sam, a0); + let c = &mut init_context(); + + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a0]); + assert_jet(c, jet_dis, sam, D(0)); + let sam = T(&mut c.stack, &[a24, a96]); + assert_jet(c, jet_dis, sam, D(0x22442)); + let sam = T(&mut c.stack, &[a96, a128]); + let res = A(&mut c.stack, &ubig!(0x1204100814dca89866103010)); + assert_jet(c, jet_dis, sam, res); + let sam = T(&mut c.stack, &[a24, a63]); + assert_jet(c, jet_dis, sam, a24); + let sam = T(&mut c.stack, &[a0, a128]); + assert_jet(c, jet_dis, sam, a0); + let sam = T(&mut c.stack, &[a128, a0]); + assert_jet(c, jet_dis, sam, a0); } #[test] fn test_mix() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - let sam = T(s, &[a0, a0]); - assert_jet(s, jet_mix, sam, D(0)); - let sam = T(s, &[a24, a96]); - let res = A(s, &ubig!(0xfaceb00c15deadbeef955115)); - assert_jet(s, jet_mix, sam, res); - let sam = T(s, &[a96, a128]); - let res = A(s, &ubig!(0xdeadbeefe8fae674eb02172699460646)); - assert_jet(s, jet_mix, sam, res); - let sam = T(s, &[a24, a63]); - let res = A(s, &ubig!(0x7fffffffff789abc)); - assert_jet(s, jet_mix, sam, res); - let sam = T(s, &[a0, a128]); - assert_jet(s, jet_mix, sam, a128); - let sam = T(s, &[a128, a0]); - assert_jet(s, jet_mix, sam, a128); + let c = &mut init_context(); + + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + let sam = T(&mut c.stack, &[a0, a0]); + assert_jet(c, jet_mix, sam, D(0)); + let sam = T(&mut c.stack, &[a24, a96]); + let res = A(&mut c.stack, &ubig!(0xfaceb00c15deadbeef955115)); + assert_jet(c, jet_mix, sam, res); + let sam = T(&mut c.stack, &[a96, a128]); + let res = A(&mut c.stack, &ubig!(0xdeadbeefe8fae674eb02172699460646)); + assert_jet(c, jet_mix, sam, res); + let sam = T(&mut c.stack, &[a24, a63]); + let res = A(&mut c.stack, &ubig!(0x7fffffffff789abc)); + assert_jet(c, jet_mix, sam, res); + let sam = T(&mut c.stack, &[a0, a128]); + assert_jet(c, jet_mix, sam, a128); + let sam = T(&mut c.stack, &[a128, a0]); + assert_jet(c, jet_mix, sam, a128); } } diff --git a/rust/ares/src/jets/cold.rs b/rust/ares/src/jets/cold.rs index c3bff84..1aa998a 100644 --- a/rust/ares/src/jets/cold.rs +++ b/rust/ares/src/jets/cold.rs @@ -18,6 +18,7 @@ impl From for Error { pub type Result = std::result::Result; +// Batteries is a core hierarchy (e.g. a path of parent batteries to a root) #[derive(Copy, Clone)] pub struct Batteries(*mut BatteriesMem); @@ -129,6 +130,8 @@ impl Batteries { } } +// BatteriesList is a linked list of core hierarchies with an iterator; used to +// store all possible parent hierarchies for a core #[derive(Copy, Clone)] pub struct BatteriesList(*mut BatteriesListMem); @@ -199,6 +202,8 @@ impl BatteriesList { } } +// NounList is a linked list of paths (path = list of nested core names) with an +// iterator; used to store all possible registered paths for a core #[derive(Copy, Clone)] struct NounList(*mut NounListMem); @@ -265,12 +270,21 @@ impl Iterator for NounList { pub struct Cold(*mut ColdMem); struct ColdMem { - /// key: outermost battery + /// key: outermost battery (e.g. furthest battery from root for a core) /// value: possible registered paths for core + /// + /// Identical nock can exist in multiple places, so the outermost battery + /// yield multiple paths. Instead of matching on the entire core in the Hamt + /// (which would require iterating through every possible pait), we match + /// the outermost battery to a path, then compare the core to the registered + /// cores for that path. battery_to_paths: Hamt, /// Roots /// key: root noun /// value: root path + /// + /// Just like battery_to_paths, but for roots (which refer to themselves as + /// their parent). root_to_paths: Hamt, /// key: registered path to core /// value: linked list of a sequence of nested batteries diff --git a/rust/ares/src/jets/form.rs b/rust/ares/src/jets/form.rs index 8e819ae..66db10b 100644 --- a/rust/ares/src/jets/form.rs +++ b/rust/ares/src/jets/form.rs @@ -10,7 +10,7 @@ crate::gdb!(); pub fn jet_scow(context: &mut Context, subject: Noun) -> Result { let aura = slot(subject, 12)?.as_direct()?; let atom = slot(subject, 13)?.as_atom()?; - util::scow(context.stack, aura, atom) + util::scow(&mut context.stack, aura, atom) } pub mod util { @@ -79,7 +79,7 @@ pub mod util { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack, A}; + use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A}; use crate::jets::JetErr; use crate::noun::{Noun, D, T}; use ares_macros::tas; @@ -93,28 +93,35 @@ mod tests { #[test] fn test_scow() { - let s = &mut init_stack(); + let c = &mut init_context(); + let aura = D(tas!(b"ud")); - let sam = T(s, &[aura, D(0)]); - let res = T(s, &[B(b'0'), D(0)]); - assert_jet(s, jet_scow, sam, res); - let sam = T(s, &[aura, D(100)]); - let res = T(s, &[B(b'1'), B(b'0'), B(b'0'), D(0)]); - assert_jet(s, jet_scow, sam, res); - let big = A(s, &ubig!(100)); - let sam = T(s, &[aura, big]); - let res = T(s, &[B(b'1'), B(b'0'), B(b'0'), D(0)]); - assert_jet(s, jet_scow, sam, res); - let sam = T(s, &[aura, D(1000)]); - let res = T(s, &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)]); - assert_jet(s, jet_scow, sam, res); - let big = A(s, &ubig!(1000)); - let sam = T(s, &[aura, big]); - let res = T(s, &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)]); - assert_jet(s, jet_scow, sam, res); - let sam = T(s, &[aura, D(9876543210)]); + let sam = T(&mut c.stack, &[aura, D(0)]); + let res = T(&mut c.stack, &[B(b'0'), D(0)]); + assert_jet(c, jet_scow, sam, res); + let sam = T(&mut c.stack, &[aura, D(100)]); + let res = T(&mut c.stack, &[B(b'1'), B(b'0'), B(b'0'), D(0)]); + assert_jet(c, jet_scow, sam, res); + let big = A(&mut c.stack, &ubig!(100)); + let sam = T(&mut c.stack, &[aura, big]); + let res = T(&mut c.stack, &[B(b'1'), B(b'0'), B(b'0'), D(0)]); + assert_jet(c, jet_scow, sam, res); + let sam = T(&mut c.stack, &[aura, D(1000)]); let res = T( - s, + &mut c.stack, + &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)], + ); + assert_jet(c, jet_scow, sam, res); + let big = A(&mut c.stack, &ubig!(1000)); + let sam = T(&mut c.stack, &[aura, big]); + let res = T( + &mut c.stack, + &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)], + ); + assert_jet(c, jet_scow, sam, res); + let sam = T(&mut c.stack, &[aura, D(9876543210)]); + let res = T( + &mut c.stack, &[ B(b'9'), B(b'.'), @@ -132,9 +139,9 @@ mod tests { D(0), ], ); - assert_jet(s, jet_scow, sam, res); + assert_jet(c, jet_scow, sam, res); let bad_aura = D(tas!(b"ux")); - let sam = T(s, &[bad_aura, D(0)]); - assert_jet_err(s, jet_scow, sam, JetErr::Punt); + let sam = T(&mut c.stack, &[bad_aura, D(0)]); + assert_jet_err(c, jet_scow, sam, JetErr::Punt); } } diff --git a/rust/ares/src/jets/hash.rs b/rust/ares/src/jets/hash.rs index f622319..a4a03dc 100644 --- a/rust/ares/src/jets/hash.rs +++ b/rust/ares/src/jets/hash.rs @@ -10,13 +10,13 @@ crate::gdb!(); pub fn jet_mug(context: &mut Context, subject: Noun) -> Result { let arg = slot(subject, 6)?; - Ok(mug(context.stack, arg).as_noun()) + Ok(mug(&mut context.stack, arg).as_noun()) } #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, init_stack, A}; + use crate::jets::util::test::{assert_jet, init_context, A}; use crate::mem::NockStack; use crate::noun::{Noun, D, T}; use ibig::ubig; @@ -47,22 +47,23 @@ mod tests { #[test] fn test_mug() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - assert_jet(s, jet_mug, a0, D(0x79ff04e8)); - assert_jet(s, jet_mug, a24, D(0x69d59d90)); - assert_jet(s, jet_mug, a63, D(0x7a9f252e)); - assert_jet(s, jet_mug, a96, D(0x2aa4c8fb)); - assert_jet(s, jet_mug, a128, D(0x44fb2c0c)); - let sam = T(s, &[a128, a128]); - assert_jet(s, jet_mug, sam, D(0x61c0ea5c)); - let sam = T(s, &[a96, a128]); - assert_jet(s, jet_mug, sam, D(0x20fb143f)); - let sam = T(s, &[a0, a0]); - assert_jet(s, jet_mug, sam, D(0x192f5588)); - let sam = T(s, &[a0, a24, a63, a96, a128]); - let sam = T(s, &[sam, a0, a24, a63, a96, a128]); - let sam = T(s, &[sam, a0, a24, a63, a96, a128]); - assert_jet(s, jet_mug, sam, D(0x7543cac7)); + let c = &mut init_context(); + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + + assert_jet(c, jet_mug, a0, D(0x79ff04e8)); + assert_jet(c, jet_mug, a24, D(0x69d59d90)); + assert_jet(c, jet_mug, a63, D(0x7a9f252e)); + assert_jet(c, jet_mug, a96, D(0x2aa4c8fb)); + assert_jet(c, jet_mug, a128, D(0x44fb2c0c)); + let sam = T(&mut c.stack, &[a128, a128]); + assert_jet(c, jet_mug, sam, D(0x61c0ea5c)); + let sam = T(&mut c.stack, &[a96, a128]); + assert_jet(c, jet_mug, sam, D(0x20fb143f)); + let sam = T(&mut c.stack, &[a0, a0]); + assert_jet(c, jet_mug, sam, D(0x192f5588)); + let sam = T(&mut c.stack, &[a0, a24, a63, a96, a128]); + let sam = T(&mut c.stack, &[sam, a0, a24, a63, a96, a128]); + let sam = T(&mut c.stack, &[sam, a0, a24, a63, a96, a128]); + assert_jet(c, jet_mug, sam, D(0x7543cac7)); } } diff --git a/rust/ares/src/jets/math.rs b/rust/ares/src/jets/math.rs index 5d075ad..a5f280c 100644 --- a/rust/ares/src/jets/math.rs +++ b/rust/ares/src/jets/math.rs @@ -5,17 +5,16 @@ * * In any case, it's important to ensure that the library only allocates on the nock stack. Gmp * has mp_set_memory_functions. I don't know if rug does any allocation on top of that. ibig does - * not appear to support custom allocation functions, but we could probably patch it. If we're + * not appear to support custom allocation functionc, but we could probably patch it. If we're * patching it, we might even be able to avoid copying the input and output at all, which might * give a greater performance advantage than using gmp anyway. * * Another approach is use a global custom allocator. This is fairly involved, but it would allow * us to use any library without worrying whether it allocates. */ -use crate::interpreter::Context; +use crate::interpreter::{Context, Error}; use crate::jets::util::*; -use crate::jets::JetErr::*; -use crate::jets::Result; +use crate::jets::{JetErr, Result}; use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES}; use either::{Left, Right}; use ibig::ops::DivRem; @@ -30,12 +29,12 @@ pub fn jet_add(context: &mut Context, subject: Noun) -> Result { let b = slot(arg, 3)?.as_atom()?; if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { - Ok(Atom::new(*stack, a.data() + b.data()).as_noun()) + Ok(Atom::new(stack, a.data() + b.data()).as_noun()) } else { - let a_big = a.as_ubig(*stack); - let b_big = b.as_ubig(*stack); - let res = UBig::add_stack(*stack, a_big, b_big); - Ok(Atom::from_ubig(*stack, &res).as_noun()) + let a_big = a.as_ubig(stack); + let b_big = b.as_ubig(stack); + let res = UBig::add_stack(stack, a_big, b_big); + Ok(Atom::from_ubig(stack, &res).as_noun()) } } @@ -45,7 +44,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result { match atom.as_either() { Left(direct) => { if direct.data() == 0 { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else { Ok(unsafe { DirectAtom::new_unchecked(direct.data() - 1) }.as_noun()) } @@ -58,7 +57,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result { } Some(first_one) => { let (mut new_indirect, new_slice) = unsafe { - IndirectAtom::new_raw_mut_bitslice(context.stack, indirect.size()) + IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size()) }; if first_one > 0 { new_slice[..first_one].fill(true); @@ -73,7 +72,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result { } } } else { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } } @@ -84,14 +83,14 @@ pub fn jet_div(context: &mut Context, subject: Noun) -> Result { let b = slot(arg, 3)?.as_atom()?; if unsafe { b.as_noun().raw_equals(D(0)) } { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun()) } else { - let a_big = a.as_ubig(*stack); - let b_big = b.as_ubig(*stack); - let res = UBig::div_stack(*stack, a_big, b_big); - Ok(Atom::from_ubig(*stack, &res).as_noun()) + let a_big = a.as_ubig(stack); + let b_big = b.as_ubig(stack); + let res = UBig::div_stack(stack, a_big, b_big); + Ok(Atom::from_ubig(stack, &res).as_noun()) } } @@ -102,7 +101,7 @@ pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result { let b = slot(arg, 3)?.as_atom()?; if unsafe { b.as_noun().raw_equals(D(0)) } { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else { let (div, rem) = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { let (div, rem) = (a.data() / b.data(), a.data() % b.data()); @@ -113,18 +112,19 @@ pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result { ) } } else { - let (div, rem) = a.as_ubig(*stack).div_rem(b.as_ubig(*stack)); + let (div, rem) = a.as_ubig(stack).div_rem(b.as_ubig(stack)); ( - Atom::from_ubig(*stack, &div).as_noun(), - Atom::from_ubig(*stack, &rem).as_noun(), + Atom::from_ubig(stack, &div).as_noun(), + Atom::from_ubig(stack, &rem).as_noun(), ) }; - Ok(T(*stack, &[div, rem])) + Ok(T(stack, &[div, rem])) } } pub fn jet_gte(context: &mut Context, subject: Noun) -> Result { + let stack = &mut context.stack; let arg = slot(subject, 6)?; let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; @@ -139,7 +139,7 @@ pub fn jet_gte(context: &mut Context, subject: Noun) -> Result { YES } else if a.bit_size() < b.bit_size() { NO - } else if a.as_ubig(context.stack) >= b.as_ubig(context.stack) { + } else if a.as_ubig(stack) >= b.as_ubig(stack) { YES } else { NO @@ -147,6 +147,7 @@ pub fn jet_gte(context: &mut Context, subject: Noun) -> Result { } pub fn jet_gth(context: &mut Context, subject: Noun) -> Result { + let stack = &mut context.stack; let arg = slot(subject, 6)?; let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; @@ -161,7 +162,7 @@ pub fn jet_gth(context: &mut Context, subject: Noun) -> Result { YES } else if a.bit_size() < b.bit_size() { NO - } else if a.as_ubig(context.stack) > b.as_ubig(context.stack) { + } else if a.as_ubig(stack) > b.as_ubig(stack) { YES } else { NO @@ -169,6 +170,7 @@ pub fn jet_gth(context: &mut Context, subject: Noun) -> Result { } pub fn jet_lte(context: &mut Context, subject: Noun) -> Result { + let stack = &mut context.stack; let arg = slot(subject, 6)?; let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; @@ -183,19 +185,20 @@ pub fn jet_lte(context: &mut Context, subject: Noun) -> Result { YES } else if a.bit_size() > b.bit_size() { NO - } else if a.as_ubig(context.stack) <= b.as_ubig(context.stack) { + } else if a.as_ubig(stack) <= b.as_ubig(stack) { YES } else { NO }) } -pub fn jet_lth(_context: &mut Context, subject: Noun) -> Result { +pub fn jet_lth(context: &mut Context, subject: Noun) -> Result { + let stack = &mut context.stack; let arg = slot(subject, 6)?; let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; - Ok(util::lth(a, b)) + Ok(util::lth(stack, a, b)) } pub fn jet_mod(context: &mut Context, subject: Noun) -> Result { @@ -205,12 +208,12 @@ pub fn jet_mod(context: &mut Context, subject: Noun) -> Result { let b = slot(arg, 3)?.as_atom()?; if unsafe { b.as_noun().raw_equals(D(0)) } { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun()) } else { - let res = a.as_ubig(*stack) % b.as_ubig(*stack); - Ok(Atom::from_ubig(*stack, &res).as_noun()) + let res = a.as_ubig(stack) % b.as_ubig(stack); + Ok(Atom::from_ubig(stack, &res).as_noun()) } } @@ -223,11 +226,11 @@ pub fn jet_mul(context: &mut Context, subject: Noun) -> Result { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { let res = a.data() as u128 * b.data() as u128; if res < DIRECT_MAX as u128 { - Ok(Atom::new(*stack, res as u64).as_noun()) + Ok(Atom::new(stack, res as u64).as_noun()) } else { Ok(unsafe { IndirectAtom::new_raw_bytes( - *stack, + stack, if res < u64::MAX as u128 { 8 } else { 16 }, &res as *const u128 as *const u8, ) @@ -235,10 +238,10 @@ pub fn jet_mul(context: &mut Context, subject: Noun) -> Result { .as_noun()) } } else { - let a_big = a.as_ubig(*stack); - let b_big = b.as_ubig(*stack); - let res = UBig::mul_stack(*stack, a_big, b_big); - Ok(Atom::from_ubig(*stack, &res).as_noun()) + let a_big = a.as_ubig(stack); + let b_big = b.as_ubig(stack); + let res = UBig::mul_stack(stack, a_big, b_big); + Ok(Atom::from_ubig(stack, &res).as_noun()) } } @@ -247,16 +250,14 @@ pub fn jet_sub(context: &mut Context, subject: Noun) -> Result { let a = slot(arg, 2)?.as_atom()?; let b = slot(arg, 3)?.as_atom()?; - Ok(sub(context.stack, a, b)?.as_noun()) + Ok(sub(&mut context.stack, a, b)?.as_noun()) } pub mod util { - use crate::jets::util::test::init_stack; + use crate::mem::NockStack; use crate::noun::{Atom, Noun, NO, YES}; - pub fn lth(a: Atom, b: Atom) -> Noun { - let s = &mut init_stack(); - + pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun { if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) { if a.data() < b.data() { YES @@ -267,7 +268,7 @@ pub mod util { YES } else if a.bit_size() > b.bit_size() { NO - } else if a.as_ubig(s) < b.as_ubig(s) { + } else if a.as_ubig(stack) < b.as_ubig(stack) { YES } else { NO @@ -278,8 +279,9 @@ pub mod util { #[cfg(test)] mod tests { use super::*; + use crate::interpreter::Error; use crate::jets::util::test::{ - assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A, + assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_context, A, }; use crate::jets::{Jet, JetErr}; use crate::mem::NockStack; @@ -326,74 +328,78 @@ mod tests { } fn assert_math_jet( - stack: &mut NockStack, + context: &mut Context, jet: Jet, sam: &[fn(&mut NockStack) -> Noun], res: UBig, ) { - let sam: Vec = sam.iter().map(|f| f(stack)).collect(); - assert_nary_jet_ubig(stack, jet, &sam, res); + let sam: Vec = sam.iter().map(|f| f(&mut context.stack)).collect(); + assert_nary_jet_ubig(context, jet, &sam, res); } fn assert_math_jet_noun( - stack: &mut NockStack, + context: &mut Context, jet: Jet, sam: &[fn(&mut NockStack) -> Noun], res: Noun, ) { - let sam: Vec = sam.iter().map(|f| f(stack)).collect(); - let sam = T(stack, &sam); - assert_jet(stack, jet, sam, res); + let sam: Vec = sam.iter().map(|f| f(&mut context.stack)).collect(); + let sam = T(&mut context.stack, &sam); + assert_jet(context, jet, sam, res); } fn assert_math_jet_err( - stack: &mut NockStack, + context: &mut Context, jet: Jet, sam: &[fn(&mut NockStack) -> Noun], err: JetErr, ) { - let sam: Vec = sam.iter().map(|f| f(stack)).collect(); - let sam = T(stack, &sam); - assert_jet_err(stack, jet, sam, err); + let sam: Vec = sam.iter().map(|f| f(&mut context.stack)).collect(); + let sam = T(&mut context.stack, &sam); + assert_jet_err(context, jet, sam, err); } #[test] fn test_add() { - let s = &mut init_stack(); + let c = &mut init_context(); + assert_math_jet( - s, + c, jet_add, &[atom_128, atom_96], ubig!(0xdeadbef00d03068514bb685765666666), ); assert_math_jet( - s, + c, jet_add, &[atom_63, atom_96], ubig!(0xfaceb00c95deadbeef123455), ); - assert_math_jet(s, jet_add, &[atom_63, atom_63], ubig!(0xfffffffffffffffe)); + assert_math_jet(c, jet_add, &[atom_63, atom_63], ubig!(0xfffffffffffffffe)); } #[test] fn test_dec() { - let s = &mut init_stack(); + let c = &mut init_context(); + let s = &mut c.stack; + let (a0, _a24, a63, _a96, a128) = atoms(s); - assert_jet_ubig(s, jet_dec, a128, ubig!(0xdeadbeef12345678fedcba987654320f)); - assert_jet(s, jet_dec, a63, D(0x7ffffffffffffffe)); - assert_jet_err(s, jet_dec, a0, Deterministic); + assert_jet_ubig(c, jet_dec, a128, ubig!(0xdeadbeef12345678fedcba987654320f)); + assert_jet(c, jet_dec, a63, D(0x7ffffffffffffffe)); + assert_jet_err(c, jet_dec, a0, JetErr::Fail(Error::Deterministic(D(0)))); } #[test] fn test_div() { - let s = &mut init_stack(); - assert_math_jet(s, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0)); - assert_math_jet(s, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018)); - assert_math_jet(s, jet_div, &[atom_63, atom_96], ubig!(0)); - assert_math_jet(s, jet_div, &[atom_63, atom_63], ubig!(1)); - assert_math_jet(s, jet_div, &[atom_63, atom_24], ubig!(0xf2044dacfe)); + let c = &mut init_context(); + + assert_math_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0)); + assert_math_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018)); + assert_math_jet(c, jet_div, &[atom_63, atom_96], ubig!(0)); + assert_math_jet(c, jet_div, &[atom_63, atom_63], ubig!(1)); + assert_math_jet(c, jet_div, &[atom_63, atom_24], ubig!(0xf2044dacfe)); assert_math_jet( - s, + c, jet_div, &[atom_128, atom_24], ubig!(0x1a507f98b6fa8605ea3a79e97bf), @@ -401,168 +407,206 @@ mod tests { let res = ubig!( _0x00000000000001000000000000000000000000000000000000000000000000000000000000000001 ); - assert_math_jet(s, jet_div, &[atom_528, atom_264], res); - assert_math_jet_err(s, jet_div, &[atom_63, atom_0], Deterministic); - assert_math_jet_err(s, jet_div, &[atom_0, atom_0], Deterministic); + assert_math_jet(c, jet_div, &[atom_528, atom_264], res); + assert_math_jet_err( + c, + jet_div, + &[atom_63, atom_0], + JetErr::Fail(Error::Deterministic(D(0))), + ); + assert_math_jet_err( + c, + jet_div, + &[atom_0, atom_0], + JetErr::Fail(Error::Deterministic(D(0))), + ); } #[test] fn test_dvr() { - let s = &mut init_stack(); - let (a0, a24, a63, a96, a128) = atoms(s); - let a264 = atom_264(s); - let a528 = atom_528(s); + let c = &mut init_context(); - let sam = T(s, &[a128, a96]); - let res_a = A(s, &ubig!(0xe349f8f0)); - let res_b = A(s, &ubig!(0xcb0ce564ec598f658409d170)); - let res = T(s, &[res_a, res_b]); - assert_jet(s, jet_dvr, sam, res); + let (a0, a24, a63, a96, a128) = atoms(&mut c.stack); + let a264 = atom_264(&mut c.stack); + let a528 = atom_528(&mut c.stack); - let sam = T(s, &[a128, a24]); - let res_a = A(s, &ubig!(0x1a507f98b6fa8605ea3a79e97bf)); - let res_b = A(s, &ubig!(0x3b2013)); - let res = T(s, &[res_a, res_b]); - assert_jet(s, jet_dvr, sam, res); + let sam = T(&mut c.stack, &[a128, a96]); + let res_a = A(&mut c.stack, &ubig!(0xe349f8f0)); + let res_b = A(&mut c.stack, &ubig!(0xcb0ce564ec598f658409d170)); + let res = T(&mut c.stack, &[res_a, res_b]); + assert_jet(c, jet_dvr, sam, res); - let sam = T(s, &[a63, a63]); - let res_a = A(s, &ubig!(1)); - let res_b = A(s, &ubig!(0)); - let res = T(s, &[res_a, res_b]); - assert_jet(s, jet_dvr, sam, res); + let sam = T(&mut c.stack, &[a128, a24]); + let res_a = A(&mut c.stack, &ubig!(0x1a507f98b6fa8605ea3a79e97bf)); + let res_b = A(&mut c.stack, &ubig!(0x3b2013)); + let res = T(&mut c.stack, &[res_a, res_b]); + assert_jet(c, jet_dvr, sam, res); - let sam = T(s, &[a0, a24]); - let res_a = A(s, &ubig!(0)); - let res_b = A(s, &ubig!(0)); - let res = T(s, &[res_a, res_b]); - assert_jet(s, jet_dvr, sam, res); + let sam = T(&mut c.stack, &[a63, a63]); + let res_a = A(&mut c.stack, &ubig!(1)); + let res_b = A(&mut c.stack, &ubig!(0)); + let res = T(&mut c.stack, &[res_a, res_b]); + assert_jet(c, jet_dvr, sam, res); - let sam = T(s, &[a528, a264]); + let sam = T(&mut c.stack, &[a0, a24]); + let res_a = A(&mut c.stack, &ubig!(0)); + let res_b = A(&mut c.stack, &ubig!(0)); + let res = T(&mut c.stack, &[res_a, res_b]); + assert_jet(c, jet_dvr, sam, res); + + let sam = T(&mut c.stack, &[a528, a264]); let res_a = A( - s, + &mut c.stack, &ubig!( _0x00000000000001000000000000000000000000000000000000000000000000000000000000000001 ), ); - let res_b = A(s, &ubig!(0x100)); - let res = T(s, &[res_a, res_b]); - assert_jet(s, jet_dvr, sam, res); + let res_b = A(&mut c.stack, &ubig!(0x100)); + let res = T(&mut c.stack, &[res_a, res_b]); + assert_jet(c, jet_dvr, sam, res); - assert_math_jet_err(s, jet_dvr, &[atom_63, atom_0], Deterministic); + assert_math_jet_err( + c, + jet_dvr, + &[atom_63, atom_0], + JetErr::Fail(Error::Deterministic(D(0))), + ); } #[test] fn test_gte() { - let s = &mut init_stack(); - assert_math_jet_noun(s, jet_gte, &[atom_128, atom_96], YES); - assert_math_jet_noun(s, jet_gte, &[atom_96, atom_63], YES); - assert_math_jet_noun(s, jet_gte, &[atom_63, atom_96], NO); - assert_math_jet_noun(s, jet_gte, &[atom_63, atom_63], YES); - assert_math_jet_noun(s, jet_gte, &[atom_63, atom_24], YES); - assert_math_jet_noun(s, jet_gte, &[atom_128, atom_24], YES); - assert_math_jet_noun(s, jet_gte, &[atom_128, atom_128_b], YES); - assert_math_jet_noun(s, jet_gte, &[atom_128_b, atom_128], NO); + let c = &mut init_context(); + + assert_math_jet_noun(c, jet_gte, &[atom_128, atom_96], YES); + assert_math_jet_noun(c, jet_gte, &[atom_96, atom_63], YES); + assert_math_jet_noun(c, jet_gte, &[atom_63, atom_96], NO); + assert_math_jet_noun(c, jet_gte, &[atom_63, atom_63], YES); + assert_math_jet_noun(c, jet_gte, &[atom_63, atom_24], YES); + assert_math_jet_noun(c, jet_gte, &[atom_128, atom_24], YES); + assert_math_jet_noun(c, jet_gte, &[atom_128, atom_128_b], YES); + assert_math_jet_noun(c, jet_gte, &[atom_128_b, atom_128], NO); } #[test] fn test_gth() { - let s = &mut init_stack(); - assert_math_jet_noun(s, jet_gth, &[atom_128, atom_96], YES); - assert_math_jet_noun(s, jet_gth, &[atom_96, atom_63], YES); - assert_math_jet_noun(s, jet_gth, &[atom_63, atom_96], NO); - assert_math_jet_noun(s, jet_gth, &[atom_63, atom_63], NO); - assert_math_jet_noun(s, jet_gth, &[atom_63, atom_24], YES); - assert_math_jet_noun(s, jet_gth, &[atom_128, atom_24], YES); - assert_math_jet_noun(s, jet_gth, &[atom_128, atom_128_b], YES); - assert_math_jet_noun(s, jet_gth, &[atom_128_b, atom_128], NO); + let c = &mut init_context(); + + assert_math_jet_noun(c, jet_gth, &[atom_128, atom_96], YES); + assert_math_jet_noun(c, jet_gth, &[atom_96, atom_63], YES); + assert_math_jet_noun(c, jet_gth, &[atom_63, atom_96], NO); + assert_math_jet_noun(c, jet_gth, &[atom_63, atom_63], NO); + assert_math_jet_noun(c, jet_gth, &[atom_63, atom_24], YES); + assert_math_jet_noun(c, jet_gth, &[atom_128, atom_24], YES); + assert_math_jet_noun(c, jet_gth, &[atom_128, atom_128_b], YES); + assert_math_jet_noun(c, jet_gth, &[atom_128_b, atom_128], NO); } #[test] fn test_lte() { - let s = &mut init_stack(); - assert_math_jet_noun(s, jet_lte, &[atom_128, atom_96], NO); - assert_math_jet_noun(s, jet_lte, &[atom_96, atom_63], NO); - assert_math_jet_noun(s, jet_lte, &[atom_63, atom_96], YES); - assert_math_jet_noun(s, jet_lte, &[atom_63, atom_63], YES); - assert_math_jet_noun(s, jet_lte, &[atom_63, atom_24], NO); - assert_math_jet_noun(s, jet_lte, &[atom_128, atom_24], NO); - assert_math_jet_noun(s, jet_lte, &[atom_128, atom_128_b], NO); - assert_math_jet_noun(s, jet_lte, &[atom_128_b, atom_128], YES); + let c = &mut init_context(); + + assert_math_jet_noun(c, jet_lte, &[atom_128, atom_96], NO); + assert_math_jet_noun(c, jet_lte, &[atom_96, atom_63], NO); + assert_math_jet_noun(c, jet_lte, &[atom_63, atom_96], YES); + assert_math_jet_noun(c, jet_lte, &[atom_63, atom_63], YES); + assert_math_jet_noun(c, jet_lte, &[atom_63, atom_24], NO); + assert_math_jet_noun(c, jet_lte, &[atom_128, atom_24], NO); + assert_math_jet_noun(c, jet_lte, &[atom_128, atom_128_b], NO); + assert_math_jet_noun(c, jet_lte, &[atom_128_b, atom_128], YES); } #[test] fn test_lth() { - let s = &mut init_stack(); - assert_math_jet_noun(s, jet_lth, &[atom_128, atom_96], NO); - assert_math_jet_noun(s, jet_lth, &[atom_96, atom_63], NO); - assert_math_jet_noun(s, jet_lth, &[atom_63, atom_96], YES); - assert_math_jet_noun(s, jet_lth, &[atom_63, atom_63], NO); - assert_math_jet_noun(s, jet_lth, &[atom_63, atom_24], NO); - assert_math_jet_noun(s, jet_lth, &[atom_128, atom_24], NO); - assert_math_jet_noun(s, jet_lth, &[atom_128, atom_128_b], NO); - assert_math_jet_noun(s, jet_lth, &[atom_128_b, atom_128], YES); + let c = &mut init_context(); + + assert_math_jet_noun(c, jet_lth, &[atom_128, atom_96], NO); + assert_math_jet_noun(c, jet_lth, &[atom_96, atom_63], NO); + assert_math_jet_noun(c, jet_lth, &[atom_63, atom_96], YES); + assert_math_jet_noun(c, jet_lth, &[atom_63, atom_63], NO); + assert_math_jet_noun(c, jet_lth, &[atom_63, atom_24], NO); + assert_math_jet_noun(c, jet_lth, &[atom_128, atom_24], NO); + assert_math_jet_noun(c, jet_lth, &[atom_128, atom_128_b], NO); + assert_math_jet_noun(c, jet_lth, &[atom_128_b, atom_128], YES); } #[test] fn test_mod() { - let s = &mut init_stack(); + let c = &mut init_context(); + assert_math_jet( - s, + c, jet_mod, &[atom_128, atom_96], ubig!(0xcb0ce564ec598f658409d170), ); - assert_math_jet(s, jet_mod, &[atom_96, atom_63], ubig!(0x15deadc0e4af946e)); - assert_math_jet(s, jet_mod, &[atom_63, atom_96], ubig!(0x7fffffffffffffff)); - assert_math_jet(s, jet_mod, &[atom_63, atom_63], ubig!(0)); - assert_math_jet(s, jet_mod, &[atom_63, atom_24], ubig!(0x798385)); - assert_math_jet(s, jet_mod, &[atom_128, atom_24], ubig!(0x3b2013)); - assert_math_jet(s, jet_mod, &[atom_528, atom_264], ubig!(0x100)); - assert_math_jet_err(s, jet_mod, &[atom_63, atom_0], Deterministic); - assert_math_jet_err(s, jet_mod, &[atom_0, atom_0], Deterministic); + assert_math_jet(c, jet_mod, &[atom_96, atom_63], ubig!(0x15deadc0e4af946e)); + assert_math_jet(c, jet_mod, &[atom_63, atom_96], ubig!(0x7fffffffffffffff)); + assert_math_jet(c, jet_mod, &[atom_63, atom_63], ubig!(0)); + assert_math_jet(c, jet_mod, &[atom_63, atom_24], ubig!(0x798385)); + assert_math_jet(c, jet_mod, &[atom_128, atom_24], ubig!(0x3b2013)); + assert_math_jet(c, jet_mod, &[atom_528, atom_264], ubig!(0x100)); + assert_math_jet_err( + c, + jet_mod, + &[atom_63, atom_0], + JetErr::Fail(Error::Deterministic(D(0))), + ); + assert_math_jet_err( + c, + jet_mod, + &[atom_0, atom_0], + JetErr::Fail(Error::Deterministic(D(0))), + ); } #[test] fn test_mul() { - let s = &mut init_stack(); + let c = &mut init_context(); + assert_math_jet( - s, + c, jet_mul, &[atom_128, atom_96], ubig!(_0xda297567129704bf42e744f13ff0ea4fc4ac01215b708bc94f941160), ); assert_math_jet( - s, + c, jet_mul, &[atom_63, atom_96], ubig!(_0x7d6758060aef56de7cba6a1eea21524110edcbaa), ); assert_math_jet( - s, + c, jet_mul, &[atom_63, atom_63], ubig!(0x3fffffffffffffff0000000000000001), ); - assert_math_jet(s, jet_mul, &[atom_24, atom_24], ubig!(0x479bf4b7ef89)); + assert_math_jet(c, jet_mul, &[atom_24, atom_24], ubig!(0x479bf4b7ef89)); } #[test] fn test_sub() { - let s = &mut init_stack(); + let c = &mut init_context(); + assert_math_jet( - s, + c, jet_sub, &[atom_128, atom_96], ubig!(0xdeadbeee1765a66ce8fe0cd98741fdba), ); assert_math_jet( - s, + c, jet_sub, &[atom_96, atom_63], ubig!(0xfaceb00b95deadbeef123457), ); - assert_math_jet(s, jet_sub, &[atom_63, atom_63], ubig!(0)); - assert_math_jet(s, jet_sub, &[atom_128, atom_128], ubig!(0)); - assert_math_jet_err(s, jet_sub, &[atom_63, atom_96], Deterministic); + assert_math_jet(c, jet_sub, &[atom_63, atom_63], ubig!(0)); + assert_math_jet(c, jet_sub, &[atom_128, atom_128], ubig!(0)); + assert_math_jet_err( + c, + jet_sub, + &[atom_63, atom_96], + JetErr::Fail(Error::Deterministic(D(0))), + ); } } diff --git a/rust/ares/src/jets/nock.rs b/rust/ares/src/jets/nock.rs index a3dc460..b0337c5 100644 --- a/rust/ares/src/jets/nock.rs +++ b/rust/ares/src/jets/nock.rs @@ -1,25 +1,83 @@ /** Virtualization jets */ -use crate::interpreter::Context; +use crate::hamt::Hamt; +use crate::interpreter::{Context, Error}; use crate::jets::util::slot; -use crate::jets::Result; -use crate::noun::Noun; +use crate::jets::{JetErr, Result}; +use crate::noun::{Noun, T}; crate::gdb!(); -// XX: interpret should accept optional scry function and potentially produce blocked +// Deterministic scry crashes should have the following behaviour: +// +// root <-- bail, %crud +// mink <-- return Deterministic +// scry <-- return ScryCrashed +// +// root <-- bail, %crud +// mink <-- return Deterministic +// mink <-- return ScryCrashed +// scry <-- return ScryCrashed +// scry <-- return ScryCrashed +// +// root +// mink <-- return Tone +// mink <-- return Deterministic +// mink <-- return ScryCrashed +// scry <-- return ScryCrashed +// scry <-- return ScryCrashed +// scry +// pub fn jet_mink(context: &mut Context, subject: Noun) -> Result { let arg = slot(subject, 6)?; // mink sample = [nock scry_namespace] // = [[subject formula] scry_namespace] let v_subject = slot(arg, 4)?; let v_formula = slot(arg, 5)?; - let _scry = slot(arg, 3)?; - util::mink(context, v_subject, v_formula) + let scry_handler = slot(arg, 3)?; + + let old_cache = context.cache; + let old_scry_stack = context.scry_stack; + + context.cache = Hamt::::new(); + context.scry_stack = T(&mut context.stack, &[scry_handler, old_scry_stack]); + + match util::mink(context, v_subject, v_formula) { + Ok(noun) => { + context.cache = old_cache; + context.scry_stack = old_scry_stack; + Ok(noun) + } + 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. + if unsafe { context.scry_stack.raw_equals(old_scry_stack) } { + Err(JetErr::Fail(Error::Deterministic(trace))) + } else { + Err(JetErr::Fail(error)) + } + } + Error::Deterministic(_) | Error::ScryBlocked(_) => { + panic!("scry: mink: unhandled errors in helper") + } + }, + } } pub mod util { - use crate::interpreter::{interpret, Context, NockErr, Tone}; + use crate::interpreter::{interpret, Context, Error}; use crate::jets; use crate::jets::form::util::scow; use crate::jets::util::rip; @@ -27,21 +85,19 @@ pub mod util { use crate::mem::NockStack; use crate::noun::{tape, Cell, Noun, D, T}; use ares_macros::tas; + use either::{Left, Right}; use std::result; pub const LEAF: Noun = D(tas!(b"leaf")); pub const ROSE: Noun = D(tas!(b"rose")); - pub fn mink(context: &mut Context, subject: Noun, formula: Noun) -> jets::Result { - // XX: no partial traces; all of our traces go down to the "home road" + pub fn mink(context: &mut Context, subject: Noun, formula: Noun) -> Result { match interpret(context, subject, formula) { - Ok(res) => Ok(T(context.stack, &[D(0), res])), + Ok(res) => Ok(T(&mut context.stack, &[D(0), res])), Err(err) => match err { - Tone::Blocked(block) => Ok(T(context.stack, &[D(1), block])), - Tone::Error(err, trace) => match err { - NockErr::Deterministic => Ok(T(context.stack, &[D(2), trace])), - NockErr::NonDeterministic => Err(JetErr::NonDeterministic), - }, + Error::ScryBlocked(path) => Ok(T(&mut context.stack, &[D(1), path])), + Error::Deterministic(trace) => Ok(T(&mut context.stack, &[D(2), trace])), + Error::NonDeterministic(_) | Error::ScryCrashed(_) => Err(err), }, } } @@ -55,14 +111,14 @@ pub mod util { match tag.data() { x if x < 2 => return Ok(tone), - x if x > 2 => return Err(JetErr::Deterministic), + x if x > 2 => return Err(JetErr::Fail(Error::Deterministic(D(0)))), _ => {} } if unsafe { original_list.raw_equals(D(0)) } { return Ok(tone); } else if original_list.atom().is_some() { - return Err(JetErr::Deterministic); + return Err(JetErr::Fail(Error::Deterministic(D(0)))); } // XX: trim traces longer than 1024 frames @@ -71,7 +127,7 @@ pub mod util { let mut res = D(0); let mut list = original_list; // Unused if flopping - let (mut new_cell, mut new_memory) = Cell::new_raw_mut(context.stack); + let (mut new_cell, mut new_memory) = Cell::new_raw_mut(&mut context.stack); let mut memory = new_memory; // loop guaranteed to run at least once @@ -81,7 +137,7 @@ pub mod util { } else if !flop && res.raw_equals(D(0)) { res = new_cell.as_noun(); } else if !flop { - (new_cell, new_memory) = Cell::new_raw_mut(context.stack); + (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack); (*memory).tail = new_cell.as_noun(); memory = new_memory } @@ -92,31 +148,54 @@ pub mod util { let dat = trace.tail(); let tank: Noun = match tag.data() { - tas!(b"mean") => { - if let Ok(atom) = dat.as_atom() { - let tape = rip(context.stack, 3, 1, atom)?; - T(context.stack, &[LEAF, tape]) - } else { - let tone = mink(context, dat, dat.as_cell()?.head())?.as_cell()?; - if !tone.head().raw_equals(D(0)) { - let tape = tape(context.stack, "####"); - T(context.stack, &[LEAF, tape]) - } else { - // XX: need to check that this is actually a tank - // return leaf+"mean.mook" if not - tone.tail() + tas!(b"hunk") => match dat.as_either_atom_cell() { + Left(_) => { + let stack = &mut context.stack; + let tape = tape(stack, "mook.hunk"); + T(stack, &[LEAF, tape]) + } + Right(cell) => { + // XX: need to check that this is actually a path + // return leaf+"mook.hunk" if not + let path = cell.tail(); + smyt(&mut context.stack, path)? + } + }, + tas!(b"mean") => match dat.as_either_atom_cell() { + Left(atom) => { + let stack = &mut context.stack; + let tape = rip(stack, 3, 1, atom)?; + T(stack, &[LEAF, tape]) + } + Right(cell) => { + 'tank: { + if let Ok(tone) = mink(context, dat, cell.head()) { + if let Some(cell) = tone.cell() { + if cell.head().raw_equals(D(0)) { + // XX: need to check that this is + // actually a path; + // return leaf+"mook.mean" if not + break 'tank cell.tail(); + } + } + } + + let stack = &mut context.stack; + let tape = tape(stack, "####"); + T(stack, &[LEAF, tape]) } } - } + }, tas!(b"spot") => { let stack = &mut context.stack; + let spot = dat.as_cell()?; let pint = spot.tail().as_cell()?; let pstr = pint.head().as_cell()?; let pend = pint.tail().as_cell()?; - let colo = T(*stack, &[D(b':' as u64), D(0)]); - let trel = T(*stack, &[colo, D(0), D(0)]); + let colo = T(stack, &[D(b':' as u64), D(0)]); + let trel = T(stack, &[colo, D(0), D(0)]); let smyt = smyt(stack, spot.head())?; @@ -134,7 +213,7 @@ pub mod util { list = list.tail().as_cell()?; } // "{end_col}]>" - let p4 = T(*stack, &[D(b']' as u64), D(b'>' as u64), D(0)]); + let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)]); (*list.tail_as_mut()) = p4; list = end_lin.as_cell()?; @@ -145,7 +224,7 @@ pub mod util { list = list.tail().as_cell()?; } // "{end_lin} {end_col}]>" - let p3 = T(*stack, &[D(b' ' as u64), end_col]); + let p3 = T(stack, &[D(b' ' as u64), end_col]); (*list.tail_as_mut()) = p3; list = str_col.as_cell()?; @@ -157,7 +236,7 @@ pub mod util { } // "{str_col}].[{end_lin} {end_col}]>" let p2 = T( - *stack, + stack, &[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin], ); (*list.tail_as_mut()) = p2; @@ -170,19 +249,20 @@ pub mod util { list = list.tail().as_cell()?; } // "{str_lin} {str_col}].[{end_lin} {end_col}]>" - let p1 = T(*stack, &[D(b' ' as u64), str_col]); + let p1 = T(stack, &[D(b' ' as u64), str_col]); (*list.tail_as_mut()) = p1; // "<[{str_lin} {str_col}].[{end_lin} {end_col}]>" - let tape = T(*stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]); - let finn = T(*stack, &[LEAF, tape]); + let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]); + let finn = T(stack, &[LEAF, tape]); - T(*stack, &[ROSE, trel, smyt, finn, D(0)]) + T(stack, &[ROSE, trel, smyt, finn, D(0)]) } _ => { - let tape = rip(context.stack, 3, 1, tag.as_atom())?; + let stack = &mut context.stack; + let tape = rip(stack, 3, 1, tag.as_atom())?; T( - context.stack, + stack, &[ D(tas!(b"m")), D(tas!(b"o")), @@ -194,12 +274,11 @@ pub mod util { ) } // XX: TODO // %hand - // %hunk // %lose }; if flop { - res = T(context.stack, &[tank, res]); + res = T(&mut context.stack, &[tank, res]); } else { (*memory).head = tank; } @@ -210,7 +289,7 @@ pub mod util { (*memory).tail = D(0); } - let toon = Cell::new(context.stack, D(2), res); + let toon = Cell::new(&mut context.stack, D(2), res); Ok(toon) } } @@ -244,7 +323,7 @@ pub mod util { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, init_stack}; + use crate::jets::util::test::{assert_jet, init_context}; use crate::mem::NockStack; use crate::noun::{D, T}; use crate::serf::TERMINATOR; @@ -265,31 +344,36 @@ mod tests { #[test] fn test_mink_success() { - let sack = &mut init_stack(); + let context = &mut init_context(); + let stack = &mut context.stack; + let subj = D(0); - let form = T(sack, &[D(1), D(53)]); - let nock = T(sack, &[subj, form]); + let form = T(stack, &[D(1), D(53)]); + let nock = T(stack, &[subj, form]); let scry = D(0); - let samp = T(sack, &[nock, scry]); - let rest = T(sack, &[D(0), D(53)]); - assert_jet(sack, jet_mink, samp, rest); + let samp = T(stack, &[nock, scry]); + let rest = T(stack, &[D(0), D(53)]); + assert_jet(context, jet_mink, samp, rest); } #[test] fn test_mink_zapzap() { - let sack = &mut init_stack(); + let context = &mut init_context(); + let stack = &mut context.stack; + let subj = D(0); - let form = T(sack, &[D(0), D(0)]); - let nock = T(sack, &[subj, form]); + let form = T(stack, &[D(0), D(0)]); + let nock = T(stack, &[subj, form]); let scry = D(0); - let samp = T(sack, &[nock, scry]); - let rest = T(sack, &[D(2), D(0)]); - assert_jet(sack, jet_mink, samp, rest); + let samp = T(stack, &[nock, scry]); + let rest = T(stack, &[D(2), D(0), D(0)]); + assert_jet(context, jet_mink, samp, rest); } #[test] fn test_mink_trace() { - let sack = &mut init_stack(); + let context = &mut init_context(); + let stack = &mut context.stack; let subj = D(0); let scry = D(0); @@ -313,63 +397,63 @@ mod tests { // https://stackoverflow.com/questions/60686259/mutable-borrow-in-function-argument let hint_spot = D(1953460339); - let hint_path = T(sack, &[D(1953719668), D(0)]); + let hint_path = T(stack, &[D(1953719668), D(0)]); let hint_dyn = D(1); let hint_row = D(1); - let make_hint = |sack: &mut NockStack, col_start: u64, col_end: u64| { - let start = T(sack, &[hint_row, D(col_start)]); - let end = T(sack, &[hint_row, D(col_end)]); + let make_hint = |stack: &mut NockStack, col_start: u64, col_end: u64| { + let start = T(stack, &[hint_row, D(col_start)]); + let end = T(stack, &[hint_row, D(col_end)]); - T(sack, &[hint_spot, hint_dyn, hint_path, start, end]) + T(stack, &[hint_spot, hint_dyn, hint_path, start, end]) }; - let sss3s1 = T(sack, &[D(0), D(3)]); - let sss3s2s1 = make_hint(sack, 20, 22); - let sss3s2s2 = T(sack, &[D(1), D(53)]); - let sss3s2 = T(sack, &[D(11), sss3s2s1, sss3s2s2]); - let sss3 = T(sack, &[D(7), sss3s1, sss3s2]); + let sss3s1 = T(stack, &[D(0), D(3)]); + let sss3s2s1 = make_hint(stack, 20, 22); + let sss3s2s2 = T(stack, &[D(1), D(53)]); + let sss3s2 = T(stack, &[D(11), sss3s2s1, sss3s2s2]); + let sss3 = T(stack, &[D(7), sss3s1, sss3s2]); let sss2s1 = sss3s1; - let sss2s2s1 = make_hint(sack, 16, 18); - let sss2s2s2 = T(sack, &[D(0), D(0)]); - let sss2s2 = T(sack, &[D(11), sss2s2s1, sss2s2s2]); - let sss2 = T(sack, &[D(7), sss2s1, sss2s2]); + let sss2s2s1 = make_hint(stack, 16, 18); + let sss2s2s2 = T(stack, &[D(0), D(0)]); + let sss2s2 = T(stack, &[D(11), sss2s2s1, sss2s2s2]); + let sss2 = T(stack, &[D(7), sss2s1, sss2s2]); - let sss1s1 = T(sack, &[D(1), D(0)]); - let sss1s2 = T(sack, &[D(0), D(2)]); - let sss1 = T(sack, &[D(5), sss1s1, sss1s2]); + let sss1s1 = T(stack, &[D(1), D(0)]); + let sss1s2 = T(stack, &[D(0), D(2)]); + let sss1 = T(stack, &[D(5), sss1s1, sss1s2]); - let ss2 = T(sack, &[D(6), sss1, sss2, sss3]); + let ss2 = T(stack, &[D(6), sss1, sss2, sss3]); - let ss1s1 = make_hint(sack, 13, 14); + let ss1s1 = make_hint(stack, 13, 14); let ss1s2 = sss1s1; - let ss1 = T(sack, &[D(11), ss1s1, ss1s2]); + let ss1 = T(stack, &[D(11), ss1s1, ss1s2]); - let s2 = T(sack, &[D(8), ss1, ss2]); - let s1 = make_hint(sack, 9, 22); - let form = T(sack, &[D(11), s1, s2]); + let s2 = T(stack, &[D(8), ss1, ss2]); + let s1 = make_hint(stack, 9, 22); + let form = T(stack, &[D(11), s1, s2]); - let nock = T(sack, &[subj, form]); - let samp = T(sack, &[nock, scry]); + let nock = T(stack, &[subj, form]); + let samp = T(stack, &[nock, scry]); // trace // [%2 trace=~[[~.spot [[1.953.719.668 0] [1 16] 1 18]] [~.spot [[1.953.719.668 0] [1 9] 1 22]]]] - let ttt2t1 = T(sack, &[D(1), D(9)]); - let ttt2t2 = T(sack, &[D(1), D(22)]); - let ttt2 = T(sack, &[hint_path, ttt2t1, ttt2t2]); + let ttt2t1 = T(stack, &[D(1), D(9)]); + let ttt2t2 = T(stack, &[D(1), D(22)]); + let ttt2 = T(stack, &[hint_path, ttt2t1, ttt2t2]); - let ttt1t1 = T(sack, &[D(1), D(16)]); - let ttt1t2 = T(sack, &[D(1), D(18)]); - let ttt1 = T(sack, &[hint_path, ttt1t1, ttt1t2]); + let ttt1t1 = T(stack, &[D(1), D(16)]); + let ttt1t2 = T(stack, &[D(1), D(18)]); + let ttt1 = T(stack, &[hint_path, ttt1t1, ttt1t2]); - let tt2 = T(sack, &[hint_spot, ttt2]); - let tt1 = T(sack, &[hint_spot, ttt1]); + let tt2 = T(stack, &[hint_spot, ttt2]); + let tt1 = T(stack, &[hint_spot, ttt1]); - let t1 = T(sack, &[tt1, tt2, D(0)]); + let t1 = T(stack, &[tt1, tt2, D(0)]); - let rest = T(sack, &[D(2), t1]); + let rest = T(stack, &[D(2), t1, D(0)]); - assert_jet(sack, jet_mink, samp, rest); + assert_jet(context, jet_mink, samp, rest); } } diff --git a/rust/ares/src/jets/sort.rs b/rust/ares/src/jets/sort.rs index 65b105a..929a5ff 100644 --- a/rust/ares/src/jets/sort.rs +++ b/rust/ares/src/jets/sort.rs @@ -25,7 +25,7 @@ pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result { match e.data().cmp(&f.data()) { Ordering::Greater => Ok(NO), Ordering::Less => Ok(YES), - Ordering::Equal => Ok(util::dor(a, b)), + Ordering::Equal => Ok(util::dor(stack, a, b)), } } @@ -42,30 +42,31 @@ pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result { match c.data().cmp(&d.data()) { Ordering::Greater => Ok(NO), Ordering::Less => Ok(YES), - Ordering::Equal => Ok(util::dor(a, b)), + Ordering::Equal => Ok(util::dor(stack, a, b)), } } -pub fn jet_dor(_context: &mut Context, subject: Noun) -> jets::Result { +pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result { let sam = slot(subject, 6)?; let a = slot(sam, 2)?; let b = slot(sam, 3)?; - Ok(util::dor(a, b)) + Ok(util::dor(&mut context.stack, a, b)) } pub mod util { use crate::jets::math::util::lth; use crate::jets::util::slot; + use crate::mem::NockStack; use crate::noun::{Noun, NO, YES}; use either::{Left, Right}; - pub fn dor(a: Noun, b: Noun) -> Noun { + pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> Noun { if unsafe { a.raw_equals(b) } { YES } else { match (a.as_either_atom_cell(), b.as_either_atom_cell()) { - (Left(atom_a), Left(atom_b)) => lth(atom_a, atom_b), + (Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b), (Left(_), Right(_)) => YES, (Right(_), Left(_)) => NO, (Right(cell_a), Right(cell_b)) => { @@ -77,9 +78,9 @@ pub mod util { let a_tail = slot(cell_a.as_noun(), 3).unwrap(); let b_tail = slot(cell_b.as_noun(), 3).unwrap(); if unsafe { a_head.raw_equals(b_head) } { - dor(a_tail, b_tail) + dor(stack, a_tail, b_tail) } else { - dor(a_head, b_head) + dor(stack, a_head, b_head) } } } @@ -90,44 +91,47 @@ pub mod util { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, init_stack, A}; + use crate::jets::util::test::{assert_jet, init_context, A}; use crate::noun::{D, T}; use ibig::ubig; #[test] fn test_dor() { - let s = &mut init_stack(); - let sam = T(s, &[D(1), D(1)]); - assert_jet(s, jet_dor, sam, YES); + let c = &mut init_context(); - let a = A(s, &ubig!(_0x3fffffffffffffff)); - let sam = T(s, &[a, D(1)]); - assert_jet(s, jet_dor, sam, NO); + let sam = T(&mut c.stack, &[D(1), D(1)]); + assert_jet(c, jet_dor, sam, YES); - let a = A(s, &ubig!(_0x3fffffffffffffff)); - let sam = T(s, &[a, a]); - assert_jet(s, jet_dor, sam, YES); + let a = A(&mut c.stack, &ubig!(_0x3fffffffffffffff)); + let sam = T(&mut c.stack, &[a, D(1)]); + assert_jet(c, jet_dor, sam, NO); + + let a = A(&mut c.stack, &ubig!(_0x3fffffffffffffff)); + let sam = T(&mut c.stack, &[a, a]); + assert_jet(c, jet_dor, sam, YES); } #[test] fn test_gor() { - let s = &mut init_stack(); - let sam = T(s, &[D(1), D(1)]); - assert_jet(s, jet_gor, sam, YES); + let c = &mut init_context(); - let a = A(s, &ubig!(_0x3fffffffffffffff)); - let sam = T(s, &[a, a]); - assert_jet(s, jet_gor, sam, YES); + let sam = T(&mut c.stack, &[D(1), D(1)]); + assert_jet(c, jet_gor, sam, YES); + + let a = A(&mut c.stack, &ubig!(_0x3fffffffffffffff)); + let sam = T(&mut c.stack, &[a, a]); + assert_jet(c, jet_gor, sam, YES); } #[test] fn test_mor() { - let s = &mut init_stack(); - let sam = T(s, &[D(1), D(1)]); - assert_jet(s, jet_mor, sam, YES); + let c = &mut init_context(); - let a = A(s, &ubig!(_0x3fffffffffffffff)); - let sam = T(s, &[a, a]); - assert_jet(s, jet_mor, sam, YES); + let sam = T(&mut c.stack, &[D(1), D(1)]); + assert_jet(c, jet_mor, sam, YES); + + let a = A(&mut c.stack, &ubig!(_0x3fffffffffffffff)); + let sam = T(&mut c.stack, &[a, a]); + assert_jet(c, jet_mor, sam, YES); } } diff --git a/rust/ares/src/jets/text.rs b/rust/ares/src/jets/text.rs index c26fdf7..421f46d 100644 --- a/rust/ares/src/jets/text.rs +++ b/rust/ares/src/jets/text.rs @@ -13,8 +13,9 @@ pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result { } pub mod util { + use crate::interpreter::Error; use crate::jets::JetErr; - use crate::noun::Noun; + use crate::noun::{Noun, D}; pub fn lent(tape: Noun) -> Result { let mut len = 0usize; @@ -24,7 +25,7 @@ pub mod util { if atom.as_bitslice().first_one().is_none() { break; } else { - return Err(JetErr::Deterministic); + return Err(JetErr::Fail(Error::Deterministic(D(0)))); } } let cell = list.as_cell()?; @@ -39,20 +40,22 @@ pub mod util { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack}; + use crate::interpreter::Error; + use crate::jets::util::test::{assert_jet, assert_jet_err, init_context}; use crate::jets::JetErr; use crate::noun::{D, T}; #[test] fn test_lent() { - let s = &mut init_stack(); - assert_jet(s, jet_lent, D(0), D(0)); - let sam = T(s, &[D(1), D(2), D(3), D(0)]); - assert_jet(s, jet_lent, sam, D(3)); - let sam = T(s, &[D(3), D(2), D(1), D(0)]); - assert_jet(s, jet_lent, sam, D(3)); - assert_jet_err(s, jet_lent, D(1), JetErr::Deterministic); - let sam = T(s, &[D(3), D(2), D(1)]); - assert_jet_err(s, jet_lent, sam, JetErr::Deterministic); + let c = &mut init_context(); + + assert_jet(c, jet_lent, D(0), D(0)); + let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]); + assert_jet(c, jet_lent, sam, D(3)); + let sam = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]); + assert_jet(c, jet_lent, sam, D(3)); + assert_jet_err(c, jet_lent, D(1), JetErr::Fail(Error::Deterministic(D(0)))); + let sam = T(&mut c.stack, &[D(3), D(2), D(1)]); + assert_jet_err(c, jet_lent, sam, JetErr::Fail(Error::Deterministic(D(0)))); } } diff --git a/rust/ares/src/jets/tree.rs b/rust/ares/src/jets/tree.rs index 891e793..29e5b11 100644 --- a/rust/ares/src/jets/tree.rs +++ b/rust/ares/src/jets/tree.rs @@ -1,9 +1,8 @@ /** Tree jets */ -use crate::interpreter::Context; +use crate::interpreter::{Context, Error}; use crate::jets::util::*; -use crate::jets::JetErr::*; -use crate::jets::Result; +use crate::jets::{JetErr, Result}; use crate::noun::{Noun, D}; crate::gdb!(); @@ -15,7 +14,7 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result { unsafe { if met < 2 { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else if *(tom.as_bitslice().get_unchecked(met - 2)) { Ok(D(3)) } else { @@ -31,7 +30,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result { let met = met(0, tom); if met < 2 { - Err(Deterministic) + Err(JetErr::Fail(Error::Deterministic(D(0)))) } else { let c = bex(stack, met - 1); let d = bex(stack, met - 2); @@ -44,39 +43,40 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result { #[cfg(test)] mod tests { use super::*; - use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack}; + use crate::interpreter::Error; + use crate::jets::util::test::{assert_jet, assert_jet_err, init_context}; use crate::jets::JetErr; use crate::noun::D; #[test] fn test_cap() { - let s = &mut init_stack(); + let c = &mut init_context(); - assert_jet_err(s, jet_cap, D(0), JetErr::Deterministic); - assert_jet_err(s, jet_cap, D(1), JetErr::Deterministic); + assert_jet_err(c, jet_cap, D(0), JetErr::Fail(Error::Deterministic(D(0)))); + assert_jet_err(c, jet_cap, D(1), JetErr::Fail(Error::Deterministic(D(0)))); - assert_jet(s, jet_cap, D(2), D(2)); - assert_jet(s, jet_cap, D(3), D(3)); - assert_jet(s, jet_cap, D(4), D(2)); - assert_jet(s, jet_cap, D(5), D(2)); - assert_jet(s, jet_cap, D(6), D(3)); - assert_jet(s, jet_cap, D(7), D(3)); - assert_jet(s, jet_cap, D(8), D(2)); + assert_jet(c, jet_cap, D(2), D(2)); + assert_jet(c, jet_cap, D(3), D(3)); + assert_jet(c, jet_cap, D(4), D(2)); + assert_jet(c, jet_cap, D(5), D(2)); + assert_jet(c, jet_cap, D(6), D(3)); + assert_jet(c, jet_cap, D(7), D(3)); + assert_jet(c, jet_cap, D(8), D(2)); } #[test] fn test_mas() { - let s = &mut init_stack(); + let c = &mut init_context(); - assert_jet_err(s, jet_mas, D(0), JetErr::Deterministic); - assert_jet_err(s, jet_mas, D(1), JetErr::Deterministic); + assert_jet_err(c, jet_mas, D(0), JetErr::Fail(Error::Deterministic(D(0)))); + assert_jet_err(c, jet_mas, D(1), JetErr::Fail(Error::Deterministic(D(0)))); - 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)); + assert_jet(c, jet_mas, D(2), D(1)); + assert_jet(c, jet_mas, D(3), D(1)); + assert_jet(c, jet_mas, D(4), D(2)); + assert_jet(c, jet_mas, D(5), D(3)); + assert_jet(c, jet_mas, D(6), D(2)); + assert_jet(c, jet_mas, D(7), D(3)); + assert_jet(c, jet_mas, D(8), D(4)); } } diff --git a/rust/ares/src/jets/warm.rs b/rust/ares/src/jets/warm.rs index 4a3b52d..d355f09 100644 --- a/rust/ares/src/jets/warm.rs +++ b/rust/ares/src/jets/warm.rs @@ -6,6 +6,7 @@ use crate::mem::{NockStack, Preserve}; use crate::noun::{Noun, Slots}; use std::ptr::{copy_nonoverlapping, null_mut}; +/// key = formula pub struct Warm(Hamt); impl Preserve for Warm { @@ -129,6 +130,9 @@ impl Warm { warm } + /// Walk through the linked list of WarmEntry objects and do a partial check + /// against the subject using Batteries (walk to root of parent batteries). + /// If there's a match, then we've found a valid jet. pub fn find_jet(&mut self, stack: &mut NockStack, s: &mut Noun, f: &mut Noun) -> Option { let warm_it = self.0.lookup(stack, f)?; for (_path, batteries, jet) in warm_it { diff --git a/rust/ares/src/main.rs b/rust/ares/src/main.rs index 73ea4f5..fc6953c 100644 --- a/rust/ares/src/main.rs +++ b/rust/ares/src/main.rs @@ -4,7 +4,8 @@ use ares::jets::cold::Cold; use ares::jets::hot::Hot; use ares::jets::warm::Warm; use ares::mem::NockStack; -use ares::noun::{IndirectAtom, Noun}; +use ares::newt::Newt; +use ares::noun::{IndirectAtom, Noun, D}; use ares::serf::serf; use ares::serialization::{cue, jam}; use memmap::Mmap; @@ -65,24 +66,26 @@ fn main() -> io::Result<()> { let input_cell = input .as_cell() .expect("Input must be jam of subject/formula pair"); - let mut cache = Hamt::::new(); - let mut cold = Cold::new(&mut stack); - let mut warm = Warm::new(); + let newt = Newt::new_mock(); + let cache = Hamt::::new(); + let cold = Cold::new(&mut stack); + let warm = Warm::new(); let hot = Hot::init(&mut stack); let mut context = Context { - stack: &mut stack, - newt: None, - cache: &mut cache, - cold: &mut cold, - warm: &mut warm, - hot: &hot, + stack, + newt, + cache, + cold, + warm, + hot, + scry_stack: D(0), }; let result = interpret(&mut context, input_cell.head(), input_cell.tail()).expect("nock failed"); if let Ok(atom) = result.as_atom() { println!("Result: {}", atom); } - let jammed_result = jam(&mut stack, result); + let jammed_result = jam(&mut context.stack, result); let f_out = OpenOptions::new() .read(true) .write(true) diff --git a/rust/ares/src/newt.rs b/rust/ares/src/newt.rs index 1b996a9..2723a09 100644 --- a/rust/ares/src/newt.rs +++ b/rust/ares/src/newt.rs @@ -75,6 +75,13 @@ impl Newt { } } + pub fn new_mock() -> Newt { + Newt { + input: std::fs::File::open("/dev/null").expect("newt: could not open /dev/null"), + output: std::fs::File::open("/dev/null").expect("newt: could not open /dev/null"), + } + } + /** Write a noun to the newt. * * NB: we write 64-bit words, while vere writes bytes. The extra zero bytes shouldn't be a diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index fdddfe7..52b180d 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -1,6 +1,6 @@ use crate::hamt::Hamt; use crate::interpreter; -use crate::interpreter::{inc, interpret, Tone}; +use crate::interpreter::{inc, interpret, Error}; use crate::jets::cold::Cold; use crate::jets::hot::Hot; use crate::jets::nock::util::mook; @@ -30,13 +30,7 @@ struct Context { snapshot: DoubleJam, arvo: Noun, mug: u32, - stack: NockStack, - newt: Newt, - cache: Hamt, - // XX: persistent memo cache - cold: Cold, - warm: Warm, - hot: Hot, + nock_context: interpreter::Context, } impl Context { @@ -55,51 +49,23 @@ impl Context { let (epoch, event_num, arvo) = snapshot.load(&mut stack).unwrap_or((0, 0, D(0))); let mug = mug_u32(&mut stack, arvo); + let nock_context = interpreter::Context { + stack, + newt, + cold, + warm, + hot, + cache, + scry_stack: D(0), + }; + Context { epoch, event_num, snapshot, arvo, mug, - stack, - newt, - cache, - cold, - warm, - hot, - } - } - - // - // Getters - // - - pub fn epoch(&self) -> u64 { - self.epoch - } - - pub fn event_num(&self) -> u64 { - self.event_num - } - - pub fn arvo(&self) -> Noun { - self.arvo - } - - pub fn stack_as_mut(&mut self) -> &mut NockStack { - &mut self.stack - } - - pub fn for_interpreter(&mut self) -> interpreter::Context { - self.cache = Hamt::::new(); - - interpreter::Context { - stack: &mut self.stack, - newt: Some(&mut self.newt), - cache: &mut self.cache, - cold: &mut self.cold, - warm: &mut self.warm, - hot: &self.hot, + nock_context, } } @@ -111,8 +77,9 @@ impl Context { // XX: assert event numbers are continuous self.arvo = new_arvo; self.event_num = new_event_num; - self.snapshot.save(&mut self.stack, &mut self.arvo); - self.mug = mug_u32(&mut self.stack, self.arvo); + self.snapshot + .save(&mut self.nock_context.stack, &mut self.arvo); + self.mug = mug_u32(&mut self.nock_context.stack, self.arvo); } // @@ -121,7 +88,7 @@ impl Context { pub fn sync(&mut self) { self.snapshot - .sync(&mut self.stack, self.epoch, self.event_num); + .sync(&mut self.nock_context.stack, self.epoch, self.event_num); } // @@ -129,43 +96,65 @@ impl Context { // pub fn next(&mut self) -> Option { - self.newt.next(&mut self.stack) + self.nock_context.newt.next(&mut self.nock_context.stack) } pub fn ripe(&mut self) { - self.newt - .ripe(&mut self.stack, self.event_num, self.mug as u64); + self.nock_context.newt.ripe( + &mut self.nock_context.stack, + self.event_num, + self.mug as u64, + ); } pub fn live(&mut self) { - self.newt.live(&mut self.stack); + self.nock_context.newt.live(&mut self.nock_context.stack); } pub fn peek_done(&mut self, dat: Noun) { - self.newt.peek_done(&mut self.stack, dat); + self.nock_context + .newt + .peek_done(&mut self.nock_context.stack, dat); } pub fn play_done(&mut self) { - self.newt.play_done(&mut self.stack, self.mug as u64); + self.nock_context + .newt + .play_done(&mut self.nock_context.stack, self.mug as u64); } pub fn play_bail(&mut self, dud: Noun) { - self.newt - .play_bail(&mut self.stack, self.event_num, self.mug as u64, dud); + self.nock_context.newt.play_bail( + &mut self.nock_context.stack, + self.event_num, + self.mug as u64, + dud, + ); } pub fn work_done(&mut self, fec: Noun) { - self.newt - .work_done(&mut self.stack, self.event_num, self.mug as u64, fec); + self.nock_context.newt.work_done( + &mut self.nock_context.stack, + self.event_num, + self.mug as u64, + fec, + ); } pub fn work_swap(&mut self, job: Noun, fec: Noun) { - self.newt - .work_swap(&mut self.stack, self.event_num, self.mug as u64, job, fec); + self.nock_context.newt.work_swap( + &mut self.nock_context.stack, + self.event_num, + self.mug as u64, + job, + fec, + ); } pub fn work_bail(&mut self, lud: Noun) { - self.newt.work_bail(&mut self.stack, lud); + self.nock_context + .newt + .work_bail(&mut self.nock_context.stack, lud); } } @@ -203,8 +192,11 @@ pub fn serf() -> io::Result<()> { // Can't use for loop because it borrows newt while let Some(writ) = context.next() { - // XX: probably want to bookend this logic frame_push / frame_pop - // preserve jet state and persistent cache, lose everything else + // Reset the local cache and scry handler stack + context.nock_context.cache = Hamt::::new(); + context.nock_context.scry_stack = D(0); + context.nock_context.stack.frame_push(0); + let tag = slot(writ, 2)?.as_direct().unwrap(); match tag.data() { tas!(b"live") => { @@ -231,7 +223,7 @@ pub fn serf() -> io::Result<()> { } tas!(b"play") => { let lit = slot(writ, 7)?; - if context.epoch() == 0 && context.event_num() == 0 { + if context.epoch == 0 && context.event_num == 0 { // apply lifecycle to first batch play_life(&mut context, lit); } else { @@ -247,54 +239,64 @@ pub fn serf() -> io::Result<()> { }; clear_interrupt(); + + // Persist data that should survive between events + // XX: Such data should go in the PMA once that's available + unsafe { + let stack = &mut context.nock_context.stack; + stack.preserve(&mut context.nock_context.cold); + stack.preserve(&mut context.nock_context.warm); + stack.frame_pop(); + } } Ok(()) } -fn burn(context: &mut Context, subject: Noun, formula: Noun) -> Result { - let burn_context = &mut context.for_interpreter(); - interpret(burn_context, subject, formula) -} - -fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result { - let arvo = context.arvo(); - let pul = T(context.stack_as_mut(), &[D(9), D(axis), D(0), D(2)]); - let sam = T(context.stack_as_mut(), &[D(6), D(0), D(7)]); - let fol = T( - context.stack_as_mut(), - &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)], - ); - let sub = T(context.stack_as_mut(), &[arvo, ovo]); - burn(context, sub, fol) +fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result { + let arvo = context.arvo; + let stack = &mut context.nock_context.stack; + let pul = T(stack, &[D(9), D(axis), D(0), D(2)]); + let sam = T(stack, &[D(6), D(0), D(7)]); + let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]); + let sub = T(stack, &[arvo, ovo]); + interpret(&mut context.nock_context, sub, fol) } fn goof(context: &mut Context, trace: Noun) -> Noun { - let tone = Cell::new(context.stack_as_mut(), D(2), trace); - let mook_context = &mut context.for_interpreter(); - - let tang = mook(mook_context, tone, false) + // XX: trace is a $tang with at least one $tank, which we pick off the top. + // Actual input to +mook should be (roll trace weld) ( or (zing trace)). + let head = trace.cell().unwrap().head(); + let tone = Cell::new(&mut context.nock_context.stack, D(2), head); + let tang = mook(&mut context.nock_context, tone, false) .expect("serf: goof: +mook crashed on bail") .tail(); - // XX: noun::Tone or noun::NockErr should use a bail enum system similar to u3m_bail motes; + // XX: noun::Error should use a bail enum system similar to u3m_bail motes; // might be able to replace NockErr with mote and map determinism to individual motes; // for, always set to %exit - T(mook_context.stack, &[D(tas!(b"exit")), tang]) + T(&mut context.nock_context.stack, &[D(tas!(b"exit")), tang]) } /** Run slam, process stack trace to tang if error */ fn soft(context: &mut Context, ovo: Noun) -> Result { match slam(context, POKE_AXIS, ovo) { Ok(res) => Ok(res), - Err(Tone::Error(_, trace)) => Err(goof(context, trace)), - Err(Tone::Blocked(_)) => panic!("soft: blocked err handling unimplemented"), + Err(error) => match error { + Error::Deterministic(trace) | Error::NonDeterministic(trace) => { + Err(goof(context, trace)) + } + Error::ScryBlocked(_) | Error::ScryCrashed(_) => { + panic!("serf: soft: .^ invalid outside of virtual Nock") + } + }, } } fn play_life(context: &mut Context, eve: Noun) { - let sub = T(context.stack_as_mut(), &[D(0), D(3)]); - let lyf = T(context.stack_as_mut(), &[D(2), sub, D(0), D(2)]); - match burn(context, eve, lyf) { + let stack = &mut context.nock_context.stack; + let sub = T(stack, &[D(0), D(3)]); + let lyf = T(stack, &[D(2), sub, D(0), D(2)]); + match interpret(&mut context.nock_context, eve, lyf) { Ok(gat) => { let eved = lent(eve).expect("serf: play: boot event number failure") as u64; let arvo = slot(gat, 7).expect("serf: play: lifecycle didn't return initial Arvo"); @@ -302,18 +304,20 @@ fn play_life(context: &mut Context, eve: Noun) { context.event_update(eved, arvo); context.play_done(); } - Err(Tone::Error(_, trace)) => { - let goof = goof(context, trace); - context.play_bail(goof); - } - Err(Tone::Blocked(_)) => { - panic!("play: blocked err handling unimplemented") - } + Err(error) => match error { + Error::Deterministic(trace) | Error::NonDeterministic(trace) => { + let goof = goof(context, trace); + context.play_bail(goof); + } + Error::ScryBlocked(_) | Error::ScryCrashed(_) => { + panic!("serf: soft: .^ invalid outside of virtual Nock") + } + }, } } fn play_list(context: &mut Context, mut lit: Noun) { - let mut eve = context.event_num(); + let mut eve = context.event_num; while let Ok(cell) = lit.as_cell() { let ovo = cell.head(); match soft(context, ovo) { @@ -340,7 +344,7 @@ fn work(context: &mut Context, job: Noun) { Ok(res) => { let cell = res.as_cell().expect("serf: work: +slam returned atom"); let fec = cell.head(); - let eve = context.event_num(); + let eve = context.event_num; context.event_update(eve + 1, cell.tail()); context.work_done(fec); @@ -358,21 +362,19 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) { clear_interrupt(); + let stack = &mut context.nock_context.stack; // crud = [+(now) [%$ %arvo ~] [%crud goof ovo]] let job_cell = job.as_cell().expect("serf: work: job not a cell"); let job_now = job_cell.head().as_atom().expect("serf: work: now not atom"); - let now = inc(context.stack_as_mut(), job_now).as_noun(); - let wire = T(context.stack_as_mut(), &[D(0), D(tas!(b"arvo")), D(0)]); - let crud = T( - context.stack_as_mut(), - &[now, wire, D(tas!(b"crud")), goof, job_cell.tail()], - ); + let now = inc(stack, job_now).as_noun(); + let wire = T(stack, &[D(0), D(tas!(b"arvo")), D(0)]); + let crud = T(stack, &[now, wire, D(tas!(b"crud")), goof, job_cell.tail()]); match soft(context, crud) { Ok(res) => { let cell = res.as_cell().expect("serf: work: crud +slam returned atom"); let fec = cell.head(); - let eve = context.event_num(); + let eve = context.event_num; context.event_update(eve + 1, cell.tail()); context.work_swap(crud, fec); @@ -384,8 +386,9 @@ fn work_swap(context: &mut Context, job: Noun, goof: Noun) { } fn work_bail(context: &mut Context, goofs: &[Noun]) { - let lest = T(context.stack_as_mut(), goofs); - let lud = T(context.stack_as_mut(), &[lest, D(0)]); + let stack = &mut context.nock_context.stack; + let lest = T(stack, goofs); + let lud = T(stack, &[lest, D(0)]); context.work_bail(lud); }