WIP 09/12

This commit is contained in:
Alex Shelkovnykov 2023-09-12 22:20:15 -06:00
parent 54a9ec980f
commit 67abda479e
11 changed files with 1173 additions and 829 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,17 @@
:: A working pill that grows towards arvo.hoon. Requires playpen.hoon from this
:: scaffolding directory.
::
/+ cradle
/+ playpen
!.
=/ core
=> cradle
=> playpen
!=
=>
|%
+$ card (cask)
++ cask |$ [a] (pair mark a)
+$ knot @ta
++ list |$ [item] $@(~ [i=item t=(list item)])
+$ mark @tas
+$ card (cask)
+$ ovum [=wire =card]
++ pair |$ [head tail] [p=head q=tail]
+$ path (list knot)
+$ wire path
:: mutually recursive Ackermann functions
:: test turning %spot hints on/off
@ -74,4 +70,4 @@
arvo .*([arvo -.epic] [%9 2 %10 [6 %0 3] %0 2])
==
--
[%pill %baby [aeon .*(cradle core) ~] ~ ~]
[%pill %toddler [aeon .*(playpen core) ~] ~ ~]

View File

@ -948,14 +948,17 @@ fn match_hint_pre_nock(
match tag.data() {
tas!(b"slog") => {
// eprintln!("serf -> %slog start");
let slog_cell = res?.cell()?;
let pri = slog_cell.head().direct()?.data();
let tank = slog_cell.tail();
if let Some(not) = newt {
// eprintln!("serf -> %slog hit newt");
not.slog(stack, pri, tank);
} else {
println!("raw slog: {} {}", pri, tank);
eprintln!("raw slog: {} {}", pri, tank);
}
// eprintln!("serf -> %slog end");
}
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();
@ -986,7 +989,7 @@ fn match_hint_pre_nock(
if let Ok(Ok(toon)) = mook(stack, newt, tone, true).map(|t| t.as_cell()) {
if unsafe { !toon.head().raw_equals(D(2)) } {
// Print jet errors and punt to Nock
// Print jet error and punt to Nock
eprintln!("\r%hela failed: toon not %2");
return None;
}

View File

@ -1,13 +1,16 @@
pub mod bits;
pub mod form;
pub mod hash;
pub mod math;
pub mod nock;
pub mod text;
pub mod tree;
use crate::jets::bits::*;
use crate::jets::hash::*;
use crate::jets::math::*;
use crate::jets::nock::*;
use crate::jets::text::*;
use crate::jets::tree::*;
use crate::mem::NockStack;
use crate::newt::Newt;
@ -59,6 +62,8 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
tas!(b"cap") => Some(jet_cap),
tas!(b"mas") => Some(jet_mas),
//
tas!(b"lent") => Some(jet_lent),
//
tas!(b"bex") => Some(jet_bex),
tas!(b"can") => Some(jet_can),
tas!(b"cat") => Some(jet_cat),
@ -78,6 +83,9 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
//
tas!(b"mug") => Some(jet_mug),
//
// Not currently in any pill
// tas!(b"scow") => Some(jet_scow),
//
tas!(b"mink") => Some(jet_mink),
_ => {
// eprintln!("Unknown jet: {:?}", jet_name);

136
rust/ares/src/jets/form.rs Normal file
View File

@ -0,0 +1,136 @@
/** Formatting jets
*/
use crate::jets::Result;
use crate::jets::util::slot;
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::Noun;
crate::gdb!();
pub fn jet_scow(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> Result {
let aura = slot(subject, 12)?.as_direct()?;
let atom = slot(subject, 13)?.as_atom()?;
util::scow(stack, aura, atom)
}
pub mod util {
use crate::jets;
use crate::jets::JetErr;
use crate::jets::util::rip;
use crate::jets::text::util::lent;
use crate::mem::NockStack;
use crate::noun::{Atom, DirectAtom, Cell, CellMemory, D, T};
use ares_macros::tas;
use std::result;
fn num_to_ascii(num: u64) -> result::Result<u64, JetErr> {
if num > 9 {
Err(JetErr::Deterministic)
} else {
Ok(num + 48)
}
}
pub fn scow(
stack: &mut NockStack,
aura: DirectAtom, // XX: technically this should be Atom?
atom: Atom
) -> jets::Result {
match aura.data() {
tas!(b"ud") => {
eprintln!("1");
let tape = rip(stack, 3, 1, atom)?;
let mut lent = lent(tape)?;
eprintln!("2");
if lent == 0 {
assert!(tape.is_atom());
return Ok(T(stack, &[D(num_to_ascii(0)?), D(0)]));
}
eprintln!("3");
unsafe {
let mut list = tape.as_cell()?;
let (root, mut memory) = Cell::new_raw_mut(stack);
(*memory).head = D(num_to_ascii(list.head().as_direct()?.data())?);
lent -= 1;
eprintln!("4");
let mut new_cell: Cell;
let mut new_memory: *mut CellMemory;
while lent > 0 {
list = list.tail().as_cell()?;
if lent % 3 == 0 {
(new_cell, new_memory) = Cell::new_raw_mut(stack);
(*memory).tail = new_cell.as_noun();
memory = new_memory;
(*memory).head = D(46); // '.'
}
(new_cell, new_memory) = Cell::new_raw_mut(stack);
(*memory).tail = new_cell.as_noun();
memory = new_memory;
(*memory).head = D(num_to_ascii(tape.as_cell()?.head().as_direct()?.data())?);
lent -= 1;
}
eprintln!("5");
(*memory).tail = D(0);
// 1 1 1
// 10 2 2
// 100 3 0
// 1.000 4 1
// 10.000 5 2
// 100.000 6 0
// 1.000.000 7 1
eprintln!("6");
Ok(root.as_noun())
}
}
_ => Err(JetErr::Punt)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::JetErr;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack, A};
use crate::noun::{D, T};
use ares_macros::tas;
use ibig::ubig;
#[test]
fn test_scow() {
let s = &mut init_stack();
let aura = D(tas!(b"ud"));
let sam = T(s, &[aura, D(0)]);
let res = T(s, &[D(48), D(0)]);
assert_jet(s, jet_scow, sam, res);
let sam = T(s, &[aura, D(100)]);
let res = T(s, &[D(49), D(48), D(48), 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, &[D(49), D(48), D(48), D(0)]);
assert_jet(s, jet_scow, sam, res);
let sam = T(s, &[aura, D(1000)]);
let res = T(s, &[D(49), D(46), D(48), D(48), D(48), 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, &[D(49), D(46), D(48), D(48), D(48), D(0)]);
assert_jet(s, 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);
}
}

View File

@ -1,7 +1,7 @@
use crate::jets::util::*;
/** Hash jets
*/
use crate::jets::Result;
use crate::jets::util::*;
use crate::mem::NockStack;
use crate::mug::mug;
use crate::newt::Newt;

View File

@ -33,10 +33,11 @@ pub fn jet_mink(
pub mod util {
use crate::jets::util::rip;
use crate::jets::{jet_mink, JetErr, Result};
use crate::jets::{JetErr, Result, jet_mink};
use crate::jets::form::util::scow;
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{tape, Noun, D, T};
use crate::noun::{Noun, Cell, D, T, tape};
use ares_macros::tas;
const LEAF: Noun = D(tas!(b"leaf"));
@ -96,49 +97,86 @@ pub mod util {
}
}
tas!(b"spot") => {
let subj = T(stack, &[D(0), dat, D(0)]);
let tone = jet_mink(stack, newt, subj)?.as_cell()?;
if unsafe { !tone.head().raw_equals(D(0)) } {
// XX test this in Vere
// if the formula in dat crashes, we produce leaf+"mook.spot"
let msg = tape(stack, "mook.spot");
T(stack, &[LEAF, msg])
} else {
let spot = tone.tail().as_cell()?;
let pint = spot.tail().as_cell()?;
let pstr = pint.head().as_cell()?;
let pend = pint.tail().as_cell()?;
// let subj = T(stack, &[D(0), dat, D(0)]);
// let tone = jet_mink(stack, newt, subj)?.as_cell()?;
// eprintln!("dat = {}", dat);
// eprintln!("tone = {}", tone);
// if unsafe { !tone.head().raw_equals(D(0)) } {
// // XX test this in Vere
// // if the formula in dat crashes, we produce leaf+"mook.spot"
// let msg = tape(stack, "mook.spot");
// T(stack, &[LEAF, msg])
// } else {
// let spot = tone.tail().as_cell()?;
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(tas!(b":")), D(0)]);
let trel = T(stack, &[colo, D(0), D(0)]);
let colo = T(stack, &[D(tas!(b":")), D(0)]);
let trel = T(stack, &[colo, D(0), D(0)]);
let smyt = smyt(stack, spot.head())?;
let smyt = smyt(stack, spot.head())?;
// XX: numbers not +scow-ed
let text = format!(
"<[{} {}.{} {}]>",
pstr.head().as_atom()?.as_either().either(
|l| l.data().to_string(),
|r| r.as_ubig(stack).to_string()
),
pstr.tail().as_atom()?.as_either().either(
|l| l.data().to_string(),
|r| r.as_ubig(stack).to_string()
),
pend.head().as_atom()?.as_either().either(
|l| l.data().to_string(),
|r| r.as_ubig(stack).to_string()
),
pend.tail().as_atom()?.as_either().either(
|l| l.data().to_string(),
|r| r.as_ubig(stack).to_string()
)
);
let tape = tape(stack, &text);
let aura = D(tas!(b"ud")).as_direct()?;
let str_lin = scow(stack, aura, pstr.head().as_atom()?)?;
let str_col = scow(stack, aura, pstr.tail().as_atom()?)?;
let end_lin = scow(stack, aura, pend.head().as_atom()?)?;
let end_col = scow(stack, aura, pend.tail().as_atom()?)?;
let mut list: Cell;
unsafe {
list = end_col.as_cell()?;
loop {
if let Some(_) = list.tail().atom() {
break;
}
list = list.tail().as_cell()?;
}
// "{end_col}]>"
let p4 = T(stack, &[D(93), D(62), D(0)]);
(*list.tail_as_mut()) = p4;
list = end_lin.as_cell()?;
loop {
if let Some(_) = list.tail().atom() {
break;
}
list = list.tail().as_cell()?;
}
// "{end_lin} {end_col}]>"
let p3 = T(stack, &[D(32), end_col]);
(*list.tail_as_mut()) = p3;
list = str_col.as_cell()?;
loop {
if let Some(_) = list.tail().atom() {
break;
}
list = list.tail().as_cell()?;
}
// "{str_col}.{end_lin} {end_col}]>"
let p2 = T(stack, &[D(46), end_lin]);
(*list.tail_as_mut()) = p2;
list = str_lin.as_cell()?;
loop {
if let Some(_) = list.tail().atom() {
break;
}
list = list.tail().as_cell()?;
}
// "{str_lin} {str_col}.{end_lin} {end_col}]>"
let p1 = T(stack, &[D(32), str_col]);
(*list.tail_as_mut()) = p1;
// "<[{str_lin} {str_col}.{end_lin} {end_col}]>"
let tape = T(stack, &[D(91), D(60), str_lin]);
let finn = T(stack, &[LEAF, tape]);
T(stack, &[ROSE, trel, smyt, finn])
}
// }
}
_ => {
let tape = rip(stack, 3, 1, tag.as_atom())?;
@ -163,10 +201,11 @@ pub mod util {
list = cell.tail();
}
Ok(res)
let ress = T(stack, &[D(2), res]);
Ok(ress)
} else {
// XX: need non-tail recursive helper to build +mook without +flop, because no helper in noun.rs to allocate Cell and set tail later (like u3i_defcons in Vere)
Ok(D(0))
Ok(T(stack, &[D(2), D(0)]))
}
}

View File

@ -0,0 +1,64 @@
/** Text processing jets
*/
use crate::jets::Result;
use crate::jets::util::slot;
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Noun, D};
crate::gdb!();
pub fn jet_lent(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> Result {
let tape = slot(subject, 6)?;
util::lent(tape).map(|x| D(x as u64))
}
pub mod util {
use crate::jets::JetErr;
use crate::noun::Noun;
pub fn lent(tape: Noun) -> Result<usize, JetErr> {
let mut len = 0usize;
let mut list = tape;
loop {
if let Some(atom) = list.atom() {
if let None = atom.as_bitslice().first_one() {
break;
} else {
return Err(JetErr::Deterministic);
}
}
let cell = list.as_cell()?;
// don't need checked_add or indirect atom result: 2^63-1 atoms would be 64 ebibytes
len += 1;
list = cell.tail();
}
Ok(len)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::JetErr;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
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);
}
}

View File

@ -58,6 +58,7 @@ use either::Either;
use std::io::{Read, Write};
use std::os::unix::prelude::FromRawFd;
use std::ptr::copy_nonoverlapping;
use std::slice::from_raw_parts_mut;
crate::gdb!();
@ -80,13 +81,20 @@ impl Newt {
* problem.
*/
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) {
// eprintln!("serf -> writing noun: {}", noun);
let atom = jam(stack, noun);
// eprintln!("serf -> jammed noun: {}", atom);
let size = atom.size() << 3;
let mut buf = vec![0u8; size + 5];
// eprintln!("serf -> buffer size: {}", size);
// let mut buf = vec![0u8; size + 5];
// XX: checked add?
let buf = unsafe { from_raw_parts_mut(stack.struct_alloc::<u8>(size + 5), size + 5) };
// eprintln!("serf -> heap allocation?");
buf[1] = size as u8;
buf[2] = (size >> 8) as u8;
buf[3] = (size >> 16) as u8;
buf[4] = (size >> 24) as u8;
// eprintln!("serf -> matching atom");
match atom.as_either() {
Either::Left(direct) => unsafe {
copy_nonoverlapping(
@ -105,10 +113,12 @@ impl Newt {
},
};
self.output.write_all(&buf).unwrap();
// eprintln!("serf -> done writing noun");
}
/** Send %ripe, the first event. */
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) {
// eprintln!("serf -> ripe");
let version = T(
stack,
&[
@ -123,42 +133,50 @@ impl Newt {
/** Send %live, acknowledging. */
pub fn live(&mut self, stack: &mut NockStack) {
// eprintln!("serf -> live");
let live = T(stack, &[D(tas!(b"live")), D(0)]);
self.write_noun(stack, live);
}
/** Send %slog, pretty-printed debug output. */
pub fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) {
// eprintln!("serf -> starting slog");
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank]);
self.write_noun(stack, slog);
// eprintln!("serf -> ending slog");
}
/** Send %flog, raw debug output. */
pub fn flog(&mut self, stack: &mut NockStack, cord: Noun) {
// eprintln!("serf -> flog");
let flog = T(stack, &[D(tas!(b"flog")), cord]);
self.write_noun(stack, flog);
}
/** Send %peek %done, successfully scried. */
pub fn peek_done(&mut self, stack: &mut NockStack, dat: Noun) {
// eprintln!("serf -> peek done");
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"done")), dat]);
self.write_noun(stack, peek);
}
/** Send %peek %bail, unsuccessfully scried. */
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) {
// eprintln!("serf -> peek bail");
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud]);
self.write_noun(stack, peek);
}
/** Send %play %done, successfully replayed events. */
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) {
// eprintln!("serf -> play done");
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)]);
self.write_noun(stack, play);
}
/** Send %play %bail, failed to replay events. */
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) {
// eprintln!("serf -> play bail");
let play = T(
stack,
&[D(tas!(b"play")), D(tas!(b"bail")), D(eve), D(mug), dud],
@ -168,6 +186,7 @@ impl Newt {
/** Send %work %done, successfully ran event. */
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) {
// eprintln!("serf -> work done");
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"done")), D(eve), D(mug), fec],
@ -177,6 +196,7 @@ impl Newt {
/** Send %work %swap, successfully replaced failed event. */
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) {
// eprintln!("serf -> work swap");
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"swap")), D(eve), D(mug), job, fec],
@ -186,6 +206,7 @@ impl Newt {
/** Send %work %bail, failed to run event. */
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) {
// eprintln!("serf -> work bail");
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud]);
self.write_noun(stack, work);
}

View File

@ -454,6 +454,9 @@ impl IndirectAtom {
}
}
// XX: Need a version that either:
// a) allocates on the NockStack directly for creating a tape (or even a string?)
// b) disables no-allocation, creates a string, utilitzes it (eprintf or generate tape), and then deallocates
impl fmt::Display for IndirectAtom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x")?;

View File

@ -44,13 +44,16 @@ pub fn serf() -> io::Result<()> {
let (_epoch, mut event_number, mut arvo) = snap.load(stack).unwrap_or((0, 0, D(0)));
let mug = mug_u32(stack, arvo);
// eprintln!("serf -> something is happening");
newt.ripe(stack, event_number, mug as u64);
// Can't use for loop because it borrows newt
while let Some(writ) = newt.next(stack) {
// eprintln!("serf -> loop has begun");
let tag = slot(writ, 2)?.as_direct().unwrap();
match tag.data() {
tas!(b"live") => {
// eprintln!("serf -> incoming %live");
let inner = slot(writ, 6)?.as_direct().unwrap();
match inner.data() {
tas!(b"cram") => eprintln!("cram"),
@ -67,12 +70,14 @@ pub fn serf() -> io::Result<()> {
newt.live(stack);
}
tas!(b"peek") => {
// eprintln!("serf -> incoming %peek");
let sam = slot(writ, 7)?;
let res = slam(stack, newt, arvo, PEEK_AXIS, sam)
.expect("peek error handling unimplemented");
newt.peek_done(stack, res);
}
tas!(b"play") => {
// eprintln!("serf -> incoming %play");
let run = if event_number == 0 {
// apply lifecycle to first batch
let lit = slot(writ, 7)?;
@ -107,6 +112,7 @@ pub fn serf() -> io::Result<()> {
newt.play_done(stack, 0);
}
tas!(b"work") => {
// eprintln!("serf -> incoming %work");
let ovo = slot(writ, 7)?;
let res = slam(stack, newt, arvo, POKE_AXIS, ovo)
.expect("work error handling unimplemented")