@@ -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)]
@@ -65,6 +74,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
6574 let memo = Rc::new(Noun::from_bytes(b"memo"));
6675 let mean = Rc::new(Noun::from_bytes(b"mean"));
6776 let slog = Rc::new(Noun::from_bytes(b"slog"));
77+ let fast = Rc::new(Noun::from_bytes(b"fast"));
6878 InterpreterContext {
6979 jets,
7080 double_jets,
@@ -81,6 +91,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
8191 memo,
8292 mean,
8393 slog,
94+ fast,
8495 },
8596 big_uints,
8697 memo: BTreeMap::new(),
@@ -193,7 +204,7 @@ fn hax(
193204
194205fn tar_u32<'a>(
195206 ctx: &mut InterpreterContext,
196− subj: Rc<Noun>,
207+ subj: &'a Rc<Noun>,
197208 op: u32,
198209 formula: &'a Rc<Noun>,
199210) -> Result<Rc<Noun>, TTanks> {
@@ -216,16 +227,16 @@ fn tar_u32<'a>(
216227 match ctx.jets.get(&hash) {
217228 Some(f) => f(ctx, sample),
218229 None => {
219− let foo = tar(ctx, subj.clone(), &b)?;
230+ let foo = tar(ctx, subj, &b)?;
220231 let bar = tar(ctx, subj, &c)?;
221− tar(ctx, foo, &bar)
232+ tar(ctx, &foo, &bar)
222233 }
223234 }
224235 }
225236 _ => {
226− let foo = tar(ctx, subj.clone(), &b)?;
237+ let foo = tar(ctx, subj, &b)?;
227238 let bar = tar(ctx, subj, &c)?;
228− tar(ctx, foo, &bar)
239+ tar(ctx, &foo, &bar)
229240 }
230241 }
231242 }
@@ -236,7 +247,7 @@ fn tar_u32<'a>(
236247 4 => Ok(Rc::new(lus(&*tar(ctx, subj, &formula)?)?)),
237248 5 => {
238249 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
239− let foo = tar(ctx, subj.clone(), &b)?;
250+ let foo = tar(ctx, subj, &b)?;
240251 let bar = tar(ctx, subj, &c)?;
241252 Ok(tis(ctx, &foo, &bar).clone())
242253 }
@@ -244,29 +255,29 @@ fn tar_u32<'a>(
244255 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
245256 let (c, d) = c.as_cell().ok_or(TTanks::new())?;
246257
247− 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))?;
248259
249− let foo = tar_u32(ctx, ctx.nouns.two_three.clone(), 0, &bar)?;
250− 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)?;
251262
252263 tar(ctx, subj, &foo)
253264 }
254265 7 => {
255266 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
256267 let foo = tar(ctx, subj, &b)?;
257− tar(ctx, foo, &c)
268+ tar(ctx, &foo, &c)
258269 }
259270 8 => {
260271 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
261− let foo = tar(ctx, subj.clone(), &b)?;
262− tar(ctx, cell(&foo, &subj), &c)
272+ let foo = tar(ctx, subj, &b)?;
273+ tar(ctx, &cell(&foo, &subj), &c)
263274 }
264275 9 => {
265276 let (b, c) = formula.as_cell().ok_or(TTanks::new())?;
266277 let foo = tar(ctx, subj, &c)?;
267278 tar_u32(
268279 ctx,
269− foo,
280+ &foo,
270281 2,
271282 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
272283 )
@@ -276,7 +287,7 @@ fn tar_u32<'a>(
276287 let (b, c) = b.as_cell().ok_or(TTanks::new())?;
277288 let b = b.as_atom().ok_or(TTanks::new())?;
278289
279− let foo = tar(ctx, subj.clone(), &c)?;
290+ let foo = tar(ctx, subj, &c)?;
280291 let bar = tar(ctx, subj, &d)?;
281292 hax(ctx, b, &foo, &bar)
282293 }
@@ -285,7 +296,7 @@ fn tar_u32<'a>(
285296 match b.borrow() {
286297 Noun::Atom(_) => tar(ctx, subj, &d),
287298 Noun::Cell { p, q, .. } => {
288− let eval = |ctx: &mut InterpreterContext| tar(ctx, subj.clone(), &d);
299+ let eval = |ctx: &mut InterpreterContext| tar(ctx, subj, &d);
289300 if *p == ctx.nouns.memo {
290301 let hash = cell(&subj, &d).hash();
291302 match ctx.memo.get(&hash) {
@@ -299,11 +310,33 @@ fn tar_u32<'a>(
299310 } else if *p == ctx.nouns.mean {
300311 with_trace((subj.clone(), q.clone()), eval(ctx))
301312 } else if *p == ctx.nouns.slog {
302− let noun = tar(ctx, subj.clone(), &q)?;
313+ let noun = tar(ctx, subj, &q)?;
303314 let (_prio, tank) = noun.as_cell().ok_or(TTanks::new())?;
304315
305316 (ctx.slog)(&ram(ctx, tank.clone()).unwrap_or(String::new()));
306317 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)
307340 } else {
308341 eval(ctx)
309342 }
@@ -401,8 +434,15 @@ fn ram(ctx: &mut InterpreterContext, tank: Rc<Noun>) -> Option<String> {
401434pub fn ram_ttanks(ctx: &mut InterpreterContext, tanks: TTanks) -> String {
402435 let mut target = String::new();
403436
404− 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+
405443 target.push_str(&*ram_ttank(ctx, tank.clone()));
444+
445+ first = false;
406446 }
407447
408448 target
@@ -411,7 +451,7 @@ pub fn ram_ttanks(ctx: &mut InterpreterContext, tanks: TTanks) -> String {
411451pub fn ram_ttank(ctx: &mut InterpreterContext, ttank: TTank) -> String {
412452 let (subj, q) = ttank;
413453
414− let tank = match tar(ctx, subj.clone(), &q) {
454+ let tank = match tar(ctx, &subj, &q) {
415455 Ok(gate) => match eval_pulled_gate(ctx, gate) {
416456 Ok(tank) => tank,
417457 Err(_) => {
@@ -444,13 +484,13 @@ pub const EMPTY_TANKS: TTanks = TTanks::new();
444484
445485pub fn tar<'a>(
446486 ctx: &mut InterpreterContext,
447− subj: Rc<Noun>,
487+ subj: &'a Rc<Noun>,
448488 formula: &'a Noun,
449489) -> Result<Rc<Noun>, TTanks> {
450490 let (op, formula) = formula.as_cell().ok_or(TTanks::new())?;
451491 match op.borrow() {
452492 Noun::Cell { .. } => {
453− let foo = tar(ctx, subj.clone(), &op)?;
493+ let foo = tar(ctx, subj, &op)?;
454494 let bar = tar(ctx, subj, &formula)?;
455495 Ok(cell(&foo, &bar))
456496 }
@@ -471,7 +511,7 @@ pub fn eval_gate(
471511 ctx: &mut InterpreterContext,
472512 gate_factory: &Rc<Noun>,
473513) -> Result<Rc<Noun>, TTanks> {
474− let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
514+ let pulled_gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
475515 eval_pulled_gate(ctx, pulled_gate)
476516}
477517
@@ -480,7 +520,7 @@ pub fn slam(
480520 gate_factory: &Rc<Noun>,
481521 sample: &Rc<Noun>,
482522) -> Result<Rc<Noun>, TTanks> {
483− let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
523+ let gate = tar(ctx, &ctx.nouns.sig.clone(), &gate_factory)?;
484524
485525 eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
486526}
@@ -490,7 +530,7 @@ pub fn slam(
490530pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Result<Rc<Noun>, TTanks> {
491531 tar(
492532 ctx,
493− gate,
533+ &gate,
494534 &cell(
495535 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
496536 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),