on master help sign in
13 files changed+1270−328
since splitsnapshots
unifiedsplit
nock/Cargo.lock+141−5 nock/Cargo.toml+7 nock/hello.hoon+2−1 nock/hello.nock nock/src/interpreter.rs+225−54 nock/src/jets.rs+304−129 nock/src/lib.rs+2−37 nock/src/main.rs+44−18 nock/src/noun.rs+313 nock/test.hoon+3 nock/wock.hoon+198−10 wock-web/src/lib.rs+31−74 wock.nock
nock/Cargo.lock+141−5
@@ -1,6 +1,6 @@
11# This file is automatically @generated by Cargo.
22# It is not intended for manual editing.
3−version = 3
3+version = 4
44
55[[package]]
66name = "anstream"
@@ -63,6 +63,12 @@ version = "0.8.0"
6363source = "registry+https://github.com/rust-lang/crates.io-index"
6464checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
6565
66+[[package]]
67+name = "bitflags"
68+version = "2.6.0"
69+source = "registry+https://github.com/rust-lang/crates.io-index"
70+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
71+
6672[[package]]
6773name = "bitter"
6874version = "0.7.0"
@@ -87,6 +93,12 @@ version = "3.16.0"
8793source = "registry+https://github.com/rust-lang/crates.io-index"
8894checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
8995
96+[[package]]
97+name = "bytecount"
98+version = "0.6.8"
99+source = "registry+https://github.com/rust-lang/crates.io-index"
100+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
101+
90102[[package]]
91103name = "cc"
92104version = "1.1.31"
@@ -102,6 +114,12 @@ version = "1.0.0"
102114source = "registry+https://github.com/rust-lang/crates.io-index"
103115checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
104116
117+[[package]]
118+name = "cfg_aliases"
119+version = "0.2.1"
120+source = "registry+https://github.com/rust-lang/crates.io-index"
121+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
122+
105123[[package]]
106124name = "clap"
107125version = "4.5.20"
@@ -130,10 +148,10 @@ version = "4.5.18"
130148source = "registry+https://github.com/rust-lang/crates.io-index"
131149checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
132150dependencies = [
133− "heck",
151+ "heck 0.5.0",
134152 "proc-macro2",
135153 "quote",
136− "syn",
154+ "syn 2.0.85",
137155]
138156
139157[[package]]
@@ -158,6 +176,22 @@ dependencies = [
158176 "windows-sys 0.48.0",
159177]
160178
179+[[package]]
180+name = "ctrlc"
181+version = "3.4.5"
182+source = "registry+https://github.com/rust-lang/crates.io-index"
183+checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
184+dependencies = [
185+ "nix",
186+ "windows-sys 0.59.0",
187+]
188+
189+[[package]]
190+name = "fnv"
191+version = "1.0.7"
192+source = "registry+https://github.com/rust-lang/crates.io-index"
193+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
194+
161195[[package]]
162196name = "fplist"
163197version = "0.2.1"
@@ -170,6 +204,12 @@ version = "2.0.0"
170204source = "registry+https://github.com/rust-lang/crates.io-index"
171205checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
172206
207+[[package]]
208+name = "heck"
209+version = "0.4.1"
210+source = "registry+https://github.com/rust-lang/crates.io-index"
211+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
212+
173213[[package]]
174214name = "heck"
175215version = "0.5.0"
@@ -215,6 +255,18 @@ version = "0.5.2"
215255source = "registry+https://github.com/rust-lang/crates.io-index"
216256checksum = "9252111cf132ba0929b6f8e030cac2a24b507f3a4d6db6fb2896f27b354c714b"
217257
258+[[package]]
259+name = "nix"
260+version = "0.29.0"
261+source = "registry+https://github.com/rust-lang/crates.io-index"
262+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
263+dependencies = [
264+ "bitflags",
265+ "cfg-if",
266+ "cfg_aliases",
267+ "libc",
268+]
269+
218270[[package]]
219271name = "nock"
220272version = "0.1.0"
@@ -223,13 +275,16 @@ dependencies = [
223275 "bitter",
224276 "bitvec",
225277 "clap",
278+ "ctrlc",
226279 "fplist",
280+ "lazy_static",
227281 "murmur3",
228282 "num-bigint",
229283 "num-integer",
230284 "num-traits",
231285 "spinoff",
232286 "stacker",
287+ "tabled",
233288 "web-sys",
234289 "xxhash-rust",
235290]
@@ -268,12 +323,47 @@ version = "1.20.2"
268323source = "registry+https://github.com/rust-lang/crates.io-index"
269324checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
270325
326+[[package]]
327+name = "papergrid"
328+version = "0.12.0"
329+source = "registry+https://github.com/rust-lang/crates.io-index"
330+checksum = "c7419ad52a7de9b60d33e11085a0fe3df1fbd5926aa3f93d3dd53afbc9e86725"
331+dependencies = [
332+ "bytecount",
333+ "fnv",
334+ "unicode-width",
335+]
336+
271337[[package]]
272338name = "paste"
273339version = "1.0.15"
274340source = "registry+https://github.com/rust-lang/crates.io-index"
275341checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
276342
343+[[package]]
344+name = "proc-macro-error"
345+version = "1.0.4"
346+source = "registry+https://github.com/rust-lang/crates.io-index"
347+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
348+dependencies = [
349+ "proc-macro-error-attr",
350+ "proc-macro2",
351+ "quote",
352+ "syn 1.0.109",
353+ "version_check",
354+]
355+
356+[[package]]
357+name = "proc-macro-error-attr"
358+version = "1.0.4"
359+source = "registry+https://github.com/rust-lang/crates.io-index"
360+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
361+dependencies = [
362+ "proc-macro2",
363+ "quote",
364+ "version_check",
365+]
366+
277367[[package]]
278368name = "proc-macro2"
279369version = "1.0.89"
@@ -343,6 +433,17 @@ version = "0.11.1"
343433source = "registry+https://github.com/rust-lang/crates.io-index"
344434checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
345435
436+[[package]]
437+name = "syn"
438+version = "1.0.109"
439+source = "registry+https://github.com/rust-lang/crates.io-index"
440+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
441+dependencies = [
442+ "proc-macro2",
443+ "quote",
444+ "unicode-ident",
445+]
446+
346447[[package]]
347448name = "syn"
348449version = "2.0.85"
@@ -354,6 +455,29 @@ dependencies = [
354455 "unicode-ident",
355456]
356457
458+[[package]]
459+name = "tabled"
460+version = "0.16.0"
461+source = "registry+https://github.com/rust-lang/crates.io-index"
462+checksum = "77c9303ee60b9bedf722012ea29ae3711ba13a67c9b9ae28993838b63057cb1b"
463+dependencies = [
464+ "papergrid",
465+ "tabled_derive",
466+]
467+
468+[[package]]
469+name = "tabled_derive"
470+version = "0.8.0"
471+source = "registry+https://github.com/rust-lang/crates.io-index"
472+checksum = "bf0fb8bfdc709786c154e24a66777493fb63ae97e3036d914c8666774c477069"
473+dependencies = [
474+ "heck 0.4.1",
475+ "proc-macro-error",
476+ "proc-macro2",
477+ "quote",
478+ "syn 1.0.109",
479+]
480+
357481[[package]]
358482name = "tap"
359483version = "1.0.1"
@@ -366,12 +490,24 @@ version = "1.0.13"
366490source = "registry+https://github.com/rust-lang/crates.io-index"
367491checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
368492
493+[[package]]
494+name = "unicode-width"
495+version = "0.1.11"
496+source = "registry+https://github.com/rust-lang/crates.io-index"
497+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
498+
369499[[package]]
370500name = "utf8parse"
371501version = "0.2.2"
372502source = "registry+https://github.com/rust-lang/crates.io-index"
373503checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
374504
505+[[package]]
506+name = "version_check"
507+version = "0.9.5"
508+source = "registry+https://github.com/rust-lang/crates.io-index"
509+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
510+
375511[[package]]
376512name = "wasm-bindgen"
377513version = "0.2.95"
@@ -394,7 +530,7 @@ dependencies = [
394530 "once_cell",
395531 "proc-macro2",
396532 "quote",
397− "syn",
533+ "syn 2.0.85",
398534 "wasm-bindgen-shared",
399535]
400536
@@ -416,7 +552,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
416552dependencies = [
417553 "proc-macro2",
418554 "quote",
419− "syn",
555+ "syn 2.0.85",
420556 "wasm-bindgen-backend",
421557 "wasm-bindgen-shared",
422558]
nock/Cargo.toml+7
@@ -17,6 +17,9 @@ stacker = "0.1.17"
1717murmur3 = "0.5.2"
1818web-sys = "0.3.70"
1919fplist = "0.2.1"
20+ctrlc = "3.4.5"
21+lazy_static = "1.5.0"
22+tabled = "0.16.0"
2023
2124[dependencies.xxhash-rust]
2225version = "0.8.5"
@@ -26,6 +29,9 @@ features = ["xxh3"]
2629# Tell `rustc` to optimize for small code size.
2730opt-level = 3
2831
32+[features]
33+count-jets = []
34+
2935[[bin]]
3036name = "nock"
3137path = "src/main.rs"
@@ -33,3 +39,4 @@ path = "src/main.rs"
3339[[bin]]
3440name = "hash-gate"
3541path = "src/hash-gate.rs"
42+
nock/hello.hoon+2−1
@@ -1,5 +1,6 @@
11|= name=@t
2+~& name
23?+ name (crip (weld "Hello, " (trip name)))
34 'Curtis' 'Hello, daddy...'
4− '' 'Hello, world!'
5+ %'' 'Hello, world!'
56==
nock/hello.nock

Binary file not shown.

nock/src/interpreter.rs+225−54
@@ -1,14 +1,23 @@
1+use core::str;
12use std::borrow::Borrow;
23use std::collections::BTreeMap;
4+use std::collections::HashMap;
35use std::rc::Rc;
6+use std::sync::Mutex;
47
58use fplist::cons;
69use fplist::PersistentList;
10+use lazy_static::lazy_static;
711use num_bigint::BigUint;
812
913use crate::jets::*;
1014use crate::noun::*;
1115
16+// #[cfg(feature = "count-jets")]
17+lazy_static! {
18+ pub static ref JET_COUNTER: Mutex<HashMap<Atom, u32>> = Mutex::new(HashMap::new());
19+}
20+
1221#[derive(Clone)]
1322pub struct Nouns {
1423 pub y: Rc<Noun>,
@@ -22,6 +31,8 @@ pub struct Nouns {
2231 pub two_three: Rc<Noun>,
2332 pub memo: Rc<Noun>,
2433 pub mean: Rc<Noun>,
34+ pub slog: Rc<Noun>,
35+ pub fast: Rc<Noun>,
2536}
2637
2738#[derive(Clone)]
@@ -40,6 +51,7 @@ pub struct InterpreterContext {
4051 pub nouns: Nouns,
4152 pub big_uints: BigUints,
4253 pub memo: BTreeMap<Hash, Rc<Noun>>,
54+ pub slog: fn(&String) -> (),
4355}
4456
4557pub fn generate_interpreter_context() -> InterpreterContext {
@@ -61,6 +73,8 @@ pub fn generate_interpreter_context() -> InterpreterContext {
6173 let two_three = cell(&two, &three);
6274 let memo = Rc::new(Noun::from_bytes(b"memo"));
6375 let mean = Rc::new(Noun::from_bytes(b"mean"));
76+ let slog = Rc::new(Noun::from_bytes(b"slog"));
77+ let fast = Rc::new(Noun::from_bytes(b"fast"));
6478 InterpreterContext {
6579 jets,
6680 double_jets,
@@ -76,9 +90,12 @@ pub fn generate_interpreter_context() -> InterpreterContext {
7690 two_three,
7791 memo,
7892 mean,
93+ slog,
94+ fast,
7995 },
8096 big_uints,
8197 memo: BTreeMap::new(),
98+ slog: |str: &String| eprintln!("{}", str),
8299 }
83100}
84101
@@ -89,7 +106,7 @@ fn wut<'a>(ctx: &'a InterpreterContext, noun: &Noun) -> &'a Rc<Noun> {
89106 }
90107}
91108
92−fn lus(noun: &Noun) -> Result<Noun, Tanks> {
109+fn lus(noun: &Noun) -> Result<Noun, TTanks> {
93110 match noun {
94111 Noun::Cell { .. } => Err(PersistentList::new()),
95112 Noun::Atom(atm) => Ok(Noun::Atom(atm + 1u32)),
@@ -104,7 +121,7 @@ fn tis<'a>(ctx: &'a InterpreterContext, lhs: &Noun, rhs: &Noun) -> &'a Rc<Noun>
104121 }
105122}
106123
107−fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Result<Rc<Noun>, Tanks> {
124+fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Result<Rc<Noun>, TTanks> {
108125 let mut addr_iter = addr.iter_u32_digits();
109126
110127 match (addr_iter.next(), addr_iter.next()) {
@@ -124,7 +141,7 @@ fn fas(ctx: &InterpreterContext, addr: &Atom, noun: &Noun) -> Result<Rc<Noun>, T
124141 }
125142}
126143
127−fn fas_u32(addr: u32, noun: &Noun) -> Result<Rc<Noun>, Tanks> {
144+fn fas_u32(addr: u32, noun: &Noun) -> Result<Rc<Noun>, TTanks> {
128145 match addr {
129146 0 => Err(PersistentList::new()),
130147 1 => Ok(Rc::new(noun.clone())),
@@ -142,7 +159,7 @@ fn fas_u32(addr: u32, noun: &Noun) -> Result<Rc<Noun>, Tanks> {
142159 }
143160}
144161
145−fn hax_u32(addr: u32, new_value: &Rc<Noun>, target: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
162+fn hax_u32(addr: u32, new_value: &Rc<Noun>, target: &Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
146163 match addr {
147164 0 => Err(PersistentList::new()),
148165 1 => Ok(new_value.clone()),
@@ -164,11 +181,11 @@ fn hax(
164181 addr: &Atom,
165182 new_value: &Rc<Noun>,
166183 target: &Rc<Noun>,
167−) -> Result<Rc<Noun>, Tanks> {
184+) -> Result<Rc<Noun>, TTanks> {
168185 let mut addr_iter = addr.iter_u32_digits();
169186
170187 match (addr_iter.next(), addr_iter.next()) {
171− (None, _) => Err(Tanks::new()),
188+ (None, _) => Err(TTanks::new()),
172189 (Some(x), None) => hax_u32(x, new_value, target),
173190 _ => hax(
174191 ctx,
@@ -187,18 +204,18 @@ fn hax(
187204
188205fn tar_u32<'a>(
189206 ctx: &mut InterpreterContext,
190− subj: Rc<Noun>,
207+ subj: &'a Rc<Noun>,
191208 op: u32,
192209 formula: &'a Rc<Noun>,
193−) -> Result<Rc<Noun>, Tanks> {
210+) -> Result<Rc<Noun>, TTanks> {
194211 match op {
195212 0 => {
196− let b = formula.as_atom().ok_or(Tanks::new())?;
213+ let b = formula.as_atom().ok_or(TTanks::new())?;
197214 fas(ctx, b, &*subj)
198215 }
199216 1 => Ok(formula.clone()),
200217 2 => {
201− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
218+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
202219
203220 match c.borrow() {
204221 Noun::Cell { p, q, .. }
@@ -210,16 +227,16 @@ fn tar_u32<'a>(
210227 match ctx.jets.get(&hash) {
211228 Some(f) => f(ctx, sample),
212229 None => {
213− let foo = tar(ctx, subj.clone(), &b)?;
230+ let foo = tar(ctx, subj, &b)?;
214231 let bar = tar(ctx, subj, &c)?;
215− tar(ctx, foo, &bar)
232+ tar(ctx, &foo, &bar)
216233 }
217234 }
218235 }
219236 _ => {
220− let foo = tar(ctx, subj.clone(), &b)?;
237+ let foo = tar(ctx, subj, &b)?;
221238 let bar = tar(ctx, subj, &c)?;
222− tar(ctx, foo, &bar)
239+ tar(ctx, &foo, &bar)
223240 }
224241 }
225242 }
@@ -229,57 +246,57 @@ fn tar_u32<'a>(
229246 }
230247 4 => Ok(Rc::new(lus(&*tar(ctx, subj, &formula)?)?)),
231248 5 => {
232− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
233− let foo = tar(ctx, subj.clone(), &b)?;
249+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
250+ let foo = tar(ctx, subj, &b)?;
234251 let bar = tar(ctx, subj, &c)?;
235252 Ok(tis(ctx, &foo, &bar).clone())
236253 }
237254 6 => {
238− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
239− let (c, d) = c.as_cell().ok_or(Tanks::new())?;
255+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
256+ let (c, d) = c.as_cell().ok_or(TTanks::new())?;
240257
241− let bar = tar_u32(ctx, subj.clone(), 4, &cell(&ctx.nouns.four.clone(), &b))?;
258+ let bar = tar_u32(ctx, subj, 4, &cell(&ctx.nouns.four.clone(), &b))?;
242259
243− let foo = tar_u32(ctx, ctx.nouns.two_three.clone(), 0, &bar)?;
244− let foo = tar_u32(ctx, cell(&c, &d), 0, &foo)?;
260+ let foo = tar_u32(ctx, &ctx.nouns.two_three.clone(), 0, &bar)?;
261+ let foo = tar_u32(ctx, &cell(&c, &d), 0, &foo)?;
245262
246263 tar(ctx, subj, &foo)
247264 }
248265 7 => {
249− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
266+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
250267 let foo = tar(ctx, subj, &b)?;
251− tar(ctx, foo, &c)
268+ tar(ctx, &foo, &c)
252269 }
253270 8 => {
254− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
255− let foo = tar(ctx, subj.clone(), &b)?;
256− tar(ctx, cell(&foo, &subj), &c)
271+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
272+ let foo = tar(ctx, subj, &b)?;
273+ tar(ctx, &cell(&foo, &subj), &c)
257274 }
258275 9 => {
259− let (b, c) = formula.as_cell().ok_or(Tanks::new())?;
276+ let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
260277 let foo = tar(ctx, subj, &c)?;
261278 tar_u32(
262279 ctx,
263− foo,
280+ &foo,
264281 2,
265282 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
266283 )
267284 }
268285 10 => {
269− let (b, d) = formula.as_cell().ok_or(Tanks::new())?;
270− let (b, c) = b.as_cell().ok_or(Tanks::new())?;
271− let b = b.as_atom().ok_or(Tanks::new())?;
286+ let (b, d) = formula.as_cell().ok_or(TTanks::new())?;
287+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
288+ let b = b.as_atom().ok_or(TTanks::new())?;
272289
273− let foo = tar(ctx, subj.clone(), &c)?;
290+ let foo = tar(ctx, subj, &c)?;
274291 let bar = tar(ctx, subj, &d)?;
275292 hax(ctx, b, &foo, &bar)
276293 }
277294 11 => {
278− let (b, d) = formula.as_cell().ok_or(Tanks::new())?;
295+ let (b, d) = formula.as_cell().ok_or(TTanks::new())?;
279296 match b.borrow() {
280297 Noun::Atom(_) => tar(ctx, subj, &d),
281298 Noun::Cell { p, q, .. } => {
282− let eval = |ctx: &mut InterpreterContext| tar(ctx, subj.clone(), &d);
299+ let eval = |ctx: &mut InterpreterContext| tar(ctx, subj, &d);
283300 if *p == ctx.nouns.memo {
284301 let hash = cell(&subj, &d).hash();
285302 match ctx.memo.get(&hash) {
@@ -292,37 +309,188 @@ fn tar_u32<'a>(
292309 }
293310 } else if *p == ctx.nouns.mean {
294311 with_trace((subj.clone(), q.clone()), eval(ctx))
312+ } else if *p == ctx.nouns.slog {
313+ let noun = tar(ctx, subj, &q)?;
314+ let (_prio, tank) = noun.as_cell().ok_or(TTanks::new())?;
315+
316+ (ctx.slog)(&ram(ctx, tank.clone()).unwrap_or(String::new()));
317+ eval(ctx)
318+ } else if *p == ctx.nouns.fast {
319+ if cfg!(feature = "count-jets") {
320+ let tag = q.as_cell().unwrap().1.as_cell().unwrap().0.as_atom();
321+ match tag {
322+ None => (),
323+ Some(tag) => {
324+ let mut counter = JET_COUNTER.lock().unwrap();
325+ match counter.get(tag) {
326+ None => {
327+ counter.insert(tag.clone(), 1);
328+ ()
329+ }
330+ Some(v) => {
331+ let v = *v;
332+ counter.insert(tag.clone(), v + 1);
333+ ()
334+ }
335+ }
336+ }
337+ }
338+ }
339+ eval(ctx)
295340 } else {
296341 eval(ctx)
297342 }
298343 }
299344 }
300345 }
301− _ => Err(Tanks::new()),
346+ _ => Err(TTanks::new()),
302347 }
303348}
304349
305−fn with_trace<T>(tank: (Rc<Noun>, Rc<Noun>), src: Result<T, Tanks>) -> Result<T, Tanks> {
350+fn ram(ctx: &mut InterpreterContext, tank: Rc<Noun>) -> Option<String> {
351+ match tank.borrow() {
352+ Noun::Atom(str) => {
353+ let mut bytes = str.to_bytes_le();
354+ Some(String::from(str::from_utf8_mut(&mut bytes).ok()?))
355+ }
356+ Noun::Cell { p, q, .. } => {
357+ let tag = p.as_atom()?.to_bytes_le();
358+ if tag == b"leaf" {
359+ let mut bytes = crip(ctx, q.clone()).ok()?.as_bytes()?;
360+ Some(String::from(str::from_utf8_mut(&mut bytes).ok()?))
361+ } else if tag == b"palm" {
362+ let (spacers, tanks) = q.as_cell()?;
363+ let (mid, open, flat_open, close) = spacers.tuple_4()?;
364+
365+ let mut mid = crip(ctx, mid.clone()).ok()?.as_bytes()?;
366+ let mid = String::from(str::from_utf8_mut(&mut mid).ok()?);
367+
368+ let mut open = crip(ctx, open.clone()).ok()?.as_bytes()?;
369+ let open = String::from(str::from_utf8_mut(&mut open).ok()?);
370+
371+ let mut flat_open = crip(ctx, flat_open.clone()).ok()?.as_bytes()?;
372+ let flat_open = String::from(str::from_utf8_mut(&mut flat_open).ok()?);
373+
374+ let mut close = crip(ctx, close.clone()).ok()?.as_bytes()?;
375+ let close = String::from(str::from_utf8_mut(&mut close).ok()?);
376+
377+ let mut target = String::new();
378+
379+ target.push_str(&*open);
380+ target.push_str(&*flat_open);
381+
382+ let mut is_first = true;
383+ for tank in tanks.list_iter() {
384+ if !is_first {
385+ target.push_str(&*mid);
386+ }
387+
388+ target.push_str(&*(ram(ctx, tank.clone())?));
389+
390+ is_first = false;
391+ }
392+
393+ target.push_str(&*close);
394+
395+ Some(target)
396+ } else if tag == b"rose" {
397+ let (spacers, tanks) = q.as_cell()?;
398+ let (mid, open, close) = spacers.tuple_3()?;
399+
400+ let mut mid = crip(ctx, mid.clone()).ok()?.as_bytes()?;
401+ let mid = String::from(str::from_utf8_mut(&mut mid).ok()?);
402+
403+ let mut open = crip(ctx, open.clone()).ok()?.as_bytes()?;
404+ let open = String::from(str::from_utf8_mut(&mut open).ok()?);
405+
406+ let mut close = crip(ctx, close.clone()).ok()?.as_bytes()?;
407+ let close = String::from(str::from_utf8_mut(&mut close).ok()?);
408+
409+ let mut target = String::new();
410+
411+ target.push_str(&*open);
412+
413+ let mut is_first = true;
414+ for tank in tanks.list_iter() {
415+ if !is_first {
416+ target.push_str(&*mid);
417+ }
418+
419+ target.push_str(&*(ram(ctx, tank.clone())?));
420+
421+ is_first = false;
422+ }
423+
424+ target.push_str(&*close);
425+
426+ Some(target)
427+ } else {
428+ None
429+ }
430+ }
431+ }
432+}
433+
434+pub fn ram_ttanks(ctx: &mut InterpreterContext, tanks: TTanks) -> String {
435+ let mut target = String::new();
436+
437+ let mut first = true;
438+ for tank in tanks.iter().collect::<Vec<_>>().iter().cloned().rev() {
439+ if !first {
440+ target.push('\n');
441+ }
442+
443+ target.push_str(&*ram_ttank(ctx, tank.clone()));
444+
445+ first = false;
446+ }
447+
448+ target
449+}
450+
451+pub fn ram_ttank(ctx: &mut InterpreterContext, ttank: TTank) -> String {
452+ let (subj, q) = ttank;
453+
454+ let tank = match tar(ctx, &subj, &q) {
455+ Ok(gate) => match eval_pulled_gate(ctx, gate) {
456+ Ok(tank) => tank,
457+ Err(_) => {
458+ return String::new();
459+ }
460+ },
461+ Err(_) => {
462+ return String::new();
463+ }
464+ };
465+ ram(ctx, tank).unwrap_or(String::new())
466+}
467+
468+pub fn crip(ctx: &mut InterpreterContext, tape: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
469+ RAP(ctx, &cell(&Rc::new(Noun::from_u32(3)), &tape))
470+}
471+
472+fn with_trace<T>(tank: (Rc<Noun>, Rc<Noun>), src: Result<T, TTanks>) -> Result<T, TTanks> {
306473 match src {
307474 Ok(a) => Ok(a),
308475 Err(tanks) => Err(cons(tank, tanks)),
309476 }
310477}
311478
312−pub type Tank = Rc<Noun>;
313−pub type Tanks = PersistentList<(Rc<Noun>, Rc<Noun>)>;
479+/// Not actually a tank, but rather a thunk (subject, formula) which calculates the tank.
480+pub type TTank = (Rc<Noun>, Rc<Noun>);
481+pub type TTanks = PersistentList<TTank>;
314482
315−pub const EMPTY_TANKS: Tanks = Tanks::new();
483+pub const EMPTY_TANKS: TTanks = TTanks::new();
316484
317485pub fn tar<'a>(
318486 ctx: &mut InterpreterContext,
319− subj: Rc<Noun>,
487+ subj: &'a Rc<Noun>,
320488 formula: &'a Noun,
321−) -> Result<Rc<Noun>, Tanks> {
322− let (op, formula) = formula.as_cell().ok_or(Tanks::new())?;
489+) -> Result<Rc<Noun>, TTanks> {
490+ let (op, formula) = formula.as_cell().ok_or(TTanks::new())?;
323491 match op.borrow() {
324492 Noun::Cell { .. } => {
325− let foo = tar(ctx, subj.clone(), &op)?;
493+ let foo = tar(ctx, subj, &op)?;
326494 let bar = tar(ctx, subj, &formula)?;
327495 Ok(cell(&foo, &bar))
328496 }
@@ -333,14 +501,17 @@ pub fn tar<'a>(
333501 1 => Some(op_iter.next().unwrap()),
334502 _ => None,
335503 };
336− let op = op.ok_or(Tanks::new())?;
504+ let op = op.ok_or(TTanks::new())?;
337505 stacker::maybe_grow(32 * 1024, 1024 * 1024, || tar_u32(ctx, subj, op, formula))
338506 }
339507 }
340508}
341509
342−pub fn eval_gate(ctx: &mut InterpreterContext, gate_factory: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
343− let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
510+pub fn eval_gate(
511+ ctx: &mut InterpreterContext,
512+ gate_factory: &Rc<Noun>,
513+) -> Result<Rc<Noun>, TTanks> {
514+ let pulled_gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
344515 eval_pulled_gate(ctx, pulled_gate)
345516}
346517
@@ -348,18 +519,18 @@ pub fn slam(
348519 ctx: &mut InterpreterContext,
349520 gate_factory: &Rc<Noun>,
350521 sample: &Rc<Noun>,
351−) -> Result<Rc<Noun>, Tanks> {
352− let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
522+) -> Result<Rc<Noun>, TTanks> {
523+ let gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
353524
354525 eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
355526}
356527
357528/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
358529/// Also for calling gates from within jets.
359−pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
530+pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
360531 tar(
361532 ctx,
362− gate,
533+ &gate,
363534 &cell(
364535 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
365536 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),
@@ -373,13 +544,13 @@ pub fn slam_pulled_gate(
373544 ctx: &mut InterpreterContext,
374545 gate: &Rc<Noun>,
375546 sample: &Rc<Noun>,
376−) -> Result<Rc<Noun>, Tanks> {
547+) -> Result<Rc<Noun>, TTanks> {
377548 eval_pulled_gate(ctx, replace_sample(gate, sample)?)
378549}
379550
380−pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Result<Rc<Noun>, Tanks> {
381− let (battery, payload) = gate.as_cell().ok_or(Tanks::new())?;
382− let (_sample, context) = payload.as_cell().ok_or(Tanks::new())?;
551+pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
552+ let (battery, payload) = gate.as_cell().ok_or(TTanks::new())?;
553+ let (_sample, context) = payload.as_cell().ok_or(TTanks::new())?;
383554
384555 Ok(cell(battery, &cell(sample, context)))
385556}
nock/src/jets.rs+304−129
@@ -2,14 +2,15 @@ use core::panic;
22use murmur3::murmur3_32;
33use num_integer::Integer;
44use std::{
5+ borrow::Borrow,
56 collections::BTreeMap,
67 iter::{once, repeat_n, zip},
78 rc::Rc,
89};
910
1011use crate::{
11− interpreter::{slam_pulled_gate, InterpreterContext, Tanks},
12− noun::{self, cell, Atom, Edge, Hair, Nail, Noun},
12+ interpreter::{slam_pulled_gate, InterpreterContext, TTanks, EMPTY_TANKS},
13+ noun::{self, cell, AsNoun, Atom, Edge, Hair, Nail, Noun},
1314};
1415
1516fn traverse_iter_result<E: Clone, T: Clone, I: Iterator<Item = Result<T, E>>>(
@@ -107,18 +108,23 @@ pub fn generate_jets() -> Jets {
107108 (124976064672625230427889101290245200507, TRIP),
108109 (4078279288073906183633157465551067635, MUK),
109110 (261900159748071234702685239353558471892, MUG),
111+ (198191257620924788695943358402651905954, AOR),
112+ (299422828284010240628877806738195667652, DOR),
113+ (166326796552601297695313176538120818632, GOR),
114+ (7942398240152905363972500667649380756, MOR),
115+ (315687984998079865981003916817293521765, LOOK),
110116 ])
111117}
112118
113−pub type Jet = fn(ctx: &mut InterpreterContext, &Rc<Noun>) -> Result<Rc<Noun>, Tanks>;
119+pub type Jet = fn(ctx: &mut InterpreterContext, &Rc<Noun>) -> Result<Rc<Noun>, TTanks>;
114120pub type DoubleJet = fn(ctx: &mut InterpreterContext, &Rc<Noun>, &Rc<Noun>) -> Option<Rc<Noun>>;
115121
116−static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Result<Rc<Noun>, Tanks> =
122+static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Result<Rc<Noun>, TTanks> =
117123 |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> Atom| {
118− let (p, q) = n.as_cell().ok_or(Tanks::new())?;
124+ let (p, q) = n.as_cell().ok_or(TTanks::new())?;
119125 Ok(Rc::new(Noun::Atom(f(
120− p.as_atom().ok_or(Tanks::new())?,
121− q.as_atom().ok_or(Tanks::new())?,
126+ p.as_atom().ok_or(TTanks::new())?,
127+ q.as_atom().ok_or(TTanks::new())?,
122128 ))))
123129 };
124130
@@ -126,13 +132,13 @@ static BINARY_ATOM_LOOB: fn(
126132 &InterpreterContext,
127133 &Rc<Noun>,
128134 fn(&Atom, &Atom) -> bool,
129−) -> Result<Rc<Noun>, Tanks> =
135+) -> Result<Rc<Noun>, TTanks> =
130136 |ctx: &InterpreterContext, n: &Rc<Noun>, f: fn(&Atom, &Atom) -> bool| {
131− let (p, q) = n.as_cell().ok_or(Tanks::new())?;
137+ let (p, q) = n.as_cell().ok_or(TTanks::new())?;
132138
133139 if f(
134− p.as_atom().ok_or(Tanks::new())?,
135− q.as_atom().ok_or(Tanks::new())?,
140+ p.as_atom().ok_or(TTanks::new())?,
141+ q.as_atom().ok_or(TTanks::new())?,
136142 ) {
137143 Ok(ctx.nouns.sig.clone())
138144 } else {
@@ -143,18 +149,22 @@ static BINARY_ATOM_LOOB: fn(
143149static BINARY_ATOM_PAIR: fn(
144150 &Rc<Noun>,
145151 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())?;
152+) -> Result<Rc<Noun>, TTanks> = |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> (Atom, Atom)| {
153+ let (p, q) = n.as_cell().ok_or(TTanks::new())?;
148154
149155 let (a, b) = f(
150− p.as_atom().ok_or(Tanks::new())?,
151− q.as_atom().ok_or(Tanks::new())?,
156+ p.as_atom().ok_or(TTanks::new())?,
157+ q.as_atom().ok_or(TTanks::new())?,
152158 );
153159 Ok(cell(&Rc::new(Noun::Atom(a)), &Rc::new(Noun::Atom(b))))
154160};
155161
156162static ADD: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a + b);
157−static DEC: Jet = |_ctx, n| Ok(Rc::new(Noun::Atom(n.as_atom().ok_or(Tanks::new())? - 1u32)));
163+static DEC: Jet = |_ctx, n| {
164+ Ok(Rc::new(Noun::Atom(
165+ n.as_atom().ok_or(TTanks::new())? - 1u32,
166+ )))
167+};
158168static DVR: Jet = |_ctx, n| BINARY_ATOM_PAIR(n, |a, b| a.div_rem(&b));
159169static DIV: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a / b);
160170static GTE: Jet = |ctx, n| BINARY_ATOM_LOOB(ctx, n, |a, b| a >= b);
@@ -168,30 +178,30 @@ static MUL: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a * b);
168178static SUB: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a - b);
169179
170180static CAP: Jet = |ctx, n| {
171− let n = n.as_atom().ok_or(Tanks::new())?;
181+ let n = n.as_atom().ok_or(TTanks::new())?;
172182 CAP_ATOM(ctx, n.clone())
173183};
174184
175−static CAP_ATOM: fn(&InterpreterContext, Atom) -> Result<Rc<Noun>, Tanks> = |ctx, n: Atom| {
185+static CAP_ATOM: fn(&InterpreterContext, Atom) -> Result<Rc<Noun>, TTanks> = |ctx, n: Atom| {
176186 let mut n_iter = n.iter_u32_digits();
177187
178188 match n_iter.len() {
179− 0 => Err(Tanks::new()),
189+ 0 => Err(TTanks::new()),
180190 1 => CAP_U32(ctx, n_iter.next().unwrap()),
181191 _ => CAP_ATOM(ctx, n >> 1),
182192 }
183193};
184−static CAP_U32: fn(ctx: &InterpreterContext, u32) -> Result<Rc<Noun>, Tanks> = |ctx, n| match n {
185− 0 | 1 => Err(Tanks::new()),
194+static CAP_U32: fn(ctx: &InterpreterContext, u32) -> Result<Rc<Noun>, TTanks> = |ctx, n| match n {
195+ 0 | 1 => Err(TTanks::new()),
186196 2 => Ok(ctx.nouns.two.clone()),
187197 3 => Ok(ctx.nouns.three.clone()),
188198 n => CAP_U32(ctx, n >> 1),
189199};
190200
191201static MAS: Jet = |ctx, n| {
192− let n = n.as_atom().ok_or(Tanks::new())?;
202+ let n = n.as_atom().ok_or(TTanks::new())?;
193203 Ok(Rc::new(Noun::Atom(
194− MAS_ATOM(ctx, n.clone()).ok_or(Tanks::new())?,
204+ MAS_ATOM(ctx, n.clone()).ok_or(TTanks::new())?,
195205 )))
196206};
197207static MAS_ATOM: fn(&InterpreterContext, Atom) -> Option<Atom> = |ctx, n| {
@@ -213,22 +223,22 @@ static MAS_U32: fn(u32) -> u32 = |n| match n {
213223};
214224
215225static PEG: Jet = |ctx, n| {
216− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
226+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
217227
218− let a = a.as_atom().ok_or(Tanks::new())?;
219− let b = b.as_atom().ok_or(Tanks::new())?;
228+ let a = a.as_atom().ok_or(TTanks::new())?;
229+ let b = b.as_atom().ok_or(TTanks::new())?;
220230
221231 if *a == Atom::ZERO {
222− return Err(Tanks::new());
232+ return Err(TTanks::new());
223233 };
224234
225235 Ok(Rc::new(Noun::Atom(PEG_ATOM(ctx, a, b.clone())?)))
226236};
227−static PEG_ATOM: fn(&InterpreterContext, &Atom, Atom) -> Result<Atom, Tanks> = |ctx, a, b| {
237+static PEG_ATOM: fn(&InterpreterContext, &Atom, Atom) -> Result<Atom, TTanks> = |ctx, a, b| {
228238 let mut b_iter = b.iter_u32_digits();
229239
230240 match b_iter.len() {
231− 0 => Err(Tanks::new()),
241+ 0 => Err(TTanks::new()),
232242 1 => Ok(PEG_U32(a, b_iter.next().unwrap())),
233243 _ => Ok((&b & &ctx.big_uints.one) + (PEG_ATOM(ctx, a, b >> 1)? << 1)),
234244 }
@@ -242,7 +252,7 @@ static PEG_U32: fn(&Atom, u32) -> Atom = |a, b| match b {
242252};
243253
244254static FAND: Jet = |ctx, n| {
245− let (nedl, hstk) = n.as_cell().ok_or(Tanks::new())?;
255+ let (nedl, hstk) = n.as_cell().ok_or(TTanks::new())?;
246256 if nedl.is_sig() || hstk.is_sig() {
247257 return Ok(ctx.nouns.sig.clone());
248258 }
@@ -272,7 +282,7 @@ static FAND: Jet = |ctx, n| {
272282};
273283
274284static FIND: Jet = |ctx, n| {
275− let (nedl, hstk) = n.as_cell().ok_or(Tanks::new())?;
285+ let (nedl, hstk) = n.as_cell().ok_or(TTanks::new())?;
276286 if nedl.is_sig() || hstk.is_sig() {
277287 return Ok(ctx.nouns.sig.clone());
278288 }
@@ -305,13 +315,13 @@ static FLOP: Jet = |ctx, n| {
305315};
306316
307317static GULF: Jet = |_ctx, n| {
308− let (from, to) = n.as_cell().ok_or(Tanks::new())?;
318+ let (from, to) = n.as_cell().ok_or(TTanks::new())?;
309319
310− let mut from = (*from.as_atom().ok_or(Tanks::new())?).clone();
311− let to = to.as_atom().ok_or(Tanks::new())?.clone();
320+ let mut from = (*from.as_atom().ok_or(TTanks::new())?).clone();
321+ let to = to.as_atom().ok_or(TTanks::new())?.clone();
312322
313323 if from > to {
314− return Err(Tanks::new());
324+ return Err(TTanks::new());
315325 }
316326
317327 let mut tmp = Vec::new();
@@ -325,10 +335,10 @@ static GULF: Jet = |_ctx, n| {
325335};
326336
327337static INTO: Jet = |_ctx, n| {
328− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
329− let (b, c) = b.as_cell().ok_or(Tanks::new())?;
338+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
339+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
330340
331− let mut b_iter = b.as_atom().ok_or(Tanks::new())?.iter_u32_digits();
341+ let mut b_iter = b.as_atom().ok_or(TTanks::new())?.iter_u32_digits();
332342
333343 match b_iter.len() {
334344 0 => Ok(cell(&c, &a)),
@@ -358,7 +368,7 @@ static INTO: Jet = |_ctx, n| {
358368};
359369
360370static JOIN: Jet = |_ctx, n| {
361− let (sep, list) = n.as_cell().ok_or(Tanks::new())?;
371+ let (sep, list) = n.as_cell().ok_or(TTanks::new())?;
362372 Ok(Noun::list_refs(
363373 list.list_iter()
364374 .intersperse(sep)
@@ -376,7 +386,7 @@ static LENT: Jet = |_ctx, n| {
376386};
377387
378388static LEVY: Jet = |ctx, n| {
379− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
389+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
380390 if traverse_iter_result(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
381391 .iter()
382392 .all(|x| x.is_y())
@@ -388,7 +398,7 @@ static LEVY: Jet = |ctx, n| {
388398};
389399
390400static LIEN: Jet = |ctx, n| {
391− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
401+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
392402 if traverse_iter_result(a.list_iter().map(|n| slam_pulled_gate(ctx, b, n)))?
393403 .iter()
394404 .any(|x| x.is_y())
@@ -400,7 +410,7 @@ static LIEN: Jet = |ctx, n| {
400410};
401411
402412static MURN: Jet = |ctx, n| {
403− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
413+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
404414
405415 Ok(Noun::list_refs(
406416 traverse_iter_result(
@@ -413,7 +423,7 @@ static MURN: Jet = |ctx, n| {
413423};
414424
415425static REAP: Jet = |_ctx, n| {
416− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
426+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
417427
418428 Ok(Noun::list_refs(repeat_n(
419429 b.clone(),
@@ -421,17 +431,17 @@ static REAP: Jet = |_ctx, n| {
421431 )))
422432};
423433
424−static REAR: Jet = |_ctx, n| n.list_iter().last().ok_or(Tanks::new()).cloned();
434+static REAR: Jet = |_ctx, n| n.list_iter().last().ok_or(TTanks::new()).cloned();
425435
426436static REEL: Jet = |ctx, n| {
427− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
437+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
428438
429439 list.list_iter().collect::<Vec<_>>().iter().rfold(
430440 Ok(gate
431441 .gate_sample()
432− .ok_or(Tanks::new())?
442+ .ok_or(TTanks::new())?
433443 .as_cell()
434− .ok_or(Tanks::new())?
444+ .ok_or(TTanks::new())?
435445 .1
436446 .clone()),
437447 |acc, next| {
@@ -442,15 +452,15 @@ static REEL: Jet = |ctx, n| {
442452};
443453
444454static ROLL: Jet = |ctx, n| {
445− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
455+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
446456
447457 list.list_iter().fold(
448458 Ok(gate
449459 .clone()
450460 .gate_sample()
451− .ok_or(Tanks::new())?
461+ .ok_or(TTanks::new())?
452462 .as_cell()
453− .ok_or(Tanks::new())?
463+ .ok_or(TTanks::new())?
454464 .1
455465 .clone()),
456466 |acc, next| {
@@ -461,7 +471,7 @@ static ROLL: Jet = |ctx, n| {
461471};
462472
463473static SCAG: Jet = |_ctx, n| {
464− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
474+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
465475
466476 Ok(Noun::list_refs(
467477 b.list_iter()
@@ -474,7 +484,7 @@ static SCAG: Jet = |_ctx, n| {
474484};
475485
476486static SKID: Jet = |ctx, n| {
477− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
487+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
478488
479489 let slammed_n = traverse_iter_result(
480490 list.list_iter()
@@ -489,7 +499,7 @@ static SKID: Jet = |ctx, n| {
489499};
490500
491501static SKIM: Jet = |ctx, n| {
492− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
502+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
493503
494504 Ok(Noun::list_refs(
495505 traverse_iter_result(
@@ -503,7 +513,7 @@ static SKIM: Jet = |ctx, n| {
503513};
504514
505515static SKIP: Jet = |ctx, n| {
506− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
516+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
507517
508518 Ok(Noun::list_refs(
509519 traverse_iter_result(
@@ -517,9 +527,9 @@ static SKIP: Jet = |ctx, n| {
517527};
518528
519529static SLAG: Jet = |ctx, n| {
520− let (a, list) = n.as_cell().ok_or(Tanks::new())?;
530+ let (a, list) = n.as_cell().ok_or(TTanks::new())?;
521531
522− let mut a_iter = a.as_atom().ok_or(Tanks::new())?.iter_u32_digits();
532+ let mut a_iter = a.as_atom().ok_or(TTanks::new())?.iter_u32_digits();
523533
524534 match a_iter.len() {
525535 0 => Ok(list.clone()),
@@ -536,12 +546,12 @@ static SLAG: Jet = |ctx, n| {
536546};
537547
538548static SNAG: Jet = |_ctx, n| {
539− let (a, list) = n.as_cell().ok_or(Tanks::new())?;
549+ let (a, list) = n.as_cell().ok_or(TTanks::new())?;
540550
541551 list.list_iter()
542552 .nth(a.as_u32().unwrap() as usize)
543553 .cloned()
544− .ok_or(Tanks::new())
554+ .ok_or(TTanks::new())
545555};
546556
547557static SNIP: Jet = |_ctx, n| {
@@ -558,7 +568,7 @@ static SNIP: Jet = |_ctx, n| {
558568};
559569
560570static SNOC: Jet = |_ctx, n| {
561− let (list, b) = n.as_cell().ok_or(Tanks::new())?;
571+ let (list, b) = n.as_cell().ok_or(TTanks::new())?;
562572
563573 Ok(Noun::list_refs(
564574 list.list_iter()
@@ -589,15 +599,15 @@ static SNOC: Jet = |_ctx, n| {
589599// };
590600
591601static SPIN: Jet = |ctx, n| {
592− let (list, b) = n.as_cell().ok_or(Tanks::new())?;
593− let (acc, gate) = b.as_cell().ok_or(Tanks::new())?;
602+ let (list, b) = n.as_cell().ok_or(TTanks::new())?;
603+ let (acc, gate) = b.as_cell().ok_or(TTanks::new())?;
594604
595605 let mut res = Vec::new();
596606 let mut acc = acc.clone();
597607
598608 for n in list.list_iter() {
599609 let foo = slam_pulled_gate(ctx, gate, &cell(&n, &acc))?;
600− let (el, new_acc) = foo.as_cell().ok_or(Tanks::new())?;
610+ let (el, new_acc) = foo.as_cell().ok_or(TTanks::new())?;
601611 acc = new_acc.clone();
602612 res.push(el.clone());
603613 }
@@ -606,20 +616,20 @@ static SPIN: Jet = |ctx, n| {
606616};
607617
608618static SPUN: Jet = |ctx, n| {
609− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
619+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
610620
611621 let mut res = Vec::new();
612622 let mut acc = gate
613623 .gate_sample()
614− .ok_or(Tanks::new())?
624+ .ok_or(TTanks::new())?
615625 .as_cell()
616− .ok_or(Tanks::new())?
626+ .ok_or(TTanks::new())?
617627 .1
618628 .clone();
619629
620630 for n in list.list_iter() {
621631 let foo = slam_pulled_gate(ctx, gate, &cell(&n, &acc))?;
622− let (el, new_acc) = foo.as_cell().ok_or(Tanks::new())?;
632+ let (el, new_acc) = foo.as_cell().ok_or(TTanks::new())?;
623633 acc = new_acc.clone();
624634 res.push(el.clone());
625635 }
@@ -628,7 +638,7 @@ static SPUN: Jet = |ctx, n| {
628638};
629639
630640static TURN: Jet = |ctx, n| {
631− let (list, gate) = n.as_cell().ok_or(Tanks::new())?;
641+ let (list, gate) = n.as_cell().ok_or(TTanks::new())?;
632642 Ok(Noun::list_refs(
633643 traverse_iter_result(list.list_iter().map(|x| slam_pulled_gate(ctx, gate, x)))?
634644 .iter()
@@ -637,7 +647,7 @@ static TURN: Jet = |ctx, n| {
637647};
638648
639649static WELD: Jet = |_ctx, n| {
640− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
650+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
641651
642652 Ok(Noun::list_refs(
643653 a.list_iter()
@@ -670,18 +680,20 @@ static BEX: Jet = |ctx, n| {
670680};
671681
672682static END: Jet = |ctx, n| {
673− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
683+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
674684 let bite = a.as_bite();
675685
676686 let bits = bite.bits();
677687
678688 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
679689
680− Ok(Rc::new(Noun::Atom(mask & b.as_atom().ok_or(Tanks::new())?)))
690+ Ok(Rc::new(Noun::Atom(
691+ mask & b.as_atom().ok_or(TTanks::new())?,
692+ )))
681693};
682694
683695static CAN: Jet = |ctx, n| {
684− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
696+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
685697 let bloq = a.as_u32().unwrap();
686698 let bloq_ = 2u32.pow(bloq);
687699
@@ -696,16 +708,16 @@ static CAN: Jet = |ctx, n| {
696708 Some((acc? << bits) | (mask & q.as_atom()?))
697709 },
698710 );
699− Ok(Rc::new(Noun::Atom(atom.ok_or(Tanks::new())?)))
711+ Ok(Rc::new(Noun::Atom(atom.ok_or(TTanks::new())?)))
700712};
701713
702714static CAT: Jet = |_ctx, n| {
703− let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
704− let (b, c) = b.as_cell().ok_or(Tanks::new())?;
715+ let (bloq, b) = n.as_cell().ok_or(TTanks::new())?;
716+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
705717
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())?;
718+ let bloq = bloq.as_u32().ok_or(TTanks::new())?;
719+ let b = b.as_atom().ok_or(TTanks::new())?;
720+ let c = c.as_atom().ok_or(TTanks::new())?;
709721
710722 Ok(Rc::new(Noun::Atom(
711723 (c << (met(bloq, &b) * 2u32.pow(bloq))) | b,
@@ -713,8 +725,8 @@ static CAT: Jet = |_ctx, n| {
713725};
714726
715727static MET: Jet = |_ctx, n| {
716− let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
717− let b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
728+ let (bloq, b) = n.as_cell().ok_or(TTanks::new())?;
729+ let b: Atom = b.as_atom().ok_or(TTanks::new())?.clone();
718730 let bloq = bloq.as_u32().unwrap();
719731
720732 Ok(Rc::new(Noun::from_u32(met(bloq, &b))))
@@ -725,28 +737,28 @@ fn met(bloq: u32, a: &Atom) -> u32 {
725737}
726738
727739static CUT: Jet = |ctx, n| {
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())?;
740+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
741+ let (b, d) = b.as_cell().ok_or(TTanks::new())?;
742+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
731743
732744 let bits = 2u32.pow(a.as_u32().unwrap());
733745
734746 let mask = (&ctx.big_uints.one << (bits * c.as_u32().unwrap())) - &ctx.big_uints.one;
735747
736748 Ok(Rc::new(Noun::Atom(
737− (d.as_atom().ok_or(Tanks::new())? >> (bits * b.as_u32().unwrap())) & mask,
749+ (d.as_atom().ok_or(TTanks::new())? >> (bits * b.as_u32().unwrap())) & mask,
738750 )))
739751};
740752
741753static FIL: Jet = |ctx, n| {
742− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
743− let (b, c) = b.as_cell().ok_or(Tanks::new())?;
754+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
755+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
744756
745757 let bits = 2u32.pow(a.as_u32().unwrap());
746758
747759 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
748760
749− let src = c.as_atom().ok_or(Tanks::new())? & mask;
761+ let src = c.as_atom().ok_or(TTanks::new())? & mask;
750762
751763 let mut target = ctx.big_uints.zero.clone();
752764
@@ -758,30 +770,30 @@ static FIL: Jet = |ctx, n| {
758770};
759771
760772static LSH: Jet = |_ctx, n| {
761− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
773+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
762774 let a = a.as_bite();
763− let b = b.as_atom().ok_or(Tanks::new())?;
775+ let b = b.as_atom().ok_or(TTanks::new())?;
764776
765777 Ok(Rc::new(Noun::Atom(b << a.bits())))
766778};
767779
768780static RSH: Jet = |_ctx, n| {
769− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
781+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
770782 let a = a.as_bite();
771− let b = b.as_atom().ok_or(Tanks::new())?;
783+ let b = b.as_atom().ok_or(TTanks::new())?;
772784
773785 Ok(Rc::new(Noun::Atom(b >> a.bits())))
774786};
775787
776−static RAP: Jet = |ctx, n| {
777− let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
788+pub static RAP: Jet = |ctx, n| {
789+ let (bloq, b) = n.as_cell().ok_or(TTanks::new())?;
778790 let bloq = bloq.as_u32().unwrap();
779791 let bits = 2u32.pow(bloq);
780792
781793 let mut target = ctx.big_uints.zero.clone();
782794
783795 for el in b.list_iter().collect::<Vec<_>>().iter().rev() {
784− let el = el.as_atom().ok_or(Tanks::new())?;
796+ let el = el.as_atom().ok_or(TTanks::new())?;
785797 if el != &ctx.big_uints.zero {
786798 target = (target << (bits * met(bloq, &el))) | el;
787799 }
@@ -791,7 +803,7 @@ static RAP: Jet = |ctx, n| {
791803};
792804
793805static REP: Jet = |ctx, n| {
794− let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
806+ let (bite, b) = n.as_cell().ok_or(TTanks::new())?;
795807 let bite = bite.as_bite();
796808
797809 let bits = bite.bits();
@@ -800,18 +812,18 @@ static REP: Jet = |ctx, n| {
800812 let mut target = ctx.big_uints.zero.clone();
801813
802814 for el in b.list_iter().collect::<Vec<_>>().iter().rev() {
803− target = (target << bits) | (el.as_atom().ok_or(Tanks::new())? & &mask);
815+ target = (target << bits) | (el.as_atom().ok_or(TTanks::new())? & &mask);
804816 }
805817
806818 Ok(Rc::new(Noun::Atom(target)))
807819};
808820
809821static REV: Jet = |ctx, n| {
810− let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
811− let (len, dat) = b.as_cell().ok_or(Tanks::new())?;
822+ let (bloq, b) = n.as_cell().ok_or(TTanks::new())?;
823+ let (len, dat) = b.as_cell().ok_or(TTanks::new())?;
812824 let bloq = bloq.as_u32().unwrap();
813825 let len = len.as_u32().unwrap();
814− let mut dat: Atom = dat.as_atom().ok_or(Tanks::new())?.clone();
826+ let mut dat: Atom = dat.as_atom().ok_or(TTanks::new())?.clone();
815827
816828 let bits = 2u32.pow(bloq);
817829 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -827,9 +839,9 @@ static REV: Jet = |ctx, n| {
827839};
828840
829841static RIP: Jet = |ctx, n| {
830− let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
842+ let (bite, b) = n.as_cell().ok_or(TTanks::new())?;
831843 let bite = bite.as_bite();
832− let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
844+ let mut b: Atom = b.as_atom().ok_or(TTanks::new())?.clone();
833845
834846 let bits = bite.bits();
835847 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -845,11 +857,11 @@ static RIP: Jet = |ctx, n| {
845857};
846858
847859static RUN: Jet = |ctx, n| {
848− let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
849− let (b, gate) = b.as_cell().ok_or(Tanks::new())?;
860+ let (bite, b) = n.as_cell().ok_or(TTanks::new())?;
861+ let (b, gate) = b.as_cell().ok_or(TTanks::new())?;
850862
851863 let bite = bite.as_bite();
852− let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
864+ let mut b: Atom = b.as_atom().ok_or(TTanks::new())?.clone();
853865
854866 let bits = bite.bits();
855867 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -860,7 +872,7 @@ static RUN: Jet = |ctx, n| {
860872 target = (target << bits)
861873 | ((*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?)
862874 .as_atom()
863− .ok_or(Tanks::new())?
875+ .ok_or(TTanks::new())?
864876 & &mask);
865877 b = b >> bits;
866878 }
@@ -869,11 +881,11 @@ static RUN: Jet = |ctx, n| {
869881};
870882
871883static RUT: Jet = |ctx, n| {
872− let (bite, b) = n.as_cell().ok_or(Tanks::new())?;
873− let (b, gate) = b.as_cell().ok_or(Tanks::new())?;
884+ let (bite, b) = n.as_cell().ok_or(TTanks::new())?;
885+ let (b, gate) = b.as_cell().ok_or(TTanks::new())?;
874886
875887 let bite = bite.as_bite();
876− let mut b: Atom = b.as_atom().ok_or(Tanks::new())?.clone();
888+ let mut b: Atom = b.as_atom().ok_or(TTanks::new())?.clone();
877889
878890 let bits = bite.bits();
879891 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
@@ -884,7 +896,7 @@ static RUT: Jet = |ctx, n| {
884896 target.push(
885897 (*slam_pulled_gate(ctx, gate, &Rc::new(Noun::Atom(&mask & &b)))?)
886898 .as_atom()
887− .ok_or(Tanks::new())?
899+ .ok_or(TTanks::new())?
888900 & &mask,
889901 );
890902 b = b >> bits;
@@ -894,12 +906,12 @@ static RUT: Jet = |ctx, n| {
894906};
895907
896908static SEW: Jet = |ctx, n| {
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())?;
909+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
910+ let (b, recipient) = b.as_cell().ok_or(TTanks::new())?;
911+ let (sew_start, c) = b.as_cell().ok_or(TTanks::new())?;
912+ let (number_of_blocks, donor) = c.as_cell().ok_or(TTanks::new())?;
913+ let recipient = recipient.as_atom().ok_or(TTanks::new())?;
914+ let donor = donor.as_atom().ok_or(TTanks::new())?;
903915
904916 let bloq = a.as_u32().unwrap();
905917 let bits = 2u32.pow(bloq);
@@ -915,12 +927,12 @@ static SEW: Jet = |ctx, n| {
915927};
916928
917929static SWP: Jet = |ctx, n| {
918− let (bloq, b) = n.as_cell().ok_or(Tanks::new())?;
930+ let (bloq, b) = n.as_cell().ok_or(TTanks::new())?;
919931 let bloq = bloq.as_u32().unwrap();
920932 let bits = 2u32.pow(bloq);
921933 let mask = (&ctx.big_uints.one << bits) - &ctx.big_uints.one;
922934
923− let mut source = b.as_atom().ok_or(Tanks::new())?.clone();
935+ let mut source = b.as_atom().ok_or(TTanks::new())?.clone();
924936 let mut target = ctx.big_uints.zero.clone();
925937
926938 while source > ctx.big_uints.zero {
@@ -932,7 +944,7 @@ static SWP: Jet = |ctx, n| {
932944};
933945
934946static XEB: Jet = |_ctx, n| {
935− let mut a = n.as_atom().ok_or(Tanks::new())?.clone();
947+ let mut a = n.as_atom().ok_or(TTanks::new())?.clone();
936948
937949 let mut c = 0;
938950
@@ -949,22 +961,22 @@ static DIS: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a & b);
949961static MIX: Jet = |_ctx, n| BINARY_ATOM(n, |a, b| a ^ b);
950962
951963static NOT: Jet = |ctx, n| {
952− let (a, b) = n.as_cell().ok_or(Tanks::new())?;
953− let (b, c) = b.as_cell().ok_or(Tanks::new())?;
964+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
965+ let (b, c) = b.as_cell().ok_or(TTanks::new())?;
954966
955967 let bloq = a.as_u32().unwrap();
956968 let bits = 2u32.pow(bloq);
957969 let mask = (&ctx.big_uints.one << (bits * b.as_u32().unwrap())) - &ctx.big_uints.one;
958970
959− let target = c.as_atom().ok_or(Tanks::new())? ^ &mask;
971+ let target = c.as_atom().ok_or(TTanks::new())? ^ &mask;
960972
961973 Ok(Rc::new(Noun::Atom(target)))
962974};
963975
964976static LAST: Jet = |_ctx, n| {
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())?;
977+ let (a, b) = n.as_cell().ok_or(TTanks::new())?;
978+ let a = a.as_hair().ok_or(TTanks::new())?;
979+ let b = b.as_hair().ok_or(TTanks::new())?;
968980 Ok(Noun::from_hair(last(&a, &b)))
969981};
970982
@@ -985,22 +997,185 @@ fn last<'a>(a: &'a Hair, b: &'a Hair) -> &'a Hair {
985997}
986998
987999static TRIP: Jet = |_ctx, n| {
988− let a = n.as_atom().ok_or(Tanks::new())?;
1000+ let a = n.as_atom().ok_or(TTanks::new())?;
9891001 Ok(Noun::list(
9901002 a.to_bytes_le().iter().map(|b| Noun::from_u32(*b as u32)),
9911003 ))
9921004};
9931005
9941006static MUK: Jet = |_ctx, n| {
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())?;
1007+ let (seed, len) = n.as_cell().ok_or(TTanks::new())?;
1008+ let (len, key) = len.as_cell().ok_or(TTanks::new())?;
1009+ let seed = seed.as_u32().ok_or(TTanks::new())?;
1010+ let len = len.as_u32().ok_or(TTanks::new())?;
1011+ let key = key.as_atom().ok_or(TTanks::new())?;
10001012
10011013 Ok(Rc::new(Noun::from_u32(muk(seed, len, key))))
10021014};
10031015
1016+static AOR: Jet = |ctx, n| {
1017+ let (a, b) = n.as_cell().ok_or(EMPTY_TANKS)?;
1018+
1019+ if a == b {
1020+ Ok(ctx.nouns.y.clone())
1021+ } else {
1022+ match (a.borrow(), b.borrow()) {
1023+ (Noun::Cell { .. }, Noun::Atom(_)) => Ok(ctx.nouns.n.clone()),
1024+ (Noun::Cell { p: a_p, q: a_q, .. }, Noun::Cell { p: b_p, q: b_q, .. }) => {
1025+ if a_p == b_p {
1026+ AOR(ctx, &cell(a_q, b_q))
1027+ } else {
1028+ AOR(ctx, &cell(a_p, b_p))
1029+ }
1030+ }
1031+ (Noun::Atom(_), Noun::Cell { .. }) => Ok(ctx.nouns.y.clone()),
1032+ (Noun::Atom(a), Noun::Atom(b)) => {
1033+ let a = a.to_bytes_le();
1034+ let b = b.to_bytes_le();
1035+
1036+ let mut i = 0;
1037+ loop {
1038+ let c = a.get(i).unwrap_or(&0);
1039+ let d = b.get(i).unwrap_or(&0);
1040+
1041+ if a[0] == b[0] {
1042+ i += 1;
1043+ } else {
1044+ if c < d {
1045+ return Ok(ctx.nouns.y.clone());
1046+ } else {
1047+ return Ok(ctx.nouns.n.clone());
1048+ }
1049+ }
1050+ }
1051+ }
1052+ }
1053+ }
1054+};
1055+
1056+static DOR: Jet = |ctx, n| {
1057+ let (a, b) = n.as_cell().ok_or(EMPTY_TANKS)?;
1058+
1059+ if a == b {
1060+ Ok(ctx.nouns.y.clone())
1061+ } else {
1062+ match (a.borrow(), b.borrow()) {
1063+ (Noun::Cell { .. }, Noun::Atom(_)) => Ok(ctx.nouns.n.clone()),
1064+ (Noun::Cell { p: a_p, q: a_q, .. }, Noun::Cell { p: b_p, q: b_q, .. }) => {
1065+ if a_p == b_p {
1066+ DOR(ctx, &cell(a_q, b_q))
1067+ } else {
1068+ DOR(ctx, &cell(a_p, b_p))
1069+ }
1070+ }
1071+ (Noun::Atom(_), Noun::Cell { .. }) => Ok(ctx.nouns.y.clone()),
1072+ (Noun::Atom(a), Noun::Atom(b)) => {
1073+ if a < b {
1074+ Ok(ctx.nouns.y.clone())
1075+ } else {
1076+ Ok(ctx.nouns.n.clone())
1077+ }
1078+ }
1079+ }
1080+ }
1081+};
1082+
1083+static GOR: Jet = |ctx, n| {
1084+ let (a, b) = n.as_cell().ok_or(EMPTY_TANKS)?;
1085+ let c = a.mug();
1086+ let d = b.mug();
1087+
1088+ if c == d {
1089+ DOR(ctx, n)
1090+ } else {
1091+ if c < d {
1092+ Ok(ctx.nouns.y.clone())
1093+ } else {
1094+ Ok(ctx.nouns.n.clone())
1095+ }
1096+ }
1097+};
1098+
1099+static GOR_PAIR: fn(&mut InterpreterContext, &Rc<Noun>, &Rc<Noun>) -> Result<bool, TTanks> =
1100+ |ctx, a, b| {
1101+ let c = a.mug();
1102+ let d = b.mug();
1103+
1104+ if c == d {
1105+ Ok(DOR(ctx, &(a.clone(), b.clone()).as_noun())? == ctx.nouns.y)
1106+ } else {
1107+ Ok(c < d)
1108+ }
1109+ };
1110+
1111+static MOR: Jet = |ctx, n| {
1112+ let (a, b) = n.as_cell().ok_or(EMPTY_TANKS)?;
1113+ let c = Noun::from_u32(a.mug()).mug();
1114+ let d = Noun::from_u32(b.mug()).mug();
1115+
1116+ if c == d {
1117+ DOR(ctx, n)
1118+ } else {
1119+ if c < d {
1120+ Ok(ctx.nouns.y.clone())
1121+ } else {
1122+ Ok(ctx.nouns.n.clone())
1123+ }
1124+ }
1125+};
1126+
1127+static LOOK: Jet = |ctx, n| {
1128+ let (cog, dab) = n.as_cell().ok_or(EMPTY_TANKS)?;
1129+ LOOK_PAIR(ctx, Atom::new(vec![1]), cog, dab)
1130+};
1131+
1132+static LOOK_PAIR: fn(
1133+ &mut InterpreterContext,
1134+ Atom,
1135+ &Rc<Noun>,
1136+ &Rc<Noun>,
1137+) -> Result<Rc<Noun>, TTanks> = |ctx, axe, cog, dab| {
1138+ if dab.is_sig() {
1139+ Ok(ctx.nouns.sig.clone())
1140+ } else {
1141+ let (node, b, c) = dab.tuple_3().ok_or(EMPTY_TANKS)?;
1142+ let l = b;
1143+ let r = c;
1144+ let (p, q) = node.as_cell().ok_or(EMPTY_TANKS)?;
1145+ if b.is_sig() && c.is_sig() {
1146+ if cog == p {
1147+ Ok((ctx.nouns.sig.clone(), Noun::Atom(axe), q.clone()).as_noun())
1148+ } else {
1149+ Ok(ctx.nouns.sig.clone())
1150+ }
1151+ } else if b.is_sig() {
1152+ if cog == p {
1153+ Ok((ctx.nouns.sig.clone(), PEG_U32(&axe, 2), q.clone()).as_noun())
1154+ } else if GOR_PAIR(ctx, cog, p)? {
1155+ Ok(ctx.nouns.sig.clone())
1156+ } else {
1157+ LOOK_PAIR(ctx, PEG_U32(&axe, 3), cog, r)
1158+ }
1159+ } else if c.is_sig() {
1160+ if cog == p {
1161+ Ok((ctx.nouns.sig.clone(), PEG_U32(&axe, 2), q.clone()).as_noun())
1162+ } else if GOR_PAIR(ctx, cog, p)? {
1163+ LOOK_PAIR(ctx, PEG_U32(&axe, 3), cog, l)
1164+ } else {
1165+ Ok(ctx.nouns.sig.clone())
1166+ }
1167+ } else {
1168+ if cog == p {
1169+ Ok((ctx.nouns.sig.clone(), PEG_U32(&axe, 2), q.clone()).as_noun())
1170+ } else if GOR_PAIR(ctx, cog, p)? {
1171+ LOOK_PAIR(ctx, PEG_U32(&axe, 6), cog, l)
1172+ } else {
1173+ LOOK_PAIR(ctx, PEG_U32(&axe, 7), cog, r)
1174+ }
1175+ }
1176+ }
1177+};
1178+
10041179static JUST: DoubleJet = |ctx, n, m| {
10051180 let char = n.as_atom()?;
10061181 let nail = m.as_nail()?;
nock/src/lib.rs+2−37
@@ -1,11 +1,9 @@
11#![feature(iter_intersperse)]
22#![feature(let_chains)]
33
4−use core::str;
5−use std::{borrow::Borrow, rc::Rc};
4+use std::rc::Rc;
65
7−use interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
8−use noun::{cell, Noun};
6+use noun::Noun;
97pub mod cue;
108pub mod interpreter;
119pub mod jam;
@@ -13,36 +11,3 @@ mod jets;
1311pub mod noun;
1412
1513pub type Vase = (Rc<Noun>, Rc<Noun>);
16−
17−pub fn wash(ctx: &mut InterpreterContext, urbit: &Rc<Noun>, tanks: Tanks) -> String {
18− let mut target = String::new();
19− for (subj, q) in tanks.iter() {
20− match tar(ctx, subj.clone(), q).unwrap().borrow() {
21− Noun::Atom(a) => {
22− target.push_str(str::from_utf8_mut(&mut *a.to_bytes_le()).unwrap());
23− }
24− gate @ Noun::Cell { .. } => {
25− let tank = eval_pulled_gate(ctx, Rc::new(gate.clone())).unwrap();
26− let mut str = slam_pulled_gate(
27− ctx,
28− &urbit,
29− &cell(
30− &Rc::new(Noun::from_bytes(b"wash")),
31− &cell(
32− &cell(&Rc::new(Noun::from_u32(0)), &Rc::new(Noun::from_u32(80))),
33− &tank,
34− ),
35− ),
36− )
37− .unwrap()
38− .as_atom()
39− .unwrap()
40− .to_bytes_le();
41−
42− target.push_str(str::from_utf8_mut(&mut *str).unwrap())
43− }
44− }
45− }
46−
47− target
48−}
nock/src/main.rs+44−18
@@ -1,7 +1,8 @@
11use clap::{command, error::Result, Parser, Subcommand};
22use core::str;
3−use nock::interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
4−use nock::wash;
3+use nock::interpreter::{
4+ ram_ttanks, slam_pulled_gate, tar, InterpreterContext, TTanks, JET_COUNTER,
5+};
56use nock::{
67 cue::cue_bytes,
78 interpreter::{generate_interpreter_context, slam},
@@ -9,7 +10,6 @@ use nock::{
910 noun::{cell, Atom, Noun},
1011};
1112use spinoff::Spinner;
12−use std::borrow::Borrow;
1313use std::cell::LazyCell;
1414use std::{
1515 fs::File,
@@ -67,9 +67,38 @@ enum RunCommand {
6767 },
6868}
6969
70+fn print_jet_counter() {
71+ let counter = JET_COUNTER.lock().unwrap();
72+ let mut builder = tabled::builder::Builder::new();
73+ builder.push_record(vec!["jet", "number of calls"]);
74+ let mut counters = counter.iter().collect::<Vec<_>>();
75+ counters.sort_unstable_by_key(|x| x.1);
76+ for (key, count) in counters {
77+ let key = String::from_utf8(key.to_bytes_le()).unwrap();
78+ builder.push_record(vec![key, count.to_string()]);
79+ }
80+ println!(
81+ "\n{}",
82+ builder
83+ .build()
84+ .with(tabled::settings::style::Style::rounded())
85+ );
86+}
87+
7088fn main() -> Result<(), std::io::Error> {
89+ if cfg!(feature = "count-jets") {
90+ ctrlc::set_handler(|| {
91+ print_jet_counter();
92+ exit(1);
93+ })
94+ .unwrap();
95+ }
96+
7197 let urbit = LazyCell::new(GENERATE_URBIT);
72− let mut ctx = generate_interpreter_context();
98+ let mut ctx = InterpreterContext {
99+ // slog: |_| {},
100+ ..generate_interpreter_context()
101+ };
73102
74103 let cli = Cli::parse();
75104
@@ -91,7 +120,7 @@ fn main() -> Result<(), std::io::Error> {
91120 spinner.fail("Gate execution failed");
92121
93122 let mut spinner = new_spinner(String::from("Building trace"));
94− let trace = wash(&mut ctx, &urbit, tanks);
123+ let trace = ram_ttanks(&mut ctx, tanks);
95124 spinner.success("Trace built");
96125 println!("{trace}");
97126 exit(1);
@@ -138,12 +167,16 @@ fn main() -> Result<(), std::io::Error> {
138167 let (_typ, nok) = read_nock_or_compile(&mut spinner, &mut ctx, &urbit, &nock)?;
139168
140169 let sig = ctx.nouns.sig.clone();
141− let result = tar(&mut ctx, sig, &nok).unwrap();
170+ let result = tar(&mut ctx, &sig, &nok).unwrap();
142171
143172 println!("{result}");
144173 }
145174 }
146175
176+ if cfg!(feature = "count-jets") {
177+ print_jet_counter()
178+ }
179+
147180 Ok(())
148181}
149182
@@ -182,13 +215,7 @@ fn compile_to_nock(
182215 &urbit,
183216 &cell(&Rc::new(Noun::from_bytes(b"hoon")), &ctx.nouns.sig),
184217 );
185− let hoon = or_wash_fail(
186− ctx,
187− urbit,
188− hoon,
189− spinner,
190− "Failed to read Hoon standard library",
191− );
218+ let hoon = or_wash_fail(ctx, hoon, spinner, "Failed to read Hoon standard library");
192219 let (hoon_type, hoon) = hoon.as_cell().unwrap();
193220
194221 spinner.update_text(format!("Compiling {root:#?}"));
@@ -206,7 +233,7 @@ fn compile_to_nock(
206233 ),
207234 ),
208235 );
209− let target = or_wash_fail(ctx, urbit, target, spinner, "Compilation failed");
236+ let target = or_wash_fail(ctx, target, spinner, "Compilation failed");
210237
211238 let (target_type, target_nock) = target.as_cell().unwrap();
212239
@@ -222,7 +249,7 @@ fn compile_to_nock(
222249 );
223250 let combined_nock = cell(
224251 target_type,
225− &or_wash_fail(ctx, urbit, combined_nock, spinner, "Failed to combine Nock"),
252+ &or_wash_fail(ctx, combined_nock, spinner, "Failed to combine Nock"),
226253 );
227254 Ok(combined_nock)
228255}
@@ -244,8 +271,7 @@ fn read_nock_or_compile(
244271
245272fn or_wash_fail(
246273 ctx: &mut InterpreterContext,
247− urbit: &Rc<Noun>,
248− source: Result<Rc<Noun>, Tanks>,
274+ source: Result<Rc<Noun>, TTanks>,
249275 spinner: &mut Spinner,
250276 fail_err: &str,
251277) -> Rc<Noun> {
@@ -253,7 +279,7 @@ fn or_wash_fail(
253279 Ok(source) => source,
254280 Err(tanks) => {
255281 spinner.fail(fail_err);
256− let washed_tanks = wash(ctx, urbit, tanks);
282+ let washed_tanks = ram_ttanks(ctx, tanks);
257283 eprintln!("{}", washed_tanks);
258284 exit(1)
259285 }
nock/src/noun.rs+313
@@ -47,6 +47,10 @@ impl PartialEq for Noun {
4747impl<'a> Noun {
4848 pub const SIG: Noun = Noun::Atom(BigUint::ZERO);
4949
50+ pub fn rc(self: Self) -> Rc<Self> {
51+ Rc::new(self)
52+ }
53+
5054 pub fn from_u32(a: u32) -> Noun {
5155 Noun::Atom(Atom::new(vec![a]))
5256 }
@@ -100,6 +104,59 @@ impl<'a> Noun {
100104 }
101105 }
102106
107+ pub fn as_cell_cloned(self: &'a Self) -> Option<(Rc<Noun>, Rc<Noun>)> {
108+ match self {
109+ Noun::Cell { p, q, .. } => Option::Some((p.clone(), q.clone())),
110+ _ => Option::None,
111+ }
112+ }
113+
114+ pub fn tuple_2(self: &Self) -> Option<(&Rc<Noun>, &Rc<Noun>)> {
115+ self.as_cell()
116+ }
117+
118+ pub fn tuple_3(self: &Self) -> Option<(&Rc<Noun>, &Rc<Noun>, &Rc<Noun>)> {
119+ let (a, b) = self.as_cell()?;
120+ let (b, c) = b.as_cell()?;
121+
122+ Some((a, b, c))
123+ }
124+ pub fn tuple_4(self: &Self) -> Option<(&Rc<Noun>, &Rc<Noun>, &Rc<Noun>, &Rc<Noun>)> {
125+ let (a, b) = self.as_cell()?;
126+ let (b, c) = b.as_cell()?;
127+ let (c, d) = c.as_cell()?;
128+
129+ Some((a, b, c, d))
130+ }
131+
132+ pub fn tuple_5(self: &Self) -> Option<(&Rc<Noun>, &Rc<Noun>, &Rc<Noun>, &Rc<Noun>, &Rc<Noun>)> {
133+ let (a, b) = self.as_cell()?;
134+ let (b, c) = b.as_cell()?;
135+ let (c, d) = c.as_cell()?;
136+ let (d, e) = d.as_cell()?;
137+
138+ Some((a, b, c, d, e))
139+ }
140+
141+ pub fn tuple_6(
142+ self: &Self,
143+ ) -> Option<(
144+ &Rc<Noun>,
145+ &Rc<Noun>,
146+ &Rc<Noun>,
147+ &Rc<Noun>,
148+ &Rc<Noun>,
149+ &Rc<Noun>,
150+ )> {
151+ let (a, b) = self.as_cell()?;
152+ let (b, c) = b.as_cell()?;
153+ let (c, d) = c.as_cell()?;
154+ let (d, e) = d.as_cell()?;
155+ let (e, f) = e.as_cell()?;
156+
157+ Some((a, b, c, d, e, f))
158+ }
159+
103160 pub fn is_sig(self: &Self) -> bool {
104161 match self {
105162 Noun::Atom(n) if *n == Atom::ZERO => true,
@@ -244,6 +301,262 @@ impl<'a> Noun {
244301 }
245302}
246303
304+pub trait AsNoun {
305+ fn as_noun(self: &Self) -> Rc<Noun>;
306+}
307+
308+impl AsNoun for Atom {
309+ fn as_noun(self: &Self) -> Rc<Noun> {
310+ Rc::new(Noun::Atom(self.clone()))
311+ }
312+}
313+
314+impl AsNoun for Noun {
315+ fn as_noun(self: &Self) -> Rc<Noun> {
316+ Rc::new(self.clone())
317+ }
318+}
319+
320+impl AsNoun for Rc<Noun> {
321+ fn as_noun(self: &Self) -> Rc<Noun> {
322+ self.clone()
323+ }
324+}
325+
326+impl<A, B> AsNoun for (A, B)
327+where
328+ A: AsNoun,
329+ B: AsNoun,
330+{
331+ fn as_noun(self: &Self) -> Rc<Noun> {
332+ let (a, b) = self;
333+
334+ cell(&a.as_noun(), &b.as_noun())
335+ }
336+}
337+
338+impl<A, B, C> AsNoun for (A, B, C)
339+where
340+ A: AsNoun,
341+ B: AsNoun,
342+ C: AsNoun,
343+{
344+ fn as_noun(self: &Self) -> Rc<Noun> {
345+ let (a, b, c) = self;
346+
347+ cell(&a.as_noun(), &cell(&b.as_noun(), &c.as_noun()))
348+ }
349+}
350+
351+impl<A, B, C, D> AsNoun for (A, B, C, D)
352+where
353+ A: AsNoun,
354+ B: AsNoun,
355+ C: AsNoun,
356+ D: AsNoun,
357+{
358+ fn as_noun(self: &Self) -> Rc<Noun> {
359+ let (a, b, c, d) = self;
360+
361+ cell(
362+ &a.as_noun(),
363+ &cell(&b.as_noun(), &cell(&c.as_noun(), &d.as_noun())),
364+ )
365+ }
366+}
367+
368+impl<A, B, C, D, E> AsNoun for (A, B, C, D, E)
369+where
370+ A: AsNoun,
371+ B: AsNoun,
372+ C: AsNoun,
373+ D: AsNoun,
374+ E: AsNoun,
375+{
376+ fn as_noun(self: &Self) -> Rc<Noun> {
377+ let (a, b, c, d, e) = self;
378+
379+ cell(
380+ &a.as_noun(),
381+ &cell(
382+ &b.as_noun(),
383+ &cell(&c.as_noun(), &cell(&d.as_noun(), &e.as_noun())),
384+ ),
385+ )
386+ }
387+}
388+
389+impl<A, B, C, D, E, F> AsNoun for (A, B, C, D, E, F)
390+where
391+ A: AsNoun,
392+ B: AsNoun,
393+ C: AsNoun,
394+ D: AsNoun,
395+ E: AsNoun,
396+ F: AsNoun,
397+{
398+ fn as_noun(self: &Self) -> Rc<Noun> {
399+ let (a, b, c, d, e, f) = self;
400+
401+ cell(
402+ &a.as_noun(),
403+ &cell(
404+ &b.as_noun(),
405+ &cell(
406+ &c.as_noun(),
407+ &cell(&d.as_noun(), &cell(&e.as_noun(), &f.as_noun())),
408+ ),
409+ ),
410+ )
411+ }
412+}
413+
414+impl From<(Rc<Noun>, Rc<Noun>)> for Noun {
415+ fn from(value: (Rc<Noun>, Rc<Noun>)) -> Self {
416+ naked_cell(&value.0, &value.1)
417+ }
418+}
419+
420+impl From<(Rc<Noun>, Rc<Noun>, Rc<Noun>)> for Noun {
421+ fn from(value: (Rc<Noun>, Rc<Noun>, Rc<Noun>)) -> Self {
422+ naked_cell(&value.0, &cell(&value.1, &value.2))
423+ }
424+}
425+
426+impl From<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> for Noun {
427+ fn from(value: (Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)) -> Self {
428+ naked_cell(&value.0, &cell(&value.1, &cell(&value.2, &value.3)))
429+ }
430+}
431+
432+impl From<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> for Noun {
433+ fn from(value: (Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)) -> Self {
434+ naked_cell(
435+ &value.0,
436+ &cell(&value.1, &cell(&value.2, &cell(&value.3, &value.4))),
437+ )
438+ }
439+}
440+
441+impl From<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> for Noun {
442+ fn from(value: (Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)) -> Self {
443+ naked_cell(
444+ &value.0,
445+ &cell(
446+ &value.1,
447+ &cell(&value.2, &cell(&value.3, &cell(&value.4, &value.5))),
448+ ),
449+ )
450+ }
451+}
452+
453+impl
454+ From<(
455+ Rc<Noun>,
456+ Rc<Noun>,
457+ Rc<Noun>,
458+ Rc<Noun>,
459+ Rc<Noun>,
460+ Rc<Noun>,
461+ Rc<Noun>,
462+ )> for Noun
463+{
464+ fn from(
465+ value: (
466+ Rc<Noun>,
467+ Rc<Noun>,
468+ Rc<Noun>,
469+ Rc<Noun>,
470+ Rc<Noun>,
471+ Rc<Noun>,
472+ Rc<Noun>,
473+ ),
474+ ) -> Self {
475+ naked_cell(
476+ &value.0,
477+ &cell(
478+ &value.1,
479+ &cell(
480+ &value.2,
481+ &cell(&value.3, &cell(&value.4, &cell(&value.5, &value.6))),
482+ ),
483+ ),
484+ )
485+ }
486+}
487+
488+impl From<Noun> for Option<(Rc<Noun>, Rc<Noun>)> {
489+ fn from(value: Noun) -> Self {
490+ value.as_cell_cloned()
491+ }
492+}
493+
494+impl From<Noun> for Option<(Rc<Noun>, Rc<Noun>, Rc<Noun>)> {
495+ fn from(value: Noun) -> Self {
496+ let (a, b) = value.as_cell_cloned()?;
497+ let (b, c) = b.as_cell_cloned()?;
498+ Some((a, b, c))
499+ }
500+}
501+
502+impl From<Noun> for Option<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> {
503+ fn from(value: Noun) -> Self {
504+ let (a, b) = value.as_cell_cloned()?;
505+ let (b, c) = b.as_cell_cloned()?;
506+ let (c, d) = c.as_cell_cloned()?;
507+ Some((a, b, c, d))
508+ }
509+}
510+
511+impl From<Noun> for Option<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> {
512+ fn from(value: Noun) -> Self {
513+ let (a, b) = value.as_cell_cloned()?;
514+ let (b, c) = b.as_cell_cloned()?;
515+ let (c, d) = c.as_cell_cloned()?;
516+ let (d, e) = d.as_cell_cloned()?;
517+ Some((a, b, c, d, e))
518+ }
519+}
520+
521+impl From<Noun> for Option<(Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>, Rc<Noun>)> {
522+ fn from(value: Noun) -> Self {
523+ let (a, b) = value.as_cell_cloned()?;
524+ let (b, c) = b.as_cell_cloned()?;
525+ let (c, d) = c.as_cell_cloned()?;
526+ let (d, e) = d.as_cell_cloned()?;
527+ let (e, f) = e.as_cell_cloned()?;
528+ Some((a, b, c, d, e, f))
529+ }
530+}
531+
532+impl From<Noun>
533+ for Option<(
534+ Rc<Noun>,
535+ Rc<Noun>,
536+ Rc<Noun>,
537+ Rc<Noun>,
538+ Rc<Noun>,
539+ Rc<Noun>,
540+ Rc<Noun>,
541+ )>
542+{
543+ fn from(value: Noun) -> Self {
544+ let (a, b) = value.as_cell_cloned()?;
545+ let (b, c) = b.as_cell_cloned()?;
546+ let (c, d) = c.as_cell_cloned()?;
547+ let (d, e) = d.as_cell_cloned()?;
548+ let (e, f) = e.as_cell_cloned()?;
549+ let (f, g) = f.as_cell_cloned()?;
550+ Some((a, b, c, d, e, f, g))
551+ }
552+}
553+
554+impl From<&[u8]> for Noun {
555+ fn from(value: &[u8]) -> Self {
556+ Noun::from_bytes(value)
557+ }
558+}
559+
247560#[derive(Clone)]
248561pub struct Edge<'a> {
249562 pub hair: Hair,
nock/test.hoonnew file+3
@@ -0,0 +1,3 @@
1+|= *
2+=/ target (gor 'd' 'c')
3+(crip "{<target>}")
nock/wock.hoon+198−10
@@ -1,16 +1,204 @@
11=>
22|%
3+++ http ^?
4+ |%
5+ :: +header-list: an ordered list of http headers
6+ ::
7+ +$ header-list
8+ (list [key=@t value=@t])
9+ :: +method: exhaustive list of http verbs
10+ ::
11+ +$ method
12+ $? %'CONNECT'
13+ %'DELETE'
14+ %'GET'
15+ %'HEAD'
16+ %'OPTIONS'
17+ %'PATCH'
18+ %'POST'
19+ %'PUT'
20+ %'TRACE'
21+ ==
22+ :: +request: a single http request
23+ ::
24+ +$ request
25+ $: :: method: http method
26+ ::
27+ method=method
28+ :: url: the url requested
29+ ::
30+ :: The url is not escaped. There is no escape.
31+ ::
32+ url=@t
33+ :: header-list: headers to pass with this request
34+ ::
35+ =header-list
36+ :: body: optionally, data to send with this request
37+ ::
38+ body=(unit octs)
39+ ==
40+ :: +response-header: the status code and header list on an http request
41+ ::
42+ :: We separate these away from the body data because we may not wait for
43+ :: the entire body before we send a %progress to the caller.
44+ ::
45+ +$ response-header
46+ $: :: status: http status code
47+ ::
48+ status-code=@ud
49+ :: headers: http headers
50+ ::
51+ headers=header-list
52+ ==
53+ :: +http-event: packetized http
54+ ::
55+ :: Urbit treats Earth's HTTP servers as pipes, where Urbit sends or
56+ :: receives one or more %http-events. The first of these will always be a
57+ :: %start or an %error, and the last will always be %cancel or will have
58+ :: :complete set to %.y to finish the connection.
59+ ::
60+ :: Calculation of control headers such as 'Content-Length' or
61+ :: 'Transfer-Encoding' should be performed at a higher level; this structure
62+ :: is merely for what gets sent to or received from Earth.
63+ ::
64+ +$ http-event
65+ $% :: %start: the first packet in a response
66+ ::
67+ $: %start
68+ :: response-header: first event information
69+ ::
70+ =response-header
71+ :: data: data to pass to the pipe
72+ ::
73+ data=(unit octs)
74+ :: whether this completes the request
75+ ::
76+ complete=?
77+ ==
78+ :: %continue: every subsequent packet
79+ ::
80+ $: %continue
81+ :: data: data to pass to the pipe
82+ ::
83+ data=(unit octs)
84+ :: complete: whether this completes the request
85+ ::
86+ complete=?
87+ ==
88+ :: %cancel: represents unsuccessful termination
89+ ::
90+ [%cancel ~]
91+ ==
92+ :: +get-header: returns the value for :header, if it exists in :header-list
93+ ::
94+ ++ get-header
95+ |= [header=@t =header-list]
96+ ^- (unit @t)
97+ ::
98+ ?~ header-list
99+ ~
100+ ::
101+ ?: =(key.i.header-list header)
102+ `value.i.header-list
103+ ::
104+ $(header-list t.header-list)
105+ :: +set-header: sets the value of an item in the header list
106+ ::
107+ :: This adds to the end if it doesn't exist.
108+ ::
109+ ++ set-header
110+ |= [header=@t value=@t =header-list]
111+ ^- ^header-list
112+ ::
113+ ?~ header-list
114+ :: we didn't encounter the value, add it to the end
115+ ::
116+ [[header value] ~]
117+ ::
118+ ?: =(key.i.header-list header)
119+ [[header value] t.header-list]
120+ ::
121+ [i.header-list $(header-list t.header-list)]
122+ :: +delete-header: removes the first instance of a header from the list
123+ ::
124+ ++ delete-header
125+ |= [header=@t =header-list]
126+ ^- ^header-list
127+ ::
128+ ?~ header-list
129+ ~
130+ :: if we see it in the list, remove it
131+ ::
132+ ?: =(key.i.header-list header)
133+ t.header-list
134+ ::
135+ [i.header-list $(header-list t.header-list)]
136+ :: +unpack-header: parse header field values
137+ ::
138+ ++ unpack-header
139+ |^ |= value=@t
140+ ^- (unit (list (map @t @t)))
141+ (rust (cass (trip value)) values)
142+ ::
143+ ++ values
144+ %+ more
145+ (ifix [. .]:(star ;~(pose ace (just '\09'))) com)
146+ pairs
147+ ::
148+ ++ pairs
149+ %+ cook
150+ ~(gas by *(map @t @t))
151+ %+ most (ifix [. .]:(star ace) mic)
152+ ;~(plug token ;~(pose ;~(pfix tis value) (easy '')))
153+ ::
154+ ++ value
155+ ;~(pose token quoted-string)
156+ ::
157+ ++ token :: 7230 token
158+ %+ cook crip
159+ ::NOTE this is ptok:de-purl:html, but can't access that here
160+ %- plus
161+ ;~ pose
162+ aln zap hax buc cen pam soq tar lus
163+ hep dot ket cab tic bar sig
164+ ==
165+ ::
166+ ++ quoted-string :: 7230 quoted string
167+ %+ cook crip
168+ %+ ifix [. .]:;~(less (jest '\\"') doq)
169+ %- star
170+ ;~ pose
171+ ;~(pfix bas ;~(pose (just '\09') ace prn))
172+ ;~(pose (just '\09') ;~(less (mask "\22\5c\7f") (shim 0x20 0xff)))
173+ ==
174+ --
175+ :: +simple-payload: a simple, one event response used for generators
176+ ::
177+ +$ simple-payload
178+ $: :: response-header: status code, etc
179+ ::
180+ =response-header
181+ :: data: the data returned as the body
182+ ::
183+ data=(unit octs)
184+ ==
185+ --
186+++ hop
187+ |$ step
188+ $%
189+ [%fetch request:http]
190+ ==
3191++ wock-app
4− |$ [model event]
192+ |$ [model step]
5193 $_ ^?
6194 |%
7195 ++ init *model
8196 ++ view |~ model *manx
9− ++ move |~ [model event] *model
197+ ++ move |~ [model step] *model
10198 --
11199++ app
12− |* [model=mold event=mold]
13− |= app=(wock-app model event)
200+ |* [model=mold step=mold]
201+ |= app=(wock-app model step)
14202 |= [cmd=@tas args=*]
15203 ?+ cmd !!
16204 %init
@@ -18,19 +206,19 @@
18206 %view
19207 (view.app (model args))
20208 %move
21− =/ [=model event-tape=tape payload=*] (,[model tape *] args)
22− (move.app [model (event [(crip event-tape) payload])])
209+ =/ [=model step-tape=tape payload=*] (,[model tape *] args)
210+ (move.app [model (step [(crip step-tape) payload])])
23211 ==
24212--
25213=>
26214|%
27−+$ event
215++$ step
28216 $%
29217 [%inc ~]
30218 [%dec ~]
31219 ==
32220--
33−%- (app @ud event)
221+%- (app @ud step)
34222|%
35223++ view
36224 |= count=@ud
@@ -40,9 +228,9 @@
40228 ;button(on-click "inc"): +
41229 ;button(on-click "dec"): -
42230 ==
43−++ init 8
231+++ init 11
44232++ move
45− |= [model=@ud step=event]
233+ |= [model=@ud step=step]
46234 ^- @ud
47235 ?- -.step
48236 %inc +(model)
wock-web/src/lib.rs+31−74
@@ -8,15 +8,17 @@ use dodrio::{
88 bumpalo::{self, Bump},
99 Attribute, Listener, Node, NodeKey, Render, RenderContext, RootRender, VdomWeak,
1010};
11+use gloo::net::{self, http::Request};
1112use nock::{
1213 cue::cue_bytes,
13− interpreter::{generate_interpreter_context, slam, InterpreterContext},
14+ interpreter::{generate_interpreter_context, ram_ttanks, slam, InterpreterContext},
1415 noun::{cell, Noun},
15− wash,
1616};
1717use wasm_bindgen::prelude::*;
18−use wasm_bindgen_futures::{spawn_local, JsFuture};
19−use web_sys::{console::error_1, Element};
18+use web_sys::{
19+ console::{error_1, log_1},
20+ Element,
21+};
2022
2123#[wasm_bindgen]
2224extern "C" {
@@ -29,41 +31,11 @@ extern "C" {
2931 fn error(s: &str);
3032}
3133
32−#[derive(Clone)]
33−struct Urbit {
34− urbit: RefCell<Option<Rc<Noun>>>,
35−}
36−
37−impl Urbit {
38− fn new() -> Urbit {
39− Urbit {
40− urbit: RefCell::new(None),
41− }
42− }
43−
44− async fn get(self: &Self) -> Rc<Noun> {
45− match self.urbit.borrow().clone() {
46− Some(urbit) => urbit,
47− None => {
48− let urbit = load_nock("/urbit.nock").await.unwrap_or_else(|err| {
49− error_1(&err);
50− panic!("Could not load urbit.")
51− });
52−
53− self.urbit.replace(Some(urbit.clone()));
54−
55− urbit
56− }
57− }
58− }
59−}
60−
6134#[derive(Clone)]
6235struct WockApp {
6336 nock: Rc<Noun>,
6437 ctx: RefCell<InterpreterContext>,
6538 model: Rc<Noun>,
66− urbit: Rc<Urbit>,
6739}
6840
6941impl<'a> Render<'a> for WockApp {
@@ -75,13 +47,9 @@ impl<'a> Render<'a> for WockApp {
7547 ) {
7648 Ok(sail) => render_sail(cx, sail),
7749 Err(tanks) => {
78− let wock_app = self.clone();
79− let mut ctx = (*self.ctx.borrow()).clone();
80− spawn_local(async move {
81− let urbit = wock_app.urbit.get().await;
82− let str = wash(&mut ctx, &urbit, tanks);
83− error_1(&JsValue::from_str(&str));
84− });
50+ let str = ram_ttanks(&mut (*self).ctx.borrow_mut(), tanks);
51+ error_1(&JsValue::from_str(&str));
52+
8553 panic!("Could not render");
8654 }
8755 }
@@ -124,17 +92,20 @@ fn render_sail<'a>(ctx: &mut RenderContext<'a>, manx: Rc<Noun>) -> Node<'a> {
12492
12593 let binding = app.ctx.clone();
12694 let mut ctx = binding.borrow_mut();
127−
12895 let sig = ctx.nouns.sig.clone();
12996
130− let event = cell(&value, &sig);
97+ let step: Rc<Noun> = Rc::new((value.clone(), sig).into());
13198
13299 match slam(
133100 &mut ctx,
134101 &app.nock,
135− &cell(
136− &Rc::new(Noun::from_bytes(b"move")),
137− &cell(&app.model, &event),
102+ &Rc::new(
103+ (
104+ Noun::from_bytes(b"move").rc(),
105+ app.model.clone(),
106+ step.clone(),
107+ )
108+ .into(),
138109 ),
139110 ) {
140111 Ok(new_model) => {
@@ -142,16 +113,14 @@ fn render_sail<'a>(ctx: &mut RenderContext<'a>, manx: Rc<Noun>) -> Node<'a> {
142113 vdom.schedule_render();
143114 }
144115 Err(tanks) => {
145− let urbit = app.urbit.clone();
146116 let mut ctx = ctx.borrow_mut().clone();
147− spawn_local(async move {
148− let urbit = urbit.get().await;
149− let str = wash(&mut ctx, &urbit, tanks);
150− error_1(&JsValue::from_str(&str));
151− });
117+
118+ let str = ram_ttanks(&mut ctx, tanks);
119+ error_1(&JsValue::from_str(&str));
120+
152121 error(&*format!(
153122 "Application failed to process event: {}",
154− event
123+ step
155124 ))
156125 }
157126 };
@@ -199,14 +168,17 @@ fn tape_to_bump_str<'a>(bump: &'a Bump, non: &Rc<Noun>) -> &'a str {
199168#[wasm_bindgen]
200169pub async fn main(path: &str) {
201170 let nock = load_nock(path).await.unwrap_or_else(|err| {
202− error_1(&err);
171+ error(&*err.to_string());
203172 panic!("Could not load nock.")
204173 });
205174
206175 let document = gloo::utils::document();
207176 let output_el: Element = document.get_element_by_id("output").unwrap();
208177
209− let mut ctx = generate_interpreter_context();
178+ let mut ctx = InterpreterContext {
179+ slog: |str: &String| log_1(&JsValue::from_str(&*str)),
180+ ..generate_interpreter_context()
181+ };
210182
211183 let model = slam(
212184 &mut ctx,
@@ -216,12 +188,7 @@ pub async fn main(path: &str) {
216188 let model = match model {
217189 Ok(model) => model,
218190 Err(tanks) => {
219− let urbit = load_nock("/urbit.nock").await.unwrap_or_else(|err| {
220− error_1(&err);
221− panic!("Could not load urbit.")
222− });
223−
224− let str = wash(&mut ctx, &urbit, tanks);
191+ let str = ram_ttanks(&mut ctx, tanks);
225192 error_1(&JsValue::from_str(&str));
226193 panic!("Could not load initial model.");
227194 }
@@ -233,25 +200,15 @@ pub async fn main(path: &str) {
233200 nock,
234201 model,
235202 ctx: RefCell::new(ctx),
236− urbit: Rc::new(Urbit::new()),
237203 },
238204 )
239205 .forget();
240206}
241207
242−pub async fn load_nock(path: &str) -> Result<Rc<Noun>, JsValue> {
243− let window = web_sys::window().unwrap();
244−
245− let resp = JsFuture::from(window.fetch_with_str(path)).await?;
246− assert!(resp.is_instance_of::<web_sys::Response>());
247− let resp: web_sys::Response = resp.dyn_into()?;
248− let blob = JsFuture::from(resp.blob()?).await?;
249− assert!(blob.is_instance_of::<web_sys::Blob>());
250− let blob: web_sys::Blob = blob.dyn_into()?;
251−
252− let nock = js_sys::Uint8Array::new(&JsFuture::from(blob.array_buffer()).await?).to_vec();
208+pub async fn load_nock(path: &str) -> Result<Rc<Noun>, net::Error> {
209+ let blob = Request::get(path).send().await?.binary().await?;
253210
254− let nock = cue_bytes(&*nock);
211+ let nock = cue_bytes(&*blob);
255212 let (_typ, nok) = nock.as_cell().unwrap();
256213
257214 Ok(nok.clone())
wock.nock

Binary file not shown.