on master help sign in
commitfff3a22e10512fb6f293036adc9a2b608991f7b3 authoriko <mail@iko.soy> dateTue 10 Sep 2024, 06:10 (2 years ago) parent46c6cb5
10 files changed+480−277
flake.lock+56 flake.nix+35−2 nock/Cargo.lock+7 nock/Cargo.toml+1 nock/res/wash.nock nock/src/interpreter.rs+76−57 nock/src/jets.rs+268−212 nock/src/main.rs+28−4 nock/src/noun.rs+2−2 urbit.hoon+7
flake.lock+56
@@ -1,5 +1,26 @@
11{
22 "nodes": {
3+ "fenix": {
4+ "inputs": {
5+ "nixpkgs": [
6+ "nixpkgs"
7+ ],
8+ "rust-analyzer-src": "rust-analyzer-src"
9+ },
10+ "locked": {
11+ "lastModified": 1725863722,
12+ "narHash": "sha256-YBcCMVp9RrN2rgqhsMhpu/iw7L8z17N4fp4A129IZ3w=",
13+ "owner": "nix-community",
14+ "repo": "fenix",
15+ "rev": "c30b094741641eef4a7200a5d52a8a16f0f345c6",
16+ "type": "github"
17+ },
18+ "original": {
19+ "owner": "nix-community",
20+ "repo": "fenix",
21+ "type": "github"
22+ }
23+ },
324 "flake-utils": {
425 "inputs": {
526 "systems": "systems"
@@ -66,6 +87,22 @@
6687 "type": "github"
6788 }
6889 },
90+ "nockapp": {
91+ "flake": false,
92+ "locked": {
93+ "lastModified": 1725567177,
94+ "narHash": "sha256-2HvzgctPBXBXZEZi9fF3RKST4i6WtKaTx/v1/3t5sVo=",
95+ "owner": "zorp-corp",
96+ "repo": "nockapp",
97+ "rev": "cbe14c452106dd929a0dee013389049888e838df",
98+ "type": "github"
99+ },
100+ "original": {
101+ "owner": "zorp-corp",
102+ "repo": "nockapp",
103+ "type": "github"
104+ }
105+ },
69106 "pdjson": {
70107 "flake": false,
71108 "locked": {
@@ -84,10 +121,12 @@
84121 },
85122 "root": {
86123 "inputs": {
124+ "fenix": "fenix",
87125 "flake-utils": "flake-utils",
88126 "libaes_siv": "libaes_siv",
89127 "murmur3": "murmur3",
90128 "nixpkgs": "nixpkgs",
129+ "nockapp": "nockapp",
91130 "pdjson": "pdjson",
92131 "sha256": "sha256",
93132 "softfloat": "softfloat",
@@ -95,6 +134,23 @@
95134 "vere": "vere"
96135 }
97136 },
137+ "rust-analyzer-src": {
138+ "flake": false,
139+ "locked": {
140+ "lastModified": 1725630423,
141+ "narHash": "sha256-gNCLk3Zg7JlAwmWbVHTH6f3+iqdeQ4fheOotCZy8x5M=",
142+ "owner": "rust-lang",
143+ "repo": "rust-analyzer",
144+ "rev": "08c7bbc2dbe4dcc8968484f1a0e1e6fe7a1d4f6d",
145+ "type": "github"
146+ },
147+ "original": {
148+ "owner": "rust-lang",
149+ "ref": "nightly",
150+ "repo": "rust-analyzer",
151+ "type": "github"
152+ }
153+ },
98154 "sha256": {
99155 "flake": false,
100156 "locked": {
flake.nix+35−2
@@ -31,9 +31,17 @@
3131 url = "github:dfoxfranke/libaes_siv";
3232 flake = false;
3333 };
34+ nockapp = {
35+ url = "github:zorp-corp/nockapp";
36+ flake = false;
37+ };
38+ fenix = {
39+ url = "github:nix-community/fenix";
40+ inputs.nixpkgs.follows = "nixpkgs";
41+ };
3442 };
35− outputs =
36− inputs@{ self, nixpkgs, flake-utils, vere, murmur3, pdjson, sha256, ... }:
43+ outputs = inputs@{ self, nixpkgs, flake-utils, vere, murmur3, pdjson, sha256
44+ , fenix, ... }:
3745 flake-utils.lib.eachDefaultSystem (system:
3846 let
3947 pkgs = import nixpkgs {
@@ -42,6 +50,31 @@
4250 };
4351 in {
4452 packages = rec {
53+ nockapp = (let toolchain = fenix.packages.${system}.minimal.toolchain;
54+ in pkgs.makeRustPlatform {
55+ rustc = toolchain;
56+ cargo = toolchain;
57+ }).buildRustPackage {
58+ doCheck = false;
59+ name = "nockapp";
60+ src = inputs.nockapp;
61+
62+ cargoLock = {
63+ lockFile = "${inputs.nockapp}/Cargo.lock";
64+ allowBuiltinFetchGit = true;
65+ };
66+ LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
67+ BINDGEN_EXTRA_CLANG_ARGS = [
68+ "-I${pkgs.glibc.dev}/include"
69+ "-I${pkgs.libclang.lib}/lib/clang/17/include"
70+ ];
71+ };
72+ urbit-nock = pkgs.runCommand "urbit.nock" { } ''
73+ mkdir -p source
74+ cp ${./urbit.hoon} source/urbit.hoon
75+ ${nockapp}/bin/choo source/urbit.hoon source
76+ cp out.jam $out
77+ '';
4578 gmp = pkgs.runCommand "gmp" {
4679 buildInputs = with pkgs; [ gnutar emscripten gcc ];
4780 } ''
nock/Cargo.lock+7
@@ -168,6 +168,12 @@ dependencies = [
168168 "wasm-bindgen",
169169]
170170
171+[[package]]
172+name = "fplist"
173+version = "0.2.1"
174+source = "registry+https://github.com/rust-lang/crates.io-index"
175+checksum = "1cadb436ce55a7716dd5b977b93a79a819a9b9bbc5746ba9e607cd389836aa8f"
176+
171177[[package]]
172178name = "funty"
173179version = "2.0.0"
@@ -238,6 +244,7 @@ dependencies = [
238244 "bitvec",
239245 "clap",
240246 "console_error_panic_hook",
247+ "fplist",
241248 "murmur3",
242249 "num-bigint",
243250 "num-integer",
nock/Cargo.toml+1
@@ -29,6 +29,7 @@ bitvec = "1.0.1"
2929stacker = "0.1.17"
3030murmur3 = "0.5.2"
3131web-sys = "0.3.70"
32+fplist = "0.2.1"
3233
3334[dependencies.xxhash-rust]
3435version = "0.8.5"
nock/res/wash.nocknew file

Binary file not shown.

nock/src/interpreter.rs+76−57
@@ -2,6 +2,9 @@ use std::borrow::Borrow;
22use std::collections::BTreeMap;
33use std::rc::Rc;
44
5+use bitvec::prelude;
6+use fplist::cons;
7+use fplist::PersistentList;
58use num_bigint::BigUint;
69
710use crate::jets::*;
@@ -18,6 +21,7 @@ pub struct Nouns {
1821 pub sig_one: Rc<Noun>,
1922 pub two_three: Rc<Noun>,
2023 pub memo: Rc<Noun>,
24+ pub mean: Rc<Noun>,
2125}
2226
2327pub struct BigUints {
@@ -54,6 +58,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
5458 let sig_one = cell(&sig, &one);
5559 let two_three = cell(&two, &three);
5660 let memo = Rc::new(Noun::from_bytes(b"memo"));
61+ let mean = Rc::new(Noun::from_bytes(b"mean"));
5762 InterpreterContext {
5863 jets,
5964 double_jets,
@@ -68,6 +73,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
6873 sig_one,
6974 two_three,
7075 memo,
76+ mean,
7177 },
7278 big_uints,
7379 memo: BTreeMap::new(),
@@ -81,10 +87,10 @@ fn wut<'a>(ctx: &'a InterpreterContext, noun: &Noun) -> &'a Rc<Noun> {
8187 }
8288}
8389
84−fn lus(noun: &Noun) -> Option<Noun> {
90+fn lus(noun: &Noun) -> Result<Noun, Tanks> {
8591 match noun {
86− Noun::Cell { .. } => None,
87− Noun::Atom(atm) => Some(Noun::Atom(atm + 1u32)),
92+ Noun::Cell { .. } => Err(PersistentList::new()),
93+ Noun::Atom(atm) => Ok(Noun::Atom(atm + 1u32)),
8894 }
8995}
9096
@@ -96,15 +102,15 @@ fn tis<'a>(ctx: &'a InterpreterContext, lhs: &Noun, rhs: &Noun) -> &'a Rc<Noun>
96102 }
97103}
98104
99−fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Option<Rc<Noun>> {
105+fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Result<Rc<Noun>, Tanks> {
100106 let mut addr_iter = addr.iter_u32_digits();
101107
102108 match (addr_iter.next(), addr_iter.next()) {
103− (None, _) => None,
109+ (None, _) => Err(PersistentList::new()),
104110 (Some(x), None) => fas_u32(x, noun),
105111 _ => {
106112 let rest = fas(ctx, &(addr >> 1u8), noun)?;
107− Some(fas_u32(
113+ Ok(fas_u32(
108114 if (addr & &ctx.big_uints.one) == ctx.big_uints.one {
109115 3
110116 } else {
@@ -116,15 +122,15 @@ fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Option<Rc<Noun>> {
116122 }
117123}
118124
119−fn fas_u32(addr: u32, noun: &Noun) -> Option<Rc<Noun>> {
125+fn fas_u32(addr: u32, noun: &Noun) -> Result<Rc<Noun>, Tanks> {
120126 match addr {
121− 0 => None,
122− 1 => Some(Rc::new(noun.clone())),
127+ 0 => Err(PersistentList::new()),
128+ 1 => Ok(Rc::new(noun.clone())),
123129 n => match noun {
124− Noun::Atom(_) => None,
130+ Noun::Atom(_) => Err(PersistentList::new()),
125131 Noun::Cell { p, q, .. } => match n {
126− 2 => Some(p.clone()),
127− 3 => Some(q.clone()),
132+ 2 => Ok(p.clone()),
133+ 3 => Ok(q.clone()),
128134 _ => {
129135 let rest = fas_u32(n >> 1, &cell(p, q))?;
130136 fas_u32(if (n & 1) == 1 { 3 } else { 2 }, &rest)
@@ -134,10 +140,10 @@ fn fas_u32(addr: u32, noun: &Noun) -> Option<Rc<Noun>> {
134140 }
135141}
136142
137−fn hax_u32(addr: u32, new_value: &Rc<Noun>, target: &Rc<Noun>) -> Option<Rc<Noun>> {
143+fn hax_u32(addr: u32, new_value: &Rc<Noun>, target: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
138144 match addr {
139− 0 => None,
140− 1 => Some(new_value.clone()),
145+ 0 => Err(PersistentList::new()),
146+ 1 => Ok(new_value.clone()),
141147 _ => {
142148 let new_value = if (addr & 1) == 1 {
143149 let foo = fas_u32(addr - 1, &target)?;
@@ -156,11 +162,11 @@ fn hax(
156162 addr: &Atom,
157163 new_value: &Rc<Noun>,
158164 target: &Rc<Noun>,
159−) -> Option<Rc<Noun>> {
165+) -> Result<Rc<Noun>, Tanks> {
160166 let mut addr_iter = addr.iter_u32_digits();
161167
162168 match (addr_iter.next(), addr_iter.next()) {
163− (None, _) => None,
169+ (None, _) => Err(Tanks::new()),
164170 (Some(x), None) => hax_u32(x, new_value, target),
165171 _ => hax(
166172 ctx,
@@ -182,15 +188,15 @@ fn tar_u32<'a>(
182188 subj: Rc<Noun>,
183189 op: u32,
184190 formula: &'a Rc<Noun>,
185−) -> Option<Rc<Noun>> {
191+) -> Result<Rc<Noun>, Tanks> {
186192 match op {
187193 0 => {
188− let b = formula.as_atom()?;
194+ let b = formula.as_atom().ok_or(Tanks::new())?;
189195 fas(ctx, b, &*subj)
190196 }
191− 1 => Some(formula.clone()),
197+ 1 => Ok(formula.clone()),
192198 2 => {
193− let (b, c) = formula.as_cell()?;
199+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
194200
195201 match c.borrow() {
196202 Noun::Cell { p, q, .. }
@@ -217,21 +223,21 @@ fn tar_u32<'a>(
217223 }
218224 3 => {
219225 let foo = tar(ctx, subj, &formula)?;
220− Some(wut(ctx, &foo).clone())
226+ Ok(wut(ctx, &foo).clone())
221227 }
222228 4 => {
223229 let foo = tar(ctx, subj, &formula)?;
224− Some(Rc::new(lus(&foo)?))
230+ Ok(Rc::new(lus(&foo)?))
225231 }
226232 5 => {
227− let (b, c) = formula.as_cell()?;
233+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
228234 let foo = tar(ctx, subj.clone(), &b)?;
229235 let bar = tar(ctx, subj, &c)?;
230− Some(tis(ctx, &foo, &bar).clone())
236+ Ok(tis(ctx, &foo, &bar).clone())
231237 }
232238 6 => {
233− let (b, c) = formula.as_cell()?;
234− let (c, d) = c.as_cell()?;
239+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
240+ let (c, d) = c.as_cell().ok_or(Tanks::new())?;
235241
236242 let bar = tar_u32(ctx, subj.clone(), 4, &cell(&ctx.nouns.four.clone(), &b))?;
237243
@@ -241,17 +247,17 @@ fn tar_u32<'a>(
241247 tar(ctx, subj, &foo)
242248 }
243249 7 => {
244− let (b, c) = formula.as_cell()?;
250+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
245251 let foo = tar(ctx, subj, &b)?;
246252 tar(ctx, foo, &c)
247253 }
248254 8 => {
249− let (b, c) = formula.as_cell()?;
255+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
250256 let foo = tar(ctx, subj.clone(), &b)?;
251257 tar(ctx, cell(&foo, &subj), &c)
252258 }
253259 9 => {
254− let (b, c) = formula.as_cell()?;
260+ let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
255261 let foo = tar(ctx, subj, &c)?;
256262 tar_u32(
257263 ctx,
@@ -261,55 +267,68 @@ fn tar_u32<'a>(
261267 )
262268 }
263269 10 => {
264− let (b, d) = formula.as_cell()?;
265− let (b, c) = b.as_cell()?;
266− let b = b.as_atom()?;
270+ let (b, d) = formula.as_cell().ok_or(Tanks::new())?;
271+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
272+ let b = b.as_atom().ok_or(Tanks::new())?;
267273
268274 let foo = tar(ctx, subj.clone(), &c)?;
269275 let bar = tar(ctx, subj, &d)?;
270276 hax(ctx, b, &foo, &bar)
271277 }
272278 11 => {
273− let (b, d) = formula.as_cell()?;
279+ let (b, d) = formula.as_cell().ok_or(Tanks::new())?;
274280 match b.borrow() {
275281 Noun::Atom(_) => tar(ctx, subj, &d),
276282 Noun::Cell { p, q, .. } => {
283+ let eval = |ctx: &mut InterpreterContext| tar(ctx, subj.clone(), &d);
277284 if *p == ctx.nouns.memo {
278− let hash = cell(&subj, formula).hash();
285+ let hash = cell(&subj, &d).hash();
279286 match ctx.memo.get(&hash) {
280− Some(target) => Some(target.clone()),
287+ Some(target) => Ok(target.clone()),
281288 None => {
282− let foo = cell(
283− &tar(ctx, subj.clone(), &q)?,
284− &tar(ctx, subj.clone(), &d)?,
285− );
286− let target = tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())?;
289+ let target = eval(ctx)?;
287290 ctx.memo.insert(hash, target.clone());
288− Some(target)
291+ Ok(target)
289292 }
290293 }
294+ } else if *p == ctx.nouns.mean {
295+ let gate = tar(ctx, subj.clone(), q)?;
296+ let trace = eval_pulled_gate(ctx, gate)?;
297+ with_trace(trace, eval(ctx))
291298 } else {
292− let foo = cell(&tar(ctx, subj.clone(), &q)?, &tar(ctx, subj.clone(), &d)?);
293− tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())
299+ eval(ctx)
294300 }
295301 }
296302 }
297303 }
298− _ => None,
304+ _ => Err(Tanks::new()),
299305 }
300306}
301307
308+fn with_trace<T>(tank: Tank, src: Result<T, Tanks>) -> Result<T, Tanks> {
309+ println!("{tank}");
310+ match src {
311+ Ok(a) => Ok(a),
312+ Err(tanks) => Err(cons(tank, tanks)),
313+ }
314+}
315+
316+pub type Tank = Rc<Noun>;
317+pub type Tanks = PersistentList<Tank>;
318+
319+pub const EMPTY_TANKS: Tanks = Tanks::new();
320+
302321pub fn tar<'a>(
303322 ctx: &mut InterpreterContext,
304323 subj: Rc<Noun>,
305324 formula: &'a Noun,
306−) -> Option<Rc<Noun>> {
307− let (op, formula) = formula.as_cell()?;
325+) -> Result<Rc<Noun>, Tanks> {
326+ let (op, formula) = formula.as_cell().ok_or(Tanks::new())?;
308327 match op.borrow() {
309328 Noun::Cell { .. } => {
310329 let foo = tar(ctx, subj.clone(), &op)?;
311330 let bar = tar(ctx, subj, &formula)?;
312− Some(cell(&foo, &bar))
331+ Ok(cell(&foo, &bar))
313332 }
314333 Noun::Atom(ref op) => {
315334 let mut op_iter = op.iter_u32_digits();
@@ -318,13 +337,13 @@ pub fn tar<'a>(
318337 1 => Some(op_iter.next().unwrap()),
319338 _ => None,
320339 };
321− let op = op?;
340+ let op = op.ok_or(Tanks::new())?;
322341 stacker::maybe_grow(32 * 1024, 1024 * 1024, || tar_u32(ctx, subj, op, formula))
323342 }
324343 }
325344}
326345
327−pub fn eval_gate(ctx: &mut InterpreterContext, gate_factory: &Rc<Noun>) -> Option<Rc<Noun>> {
346+pub fn eval_gate(ctx: &mut InterpreterContext, gate_factory: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
328347 let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
329348 eval_pulled_gate(ctx, pulled_gate)
330349}
@@ -333,7 +352,7 @@ pub fn slam(
333352 ctx: &mut InterpreterContext,
334353 gate_factory: &Rc<Noun>,
335354 sample: &Rc<Noun>,
336−) -> Option<Rc<Noun>> {
355+) -> Result<Rc<Noun>, Tanks> {
337356 let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
338357
339358 eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
@@ -341,7 +360,7 @@ pub fn slam(
341360
342361/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
343362/// Also for calling gates from within jets.
344−pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Option<Rc<Noun>> {
363+pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
345364 tar(
346365 ctx,
347366 gate,
@@ -358,13 +377,13 @@ pub fn slam_pulled_gate(
358377 ctx: &mut InterpreterContext,
359378 gate: &Rc<Noun>,
360379 sample: &Rc<Noun>,
361−) -> Option<Rc<Noun>> {
380+) -> Result<Rc<Noun>, Tanks> {
362381 eval_pulled_gate(ctx, replace_sample(gate, sample)?)
363382}
364383
365−pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Option<Rc<Noun>> {
366− let (battery, payload) = gate.as_cell()?;
367− let (_sample, context) = payload.as_cell()?;
384+pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
385+ let (battery, payload) = gate.as_cell().ok_or(Tanks::new())?;
386+ let (_sample, context) = payload.as_cell().ok_or(Tanks::new())?;
368387
369− Some(cell(battery, &cell(sample, context)))
388+ Ok(cell(battery, &cell(sample, context)))
370389}
nock/src/jets.rs+268−212
@@ -8,18 +8,20 @@ use std::{
88};
99
1010use crate::{
11− interpreter::{slam_pulled_gate, InterpreterContext},
11+ interpreter::{slam_pulled_gate, InterpreterContext, Tanks},
1212 noun::{self, cell, Atom, Edge, Hair, Nail, Noun},
1313};
1414
15−fn traverse_iter_option<T: Clone, I: Iterator<Item = Option<T>>>(xs: I) -> Option<Vec<T>> {
15+fn traverse_iter_result<E: Clone, T: Clone, I: Iterator<Item = Result<T, E>>>(
16+ xs: I,
17+) -> Result<Vec<T>, E> {
1618 let mut target: Vec<T> = Vec::new();
1719
1820 for x in xs {
1921 target.push(x.clone()?)
2022 }
2123
22− Some(target)
24+ Ok(target)
2325}
2426
2527pub type Jets = BTreeMap<noun::Hash, Jet>;
@@ -108,39 +110,51 @@ pub fn generate_jets() -> Jets {
108110 ])
109111}
110112
111−pub type Jet = fn(ctx: &mut InterpreterContext, &Rc<Noun>) -> Option<Rc<Noun>>;
113+pub type Jet = fn(ctx: &mut InterpreterContext, &Rc<Noun>) -> Result<Rc<Noun>, Tanks>;
112114pub type DoubleJet = fn(ctx: &mut InterpreterContext, &Rc<Noun>, &Rc<Noun>) -> Option<Rc<Noun>>;
113115
114−static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Option<Rc<Noun>> =
116+static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Result<Rc<Noun>, Tanks> =
115117 |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> Atom| {
116− let (p, q) = n.as_cell()?;
117− Some(Rc::new(Noun::Atom(f(p.as_atom()?, q.as_atom()?))))
118+ let (p, q) = n.as_cell().ok_or(Tanks::new())?;
119+ Ok(Rc::new(Noun::Atom(f(
120+ p.as_atom().ok_or(Tanks::new())?,
121+ q.as_atom().ok_or(Tanks::new())?,
122+ ))))
118123 };
119124
120125static BINARY_ATOM_LOOB: fn(
121126 &InterpreterContext,
122127 &Rc<Noun>,
123128 fn(&Atom, &Atom) -> bool,
124−) -> Option<Rc<Noun>> = |ctx: &InterpreterContext, n: &Rc<Noun>, f: fn(&Atom, &Atom) -> bool| {
125− let (p, q) = n.as_cell()?;
126−
127− if f(p.as_atom()?, q.as_atom()?) {
128− Some(ctx.nouns.sig.clone())
129− } else {
130− Some(ctx.nouns.one.clone())
131− }
132−};
129+) -> Result<Rc<Noun>, Tanks> =
130+ |ctx: &InterpreterContext, n: &Rc<Noun>, f: fn(&Atom, &Atom) -> bool| {
131+ let (p, q) = n.as_cell().ok_or(Tanks::new())?;
132+
133+ if f(
134+ p.as_atom().ok_or(Tanks::new())?,
135+ q.as_atom().ok_or(Tanks::new())?,
136+ ) {
137+ Ok(ctx.nouns.sig.clone())
138+ } else {
139+ Ok(ctx.nouns.one.clone())
140+ }
141+ };
133142
134−static BINARY_ATOM_PAIR: fn(&Rc<Noun>, fn(&Atom, &Atom) -> (Atom, Atom)) -> Option<Rc<Noun>> =
135− |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> (Atom, Atom)| {
136− let (p, q) = n.as_cell()?;
143+static BINARY_ATOM_PAIR: fn(
144+ &Rc<Noun>,
145+ fn(&Atom, &Atom) -> (Atom, Atom),
146+) -> Result<Rc<Noun>, Tanks> = |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> (Atom, Atom)| {
147+ let (p, q) = n.as_cell().ok_or(Tanks::new())?;
137148
138− let (a, b) = f(p.as_atom()?, q.as_atom()?);
139− Some(cell(&Rc::new(Noun::Atom(a)), &Rc::new(Noun::Atom(b))))
140− };
149+ let (a, b) = f(
150+ p.as_atom().ok_or(Tanks::new())?,
151+ q.as_atom().ok_or(Tanks::new())?,
152+ );
153+ Ok(cell(&Rc::new(Noun::Atom(a)), &Rc::new(Noun::Atom(b))))
154+};
141155
142156static ADD: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a + b);
143−static DEC: Jet = |_ctx, n| Some(Rc::new(Noun::Atom(n.as_atom()? - 1u32)));
157+static DEC: Jet = |_ctx, n| Ok(Rc::new(Noun::Atom(n.as_atom().ok_or(Tanks::new())? - 1u32)));
144158static DVR: Jet = |_ctx, n| BINARY_ATOM_PAIR(n, |a, b| a.div_rem(&b));
145159static DIV: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a / b);
146160static GTE: Jet = |ctx, n| BINARY_ATOM_LOOB(ctx, n, |a, b| a >= b);
@@ -154,29 +168,31 @@ static MUL: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a * b);
154168static SUB: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a - b);
155169
156170static CAP: Jet = |ctx, n| {
157− let n = n.as_atom()?;
171+ let n = n.as_atom().ok_or(Tanks::new())?;
158172 CAP_ATOM(ctx, n.clone())
159173};
160174
161−static CAP_ATOM: fn(&InterpreterContext, Atom) -> Option<Rc<Noun>> = |ctx, n: Atom| {
175+static CAP_ATOM: fn(&InterpreterContext, Atom) -> Result<Rc<Noun>, Tanks> = |ctx, n: Atom| {
162176 let mut n_iter = n.iter_u32_digits();
163177
164178 match n_iter.len() {
165− 0 => None,
179+ 0 => Err(Tanks::new()),
166180 1 => CAP_U32(ctx, n_iter.next().unwrap()),
167181 _ => CAP_ATOM(ctx, n >> 1),
168182 }
169183};
170−static CAP_U32: fn(ctx: &InterpreterContext, u32) -> Option<Rc<Noun>> = |ctx, n| match n {
171− 0 | 1 => None,
172− 2 => Some(ctx.nouns.two.clone()),
173− 3 => Some(ctx.nouns.three.clone()),
184+static CAP_U32: fn(ctx: &InterpreterContext, u32) -> Result<Rc<Noun>, Tanks> = |ctx, n| match n {
185+ 0 | 1 => Err(Tanks::new()),
186+ 2 => Ok(ctx.nouns.two.clone()),
187+ 3 => Ok(ctx.nouns.three.clone()),
174188 n => CAP_U32(ctx, n >> 1),
175189};
176190
177191static MAS: Jet = |ctx, n| {
178− let n = n.as_atom()?;
179− Some(Rc::new(Noun::Atom(MAS_ATOM(ctx, n.clone())?)))
192+ let n = n.as_atom().ok_or(Tanks::new())?;
193+ Ok(Rc::new(Noun::Atom(
194+ MAS_ATOM(ctx, n.clone()).ok_or(Tanks::new())?,
195+ )))
180196};
181197static MAS_ATOM: fn(&InterpreterContext, Atom) -> Option<Atom> = |ctx, n| {
182198 let mut n_iter = n.iter_u32_digits();
@@ -197,24 +213,24 @@ static MAS_U32: fn(u32) -> u32 = |n| match n {
197213};
198214
199215static PEG: Jet = |ctx, n| {
200− let (a, b) = n.as_cell()?;
216+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
201217
202− let a = a.as_atom()?;
203− let b = b.as_atom()?;
218+ let a = a.as_atom().ok_or(Tanks::new())?;
219+ let b = b.as_atom().ok_or(Tanks::new())?;
204220
205221 if *a == Atom::ZERO {
206− return None;
222+ return Err(Tanks::new());
207223 };
208224
209− Some(Rc::new(Noun::Atom(PEG_ATOM(ctx, a, b.clone())?)))
225+ Ok(Rc::new(Noun::Atom(PEG_ATOM(ctx, a, b.clone())?)))
210226};
211−static PEG_ATOM: fn(&InterpreterContext, &Atom, Atom) -> Option<Atom> = |ctx, a, b| {
227+static PEG_ATOM: fn(&InterpreterContext, &Atom, Atom) -> Result<Atom, Tanks> = |ctx, a, b| {
212228 let mut b_iter = b.iter_u32_digits();
213229
214230 match b_iter.len() {
215− 0 => None,
216− 1 => Some(PEG_U32(a, b_iter.next().unwrap())),
217− _ => Some((&b & &ctx.big_uints.one) + (PEG_ATOM(ctx, a, b >> 1)? << 1)),
231+ 0 => Err(Tanks::new()),
232+ 1 => Ok(PEG_U32(a, b_iter.next().unwrap())),
233+ _ => Ok((&b & &ctx.big_uints.one) + (PEG_ATOM(ctx, a, b >> 1)? << 1)),
218234 }
219235};
220236static PEG_U32: fn(&Atom, u32) -> Atom = |a, b| match b {
@@ -226,9 +242,9 @@ static PEG_U32: fn(&Atom, u32) -> Atom = |a, b| match b {
226242};
227243
228244static FAND: Jet = |ctx, n| {
229− let (nedl, hstk) = n.as_cell()?;
245+ let (nedl, hstk) = n.as_cell().ok_or(Tanks::new())?;
230246 if nedl.is_sig() || hstk.is_sig() {
231− return Some(ctx.nouns.sig.clone());
247+ return Ok(ctx.nouns.sig.clone());
232248 }
233249
234250 let nedl: Vec<&Rc<Noun>> = nedl.list_iter().collect();
@@ -252,13 +268,13 @@ static FAND: Jet = |ctx, n| {
252268 inner_iter = iter.clone();
253269 }
254270
255− Some(Noun::list(result.iter().map(|a| Noun::from_u32(*a))))
271+ Ok(Noun::list(result.iter().map(|a| Noun::from_u32(*a))))
256272};
257273
258274static FIND: Jet = |ctx, n| {
259− let (nedl, hstk) = n.as_cell()?;
275+ let (nedl, hstk) = n.as_cell().ok_or(Tanks::new())?;
260276 if nedl.is_sig() || hstk.is_sig() {
261− return Some(ctx.nouns.sig.clone());
277+ return Ok(ctx.nouns.sig.clone());
262278 }
263279
264280 let nedl: Vec<&Rc<Noun>> = nedl.list_iter().collect();
@@ -274,30 +290,28 @@ static FIND: Jet = |ctx, n| {
274290 .collect::<Vec<_>>()
275291 == nedl
276292 {
277− return Some(Rc::new(Noun::from_u32(i)).unit());
293+ return Ok(Rc::new(Noun::from_u32(i)).unit());
278294 }
279295
280296 inner_iter = iter.clone();
281297 }
282298
283− return Some(ctx.nouns.sig.clone());
299+ return Ok(ctx.nouns.sig.clone());
284300};
285301
286302static FLOP: Jet = |ctx, n| {
287− Some(
288− n.list_iter()
289− .fold(ctx.nouns.sig.clone(), |tail, head| cell(&head, &tail)),
290− )
303+ Ok(n.list_iter()
304+ .fold(ctx.nouns.sig.clone(), |tail, head| cell(&head, &tail)))
291305};
292306
293307static GULF: Jet = |_ctx, n| {
294− let (from, to) = n.as_cell()?;
308+ let (from, to) = n.as_cell().ok_or(Tanks::new())?;
295309
296− let mut from = (*from.as_atom()?).clone();
297− let to = to.as_atom()?.clone();
310+ let mut from = (*from.as_atom().ok_or(Tanks::new())?).clone();
311+ let to = to.as_atom().ok_or(Tanks::new())?.clone();
298312
299313 if from > to {
300− return None;
314+ return Err(Tanks::new());
301315 }
302316
303317 let mut tmp = Vec::new();
@@ -307,105 +321,119 @@ static GULF: Jet = |_ctx, n| {
307321 from += 1u32;
308322 }
309323
310− Some(Noun::list(tmp.iter().rev().map(|a| Noun::Atom(a.clone()))))
324+ Ok(Noun::list(tmp.iter().rev().map(|a| Noun::Atom(a.clone()))))
311325};
312326
313327static INTO: Jet = |_ctx, n| {
314− let (a, b) = n.as_cell()?;
315− let (b, c) = b.as_cell()?;
328+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
329+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
316330
317− let mut b_iter = b.as_atom()?.iter_u32_digits();
331+ let mut b_iter = b.as_atom().ok_or(Tanks::new())?.iter_u32_digits();
318332
319333 match b_iter.len() {
320− 0 => Some(cell(&c, &a)),
334+ 0 => Ok(cell(&c, &a)),
321335 1 => {
322336 let l = a.list_iter();
323337 let b = b_iter.next().unwrap() as usize;
324− Some(Noun::list_refs(
338+ Ok(Noun::list_refs(
325339 l.clone()
326340 .take(b)
327341 .chain(once(c))
328342 .chain(l.skip(b))
329343 .collect::<Vec<_>>()
330344 .iter()
331− .map(|x| *x),
345+ .cloned()
346+ .cloned(),
332347 ))
333348 }
334− _ => Some(Noun::list_refs(
349+ _ => Ok(Noun::list_refs(
335350 a.list_iter()
336351 .chain(once(c))
337352 .collect::<Vec<_>>()
338353 .iter()
354+ .cloned()
339355 .cloned(),
340356 )),
341357 }
342358};
343359
344360static JOIN: Jet = |_ctx, n| {
345− let (sep, list) = n.as_cell()?;
346− Some(Noun::list_refs(
361+ let (sep, list) = n.as_cell().ok_or(Tanks::new())?;
362+ Ok(Noun::list_refs(
347363 list.list_iter()
348364 .intersperse(sep)
349365 .collect::<Vec<_>>()
350366 .iter()
367+ .cloned()
351368 .cloned(),
352369 ))
353370};
354371
355372static LENT: Jet = |_ctx, n| {
356− Some(Rc::new(Noun::from_u32(
373+ Ok(Rc::new(Noun::from_u32(
357374 n.list_iter().fold(0u32, |l, _| l + 1),
358375 )))
359376};
360377
361378static LEVY: Jet = |ctx, n| {
362− let (a, b) = n.as_cell()?;
363− if traverse_iter_option(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
379+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
380+ if traverse_iter_result(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
364381 .iter()
365382 .all(|x| x.is_y())
366383 {
367− Some(ctx.nouns.y.clone())
384+ Ok(ctx.nouns.y.clone())
368385 } else {
369− Some(ctx.nouns.n.clone())
386+ Ok(ctx.nouns.n.clone())
370387 }
371388};
372389
373390static LIEN: Jet = |ctx, n| {
374− let (a, b) = n.as_cell()?;
375− if traverse_iter_option(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
391+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
392+ if traverse_iter_result(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
376393 .iter()
377394 .any(|x| x.is_y())
378395 {
379− Some(ctx.nouns.y.clone())
396+ Ok(ctx.nouns.y.clone())
380397 } else {
381− Some(ctx.nouns.n.clone())
398+ Ok(ctx.nouns.n.clone())
382399 }
383400};
384401
385402static MURN: Jet = |ctx, n| {
386− let (a, b) = n.as_cell()?;
403+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
387404
388− Some(Noun::list_refs(
389− a.list_iter()
390− .filter_map(|n| slam_pulled_gate(ctx, b, n)?.as_unit().cloned())
391− .collect::<Vec<_>>()
392− .iter(),
405+ Ok(Noun::list_refs(
406+ traverse_iter_result(
407+ a.list_iter()
408+ .map(|n| Ok(slam_pulled_gate(ctx, b, n)?.as_unit().cloned())),
409+ )?
410+ .iter()
411+ .filter_map(|x| x.clone()),
393412 ))
394413};
395414
396415static REAP: Jet = |_ctx, n| {
397− let (a, b) = n.as_cell()?;
416+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
398417
399− Some(Noun::list_refs(repeat_n(b, a.as_u32().unwrap() as usize)))
418+ Ok(Noun::list_refs(repeat_n(
419+ b.clone(),
420+ a.as_u32().unwrap() as usize,
421+ )))
400422};
401423
402−static REAR: Jet = |_ctx, n| n.list_iter().last().cloned();
424+static REAR: Jet = |_ctx, n| n.list_iter().last().ok_or(Tanks::new()).cloned();
403425
404426static REEL: Jet = |ctx, n| {
405− let (list, gate) = n.as_cell()?;
427+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
406428
407429 list.list_iter().collect::<Vec<_>>().iter().rfold(
408− Some(gate.gate_sample()?.as_cell()?.1.clone()),
430+ Ok(gate
431+ .gate_sample()
432+ .ok_or(Tanks::new())?
433+ .as_cell()
434+ .ok_or(Tanks::new())?
435+ .1
436+ .clone()),
409437 |acc, next| {
410438 let acc = acc?;
411439 slam_pulled_gate(ctx, gate, &cell(&next, &acc))
@@ -414,10 +442,17 @@ static REEL: Jet = |ctx, n| {
414442};
415443
416444static ROLL: Jet = |ctx, n| {
417− let (list, gate) = n.as_cell()?;
445+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
418446
419447 list.list_iter().fold(
420− Some(gate.clone().gate_sample()?.as_cell()?.1.clone()),
448+ Ok(gate
449+ .clone()
450+ .gate_sample()
451+ .ok_or(Tanks::new())?
452+ .as_cell()
453+ .ok_or(Tanks::new())?
454+ .1
455+ .clone()),
421456 |acc, next| {
422457 let acc = acc?;
423458 slam_pulled_gate(ctx, gate, &cell(&next, &acc))
@@ -426,105 +461,111 @@ static ROLL: Jet = |ctx, n| {
426461};
427462
428463static SCAG: Jet = |_ctx, n| {
429− let (a, b) = n.as_cell()?;
464+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
430465
431− Some(Noun::list_refs(
466+ Ok(Noun::list_refs(
432467 b.list_iter()
433468 .take(a.as_u32().unwrap() as usize)
434469 .collect::<Vec<_>>()
435470 .iter()
471+ .cloned()
436472 .cloned(),
437473 ))
438474};
439475
440476static SKID: Jet = |ctx, n| {
441− let (list, gate) = n.as_cell()?;
477+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
442478
443− let slammed_n = traverse_iter_option(
479+ let slammed_n = traverse_iter_result(
444480 list.list_iter()
445− .map(|n| Some((slam_pulled_gate(ctx, gate, n)?, n))),
481+ .map(|n| Ok((slam_pulled_gate(ctx, gate, n)?, n))),
446482 )?;
447483 let (ys, ns): (Vec<_>, _) = slammed_n.iter().partition(|(l, _)| l.is_y());
448484
449− Some(cell(
450− &Noun::list_refs(ys.iter().map(|(_, x)| *x)),
451− &Noun::list_refs(ns.iter().map(|(_, x)| *x)),
485+ Ok(cell(
486+ &Noun::list_refs(ys.iter().map(|(_, x)| (*x).clone())),
487+ &Noun::list_refs(ns.iter().map(|(_, x)| (*x).clone())),
452488 ))
453489};
454490
455491static SKIM: Jet = |ctx, n| {
456− let (list, gate) = n.as_cell()?;
492+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
457493
458− Some(Noun::list_refs(
459− traverse_iter_option(
494+ Ok(Noun::list_refs(
495+ traverse_iter_result(
460496 list.list_iter()
461− .map(|n| Some((slam_pulled_gate(ctx, gate, n)?, n))),
497+ .map(|n| Ok((slam_pulled_gate(ctx, gate, n)?, n))),
462498 )?
463499 .iter()
464500 .filter(|(l, _)| l.is_y())
465− .map(|(_, x)| *x),
501+ .map(|(_, x)| (*x).clone()),
466502 ))
467503};
468504
469505static SKIP: Jet = |ctx, n| {
470− let (list, gate) = n.as_cell()?;
506+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
471507
472− Some(Noun::list_refs(
473− traverse_iter_option(
508+ Ok(Noun::list_refs(
509+ traverse_iter_result(
474510 list.list_iter()
475− .map(|n| Some((slam_pulled_gate(ctx, gate, n)?, n))),
511+ .map(|n| Ok((slam_pulled_gate(ctx, gate, n)?, n))),
476512 )?
477513 .iter()
478514 .filter(|(l, _)| l.is_y())
479− .map(|(_, x)| x)
480− .cloned(),
515+ .map(|(_, x)| (*x).clone()),
481516 ))
482517};
483518
484519static SLAG: Jet = |ctx, n| {
485− let (a, list) = n.as_cell()?;
520+ let (a, list) = n.as_cell().ok_or(Tanks::new())?;
486521
487− let mut a_iter = a.as_atom()?.iter_u32_digits();
522+ let mut a_iter = a.as_atom().ok_or(Tanks::new())?.iter_u32_digits();
488523
489524 match a_iter.len() {
490− 0 => Some(list.clone()),
491− 1 => Some(Noun::list_refs(
525+ 0 => Ok(list.clone()),
526+ 1 => Ok(Noun::list_refs(
492527 list.list_iter()
493528 .skip(a_iter.next().unwrap() as usize)
494529 .collect::<Vec<_>>()
495530 .iter()
531+ .cloned()
496532 .cloned(),
497533 )),
498− _ => Some(ctx.nouns.sig.clone()),
534+ _ => Ok(ctx.nouns.sig.clone()),
499535 }
500536};
501537
502538static SNAG: Jet = |_ctx, n| {
503− let (a, list) = n.as_cell()?;
539+ let (a, list) = n.as_cell().ok_or(Tanks::new())?;
504540
505− list.list_iter().nth(a.as_u32().unwrap() as usize).cloned()
541+ list.list_iter()
542+ .nth(a.as_u32().unwrap() as usize)
543+ .cloned()
544+ .ok_or(Tanks::new())
506545};
507546
508547static SNIP: Jet = |_ctx, n| {
509− Some(Noun::list_refs(
548+ Ok(Noun::list_refs(
510549 n.list_iter()
511550 .collect::<Vec<_>>()
512551 .iter()
513552 .rev()
514553 .skip(1)
515554 .rev()
555+ .cloned()
516556 .cloned(),
517557 ))
518558};
519559
520560static SNOC: Jet = |_ctx, n| {
521− let (list, b) = n.as_cell()?;
561+ let (list, b) = n.as_cell().ok_or(Tanks::new())?;
522562
523− Some(Noun::list_refs(
563+ Ok(Noun::list_refs(
524564 list.list_iter()
525565 .chain(once(b))
526566 .collect::<Vec<_>>()
527567 .iter()
568+ .cloned()
528569 .cloned(),
529570 ))
530571};
@@ -548,53 +589,62 @@ static SNOC: Jet = |_ctx, n| {
548589// };
549590
550591static SPIN: Jet = |ctx, n| {
551− let (list, b) = n.as_cell()?;
552− let (acc, gate) = b.as_cell()?;
592+ let (list, b) = n.as_cell().ok_or(Tanks::new())?;
593+ let (acc, gate) = b.as_cell().ok_or(Tanks::new())?;
553594
554595 let mut res = Vec::new();
555596 let mut acc = acc.clone();
556597
557598 for n in list.list_iter() {
558599 let foo = slam_pulled_gate(ctx, gate, &cell(&n, &acc))?;
559− let (el, new_acc) = foo.as_cell()?;
600+ let (el, new_acc) = foo.as_cell().ok_or(Tanks::new())?;
560601 acc = new_acc.clone();
561602 res.push(el.clone());
562603 }
563604
564− Some(cell(&Noun::list_refs(res.iter()), &acc))
605+ Ok(cell(&Noun::list_refs(res.iter().cloned()), &acc))
565606};
566607
567608static SPUN: Jet = |ctx, n| {
568− let (list, gate) = n.as_cell()?;
609+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
569610
570611 let mut res = Vec::new();
571− let mut acc = gate.gate_sample()?.as_cell()?.1.clone();
612+ let mut acc = gate
613+ .gate_sample()
614+ .ok_or(Tanks::new())?
615+ .as_cell()
616+ .ok_or(Tanks::new())?
617+ .1
618+ .clone();
572619
573620 for n in list.list_iter() {
574621 let foo = slam_pulled_gate(ctx, gate, &cell(&n, &acc))?;
575− let (el, new_acc) = foo.as_cell()?;
622+ let (el, new_acc) = foo.as_cell().ok_or(Tanks::new())?;
576623 acc = new_acc.clone();
577624 res.push(el.clone());
578625 }
579626
580− Some(cell(&Noun::list_refs(res.iter()), &acc))
627+ Ok(cell(&Noun::list_refs(res.iter().cloned()), &acc))
581628};
582629
583630static TURN: Jet = |ctx, n| {
584− let (list, gate) = n.as_cell()?;
585− Some(Noun::list_refs(
586− traverse_iter_option(list.list_iter().map(|x| slam_pulled_gate(ctx, gate, x)))?.iter(),
631+ let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
632+ Ok(Noun::list_refs(
633+ traverse_iter_result(list.list_iter().map(|x| slam_pulled_gate(ctx, gate, x)))?
634+ .iter()
635+ .cloned(),
587636 ))
588637};
589638
590639static WELD: Jet = |_ctx, n| {
591− let (a, b) = n.as_cell()?;
640+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
592641
593− Some(Noun::list_refs(
642+ Ok(Noun::list_refs(
594643 a.list_iter()
595644 .chain(b.list_iter())
596645 .collect::<Vec<_>>()
597646 .iter()
647+ .cloned()
598648 .cloned(),
599649 ))
600650};
@@ -602,35 +652,36 @@ static WELD: Jet = |_ctx, n| {
602652static WELP: Jet = WELD;
603653
604654static ZING: Jet = |_ctx, n| {
605− Some(Noun::list_refs(
655+ Ok(Noun::list_refs(
606656 n.list_iter()
607657 .map(|l| l.list_iter())
608658 .flatten()
609659 .collect::<Vec<_>>()
610660 .iter()
661+ .cloned()
611662 .cloned(),
612663 ))
613664};
614665
615666static BEX: Jet = |ctx, n| {
616− Some(Rc::new(Noun::Atom(
667+ Ok(Rc::new(Noun::Atom(
617668 &ctx.big_uints.one << n.as_u32().unwrap(),
618669 )))
619670};
620671
621672static END: Jet = |ctx, n| {
622− let (a, b) = n.as_cell()?;
673+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
623674 let bite = a.as_bite();
624675
625676 let bits = bite.bits();
626677
627678 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
628679
629− Some(Rc::new(Noun::Atom(mask & b.as_atom()?)))
680+ Ok(Rc::new(Noun::Atom(mask & b.as_atom().ok_or(Tanks::new())?)))
630681};
631682
632683static CAN: Jet = |ctx, n| {
633− let (a, b) = n.as_cell()?;
684+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
634685 let bloq = a.as_u32().unwrap();
635686 let bloq_ = 2u32.pow(bloq);
636687
@@ -645,28 +696,28 @@ static CAN: Jet = |ctx, n| {
645696 Some((acc? << bits) | (mask & q.as_atom()?))
646697 },
647698 );
648− Some(Rc::new(Noun::Atom(atom?)))
699+ Ok(Rc::new(Noun::Atom(atom.ok_or(Tanks::new())?)))
649700};
650701
651702static CAT: Jet = |_ctx, n| {
652− let (bloq, b) = n.as_cell()?;
653− let (b, c) = b.as_cell()?;
703+ let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
704+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
654705
655− let bloq = bloq.as_u32()?;
656− let b = b.as_atom()?;
657− let c = c.as_atom()?;
706+ let bloq = bloq.as_u32().ok_or(Tanks::new())?;
707+ let b = b.as_atom().ok_or(Tanks::new())?;
708+ let c = c.as_atom().ok_or(Tanks::new())?;
658709
659− Some(Rc::new(Noun::Atom(
710+ Ok(Rc::new(Noun::Atom(
660711 (c << (met(bloq, &b) * 2u32.pow(bloq))) | b,
661712 )))
662713};
663714
664715static MET: Jet = |_ctx, n| {
665− let (bloq, b) = n.as_cell()?;
666− let b: Atom = b.as_atom()?.clone();
716+ let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
717+ let b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
667718 let bloq = bloq.as_u32().unwrap();
668719
669− Some(Rc::new(Noun::from_u32(met(bloq, &b))))
720+ Ok(Rc::new(Noun::from_u32(met(bloq, &b))))
670721};
671722
672723fn met(bloq: u32, a: &Atom) -> u32 {
@@ -674,28 +725,28 @@ fn met(bloq: u32, a: &Atom) -> u32 {
674725}
675726
676727static CUT: Jet = |ctx, n| {
677− let (a, b) = n.as_cell()?;
678− let (b, d) = b.as_cell()?;
679− let (b, c) = b.as_cell()?;
728+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
729+ let (b, d) = b.as_cell().ok_or(Tanks::new())?;
730+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
680731
681732 let bits = 2u32.pow(a.as_u32().unwrap());
682733
683734 let mask = (&ctx.big_uints.one << (bits * c.as_u32().unwrap())) - &ctx.big_uints.one;
684735
685− Some(Rc::new(Noun::Atom(
686− (d.as_atom()? >> (bits * b.as_u32().unwrap())) & mask,
736+ Ok(Rc::new(Noun::Atom(
737+ (d.as_atom().ok_or(Tanks::new())? >> (bits * b.as_u32().unwrap())) & mask,
687738 )))
688739};
689740
690741static FIL: Jet = |ctx, n| {
691− let (a, b) = n.as_cell()?;
692− let (b, c) = b.as_cell()?;
742+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
743+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
693744
694745 let bits = 2u32.pow(a.as_u32().unwrap());
695746
696747 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
697748
698− let src = c.as_atom()? & mask;
749+ let src = c.as_atom().ok_or(Tanks::new())? & mask;
699750
700751 let mut target = ctx.big_uints.zero.clone();
701752
@@ -703,44 +754,44 @@ static FIL: Jet = |ctx, n| {
703754 target = (target << bits) | &src;
704755 }
705756
706− Some(Rc::new(Noun::Atom(target)))
757+ Ok(Rc::new(Noun::Atom(target)))
707758};
708759
709760static LSH: Jet = |_ctx, n| {
710− let (a, b) = n.as_cell()?;
761+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
711762 let a = a.as_bite();
712− let b = b.as_atom()?;
763+ let b = b.as_atom().ok_or(Tanks::new())?;
713764
714− Some(Rc::new(Noun::Atom(b << a.bits())))
765+ Ok(Rc::new(Noun::Atom(b << a.bits())))
715766};
716767
717768static RSH: Jet = |_ctx, n| {
718− let (a, b) = n.as_cell()?;
769+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
719770 let a = a.as_bite();
720− let b = b.as_atom()?;
771+ let b = b.as_atom().ok_or(Tanks::new())?;
721772
722− Some(Rc::new(Noun::Atom(b >> a.bits())))
773+ Ok(Rc::new(Noun::Atom(b >> a.bits())))
723774};
724775
725776static RAP: Jet = |ctx, n| {
726− let (bloq, b) = n.as_cell()?;
777+ let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
727778 let bloq = bloq.as_u32().unwrap();
728779 let bits = 2u32.pow(bloq);
729780
730781 let mut target = ctx.big_uints.zero.clone();
731782
732783 for el in b.list_iter().collect::<Vec<_>>().iter().rev() {
733− let el = el.as_atom()?;
784+ let el = el.as_atom().ok_or(Tanks::new())?;
734785 if el != &ctx.big_uints.zero {
735786 target = (target << (bits * met(bloq, &el))) | el;
736787 }
737788 }
738789
739− Some(Rc::new(Noun::Atom(target)))
790+ Ok(Rc::new(Noun::Atom(target)))
740791};
741792
742793static REP: Jet = |ctx, n| {
743− let (bite, b) = n.as_cell()?;
794+ let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
744795 let bite = bite.as_bite();
745796
746797 let bits = bite.bits();
@@ -749,18 +800,18 @@ static REP: Jet = |ctx, n| {
749800 let mut target = ctx.big_uints.zero.clone();
750801
751802 for el in b.list_iter().collect::<Vec<_>>().iter().rev() {
752− target = (target << bits) | (el.as_atom()? & &mask);
803+ target = (target << bits) | (el.as_atom().ok_or(Tanks::new())? & &mask);
753804 }
754805
755− Some(Rc::new(Noun::Atom(target)))
806+ Ok(Rc::new(Noun::Atom(target)))
756807};
757808
758809static REV: Jet = |ctx, n| {
759− let (bloq, b) = n.as_cell()?;
760− let (len, dat) = b.as_cell()?;
810+ let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
811+ let (len, dat) = b.as_cell().ok_or(Tanks::new())?;
761812 let bloq = bloq.as_u32().unwrap();
762813 let len = len.as_u32().unwrap();
763− let mut dat: Atom = dat.as_atom()?.clone();
814+ let mut dat: Atom = dat.as_atom().ok_or(Tanks::new())?.clone();
764815
765816 let bits = 2u32.pow(bloq);
766817 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -772,13 +823,13 @@ static REV: Jet = |ctx, n| {
772823 dat = dat >> bits;
773824 }
774825
775− Some(Rc::new(Noun::Atom(target)))
826+ Ok(Rc::new(Noun::Atom(target)))
776827};
777828
778829static RIP: Jet = |ctx, n| {
779− let (bite, b) = n.as_cell()?;
830+ let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
780831 let bite = bite.as_bite();
781− let mut b: Atom = b.as_atom()?.clone();
832+ let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
782833
783834 let bits = bite.bits();
784835 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -790,15 +841,15 @@ static RIP: Jet = |ctx, n| {
790841 b = b >> bits;
791842 }
792843
793− Some(Noun::list_refs(target.iter()))
844+ Ok(Noun::list_refs(target.iter().cloned()))
794845};
795846
796847static RUN: Jet = |ctx, n| {
797− let (bite, b) = n.as_cell()?;
798− let (b, gate) = b.as_cell()?;
848+ let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
849+ let (b, gate) = b.as_cell().ok_or(Tanks::new())?;
799850
800851 let bite = bite.as_bite();
801− let mut b: Atom = b.as_atom()?.clone();
852+ let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
802853
803854 let bits = bite.bits();
804855 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -807,20 +858,22 @@ static RUN: Jet = |ctx, n| {
807858
808859 while b > ctx.big_uints.zero {
809860 target = (target << bits)
810− | ((*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?).as_atom()?
861+ | ((*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?)
862+ .as_atom()
863+ .ok_or(Tanks::new())?
811864 & &mask);
812865 b = b >> bits;
813866 }
814867
815− Some(Rc::new(Noun::Atom(target)))
868+ Ok(Rc::new(Noun::Atom(target)))
816869};
817870
818871static RUT: Jet = |ctx, n| {
819− let (bite, b) = n.as_cell()?;
820− let (b, gate) = b.as_cell()?;
872+ let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
873+ let (b, gate) = b.as_cell().ok_or(Tanks::new())?;
821874
822875 let bite = bite.as_bite();
823− let mut b: Atom = b.as_atom()?.clone();
876+ let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
824877
825878 let bits = bite.bits();
826879 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -829,21 +882,24 @@ static RUT: Jet = |ctx, n| {
829882
830883 while b > ctx.big_uints.zero {
831884 target.push(
832− (*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?).as_atom()? & &mask,
885+ (*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?)
886+ .as_atom()
887+ .ok_or(Tanks::new())?
888+ & &mask,
833889 );
834890 b = b >> bits;
835891 }
836892
837− Some(Noun::list(target.iter().cloned().map(Noun::Atom)))
893+ Ok(Noun::list(target.iter().cloned().map(Noun::Atom)))
838894};
839895
840896static SEW: Jet = |ctx, n| {
841− let (a, b) = n.as_cell()?;
842− let (b, recipient) = b.as_cell()?;
843− let (sew_start, c) = b.as_cell()?;
844− let (number_of_blocks, donor) = c.as_cell()?;
845− let recipient = recipient.as_atom()?;
846− let donor = donor.as_atom()?;
897+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
898+ let (b, recipient) = b.as_cell().ok_or(Tanks::new())?;
899+ let (sew_start, c) = b.as_cell().ok_or(Tanks::new())?;
900+ let (number_of_blocks, donor) = c.as_cell().ok_or(Tanks::new())?;
901+ let recipient = recipient.as_atom().ok_or(Tanks::new())?;
902+ let donor = donor.as_atom().ok_or(Tanks::new())?;
847903
848904 let bloq = a.as_u32().unwrap();
849905 let bits = 2u32.pow(bloq);
@@ -855,16 +911,16 @@ static SEW: Jet = |ctx, n| {
855911
856912 let target = (recipient ^ apendix) | (donor & mask);
857913
858− Some(Rc::new(Noun::Atom(target)))
914+ Ok(Rc::new(Noun::Atom(target)))
859915};
860916
861917static SWP: Jet = |ctx, n| {
862− let (bloq, b) = n.as_cell()?;
918+ let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
863919 let bloq = bloq.as_u32().unwrap();
864920 let bits = 2u32.pow(bloq);
865921 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
866922
867− let mut source = b.as_atom()?.clone();
923+ let mut source = b.as_atom().ok_or(Tanks::new())?.clone();
868924 let mut target = ctx.big_uints.zero.clone();
869925
870926 while source > ctx.big_uints.zero {
@@ -872,11 +928,11 @@ static SWP: Jet = |ctx, n| {
872928 source = source >> bits;
873929 }
874930
875− Some(Rc::new(Noun::Atom(target)))
931+ Ok(Rc::new(Noun::Atom(target)))
876932};
877933
878934static XEB: Jet = |_ctx, n| {
879− let mut a = n.as_atom()?.clone();
935+ let mut a = n.as_atom().ok_or(Tanks::new())?.clone();
880936
881937 let mut c = 0;
882938
@@ -885,7 +941,7 @@ static XEB: Jet = |_ctx, n| {
885941 c += 1;
886942 }
887943
888− Some(Rc::new(Noun::from_u32(c)))
944+ Ok(Rc::new(Noun::from_u32(c)))
889945};
890946
891947static CON: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a | b);
@@ -893,23 +949,23 @@ static DIS: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a & b);
893949static MIX: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a ^ b);
894950
895951static NOT: Jet = |ctx, n| {
896− let (a, b) = n.as_cell()?;
897− let (b, c) = b.as_cell()?;
952+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
953+ let (b, c) = b.as_cell().ok_or(Tanks::new())?;
898954
899955 let bloq = a.as_u32().unwrap();
900956 let bits = 2u32.pow(bloq);
901957 let mask = (&ctx.big_uints.one << (bits * b.as_u32().unwrap())) - &ctx.big_uints.one;
902958
903− let target = c.as_atom()? ^ &mask;
959+ let target = c.as_atom().ok_or(Tanks::new())? ^ &mask;
904960
905− Some(Rc::new(Noun::Atom(target)))
961+ Ok(Rc::new(Noun::Atom(target)))
906962};
907963
908964static LAST: Jet = |_ctx, n| {
909− let (a, b) = n.as_cell()?;
910− let a = a.as_hair()?;
911− let b = b.as_hair()?;
912− Some(Noun::from_hair(last(&a, &b)))
965+ let (a, b) = n.as_cell().ok_or(Tanks::new())?;
966+ let a = a.as_hair().ok_or(Tanks::new())?;
967+ let b = b.as_hair().ok_or(Tanks::new())?;
968+ Ok(Noun::from_hair(last(&a, &b)))
913969};
914970
915971fn last<'a>(a: &'a Hair, b: &'a Hair) -> &'a Hair {
@@ -929,20 +985,20 @@ fn last<'a>(a: &'a Hair, b: &'a Hair) -> &'a Hair {
929985}
930986
931987static TRIP: Jet = |_ctx, n| {
932− let a = n.as_atom()?;
933− Some(Noun::list(
988+ let a = n.as_atom().ok_or(Tanks::new())?;
989+ Ok(Noun::list(
934990 a.to_bytes_le().iter().map(|b| Noun::from_u32(*b as u32)),
935991 ))
936992};
937993
938994static MUK: Jet = |_ctx, n| {
939− let (seed, len) = n.as_cell()?;
940− let (len, key) = len.as_cell()?;
941− let seed = seed.as_u32()?;
942− let len = len.as_u32()?;
943− let key = key.as_atom()?;
995+ let (seed, len) = n.as_cell().ok_or(Tanks::new())?;
996+ let (len, key) = len.as_cell().ok_or(Tanks::new())?;
997+ let seed = seed.as_u32().ok_or(Tanks::new())?;
998+ let len = len.as_u32().ok_or(Tanks::new())?;
999+ let key = key.as_atom().ok_or(Tanks::new())?;
9441000
945− Some(Rc::new(Noun::from_u32(muk(seed, len, key))))
1001+ Ok(Rc::new(Noun::from_u32(muk(seed, len, key))))
9461002};
9471003
9481004static JUST: DoubleJet = |ctx, n, m| {
@@ -1006,7 +1062,7 @@ fn fail(nail: Nail) -> Edge {
10061062 }
10071063}
10081064
1009−const MUG: Jet = |__ctx, n| Some(Rc::new(Noun::from_u32(n.mug())));
1065+const MUG: Jet = |__ctx, n| Ok(Rc::new(Noun::from_u32(n.mug())));
10101066
10111067pub fn mum(syd: u32, fal: u32, key: &Atom) -> u32 {
10121068 let wyd = met(3, &key);
nock/src/main.rs+28−4
@@ -1,5 +1,6 @@
11use clap::{command, error::Result, Parser, Subcommand};
2−use nock::interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext};
2+use core::str;
3+use nock::interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
34use nock::{
45 cue::cue_bytes,
56 interpreter::{generate_interpreter_context, slam},
@@ -110,9 +111,15 @@ fn interact(gate_file: PathBuf) -> Result<(), std::io::Error> {
110111 let source = get_stdin().unwrap();
111112
112113 let mut spinner = new_spinner(String::from("Slamming gate..."));
113− let Some(slam) = slam(&mut generate_interpreter_context(), &gate, &source) else {
114− spinner.fail("Gate execution failed");
115− exit(1);
114+ let slam = match slam(&mut generate_interpreter_context(), &gate, &source) {
115+ Ok(slam) => slam,
116+ Err(tanks) => {
117+ spinner.fail("Gate execution failed");
118+ let mut ctx = generate_interpreter_context();
119+ let trace = wash(&mut ctx, tanks);
120+ println!("{trace}");
121+ exit(1);
122+ }
116123 };
117124 let Some(target) = slam.as_bytes() else {
118125 spinner.fail("The gate did not produce a valid atom");
@@ -207,3 +214,20 @@ fn read_nock_or_compile(
207214 read_nock(&path)
208215 }
209216}
217+
218+fn wash(ctx: &mut InterpreterContext, tanks: Tanks) -> String {
219+ let wash = cue_bytes(include_bytes!("../res/wash.nock"));
220+
221+ let mut target = String::new();
222+ for tank in tanks.iter() {
223+ let mut str = slam_pulled_gate(ctx, &wash, &tank)
224+ .unwrap()
225+ .as_atom()
226+ .unwrap()
227+ .to_bytes_le();
228+
229+ target.push_str(str::from_utf8_mut(&mut *str).unwrap())
230+ }
231+
232+ target
233+}
nock/src/noun.rs+2−2
@@ -55,8 +55,8 @@ impl<'a> Noun {
5555 l.rfold(Rc::new(Noun::SIG), |tail, head| cell(&Rc::new(head), &tail))
5656 }
5757
58− pub fn list_refs<I: Iterator<Item = &'a Rc<Noun>> + DoubleEndedIterator>(l: I) -> Rc<Noun> {
59− l.rfold(Rc::new(Noun::SIG), |tail, head| cell(head, &tail))
58+ pub fn list_refs<I: Iterator<Item = Rc<Noun>> + DoubleEndedIterator>(l: I) -> Rc<Noun> {
59+ l.rfold(Rc::new(Noun::SIG), |tail, head| cell(&head, &tail))
6060 }
6161
6262 pub fn unit(self: Rc<Self>) -> Rc<Noun> {
urbit.hoonnew file+7
@@ -0,0 +1,7 @@
1+|= [tag=@tas args=*]
2+?+ tag !!
3+ :: %ride (ride (,[type @] args))
4+ :: %comb (comb (,[nock nock] args))
5+ :: %hoon ..ride
6+ %wash (wash (,[[@ @] tank] args))
7+==