mirror of
https://github.com/urbit/ares.git
synced 2024-12-25 06:12:24 +03:00
jets: add mink jet
This commit is contained in:
parent
19048014a3
commit
d510a33c02
@ -4,7 +4,7 @@ use crate::jets;
|
||||
use crate::mem::unifying_equality;
|
||||
use crate::mem::NockStack;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun};
|
||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
||||
use ares_macros::tas;
|
||||
use assert_no_alloc::assert_no_alloc;
|
||||
use bitvec::prelude::{BitSlice, Lsb0};
|
||||
@ -69,41 +69,55 @@ fn noun_to_work(noun: Noun) -> NockWork {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NockErr {
|
||||
Blocked(Noun),
|
||||
Error(Noun),
|
||||
}
|
||||
|
||||
impl From<NockErr> for () {
|
||||
fn from(_: NockErr) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
/** Interpret nock */
|
||||
pub fn interpret(
|
||||
stack: &mut NockStack,
|
||||
newt: &mut Option<&mut Newt>, // For printing slogs; if None, print to stdout
|
||||
mut subject: Noun,
|
||||
formula: Noun,
|
||||
) -> Noun {
|
||||
let mut res = unsafe { DirectAtom::new_unchecked(0).as_atom().as_noun() };
|
||||
) -> Result<Noun, NockErr> {
|
||||
let mut res: Noun = D(0);
|
||||
let mut trace: Noun;
|
||||
let mut cache = Hamt::<Noun>::new();
|
||||
|
||||
let virtual_frame = stack.get_frame_pointer();
|
||||
stack.frame_push(1);
|
||||
unsafe {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Done);
|
||||
}
|
||||
push_formula(stack, formula);
|
||||
|
||||
assert_no_alloc(|| unsafe {
|
||||
push_formula(stack, formula)?;
|
||||
let tone = assert_no_alloc(|| unsafe {
|
||||
loop {
|
||||
match noun_to_work(*(stack.local_noun_pointer(0))) {
|
||||
Done => {
|
||||
stack.preserve(&mut cache);
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
break;
|
||||
break Ok(res);
|
||||
}
|
||||
NockCellComputeHead => {
|
||||
*stack.local_noun_pointer(0) = work_to_noun(NockCellComputeTail);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
NockCellComputeTail => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(NockCellCons);
|
||||
*(stack.local_noun_pointer(1)) = res;
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
NockCellCons => {
|
||||
let head = *stack.local_noun_pointer(1);
|
||||
@ -115,13 +129,16 @@ pub fn interpret(
|
||||
}
|
||||
Nock0Axis => {
|
||||
if let Ok(atom) = (*(stack.local_noun_pointer(1))).as_atom() {
|
||||
res = slot(subject, atom.as_bitslice());
|
||||
|
||||
stack.preserve(&mut cache);
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
if let Ok(x) = slot(subject, atom.as_bitslice()) {
|
||||
res = x;
|
||||
stack.preserve(&mut cache);
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
} else {
|
||||
break Err(NockErr::Error(D(1)));
|
||||
}
|
||||
} else {
|
||||
panic!("Axis must be atom");
|
||||
break Err(NockErr::Error(D(0))); // Axis must be atom
|
||||
};
|
||||
}
|
||||
Nock1Constant => {
|
||||
@ -134,19 +151,19 @@ pub fn interpret(
|
||||
Nock2ComputeSubject => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock2ComputeFormula);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock2ComputeFormula => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock2ComputeResult);
|
||||
*(stack.local_noun_pointer(1)) = res;
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock2ComputeResult => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock2RestoreSubject);
|
||||
*(stack.local_noun_pointer(2)) = subject;
|
||||
subject = *(stack.local_noun_pointer(1));
|
||||
push_formula(stack, res);
|
||||
push_formula(stack, res)?;
|
||||
}
|
||||
Nock2RestoreSubject => {
|
||||
subject = *(stack.local_noun_pointer(2));
|
||||
@ -158,7 +175,7 @@ pub fn interpret(
|
||||
Nock3ComputeChild => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock3ComputeType);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock3ComputeType => {
|
||||
res = if res.is_cell() {
|
||||
@ -174,7 +191,7 @@ pub fn interpret(
|
||||
Nock4ComputeChild => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock4Increment);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock4Increment => {
|
||||
if let Ok(atom) = res.as_atom() {
|
||||
@ -184,19 +201,19 @@ pub fn interpret(
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
} else {
|
||||
panic!("Cannot increment (Nock 4) a cell");
|
||||
break Err(NockErr::Error(D(2))); // Cannot increment (Nock 4) a cell
|
||||
};
|
||||
}
|
||||
Nock5ComputeLeftChild => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock5ComputeRightChild);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock5ComputeRightChild => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock5TestEquals);
|
||||
*(stack.local_noun_pointer(1)) = res;
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock5TestEquals => {
|
||||
let saved_value_ptr = stack.local_noun_pointer(1);
|
||||
@ -213,22 +230,22 @@ pub fn interpret(
|
||||
Nock6ComputeTest => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock6ComputeBranch);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock6ComputeBranch => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock6Done);
|
||||
if let Left(direct) = res.as_either_direct_allocated() {
|
||||
if direct.data() == 0 {
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
} else if direct.data() == 1 {
|
||||
let formula = *stack.local_noun_pointer(3);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
} else {
|
||||
panic!("Test branch of Nock 6 must return 0 or 1");
|
||||
break Err(NockErr::Error(D(3))); // Test branch of Nock 6 must return 0 or 1
|
||||
};
|
||||
} else {
|
||||
panic!("Test branch of Nock 6 must return a direct atom");
|
||||
break Err(NockErr::Error(D(4))); // Test branch of Nock 6 must return a direct atom
|
||||
}
|
||||
}
|
||||
Nock6Done => {
|
||||
@ -239,14 +256,14 @@ pub fn interpret(
|
||||
Nock7ComputeSubject => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock7ComputeResult);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock7ComputeResult => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock7RestoreSubject);
|
||||
*(stack.local_noun_pointer(1)) = subject;
|
||||
subject = res;
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock7RestoreSubject => {
|
||||
subject = *(stack.local_noun_pointer(1));
|
||||
@ -258,14 +275,14 @@ pub fn interpret(
|
||||
Nock8ComputeSubject => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock8ComputeResult);
|
||||
let formula = *stack.local_noun_pointer(1);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock8ComputeResult => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock8RestoreSubject);
|
||||
*(stack.local_noun_pointer(1)) = subject;
|
||||
subject = Cell::new(stack, res, subject).as_noun();
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock8RestoreSubject => {
|
||||
subject = *(stack.local_noun_pointer(1));
|
||||
@ -277,16 +294,21 @@ pub fn interpret(
|
||||
Nock9ComputeCore => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock9ComputeResult);
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock9ComputeResult => {
|
||||
if let Ok(formula_axis) = (*(stack.local_noun_pointer(1))).as_atom() {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock9RestoreSubject);
|
||||
*(stack.local_noun_pointer(2)) = subject;
|
||||
subject = res;
|
||||
push_formula(stack, slot(subject, formula_axis.as_bitslice()));
|
||||
let axis = if let Ok(x) = slot(subject, formula_axis.as_bitslice()) {
|
||||
x
|
||||
} else {
|
||||
break Err(NockErr::Error(D(55))); // Axis must be in subject
|
||||
};
|
||||
push_formula(stack, axis)?;
|
||||
} else {
|
||||
panic!("Axis into core must be atom");
|
||||
break Err(NockErr::Error(D(5))); // Axis into core must be atom
|
||||
}
|
||||
}
|
||||
Nock9RestoreSubject => {
|
||||
@ -299,13 +321,13 @@ pub fn interpret(
|
||||
Nock10ComputeTree => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock10ComputePatch);
|
||||
let formula = *stack.local_noun_pointer(3);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock10ComputePatch => {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock10Edit);
|
||||
*(stack.local_noun_pointer(3)) = res;
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
Nock10Edit => {
|
||||
if let Ok(edit_axis) = (*stack.local_noun_pointer(1)).as_atom() {
|
||||
@ -316,7 +338,7 @@ pub fn interpret(
|
||||
stack.preserve(&mut res);
|
||||
stack.frame_pop();
|
||||
} else {
|
||||
panic!("Axis into tree must be atom");
|
||||
break Err(NockErr::Error(D(6))); // Axis into tree must be atom
|
||||
}
|
||||
}
|
||||
Nock11ComputeHint => {
|
||||
@ -334,7 +356,7 @@ pub fn interpret(
|
||||
stack.frame_pop();
|
||||
} else {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock11ComputeResult);
|
||||
push_formula(stack, hint.tail());
|
||||
push_formula(stack, hint.tail())?;
|
||||
}
|
||||
}
|
||||
Nock11ComputeResult => {
|
||||
@ -349,7 +371,7 @@ pub fn interpret(
|
||||
} else {
|
||||
*(stack.local_noun_pointer(0)) = work_to_noun(Nock11Done);
|
||||
let formula = *stack.local_noun_pointer(2);
|
||||
push_formula(stack, formula);
|
||||
push_formula(stack, formula)?;
|
||||
}
|
||||
}
|
||||
Nock11Done => {
|
||||
@ -367,10 +389,18 @@ pub fn interpret(
|
||||
};
|
||||
}
|
||||
});
|
||||
res
|
||||
|
||||
match tone {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_err) => {
|
||||
trace = stack.get_mean_stack();
|
||||
exit_early(stack, virtual_frame, &mut trace, &mut cache);
|
||||
Err(NockErr::Error(trace))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_formula(stack: &mut NockStack, formula: Noun) {
|
||||
fn push_formula(stack: &mut NockStack, formula: Noun) -> Result<(), NockErr> {
|
||||
if let Ok(formula_cell) = formula.as_cell() {
|
||||
// Formula
|
||||
match formula_cell.head().as_either_atom_cell() {
|
||||
@ -540,20 +570,31 @@ fn push_formula(stack: &mut NockStack, formula: Noun) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("Bad formula: atoms are not formulas: {}", formula);
|
||||
return Err(NockErr::Error(D(10))); // Bad formula: atoms are not formulas: {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exit_early(stack: &mut NockStack, virtual_frame: *const u64, trace: &mut Noun, cache: &mut Hamt<Noun>) {
|
||||
unsafe {
|
||||
while stack.get_frame_pointer() != virtual_frame {
|
||||
stack.preserve(trace);
|
||||
stack.preserve(cache);
|
||||
stack.frame_pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Note: axis must fit in a direct atom */
|
||||
pub fn raw_slot(noun: Noun, axis: u64) -> Noun {
|
||||
slot(noun, DirectAtom::new(axis).unwrap().as_bitslice())
|
||||
slot(noun, DirectAtom::new(axis).unwrap().as_bitslice()).unwrap()
|
||||
}
|
||||
|
||||
pub fn slot(mut noun: Noun, axis: &BitSlice<u64, Lsb0>) -> Noun {
|
||||
pub fn slot(mut noun: Noun, axis: &BitSlice<u64, Lsb0>) -> Result<Noun, ()> {
|
||||
let mut cursor = if let Some(x) = axis.last_one() {
|
||||
x
|
||||
} else {
|
||||
panic!("0 is not allowed as an axis")
|
||||
return Err(()); // 0 is not allowed as an axis
|
||||
};
|
||||
loop {
|
||||
if cursor == 0 {
|
||||
@ -567,10 +608,10 @@ pub fn slot(mut noun: Noun, axis: &BitSlice<u64, Lsb0>) -> Noun {
|
||||
noun = cell.head();
|
||||
}
|
||||
} else {
|
||||
panic!("Axis tried to descend through atom: {}", noun);
|
||||
return Err(()); // Axis tried to descend through atom: {}
|
||||
};
|
||||
}
|
||||
noun
|
||||
Ok(noun)
|
||||
}
|
||||
|
||||
fn edit(
|
||||
@ -661,19 +702,28 @@ fn match_hint_pre_hint(
|
||||
let jet_name = jet_formula.tail();
|
||||
|
||||
let jet = jets::get_jet(jet_name)?;
|
||||
if let Ok(mut jet_res) = jet(stack, subject) {
|
||||
if let Ok(mut jet_res) = jet(stack, newt, subject) {
|
||||
// if in test mode, check that the jet returns the same result as the raw nock
|
||||
if jets::get_jet_test_mode(jet_name) {
|
||||
let mut nock_res = interpret(stack, newt, subject, formula);
|
||||
if unsafe { !unifying_equality(stack, &mut nock_res, &mut jet_res) } {
|
||||
eprintln!(
|
||||
"\rJet {} failed, raw: {}, jetted: {}",
|
||||
jet_name, nock_res, jet_res
|
||||
);
|
||||
return None;
|
||||
}
|
||||
// Throw away trace because we'll regenerate it later, and this is in test mode
|
||||
// so it's okay if it runs twice
|
||||
interpret(stack, newt, subject, formula)
|
||||
.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 {
|
||||
Some(jet_res)
|
||||
}
|
||||
Some(jet_res)
|
||||
} else {
|
||||
// Print jet errors and punt to Nock
|
||||
eprintln!("\rJet {} failed: ", jet_name);
|
||||
|
@ -1,14 +1,17 @@
|
||||
pub mod math;
|
||||
pub mod mink;
|
||||
|
||||
use crate::jets::math::*;
|
||||
use crate::jets::mink::*;
|
||||
use crate::mem::NockStack;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{self, Noun};
|
||||
use ares_macros::tas;
|
||||
|
||||
crate::gdb!();
|
||||
|
||||
/// Return Err if the computation crashed or should punt to Nock
|
||||
pub type Jet = fn(&mut NockStack, Noun) -> Result<Noun, JetErr>;
|
||||
pub type Jet = fn(&mut NockStack, &mut Option<&mut Newt>, Noun) -> Result<Noun, JetErr>;
|
||||
|
||||
/// Only return a deterministic error if the Nock would have deterministically crashed.
|
||||
#[derive(Debug, PartialEq)]
|
||||
@ -62,6 +65,7 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
|
||||
tas!(b"met") => Some(jet_met),
|
||||
tas!(b"mug") => Some(jet_mug),
|
||||
tas!(b"rev") => Some(jet_rev),
|
||||
tas!(b"mink") => Some(jet_mink),
|
||||
_ => {
|
||||
// eprintln!("Unknown jet: {:?}", jet_name);
|
||||
None
|
||||
|
@ -16,6 +16,7 @@ use crate::interpreter::raw_slot;
|
||||
use crate::jets::{JetErr, JetErr::*};
|
||||
use crate::mem::NockStack;
|
||||
use crate::mug::mug;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES};
|
||||
use bitvec::prelude::{BitSlice, Lsb0};
|
||||
use either::Either::*;
|
||||
@ -25,7 +26,11 @@ use std::{cmp, convert::TryFrom};
|
||||
|
||||
crate::gdb!();
|
||||
|
||||
pub fn jet_dec(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_dec(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
if let Ok(atom) = arg.as_atom() {
|
||||
match atom.as_either() {
|
||||
@ -62,7 +67,11 @@ pub fn jet_dec(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_add(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_add(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -77,7 +86,11 @@ pub fn jet_add(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_sub(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_sub(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -102,7 +115,11 @@ pub fn jet_sub(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_mul(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_mul(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -129,7 +146,11 @@ pub fn jet_mul(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_div(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_div(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -146,7 +167,11 @@ pub fn jet_div(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_mod(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_mod(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -161,7 +186,11 @@ pub fn jet_mod(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_dvr(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_dvr(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -189,7 +218,11 @@ pub fn jet_dvr(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_lth(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_lth(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -211,7 +244,11 @@ pub fn jet_lth(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn jet_lte(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_lte(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -233,7 +270,11 @@ pub fn jet_lte(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn jet_gth(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_gth(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -255,7 +296,11 @@ pub fn jet_gth(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn jet_gte(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_gte(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -277,7 +322,11 @@ pub fn jet_gte(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn jet_bex(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_bex(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6).as_direct()?.data() as usize;
|
||||
|
||||
if arg < 63 {
|
||||
@ -291,7 +340,11 @@ pub fn jet_bex(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_lsh(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_lsh(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let (bloq, step) = bite(raw_slot(arg, 2))?;
|
||||
let a = raw_slot(arg, 3).as_atom()?;
|
||||
@ -317,7 +370,11 @@ pub fn jet_lsh(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_rsh(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_rsh(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let (bloq, step) = bite(raw_slot(arg, 2))?;
|
||||
let a = raw_slot(arg, 3).as_atom()?;
|
||||
@ -343,7 +400,11 @@ pub fn jet_rsh(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_con(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_con(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -359,7 +420,11 @@ pub fn jet_con(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_dis(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_dis(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -375,7 +440,11 @@ pub fn jet_dis(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_mix(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_mix(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let a = raw_slot(arg, 2).as_atom()?;
|
||||
let b = raw_slot(arg, 3).as_atom()?;
|
||||
@ -391,7 +460,11 @@ pub fn jet_mix(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_end(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_end(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let (bloq, step) = bite(raw_slot(arg, 2))?;
|
||||
let a = raw_slot(arg, 3).as_atom()?;
|
||||
@ -416,7 +489,11 @@ pub fn jet_end(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_cat(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_cat(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let bloq = raw_slot(arg, 2).as_direct()?.data() as usize;
|
||||
if bloq >= 64 {
|
||||
@ -440,7 +517,11 @@ pub fn jet_cat(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_can(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_can(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let bloq = raw_slot(arg, 2).as_direct()?.data() as usize;
|
||||
if bloq >= 64 {
|
||||
@ -490,7 +571,11 @@ pub fn jet_can(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_rep(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_rep(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let (bloq, step) = bite(raw_slot(arg, 2))?;
|
||||
let original_list = raw_slot(arg, 3);
|
||||
@ -533,7 +618,11 @@ pub fn jet_rep(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_cut(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_cut(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let bloq = raw_slot(arg, 2).as_direct()?.data() as usize;
|
||||
if bloq >= 64 {
|
||||
@ -552,7 +641,11 @@ pub fn jet_cut(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
Ok(new_indirect.as_noun())
|
||||
}
|
||||
|
||||
pub fn jet_rip(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_rip(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let (bloq, step) = bite(raw_slot(arg, 2))?;
|
||||
let atom = raw_slot(arg, 3).as_atom()?;
|
||||
@ -571,7 +664,11 @@ pub fn jet_rip(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
pub fn jet_met(_stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_met(
|
||||
_stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let bloq = raw_slot(arg, 2).as_direct()?.data() as usize;
|
||||
if bloq >= 64 {
|
||||
@ -582,7 +679,11 @@ pub fn jet_met(_stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
Ok(D(met(bloq, a) as u64))
|
||||
}
|
||||
|
||||
pub fn jet_mug(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_mug(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
Ok(mug(stack, arg).as_noun())
|
||||
}
|
||||
@ -651,7 +752,11 @@ pub fn met(bloq: usize, a: Atom) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jet_rev(stack: &mut NockStack, subject: Noun) -> Result<Noun, JetErr> {
|
||||
pub fn jet_rev(
|
||||
stack: &mut NockStack,
|
||||
_newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let boz = raw_slot(arg, 2).as_atom()?.as_direct()?.data();
|
||||
|
||||
@ -751,7 +856,7 @@ mod tests {
|
||||
|
||||
fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) {
|
||||
let sam = T(stack, &[D(0), sam, D(0)]);
|
||||
let jet_res = assert_no_alloc(|| jet(stack, sam).unwrap());
|
||||
let jet_res = assert_no_alloc(|| jet(stack, &mut None, sam).unwrap());
|
||||
assert_noun_eq(stack, jet_res, res);
|
||||
}
|
||||
|
||||
@ -788,7 +893,7 @@ mod tests {
|
||||
|
||||
fn assert_jet_err(stack: &mut NockStack, jet: Jet, sam: Noun, err: JetErr) {
|
||||
let sam = T(stack, &[D(0), sam, D(0)]);
|
||||
let jet_res = jet(stack, sam);
|
||||
let jet_res = jet(stack, &mut None, sam);
|
||||
assert!(
|
||||
jet_res.is_err(),
|
||||
"with sample: {}, expected err: {:?}, got: {:?}",
|
||||
|
70
rust/ares/src/jets/mink.rs
Normal file
70
rust/ares/src/jets/mink.rs
Normal file
@ -0,0 +1,70 @@
|
||||
/** Virtualization jets
|
||||
*/
|
||||
use crate::interpreter::{interpret, raw_slot, NockErr};
|
||||
use crate::jets::JetErr;
|
||||
use crate::mem::NockStack;
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{Noun, D, T};
|
||||
|
||||
crate::gdb!();
|
||||
|
||||
// XX: interpret should accept optional scry function and potentially produce blocked
|
||||
pub fn jet_mink(
|
||||
stack: &mut NockStack,
|
||||
newt: &mut Option<&mut Newt>,
|
||||
subject: Noun,
|
||||
) -> Result<Noun, JetErr> {
|
||||
let arg = raw_slot(subject, 6);
|
||||
let v_subject = raw_slot(arg, 4);
|
||||
let v_formula = raw_slot(arg, 5);
|
||||
let _scry = raw_slot(arg, 3);
|
||||
|
||||
match interpret(stack, newt, v_subject, v_formula) {
|
||||
Ok(res) => Ok(T(stack, &[D(0), res])),
|
||||
Err(err) => match err {
|
||||
NockErr::Blocked(block) => Ok(T(stack, &[D(1), block])),
|
||||
NockErr::Error(error) => Ok(T(stack, &[D(2), error])),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::jets::Jet;
|
||||
use crate::mem::unifying_equality;
|
||||
use assert_no_alloc::assert_no_alloc;
|
||||
|
||||
fn init() -> NockStack {
|
||||
NockStack::new(8 << 10 << 10, 0)
|
||||
}
|
||||
|
||||
fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
|
||||
let eq = unsafe { unifying_equality(stack, &mut a, &mut b) };
|
||||
assert!(eq, "got: {}, need: {}", a, b);
|
||||
}
|
||||
|
||||
fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) {
|
||||
let sam = T(stack, &[D(0), sam, D(0)]);
|
||||
let jet_res = assert_no_alloc(|| jet(stack, &mut None, sam).unwrap());
|
||||
assert_noun_eq(stack, jet_res, res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mink_success() {
|
||||
let s = &mut init();
|
||||
let n = T(s, &[D(0), D(1), D(53)]);
|
||||
let sam = T(s, &[n, D(0)]);
|
||||
let res = T(s, &[D(0), D(53)]);
|
||||
assert_jet(s, jet_mink, sam, res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mink_zapzap() {
|
||||
let s = &mut init();
|
||||
let n = T(s, &[D(0), D(0), D(0)]);
|
||||
let sam = T(s, &[n, D(0)]);
|
||||
let res = T(s, &[D(2), D(0)]);
|
||||
assert_jet(s, jet_mink, sam, res);
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ fn main() -> io::Result<()> {
|
||||
ares::interpreter::use_gdb();
|
||||
ares::jets::use_gdb();
|
||||
ares::jets::math::use_gdb();
|
||||
ares::jets::mink::use_gdb();
|
||||
ares::mem::use_gdb();
|
||||
ares::mug::use_gdb();
|
||||
ares::newt::use_gdb();
|
||||
@ -52,7 +53,8 @@ fn main() -> io::Result<()> {
|
||||
let input_cell = input
|
||||
.as_cell()
|
||||
.expect("Input must be jam of subject/formula pair");
|
||||
let result = interpret(&mut stack, &mut None, input_cell.head(), input_cell.tail());
|
||||
let result = interpret(&mut stack, &mut None, input_cell.head(), input_cell.tail())
|
||||
.expect("nock failed");
|
||||
if let Ok(atom) = result.as_atom() {
|
||||
println!("Result: {}", atom);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ impl NockStack {
|
||||
* The initial frame is a west frame. When the stack is initialized, a number of slots is given.
|
||||
* We add three extra slots to store the “previous” frame, stack, and allocation pointer. For the
|
||||
* initial frame, the previous allocation pointer is set to the beginning (low boundary) of the
|
||||
* arena, the previous frame pointer is set to NULL, and the previous stack pointer is set to XX */
|
||||
* arena, the previous frame pointer is set to NULL, and the previous stack pointer is set to NULL */
|
||||
|
||||
/** size is in 64-bit (i.e. 8-byte) words.
|
||||
* top_slots is how many slots to allocate to the top stack frame.
|
||||
@ -91,6 +91,18 @@ impl NockStack {
|
||||
}
|
||||
}
|
||||
|
||||
/** Current frame pointer of this NockStack */
|
||||
pub fn get_frame_pointer(&self) -> *const u64 {
|
||||
self.frame_pointer
|
||||
}
|
||||
|
||||
/** Current frame pointer of this NockStack */
|
||||
pub fn get_mean_stack(&self) -> Noun {
|
||||
unsafe {
|
||||
*self.mean_stack
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks if the current stack frame has West polarity */
|
||||
#[inline]
|
||||
pub fn is_west(&self) -> bool {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::interpreter::{interpret, raw_slot};
|
||||
use crate::interpreter::{interpret, raw_slot, NockErr};
|
||||
use crate::mem::NockStack;
|
||||
use crate::mug::mug_u32;
|
||||
use crate::newt::Newt;
|
||||
@ -67,7 +67,8 @@ pub fn serf() -> io::Result<()> {
|
||||
}
|
||||
tas!(b"peek") => {
|
||||
let sam = raw_slot(writ, 7);
|
||||
let res = slam(stack, newt, arvo, PEEK_AXIS, sam);
|
||||
let res = slam(stack, newt, arvo, PEEK_AXIS, sam)
|
||||
.expect("peek error handling unimplemented");
|
||||
newt.peek_done(stack, res);
|
||||
}
|
||||
tas!(b"play") => {
|
||||
@ -76,7 +77,8 @@ pub fn serf() -> io::Result<()> {
|
||||
let lit = raw_slot(writ, 7);
|
||||
let sub = T(stack, &[D(0), D(3)]);
|
||||
let lyf = T(stack, &[D(2), sub, D(0), D(2)]);
|
||||
let gat = interpret(stack, &mut Some(newt), lit, lyf);
|
||||
let gat = interpret(stack, &mut Some(newt), lit, lyf)
|
||||
.expect("play error handling unimplemented");
|
||||
arvo = raw_slot(gat, 7);
|
||||
false
|
||||
} else {
|
||||
@ -90,7 +92,10 @@ pub fn serf() -> io::Result<()> {
|
||||
while let Ok(cell) = lit.as_cell() {
|
||||
if run {
|
||||
let ovo = cell.head();
|
||||
let res = slam(stack, newt, arvo, POKE_AXIS, ovo).as_cell().unwrap();
|
||||
let res = slam(stack, newt, arvo, POKE_AXIS, ovo)
|
||||
.expect("play error handling unimplemented")
|
||||
.as_cell()
|
||||
.unwrap();
|
||||
arvo = res.tail();
|
||||
}
|
||||
event_number += 1;
|
||||
@ -102,7 +107,10 @@ pub fn serf() -> io::Result<()> {
|
||||
}
|
||||
tas!(b"work") => {
|
||||
let ovo = raw_slot(writ, 7);
|
||||
let res = slam(stack, newt, arvo, POKE_AXIS, ovo).as_cell().unwrap();
|
||||
let res = slam(stack, newt, arvo, POKE_AXIS, ovo)
|
||||
.expect("work error handling unimplemented")
|
||||
.as_cell()
|
||||
.unwrap();
|
||||
let fec = res.head();
|
||||
arvo = res.tail();
|
||||
snap.save(stack, &mut arvo);
|
||||
@ -118,7 +126,13 @@ pub fn serf() -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn slam(stack: &mut NockStack, newt: &mut Newt, core: Noun, axis: u64, ovo: Noun) -> Noun {
|
||||
pub fn slam(
|
||||
stack: &mut NockStack,
|
||||
newt: &mut Newt,
|
||||
core: Noun,
|
||||
axis: u64,
|
||||
ovo: Noun,
|
||||
) -> Result<Noun, NockErr> {
|
||||
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)]);
|
||||
|
Loading…
Reference in New Issue
Block a user