on master help sign in
10 files changed+987−136
since splitsnapshots
unifiedsplit
nock/Cargo.lock+141−5 nock/Cargo.toml+7 nock/src/interpreter.rs+85−42 nock/src/jets.rs+171−2 nock/src/main.rs+38−3 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/src/interpreter.rs+85−42
@@ -1,15 +1,23 @@
11use core::str;
22use std::borrow::Borrow;
33use std::collections::BTreeMap;
4+use std::collections::HashMap;
45use std::rc::Rc;
6+use std::sync::Mutex;
57
68use fplist::cons;
79use fplist::PersistentList;
10+use lazy_static::lazy_static;
811use num_bigint::BigUint;
912
1013use crate::jets::*;
1114use crate::noun::*;
1215
16+// #[cfg(feature = "count-jets")]
17+lazy_static! {
18+ pub static ref JET_COUNTER: Mutex<HashMap<Atom, u32>> = Mutex::new(HashMap::new());
19+}
20+
1321#[derive(Clone)]
1422pub struct Nouns {
1523 pub y: Rc<Noun>,
@@ -24,6 +32,7 @@ pub struct Nouns {
2432 pub memo: Rc<Noun>,
2533 pub mean: Rc<Noun>,
2634 pub slog: Rc<Noun>,
35+ pub fast: Rc<Noun>,
2736}
2837
2938#[derive(Clone)]
@@ -42,6 +51,7 @@ pub struct InterpreterContext {
4251 pub nouns: Nouns,
4352 pub big_uints: BigUints,
4453 pub memo: BTreeMap<Hash, Rc<Noun>>,
54+ pub slog: fn(&String) -> (),
4555}
4656
4757pub fn generate_interpreter_context() -> InterpreterContext {
@@ -64,6 +74,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
6474 let memo = Rc::new(Noun::from_bytes(b"memo"));
6575 let mean = Rc::new(Noun::from_bytes(b"mean"));
6676 let slog = Rc::new(Noun::from_bytes(b"slog"));
77+ let fast = Rc::new(Noun::from_bytes(b"fast"));
6778 InterpreterContext {
6879 jets,
6980 double_jets,
@@ -80,9 +91,11 @@ pub fn generate_interpreter_context() -> InterpreterContext {
8091 memo,
8192 mean,
8293 slog,
94+ fast,
8395 },
8496 big_uints,
8597 memo: BTreeMap::new(),
98+ slog: |str: &String| eprintln!("{}", str),
8699 }
87100}
88101
@@ -191,7 +204,7 @@ fn hax(
191204
192205fn tar_u32<'a>(
193206 ctx: &mut InterpreterContext,
194− subj: Rc<Noun>,
207+ subj: &'a Rc<Noun>,
195208 op: u32,
196209 formula: &'a Rc<Noun>,
197210) -> Result<Rc<Noun>, TTanks> {
@@ -214,16 +227,16 @@ fn tar_u32<'a>(
214227 match ctx.jets.get(&hash) {
215228 Some(f) => f(ctx, sample),
216229 None => {
217− let foo = tar(ctx, subj.clone(), &b)?;
230+ let foo = tar(ctx, subj, &b)?;
218231 let bar = tar(ctx, subj, &c)?;
219− tar(ctx, foo, &bar)
232+ tar(ctx, &foo, &bar)
220233 }
221234 }
222235 }
223236 _ => {
224− let foo = tar(ctx, subj.clone(), &b)?;
237+ let foo = tar(ctx, subj, &b)?;
225238 let bar = tar(ctx, subj, &c)?;
226− tar(ctx, foo, &bar)
239+ tar(ctx, &foo, &bar)
227240 }
228241 }
229242 }
@@ -234,7 +247,7 @@ fn tar_u32<'a>(
234247 4 => Ok(Rc::new(lus(&*tar(ctx, subj, &formula)?)?)),
235248 5 => {
236249 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
237− let foo = tar(ctx, subj.clone(), &b)?;
250+ let foo = tar(ctx, subj, &b)?;
238251 let bar = tar(ctx, subj, &c)?;
239252 Ok(tis(ctx, &foo, &bar).clone())
240253 }
@@ -242,29 +255,29 @@ fn tar_u32<'a>(
242255 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
243256 let (c, d) = c.as_cell().ok_or(TTanks::new())?;
244257
245− 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))?;
246259
247− let foo = tar_u32(ctx, ctx.nouns.two_three.clone(), 0, &bar)?;
248− 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)?;
249262
250263 tar(ctx, subj, &foo)
251264 }
252265 7 => {
253266 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
254267 let foo = tar(ctx, subj, &b)?;
255− tar(ctx, foo, &c)
268+ tar(ctx, &foo, &c)
256269 }
257270 8 => {
258271 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
259− let foo = tar(ctx, subj.clone(), &b)?;
260− tar(ctx, cell(&foo, &subj), &c)
272+ let foo = tar(ctx, subj, &b)?;
273+ tar(ctx, &cell(&foo, &subj), &c)
261274 }
262275 9 => {
263276 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
264277 let foo = tar(ctx, subj, &c)?;
265278 tar_u32(
266279 ctx,
267− foo,
280+ &foo,
268281 2,
269282 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
270283 )
@@ -274,7 +287,7 @@ fn tar_u32<'a>(
274287 let (b, c) = b.as_cell().ok_or(TTanks::new())?;
275288 let b = b.as_atom().ok_or(TTanks::new())?;
276289
277− let foo = tar(ctx, subj.clone(), &c)?;
290+ let foo = tar(ctx, subj, &c)?;
278291 let bar = tar(ctx, subj, &d)?;
279292 hax(ctx, b, &foo, &bar)
280293 }
@@ -283,7 +296,7 @@ fn tar_u32<'a>(
283296 match b.borrow() {
284297 Noun::Atom(_) => tar(ctx, subj, &d),
285298 Noun::Cell { p, q, .. } => {
286− let eval = |ctx: &mut InterpreterContext| tar(ctx, subj.clone(), &d);
299+ let eval = |ctx: &mut InterpreterContext| tar(ctx, subj, &d);
287300 if *p == ctx.nouns.memo {
288301 let hash = cell(&subj, &d).hash();
289302 match ctx.memo.get(&hash) {
@@ -297,10 +310,32 @@ fn tar_u32<'a>(
297310 } else if *p == ctx.nouns.mean {
298311 with_trace((subj.clone(), q.clone()), eval(ctx))
299312 } else if *p == ctx.nouns.slog {
300− let noun = tar(ctx, subj.clone(), &q)?;
313+ let noun = tar(ctx, subj, &q)?;
301314 let (_prio, tank) = noun.as_cell().ok_or(TTanks::new())?;
302315
303− eprintln!("{}", ram(ctx, tank.clone()).unwrap_or(String::new()));
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+ }
304339 eval(ctx)
305340 } else {
306341 eval(ctx)
@@ -321,24 +356,22 @@ fn ram(ctx: &mut InterpreterContext, tank: Rc<Noun>) -> Option<String> {
321356 Noun::Cell { p, q, .. } => {
322357 let tag = p.as_atom()?.to_bytes_le();
323358 if tag == b"leaf" {
324− let mut bytes = crip(ctx, q.clone()).ok()?.as_atom()?.to_bytes_le();
359+ let mut bytes = crip(ctx, q.clone()).ok()?.as_bytes()?;
325360 Some(String::from(str::from_utf8_mut(&mut bytes).ok()?))
326361 } else if tag == b"palm" {
327− let (mid, foo) = q.as_cell()?;
328− let (open, foo) = foo.as_cell()?;
329− let (flat_open, foo) = foo.as_cell()?;
330− let (close, tanks) = foo.as_cell()?;
362+ let (spacers, tanks) = q.as_cell()?;
363+ let (mid, open, flat_open, close) = spacers.tuple_4()?;
331364
332− let mut mid = mid.as_bytes()?;
365+ let mut mid = crip(ctx, mid.clone()).ok()?.as_bytes()?;
333366 let mid = String::from(str::from_utf8_mut(&mut mid).ok()?);
334367
335− let mut open = open.as_bytes()?;
368+ let mut open = crip(ctx, open.clone()).ok()?.as_bytes()?;
336369 let open = String::from(str::from_utf8_mut(&mut open).ok()?);
337370
338− let mut flat_open = flat_open.as_bytes()?;
371+ let mut flat_open = crip(ctx, flat_open.clone()).ok()?.as_bytes()?;
339372 let flat_open = String::from(str::from_utf8_mut(&mut flat_open).ok()?);
340373
341− let mut close = close.as_bytes()?;
374+ let mut close = crip(ctx, close.clone()).ok()?.as_bytes()?;
342375 let close = String::from(str::from_utf8_mut(&mut close).ok()?);
343376
344377 let mut target = String::new();
@@ -361,17 +394,16 @@ fn ram(ctx: &mut InterpreterContext, tank: Rc<Noun>) -> Option<String> {
361394
362395 Some(target)
363396 } else if tag == b"rose" {
364− let (mid, foo) = q.as_cell()?;
365− let (open, foo) = foo.as_cell()?;
366− let (close, tanks) = foo.as_cell()?;
397+ let (spacers, tanks) = q.as_cell()?;
398+ let (mid, open, close) = spacers.tuple_3()?;
367399
368− let mut mid = mid.as_bytes()?;
400+ let mut mid = crip(ctx, mid.clone()).ok()?.as_bytes()?;
369401 let mid = String::from(str::from_utf8_mut(&mut mid).ok()?);
370402
371− let mut open = open.as_bytes()?;
403+ let mut open = crip(ctx, open.clone()).ok()?.as_bytes()?;
372404 let open = String::from(str::from_utf8_mut(&mut open).ok()?);
373405
374− let mut close = close.as_bytes()?;
406+ let mut close = crip(ctx, close.clone()).ok()?.as_bytes()?;
375407 let close = String::from(str::from_utf8_mut(&mut close).ok()?);
376408
377409 let mut target = String::new();
@@ -402,8 +434,15 @@ fn ram(ctx: &mut InterpreterContext, tank: Rc<Noun>) -> Option<String> {
402434pub fn ram_ttanks(ctx: &mut InterpreterContext, tanks: TTanks) -> String {
403435 let mut target = String::new();
404436
405− for tank in tanks.iter() {
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+
406443 target.push_str(&*ram_ttank(ctx, tank.clone()));
444+
445+ first = false;
407446 }
408447
409448 target
@@ -412,17 +451,21 @@ pub fn ram_ttanks(ctx: &mut InterpreterContext, tanks: TTanks) -> String {
412451pub fn ram_ttank(ctx: &mut InterpreterContext, ttank: TTank) -> String {
413452 let (subj, q) = ttank;
414453
415− let tank = match tar(ctx, subj.clone(), &q) {
454+ let tank = match tar(ctx, &subj, &q) {
416455 Ok(gate) => match eval_pulled_gate(ctx, gate) {
417456 Ok(tank) => tank,
418− Err(_) => return String::new(),
457+ Err(_) => {
458+ return String::new();
459+ }
419460 },
420− Err(_) => return String::new(),
461+ Err(_) => {
462+ return String::new();
463+ }
421464 };
422465 ram(ctx, tank).unwrap_or(String::new())
423466}
424467
425−fn crip(ctx: &mut InterpreterContext, tape: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
468+pub fn crip(ctx: &mut InterpreterContext, tape: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
426469 RAP(ctx, &cell(&Rc::new(Noun::from_u32(3)), &tape))
427470}
428471
@@ -441,13 +484,13 @@ pub const EMPTY_TANKS: TTanks = TTanks::new();
441484
442485pub fn tar<'a>(
443486 ctx: &mut InterpreterContext,
444− subj: Rc<Noun>,
487+ subj: &'a Rc<Noun>,
445488 formula: &'a Noun,
446489) -> Result<Rc<Noun>, TTanks> {
447490 let (op, formula) = formula.as_cell().ok_or(TTanks::new())?;
448491 match op.borrow() {
449492 Noun::Cell { .. } => {
450− let foo = tar(ctx, subj.clone(), &op)?;
493+ let foo = tar(ctx, subj, &op)?;
451494 let bar = tar(ctx, subj, &formula)?;
452495 Ok(cell(&foo, &bar))
453496 }
@@ -468,7 +511,7 @@ pub fn eval_gate(
468511 ctx: &mut InterpreterContext,
469512 gate_factory: &Rc<Noun>,
470513) -> Result<Rc<Noun>, TTanks> {
471− let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
514+ let pulled_gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
472515 eval_pulled_gate(ctx, pulled_gate)
473516}
474517
@@ -477,7 +520,7 @@ pub fn slam(
477520 gate_factory: &Rc<Noun>,
478521 sample: &Rc<Noun>,
479522) -> Result<Rc<Noun>, TTanks> {
480− let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
523+ let gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
481524
482525 eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
483526}
@@ -487,7 +530,7 @@ pub fn slam(
487530pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
488531 tar(
489532 ctx,
490− gate,
533+ &gate,
491534 &cell(
492535 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
493536 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),
nock/src/jets.rs+171−2
@@ -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, TTanks},
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,6 +108,11 @@ 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
@@ -1007,6 +1013,169 @@ static MUK: Jet = |_ctx, n| {
10071013 Ok(Rc::new(Noun::from_u32(muk(seed, len, key))))
10081014};
10091015
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+
10101179static JUST: DoubleJet = |ctx, n, m| {
10111180 let char = n.as_atom()?;
10121181 let nail = m.as_nail()?;
nock/src/main.rs+38−3
@@ -1,6 +1,8 @@
11use clap::{command, error::Result, Parser, Subcommand};
22use core::str;
3−use nock::interpreter::{ram_ttanks, slam_pulled_gate, tar, InterpreterContext, TTanks};
3+use nock::interpreter::{
4+ ram_ttanks, slam_pulled_gate, tar, InterpreterContext, TTanks, JET_COUNTER,
5+};
46use nock::{
57 cue::cue_bytes,
68 interpreter::{generate_interpreter_context, slam},
@@ -65,9 +67,38 @@ enum RunCommand {
6567 },
6668}
6769
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+
6888fn 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+
6997 let urbit = LazyCell::new(GENERATE_URBIT);
70− let mut ctx = generate_interpreter_context();
98+ let mut ctx = InterpreterContext {
99+ // slog: |_| {},
100+ ..generate_interpreter_context()
101+ };
71102
72103 let cli = Cli::parse();
73104
@@ -136,12 +167,16 @@ fn main() -> Result<(), std::io::Error> {
136167 let (_typ, nok) = read_nock_or_compile(&mut spinner, &mut ctx, &urbit, &nock)?;
137168
138169 let sig = ctx.nouns.sig.clone();
139− let result = tar(&mut ctx, sig, &nok).unwrap();
170+ let result = tar(&mut ctx, &sig, &nok).unwrap();
140171
141172 println!("{result}");
142173 }
143174 }
144175
176+ if cfg!(feature = "count-jets") {
177+ print_jet_counter()
178+ }
179+
145180 Ok(())
146181}
147182
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.