Forward non-deterministic errors to the senior frame

This commit is contained in:
Alex Shelkovnykov 2023-09-21 00:04:20 -06:00
parent 95083f7b78
commit 0072e09a85
7 changed files with 235 additions and 209 deletions

View File

@ -1,10 +1,12 @@
use crate::hamt::Hamt; use crate::hamt::Hamt;
use crate::jets; use crate::jets;
use crate::jets::nock::util::mook; use crate::jets::nock::util::mook;
use crate::jets::JetErr;
use crate::mem::unifying_equality; use crate::mem::unifying_equality;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::newt::Newt; use crate::newt::Newt;
use crate::noun::{Atom, Cell, IndirectAtom, Noun, Slots, D, T}; use crate::noun;
use crate::noun::{tape, Atom, Cell, IndirectAtom, Noun, Slots, D, T};
use ares_macros::tas; use ares_macros::tas;
use assert_no_alloc::assert_no_alloc; use assert_no_alloc::assert_no_alloc;
use bitvec::prelude::{BitSlice, Lsb0}; use bitvec::prelude::{BitSlice, Lsb0};
@ -226,14 +228,33 @@ enum NockWork {
#[derive(Debug)] #[derive(Debug)]
pub enum NockErr { pub enum NockErr {
Deterministic,
NonDeterministic,
}
#[derive(Debug)]
pub enum Tone {
Blocked(Noun), Blocked(Noun),
DeterministicError(Noun), Error(NockErr, Noun),
NonDeterministicError(Noun),
} }
impl From<NockErr> for () { impl From<NockErr> for () {
fn from(_: NockErr) -> Self { fn from(_: NockErr) -> Self {}
() }
impl From<noun::Error> for NockErr {
fn from(_: noun::Error) -> Self {
NockErr::Deterministic
}
}
impl From<JetErr> for NockErr {
fn from(e: JetErr) -> Self {
match e {
JetErr::Deterministic => NockErr::Deterministic,
JetErr::NonDeterministic => NockErr::NonDeterministic,
JetErr::Punt => panic!("unhandled JetErr::Punt"),
}
} }
} }
@ -243,9 +264,8 @@ pub fn interpret(
newt: &mut Option<&mut Newt>, // For printing slogs; if None, print to stdout newt: &mut Option<&mut Newt>, // For printing slogs; if None, print to stdout
mut subject: Noun, mut subject: Noun,
formula: Noun, formula: Noun,
) -> Result<Noun, NockErr> { ) -> Result<Noun, Tone> {
let mut res: Noun = D(0); let mut res: Noun = D(0);
let mut trace: Noun;
let mut cache = Hamt::<Noun>::new(); let mut cache = Hamt::<Noun>::new();
// XX: Should this come after initial frame_push()? // XX: Should this come after initial frame_push()?
let virtual_frame = stack.get_frame_pointer(); let virtual_frame = stack.get_frame_pointer();
@ -254,7 +274,6 @@ pub fn interpret(
unsafe { unsafe {
*stack.push() = NockWork::Done; *stack.push() = NockWork::Done;
}; };
push_formula(stack, formula, true)?;
// DO NOT REMOVE THIS ASSERTION // DO NOT REMOVE THIS ASSERTION
// //
// If you need to allocate for debugging, wrap the debugging code in // If you need to allocate for debugging, wrap the debugging code in
@ -266,7 +285,8 @@ pub fn interpret(
// ``` // ```
// //
// (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use) // (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use)
let tone = assert_no_alloc(|| unsafe { let nock = assert_no_alloc(|| unsafe {
push_formula(stack, formula, true)?;
loop { loop {
let work: NockWork = *stack.top(); let work: NockWork = *stack.top();
match work { match work {
@ -303,7 +323,7 @@ pub fn interpret(
res = noun; res = noun;
stack.pop::<NockWork>(); stack.pop::<NockWork>();
} else { } else {
break Err(NockErr::Error(D(1))); break Err(NockErr::Deterministic);
} }
} }
NockWork::Work1(once) => { NockWork::Work1(once) => {
@ -364,7 +384,7 @@ pub fn interpret(
stack.pop::<NockWork>(); stack.pop::<NockWork>();
} else { } else {
// Cannot increment (Nock 4) a cell // Cannot increment (Nock 4) a cell
break Err(NockErr::Error(D(2))); break Err(NockErr::Deterministic);
} }
} }
}, },
@ -405,11 +425,11 @@ pub fn interpret(
push_formula(stack, cond.once, cond.tail)?; push_formula(stack, cond.once, cond.tail)?;
} else { } else {
// Test branch of Nock 6 must return 0 or 1 // Test branch of Nock 6 must return 0 or 1
break Err(NockErr::Error(D(3))); break Err(NockErr::Deterministic);
} }
} else { } else {
// Test branch of Nock 6 must return a direct atom // Test branch of Nock 6 must return a direct atom
break Err(NockErr::Error(D(4))); break Err(NockErr::Deterministic);
} }
} }
}, },
@ -484,7 +504,7 @@ pub fn interpret(
} }
} else { } else {
// Axis into core must be atom // Axis into core must be atom
break Err(NockErr::Error(D(5))); break Err(NockErr::Deterministic);
} }
} }
Todo9::RestoreSubject => { Todo9::RestoreSubject => {
@ -513,20 +533,25 @@ pub fn interpret(
} }
NockWork::Work11D(mut dint) => match dint.todo { NockWork::Work11D(mut dint) => match dint.todo {
Todo11D::ComputeHint => { Todo11D::ComputeHint => {
if let Some(found) = match_hint_pre_hint( match match_hint_pre_hint(
stack, newt, &cache, subject, dint.tag, dint.hint, dint.body, stack, newt, &cache, subject, dint.tag, dint.hint, dint.body,
) { ) {
res = found; Ok(Some(found)) => {
stack.pop::<NockWork>(); res = found;
} else { stack.pop::<NockWork>();
dint.todo = Todo11D::ComputeResult; }
*stack.top() = NockWork::Work11D(dint); Ok(None) => {
push_formula(stack, dint.hint, false)?; dint.todo = Todo11D::ComputeResult;
*stack.top() = NockWork::Work11D(dint);
push_formula(stack, dint.hint, false)?;
}
Err(err) => {
break Err(err);
}
} }
} }
Todo11D::ComputeResult => { Todo11D::ComputeResult => {
dint.todo = Todo11D::Done; match match_hint_pre_nock(
if let Some(found) = match_hint_pre_nock(
stack, stack,
newt, newt,
subject, subject,
@ -535,12 +560,18 @@ pub fn interpret(
dint.body, dint.body,
Some(res), Some(res),
) { ) {
res = found; Ok(Some(found)) => {
stack.pop::<NockWork>(); res = found;
} else { stack.pop::<NockWork>();
dint.todo = Todo11D::Done; }
*stack.top() = NockWork::Work11D(dint); Ok(None) => {
push_formula(stack, dint.body, false)?; dint.todo = Todo11D::Done;
*stack.top() = NockWork::Work11D(dint);
push_formula(stack, dint.body, false)?;
}
Err(err) => {
break Err(err);
}
} }
} }
Todo11D::Done => { Todo11D::Done => {
@ -560,16 +591,21 @@ pub fn interpret(
}, },
NockWork::Work11S(mut sint) => match sint.todo { NockWork::Work11S(mut sint) => match sint.todo {
Todo11S::ComputeResult => { Todo11S::ComputeResult => {
sint.todo = Todo11S::Done; match match_hint_pre_nock(
if let Some(found) = match_hint_pre_nock(
stack, newt, subject, sint.tag, None, sint.body, None, stack, newt, subject, sint.tag, None, sint.body, None,
) { ) {
res = found; Ok(Some(found)) => {
stack.pop::<NockWork>(); res = found;
} else { stack.pop::<NockWork>();
sint.todo = Todo11S::Done; }
*stack.top() = NockWork::Work11S(sint); Ok(None) => {
push_formula(stack, sint.body, false)?; sint.todo = Todo11S::Done;
*stack.top() = NockWork::Work11S(sint);
push_formula(stack, sint.body, false)?;
}
Err(err) => {
break Err(err);
}
} }
} }
Todo11S::Done => { Todo11S::Done => {
@ -585,13 +621,9 @@ pub fn interpret(
} }
}); });
match tone { match nock {
Ok(res) => Ok(res), Ok(res) => Ok(res),
Err(_err) => { Err(err) => Err(exit_early(stack, &mut cache, virtual_frame, err)),
trace = stack.get_mean_stack();
exit_early(stack, virtual_frame, &mut trace, &mut cache);
Err(NockErr::Error(trace))
}
} }
} }
@ -615,7 +647,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
*stack.push() = NockWork::Work0(Nock0 { axis: axis_atom }); *stack.push() = NockWork::Work0(Nock0 { axis: axis_atom });
} else { } else {
// Axis for Nock 0 must be an atom // Axis for Nock 0 must be an atom
return Err(NockErr::Error(D(1))); return Err(NockErr::Deterministic);
} }
} }
1 => { 1 => {
@ -633,7 +665,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Argument to Nock 2 must be cell // Argument to Nock 2 must be cell
return Err(NockErr::Error(D(21))); return Err(NockErr::Deterministic);
}; };
} }
3 => { 3 => {
@ -657,7 +689,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Argument to Nock 5 must be cell // Argument to Nock 5 must be cell
return Err(NockErr::Error(D(51))); return Err(NockErr::Deterministic);
}; };
} }
6 => { 6 => {
@ -672,11 +704,11 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Argument tail to Nock 6 must be cell // Argument tail to Nock 6 must be cell
return Err(NockErr::Error(D(62))); return Err(NockErr::Deterministic);
}; };
} else { } else {
// Argument to Nock 6 must be cell // Argument to Nock 6 must be cell
return Err(NockErr::Error(D(61))); return Err(NockErr::Deterministic);
} }
} }
7 => { 7 => {
@ -689,7 +721,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Argument to Nock 7 must be cell // Argument to Nock 7 must be cell
return Err(NockErr::Error(D(71))); return Err(NockErr::Deterministic);
}; };
} }
8 => { 8 => {
@ -702,7 +734,7 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Argument to Nock 8 must be cell // Argument to Nock 8 must be cell
return Err(NockErr::Error(D(81))); return Err(NockErr::Deterministic);
}; };
} }
9 => { 9 => {
@ -716,11 +748,11 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Axis for Nock 9 must be an atom // Axis for Nock 9 must be an atom
return Err(NockErr::Error(D(92))); return Err(NockErr::Deterministic);
} }
} else { } else {
// Argument to Nock 9 must be cell // Argument to Nock 9 must be cell
return Err(NockErr::Error(D(91))); return Err(NockErr::Deterministic);
}; };
} }
10 => { 10 => {
@ -735,15 +767,15 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Axis for Nock 10 must be an atom // Axis for Nock 10 must be an atom
return Err(NockErr::Error(D(103))); return Err(NockErr::Deterministic);
} }
} else { } else {
// Heah of argument to Nock 10 must be a cell // Heah of argument to Nock 10 must be a cell
return Err(NockErr::Error(D(102))); return Err(NockErr::Deterministic);
}; };
} else { } else {
// Argument to Nock 10 must be a cell // Argument to Nock 10 must be a cell
return Err(NockErr::Error(D(101))); return Err(NockErr::Deterministic);
}; };
} }
11 => { 11 => {
@ -766,29 +798,29 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
}); });
} else { } else {
// Hint tag must be an atom // Hint tag must be an atom
return Err(NockErr::Error(D(112))); return Err(NockErr::Deterministic);
} }
} }
}; };
} else { } else {
// Argument for Nock 11 must be cell // Argument for Nock 11 must be cell
return Err(NockErr::Error(D(111))); return Err(NockErr::Deterministic);
}; };
} }
_ => { _ => {
// Invalid formula opcode // Invalid formula opcode
return Err(NockErr::Error(D(0))); return Err(NockErr::Deterministic);
} }
} }
} else { } else {
// Formula opcode must be direct atom // Formula opcode must be direct atom
return Err(NockErr::Error(D(0))); return Err(NockErr::Deterministic);
} }
} }
} }
} else { } else {
// Bad formula: atoms are not formulas // Bad formula: atoms are not formulas
return Err(NockErr::Error(D(0))); return Err(NockErr::Deterministic);
} }
} }
Ok(()) Ok(())
@ -796,17 +828,19 @@ fn push_formula(stack: &mut NockStack, formula: Noun, tail: bool) -> Result<(),
pub fn exit_early( pub fn exit_early(
stack: &mut NockStack, stack: &mut NockStack,
virtual_frame: *const u64,
trace: &mut Noun,
cache: &mut Hamt<Noun>, cache: &mut Hamt<Noun>,
) { virtual_frame: *const u64,
error: NockErr,
) -> Tone {
let mut trace = stack.get_mean_stack();
unsafe { unsafe {
while stack.get_frame_pointer() != virtual_frame { while stack.get_frame_pointer() != virtual_frame {
stack.preserve(trace); stack.preserve(&mut trace);
stack.preserve(cache); stack.preserve(cache);
stack.frame_pop(); stack.frame_pop();
} }
} };
Tone::Error(error, trace)
} }
fn edit( fn edit(
@ -888,23 +922,9 @@ fn match_hint_pre_hint(
tag: Atom, tag: Atom,
hint: Noun, hint: Noun,
body: Noun, body: Noun,
// ) -> Result<Option<Noun>, JetErr> {
// possible cases:
// 1. Deterministic error, no trace
// jet - nock mismatch
// need to add a mean hint, then fail
// 2. Deterministic error, trace
// Deterministic error in jet or nock
// 3. Nondeterministic error, trace
// Nondeterministic error in jet or nock
//
//
// 4. Nondeterministic error, no trace
// ??? does this exist?
//
) -> Result<Option<Noun>, NockErr> { ) -> Result<Option<Noun>, NockErr> {
// XX: handle IndirectAtom tags // XX: handle IndirectAtom tags
match tag.direct()?.data() { match tag.as_direct()?.data() {
// %sham hints are scaffolding until we have a real jet dashboard // %sham hints are scaffolding until we have a real jet dashboard
tas!(b"sham") => { tas!(b"sham") => {
let jet_formula = hint.as_cell()?; let jet_formula = hint.as_cell()?;
@ -914,71 +934,69 @@ fn match_hint_pre_hint(
if let Some(jet) = jets::get_jet(jet_name) { if let Some(jet) = jets::get_jet(jet_name) {
match jet(stack, newt, subject) { match jet(stack, newt, subject) {
Ok(mut jet_res) => { Ok(mut jet_res) => {
// XX: simplify this by moving jet test mode into the 11 code in interpret, or into its own function?
// if in test mode, check that the jet returns the same result as the raw nock // if in test mode, check that the jet returns the same result as the raw nock
if jets::get_jet_test_mode(jet_name) { if jets::get_jet_test_mode(jet_name) {
// Throw away trace because we'll regenerate it later, and this is in test mode // XX: we throw away trace, which might matter for non-deterministic errors
// so it's okay if it runs twice // maybe mook and slog it?
match interpret(stack, newt, subject, body) { match interpret(stack, newt, subject, body) {
Ok(mut nock_res) => { Ok(mut nock_res) => {
if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } { if unsafe {
!unifying_equality(stack, &mut nock_res, &mut jet_res)
} {
// XX: need string interpolation without allocation, then delete eprintln
// let tape = tape(stack, "jet mismatch in {}, raw: {}, jetted: {}", jet_name, nock_res, jet_res);
eprintln!( eprintln!(
"\rJet {} failed, raw: {}, jetted: {}", "\rjet {} failed, raw: {:?}, jetted: {}",
jet_name, nock_res, jet_res jet_name, nock_res, jet_res
); );
Err(Deterministic) let tape = tape(stack, "jet mismatch");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
stack.trace_push(mean);
Err(NockErr::Deterministic)
} else { } else {
Ok(Some(jet_res)) Ok(Some(nock_res))
} }
} }
Err(NockErr::DeterministicError(trace)) => { Err(Tone::Error(err, _)) => {
// 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
);
let tape = tape(stack, "jet mismatch");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
stack.trace_push(mean);
Err(err)
}
Err(Tone::Blocked(_)) => {
panic!("jet test mode: no scry handling")
} }
} }
interpret(stack, newt, subject, body)
.ok()
.map(|mut nock_res| {
if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } {
eprintln!(
"\rJet {} failed, raw: {}, jetted: {}",
jet_name, nock_res, jet_res
);
None
} else {
Some(jet_res)
}
})
.unwrap()
} else { } else {
Ok(Some(jet_res)) Ok(Some(jet_res))
} }
} }
} Err(JetErr::Punt) => Ok(None),
Err(err) => {
// XX: need string interpolation without allocation
if let Ok(mut jet_res) = jet(stack, newt, subject) { // let tape = tape(stack, "{} jet error in {}", err, jet_name);
let tape = tape(stack, "jet error");
} else { let mean = T(stack, &[D(tas!(b"mean")), tape]);
// Print jet errors and punt to Nock stack.trace_push(mean);
eprintln!("\rJet {} failed: ", jet_name); Err(err.into())
None }
} }
} else { } else {
Ok(None) Ok(None)
} }
} }
tas!(b"memo") => { tas!(b"memo") => {
let mut key = Cell::new(stack, subject, body).as_noun(); let mut key = Cell::new(stack, subject, body).as_noun();
cache.lookup(stack, &mut key) Ok(cache.lookup(stack, &mut key))
} }
_ => None, _ => Ok(None),
} }
} }
@ -991,41 +1009,27 @@ fn match_hint_pre_nock(
_hint: Option<Noun>, _hint: Option<Noun>,
_body: Noun, _body: Noun,
res: Option<Noun>, res: Option<Noun>,
) -> Result<Option<Noun>, JetErr> { ) -> Result<Option<Noun>, NockErr> {
// XX: assert Some(res) <=> Some(hint) // XX: assert Some(res) <=> Some(hint)
// XX: handle IndirectAtom tags // XX: handle IndirectAtom tags
match tag.direct()?.data() { match tag.as_direct()?.data() {
tas!(b"slog") => { tas!(b"slog") => {
let slog_cell = res?.cell()?; let slog_cell = res.ok_or(NockErr::Deterministic)?.as_cell()?;
let pri = slog_cell.head().direct()?.data(); let pri = slog_cell.head().as_direct()?.data();
let tank = slog_cell.tail(); let tank = slog_cell.tail();
if let Some(not) = newt { if let Some(not) = newt {
not.slog(stack, pri, tank); not.slog(stack, pri, tank);
} else { } else {
eprintln!("raw slog: {} {}", pri, tank); eprintln!("raw slog: {} {}", pri, tank);
} }
Ok(None)
} }
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
let trace = Cell::new(stack, tag.as_noun(), res?).as_noun(); let trace = T(stack, &[tag.as_noun(), res.ok_or(NockErr::Deterministic)?]);
stack.trace_push(trace); stack.trace_push(trace);
Ok(None)
} }
//
// u3_serf_writ -> u3_serf_work -> _serf_work -> _serf_poke -> u3m_soft -> u3dc -> u3v_do -> u3v_wish -> +wish in Arvo
// |
// V
// mook
//
// No +wish in toy Arvo; missing +slap and a ton of parsing functions needed by +ream
//
// u3t_slog = print on thing directly
// u3t_slog_trace = print stack trace = - convert tone to toon
// - presume toon is [%2 tang]
// - print each tank in tang one at at time using u3t_slog
// u3t_slog_hela = print entire stack trace = - weld stacks from all roads together
// - call u3t_slog_trace on combined stack
// u3t_slog_nara = print home road stack trace = call u3t_slog_trace on home road stack
//
tas!(b"hela") => { tas!(b"hela") => {
// XX: should this be virtualized? // XX: should this be virtualized?
// pretty sure we should be bailing on error // pretty sure we should be bailing on error
@ -1033,39 +1037,44 @@ fn match_hint_pre_nock(
let stak = stack.get_mean_stack(); let stak = stack.get_mean_stack();
let tone = Cell::new(stack, D(2), stak); let tone = Cell::new(stack, D(2), stak);
if let Ok(toon) = mook(stack, newt, tone, true) { match mook(stack, newt, tone, true) {
if unsafe { !toon.head().raw_equals(D(2)) } { Ok(toon) => {
// Print jet error and punt to Nock if unsafe { !toon.head().raw_equals(D(2)) } {
eprintln!("\r%hela failed: toon not %2"); let tape = tape(stack, "%hela failed: toon not %2");
return None; let mean = T(stack, &[D(tas!(b"mean")), tape]);
} stack.trace_push(mean);
return Err(NockErr::Deterministic);
let mut list = toon.tail();
loop {
if unsafe { list.raw_equals(D(0)) } {
break;
} }
let cell = list.as_cell().unwrap(); let mut list = toon.tail();
if let Some(not) = newt { loop {
// XX: %hela priority is configurable, but I'm not sure how if unsafe { list.raw_equals(D(0)) } {
not.slog(stack, 0, cell.head()); break;
} else { }
eprintln!("raw slog: {} {}", 0, cell.head());
let cell = list.as_cell().unwrap();
if let Some(not) = newt {
// XX: %hela priority is configurable, but I'm not sure how
not.slog(stack, 0, cell.head());
} else {
eprintln!("raw slog: {} {}", 0, cell.head());
}
list = cell.tail();
} }
list = cell.tail(); Ok(None)
}
Err(err) => {
let tape = tape(stack, "%hela failed: mook error");
let mean = T(stack, &[D(tas!(b"mean")), tape]);
stack.trace_push(mean);
Err(err.into())
} }
} else {
// Print jet errors and punt to Nock
eprintln!("\r%hela failed: mook error");
return None;
} }
} }
_ => {} _ => Ok(None),
} }
None
} }
/** Match static and dynamic hints after the nock formula is evaluated */ /** Match static and dynamic hints after the nock formula is evaluated */
@ -1077,7 +1086,7 @@ fn match_hint_post_nock(
_hint: Option<Noun>, _hint: Option<Noun>,
body: Noun, body: Noun,
res: Noun, res: Noun,
) -> Result<Option<Noun>, JetErr> { ) -> Option<Noun> {
// XX: handle IndirectAtom tags // XX: handle IndirectAtom tags
match tag.direct()?.data() { match tag.direct()?.data() {
tas!(b"memo") => { tas!(b"memo") => {
@ -1085,7 +1094,7 @@ fn match_hint_post_nock(
*cache = cache.insert(stack, &mut key, res); *cache = cache.insert(stack, &mut key, res);
} }
tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => { tas!(b"hand") | tas!(b"hunk") | tas!(b"lose") | tas!(b"mean") | tas!(b"spot") => {
// In the future, we should only do this if 11 is not in tail position // XX: we should only do this if 11 is not in tail position
stack.trace_pop(); stack.trace_pop();
} }
_ => {} _ => {}

View File

@ -172,7 +172,7 @@ pub mod util {
let step = cell.tail().as_direct()?.data() as usize; let step = cell.tail().as_direct()?.data() as usize;
Ok((bloq, step)) Ok((bloq, step))
} else { } else {
bloq(a).map(|x| (x, 1 as usize)) bloq(a).map(|x| (x, 1_usize))
} }
} }

View File

@ -29,13 +29,13 @@ pub mod util {
) -> jets::Result { ) -> jets::Result {
match aura.data() { match aura.data() {
tas!(b"ud") => { tas!(b"ud") => {
if let None = atom.as_bitslice().first_one() { if atom.as_bitslice().first_one().is_none() {
return Ok(T(stack, &[D(b'0' as u64), D(0)])); return Ok(T(stack, &[D(b'0' as u64), D(0)]));
} }
let mut root = D(0); let mut root = D(0);
let mut lent = 0; let mut lent = 0;
if let Some(_) = atom.direct() { if atom.direct().is_some() {
let mut n = atom.as_direct()?.data(); let mut n = atom.as_direct()?.data();
while n != 0 { while n != 0 {

View File

@ -1,8 +1,9 @@
/** Virtualization jets /** Virtualization jets
*/ */
use crate::interpreter::{interpret, NockErr}; use crate::interpreter::{interpret, NockErr, Tone};
use crate::jets; use crate::jets;
use crate::jets::util::slot; use crate::jets::util::slot;
use crate::jets::JetErr;
use crate::mem::NockStack; use crate::mem::NockStack;
use crate::newt::Newt; use crate::newt::Newt;
use crate::noun::{Noun, D, T}; use crate::noun::{Noun, D, T};
@ -22,12 +23,14 @@ pub fn jet_mink(
let v_formula = slot(arg, 5)?; let v_formula = slot(arg, 5)?;
let _scry = slot(arg, 3)?; let _scry = slot(arg, 3)?;
// XX: NonDeterministic errors need to bail here, too
match interpret(stack, newt, v_subject, v_formula) { match interpret(stack, newt, v_subject, v_formula) {
Ok(res) => Ok(T(stack, &[D(0), res])), Ok(res) => Ok(T(stack, &[D(0), res])),
Err(err) => match err { Err(err) => match err {
NockErr::Blocked(block) => Ok(T(stack, &[D(1), block])), Tone::Blocked(block) => Ok(T(stack, &[D(1), block])),
NockErr::Error(error) => Ok(T(stack, &[D(2), error])), Tone::Error(err, trace) => match err {
NockErr::Deterministic => Ok(T(stack, &[D(2), trace])),
NockErr::NonDeterministic => Err(JetErr::NonDeterministic),
},
}, },
} }
} }
@ -58,15 +61,20 @@ pub mod util {
let tag = tone.head().as_direct()?; let tag = tone.head().as_direct()?;
let original_list = tone.tail(); let original_list = tone.tail();
if tag.data() < 2 { // if tag.data() < 2 {
return Ok(tone); // return Ok(tone);
} else if tag.data() > 2 { // } else if tag.data() > 2 {
return Err(JetErr::Deterministic); // return Err(JetErr::Deterministic);
} // }
match tag.data() {
x if x < 2 => return Ok(tone),
x if x > 2 => return Err(JetErr::Deterministic),
_ => {}
};
if unsafe { original_list.raw_equals(D(0)) } { if unsafe { original_list.raw_equals(D(0)) } {
return Ok(tone); return Ok(tone);
} else if let Some(_) = original_list.atom() { } else if original_list.atom().is_some() {
return Err(JetErr::Deterministic); return Err(JetErr::Deterministic);
} }
@ -135,7 +143,7 @@ pub mod util {
let mut list = end_col.as_cell()?; let mut list = end_col.as_cell()?;
loop { loop {
if let Some(_) = list.tail().atom() { if list.tail().atom().is_some() {
break; break;
} }
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
@ -146,7 +154,7 @@ pub mod util {
list = end_lin.as_cell()?; list = end_lin.as_cell()?;
loop { loop {
if let Some(_) = list.tail().atom() { if list.tail().atom().is_some() {
break; break;
} }
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
@ -157,7 +165,7 @@ pub mod util {
list = str_col.as_cell()?; list = str_col.as_cell()?;
loop { loop {
if let Some(_) = list.tail().atom() { if list.tail().atom().is_some() {
break; break;
} }
list = list.tail().as_cell()?; list = list.tail().as_cell()?;
@ -171,7 +179,7 @@ pub mod util {
list = str_lin.as_cell()?; list = str_lin.as_cell()?;
loop { loop {
if let Some(_) = list.tail().atom() { if list.tail().atom().is_some() {
break; break;
} }
list = list.tail().as_cell()?; list = list.tail().as_cell()?;

View File

@ -22,7 +22,7 @@ pub mod util {
let mut list = tape; let mut list = tape;
loop { loop {
if let Some(atom) = list.atom() { if let Some(atom) = list.atom() {
if let None = atom.as_bitslice().first_one() { if atom.as_bitslice().first_one().is_none() {
break; break;
} else { } else {
return Err(JetErr::Deterministic); return Err(JetErr::Deterministic);

View File

@ -107,11 +107,11 @@ impl Newt {
); );
}, },
}; };
self.output.write_all(&buf).unwrap(); self.output.write_all(buf).unwrap();
} }
/** Send %ripe, the first event. /** Send %ripe, the first event.
* *
* eve = event number * eve = event number
* mug = mug of Arvo after above event * mug = mug of Arvo after above event
*/ */
@ -135,7 +135,7 @@ impl Newt {
} }
/** Send %slog, pretty-printed debug output. /** Send %slog, pretty-printed debug output.
* *
* pri = debug priority * pri = debug priority
* tank = output as tank * tank = output as tank
*/ */
@ -157,7 +157,7 @@ impl Newt {
} }
/** Send %peek %bail, unsuccessfully scried. /** Send %peek %bail, unsuccessfully scried.
* *
* dud = goof * dud = goof
*/ */
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) { pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) {
@ -166,7 +166,7 @@ impl Newt {
} }
/** Send %play %done, successfully replayed events. /** Send %play %done, successfully replayed events.
* *
* mug = mug of Arvo after full replay * mug = mug of Arvo after full replay
*/ */
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) { pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) {
@ -175,7 +175,7 @@ impl Newt {
} }
/** Send %play %bail, failed to replay events. /** Send %play %bail, failed to replay events.
* *
* eve = last good event number * eve = last good event number
* mug = mug of Arvo after above event * mug = mug of Arvo after above event
* dud = goof when trying next event * dud = goof when trying next event
@ -189,7 +189,7 @@ impl Newt {
} }
/** Send %work %done, successfully ran event. /** Send %work %done, successfully ran event.
* *
* eve = new event number * eve = new event number
* mug = mug of Arvo after above event * mug = mug of Arvo after above event
* fec = list of effects * fec = list of effects
@ -203,7 +203,7 @@ impl Newt {
} }
/** Send %work %swap, successfully replaced failed event. /** Send %work %swap, successfully replaced failed event.
* *
* eve = new event number * eve = new event number
* mug = mug of Arvo after above event * mug = mug of Arvo after above event
* job = event performed instead of the one given to serf by king * job = event performed instead of the one given to serf by king
@ -218,7 +218,7 @@ impl Newt {
} }
/** Send %work %bail, failed to run event. /** Send %work %bail, failed to run event.
* *
* lud = list of goof * lud = list of goof
*/ */
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) { pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) {

View File

@ -1,4 +1,4 @@
use crate::interpreter::{interpret, NockErr, inc}; use crate::interpreter::{inc, interpret, Tone};
use crate::jets::nock::util::mook; use crate::jets::nock::util::mook;
use crate::jets::text::util::lent; use crate::jets::text::util::lent;
use crate::mem::NockStack; use crate::mem::NockStack;
@ -82,7 +82,6 @@ pub fn serf() -> io::Result<()> {
let eve = slot(writ, 7)?; let eve = slot(writ, 7)?;
let sub = T(stack, &[D(0), D(3)]); let sub = T(stack, &[D(0), D(3)]);
let lyf = T(stack, &[D(2), sub, D(0), D(2)]); let lyf = T(stack, &[D(2), sub, D(0), D(2)]);
// XX: TODO
match interpret(stack, &mut Some(newt), eve, lyf) { match interpret(stack, &mut Some(newt), eve, lyf) {
Ok(gat) => { Ok(gat) => {
arvo = slot(gat, 7) arvo = slot(gat, 7)
@ -91,7 +90,7 @@ pub fn serf() -> io::Result<()> {
lent(eve).expect("serf: play: boot event number failure") as u64; lent(eve).expect("serf: play: boot event number failure") as u64;
current_mug = mug_u32(stack, arvo); current_mug = mug_u32(stack, arvo);
} }
Err(NockErr::Error(trace)) => { Err(Tone::Error(_, trace)) => {
let tone = Cell::new(stack, D(2), trace); let tone = Cell::new(stack, D(2), trace);
let tang = mook(stack, &mut Some(newt), tone, false) let tang = mook(stack, &mut Some(newt), tone, false)
.expect("serf: play: +mook crashed on bail") .expect("serf: play: +mook crashed on bail")
@ -99,7 +98,7 @@ pub fn serf() -> io::Result<()> {
let goof = T(stack, &[D(tas!(b"exit")), tang]); let goof = T(stack, &[D(tas!(b"exit")), tang]);
newt.play_bail(stack, 0, 0, goof); newt.play_bail(stack, 0, 0, goof);
} }
Err(NockErr::Blocked(_)) => { Err(Tone::Blocked(_)) => {
panic!("play: blocked err handling unimplemented") panic!("play: blocked err handling unimplemented")
} }
} }
@ -118,7 +117,7 @@ pub fn serf() -> io::Result<()> {
current_mug = mug_u32(stack, arvo); current_mug = mug_u32(stack, arvo);
current_event_num += 1; current_event_num += 1;
} }
Err(NockErr::Error(trace)) => { Err(Tone::Error(_, trace)) => {
let tone = Cell::new(stack, D(2), trace); let tone = Cell::new(stack, D(2), trace);
let tang = mook(stack, &mut Some(newt), tone, false) let tang = mook(stack, &mut Some(newt), tone, false)
.expect("serf: play: +mook crashed on bail") .expect("serf: play: +mook crashed on bail")
@ -126,7 +125,7 @@ pub fn serf() -> io::Result<()> {
let goof = T(stack, &[D(tas!(b"exit")), tang]); let goof = T(stack, &[D(tas!(b"exit")), tang]);
newt.play_bail(stack, current_event_num, current_mug as u64, goof); newt.play_bail(stack, current_event_num, current_mug as u64, goof);
} }
Err(NockErr::Blocked(_)) => { Err(Tone::Blocked(_)) => {
panic!("play: blocked err handling unimplemented") panic!("play: blocked err handling unimplemented")
} }
} }
@ -161,13 +160,18 @@ pub fn serf() -> io::Result<()> {
// //
// crud = [+(now) [%$ %arvo ~] [%crud goof ovo]] // crud = [+(now) [%$ %arvo ~] [%crud goof ovo]]
let job_cell = job.as_cell().expect("serf: work: job not a cell"); let job_cell = job.as_cell().expect("serf: work: job not a cell");
let now = inc(stack, job_cell.head().as_atom().expect("serf: work: now not atom")).as_noun(); let now = inc(
stack,
job_cell.head().as_atom().expect("serf: work: now not atom"),
)
.as_noun();
let wire = T(stack, &[D(0), D(tas!(b"arvo")), D(0)]); 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()]); let crud = T(stack, &[now, wire, D(tas!(b"crud")), goof, job_cell.tail()]);
match soft(stack, newt, arvo, POKE_AXIS, crud) { match soft(stack, newt, arvo, POKE_AXIS, crud) {
Ok(res) => { Ok(res) => {
let cell = res.as_cell().expect("serf: work: crud +slam returned atom"); let cell =
res.as_cell().expect("serf: work: crud +slam returned atom");
let fec = cell.head(); let fec = cell.head();
arvo = cell.tail(); arvo = cell.tail();
snap.save(stack, &mut arvo); snap.save(stack, &mut arvo);
@ -175,7 +179,13 @@ pub fn serf() -> io::Result<()> {
current_mug = mug_u32(stack, arvo); current_mug = mug_u32(stack, arvo);
current_event_num += 1; current_event_num += 1;
newt.work_swap(stack, current_event_num, current_mug as u64, crud, fec); newt.work_swap(
stack,
current_event_num,
current_mug as u64,
crud,
fec,
);
} }
Err(goof_crud) => { Err(goof_crud) => {
let lud = T(stack, &[goof_crud, goof, D(0)]); let lud = T(stack, &[goof_crud, goof, D(0)]);
@ -198,7 +208,7 @@ pub fn slam(
core: Noun, core: Noun,
axis: u64, axis: u64,
ovo: Noun, ovo: Noun,
) -> Result<Noun, NockErr> { ) -> Result<Noun, Tone> {
let pul = T(stack, &[D(9), D(axis), D(0), D(2)]); let pul = T(stack, &[D(9), D(axis), D(0), D(2)]);
let sam = T(stack, &[D(6), D(0), D(7)]); 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 fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]);
@ -216,7 +226,7 @@ pub fn soft(
) -> Result<Noun, Noun> { ) -> Result<Noun, Noun> {
match slam(stack, newt, core, axis, ovo) { match slam(stack, newt, core, axis, ovo) {
Ok(res) => Ok(res), Ok(res) => Ok(res),
Err(NockErr::Error(trace)) => { Err(Tone::Error(_, trace)) => {
let tone = Cell::new(stack, D(2), trace); let tone = Cell::new(stack, D(2), trace);
let tang = mook(stack, &mut Some(newt), tone, false) let tang = mook(stack, &mut Some(newt), tone, false)
.expect("serf: soft: +mook crashed on bail") .expect("serf: soft: +mook crashed on bail")
@ -226,11 +236,10 @@ pub fn soft(
let goof = T(stack, &[D(tas!(b"exit")), tang]); let goof = T(stack, &[D(tas!(b"exit")), tang]);
Err(goof) Err(goof)
} }
Err(NockErr::Blocked(_)) => panic!("soft: blocked err handling unimplemented"), Err(Tone::Blocked(_)) => panic!("soft: blocked err handling unimplemented"),
} }
} }
fn slot(noun: Noun, axis: u64) -> io::Result<Noun> { fn slot(noun: Noun, axis: u64) -> io::Result<Noun> {
noun.slot(axis) noun.slot(axis)
.map_err(|_e| io::Error::new(io::ErrorKind::InvalidInput, "Bad axis")) .map_err(|_e| io::Error::new(io::ErrorKind::InvalidInput, "Bad axis"))