@@ -1,4 +1,5 @@
11use std::borrow::Borrow;
2+use std::collections::BTreeMap;
23use std::rc::Rc;
34
45use num_bigint::BigUint;
@@ -16,6 +17,7 @@ pub struct Nouns {
1617 pub four: Rc<Noun>,
1718 pub sig_one: Rc<Noun>,
1819 pub two_three: Rc<Noun>,
20+ pub memo: Rc<Noun>,
1921}
2022
2123pub struct BigUints {
@@ -31,6 +33,7 @@ pub struct InterpreterContext {
3133 pub double_jets: DoubleJets,
3234 pub nouns: Nouns,
3335 pub big_uints: BigUints,
36+ pub memo: BTreeMap<Hash, Rc<Noun>>,
3437}
3538
3639pub fn generate_interpreter_context() -> InterpreterContext {
@@ -50,6 +53,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
5053 let four = Rc::new(Noun::Atom(big_uints.four.clone()));
5154 let sig_one = cell(&sig, &one);
5255 let two_three = cell(&two, &three);
56+ let memo = Rc::new(Noun::from_bytes(b"memo"));
5357 InterpreterContext {
5458 jets,
5559 double_jets,
@@ -63,8 +67,10 @@ pub fn generate_interpreter_context() -> InterpreterContext {
6367 four,
6468 sig_one,
6569 two_three,
70+ memo,
6671 },
6772 big_uints,
73+ memo: BTreeMap::new(),
6874 }
6975}
7076
@@ -172,15 +178,15 @@ fn hax(
172178}
173179
174180fn tar_u32<'a>(
175− ctx: &InterpreterContext,
176− subj: &'a Noun,
181+ ctx: &mut InterpreterContext,
182+ subj: Rc<Noun>,
177183 op: u32,
178184 formula: &'a Rc<Noun>,
179185) -> Option<Rc<Noun>> {
180186 match op {
181187 0 => {
182188 let b = formula.as_atom()?;
183− fas(ctx, b, subj)
189+ fas(ctx, b, &*subj)
184190 }
185191 1 => Some(formula.clone()),
186192 2 => {
@@ -196,16 +202,16 @@ fn tar_u32<'a>(
196202 match ctx.jets.get(&hash) {
197203 Some(f) => f(ctx, sample),
198204 None => {
199− let foo = tar(ctx, subj, &b)?;
205+ let foo = tar(ctx, subj.clone(), &b)?;
200206 let bar = tar(ctx, subj, &c)?;
201− tar(ctx, &foo, &bar)
207+ tar(ctx, foo, &bar)
202208 }
203209 }
204210 }
205211 _ => {
206− let foo = tar(ctx, &subj, &b)?;
207− let bar = tar(ctx, &subj, &c)?;
208− tar(ctx, &foo, &bar)
212+ let foo = tar(ctx, subj.clone(), &b)?;
213+ let bar = tar(ctx, subj, &c)?;
214+ tar(ctx, foo, &bar)
209215 }
210216 }
211217 }
@@ -219,7 +225,7 @@ fn tar_u32<'a>(
219225 }
220226 5 => {
221227 let (b, c) = formula.as_cell()?;
222− let foo = tar(ctx, &subj, &b)?;
228+ let foo = tar(ctx, subj.clone(), &b)?;
223229 let bar = tar(ctx, subj, &c)?;
224230 Some(tis(ctx, &foo, &bar).clone())
225231 }
@@ -227,36 +233,29 @@ fn tar_u32<'a>(
227233 let (b, c) = formula.as_cell()?;
228234 let (c, d) = c.as_cell()?;
229235
230− let foo = tar_u32(
231− ctx,
232− &cell(&c, &d),
233− 0,
234− &tar_u32(
235− ctx,
236− &ctx.nouns.two_three,
237− 0,
238− &tar_u32(ctx, subj, 4, &cell(&ctx.nouns.four, &b))?,
239− )?,
240− )?;
236+ let bar = tar_u32(ctx, subj.clone(), 4, &cell(&ctx.nouns.four.clone(), &b))?;
241237
242− tar(ctx, &subj, &foo)
238+ let foo = tar_u32(ctx, ctx.nouns.two_three.clone(), 0, &bar)?;
239+ let foo = tar_u32(ctx, cell(&c, &d), 0, &foo)?;
240+
241+ tar(ctx, subj, &foo)
243242 }
244243 7 => {
245244 let (b, c) = formula.as_cell()?;
246245 let foo = tar(ctx, subj, &b)?;
247− tar(ctx, &foo, &c)
246+ tar(ctx, foo, &c)
248247 }
249248 8 => {
250249 let (b, c) = formula.as_cell()?;
251− let foo = tar(ctx, &subj, &b)?;
252− tar(ctx, &cell(&foo, &Rc::new(subj.clone())), &c)
250+ let foo = tar(ctx, subj.clone(), &b)?;
251+ tar(ctx, cell(&foo, &subj), &c)
253252 }
254253 9 => {
255254 let (b, c) = formula.as_cell()?;
256− let foo = tar(ctx, &subj, &c)?;
255+ let foo = tar(ctx, subj, &c)?;
257256 tar_u32(
258257 ctx,
259− &foo,
258+ foo,
260259 2,
261260 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
262261 )
@@ -266,17 +265,33 @@ fn tar_u32<'a>(
266265 let (b, c) = b.as_cell()?;
267266 let b = b.as_atom()?;
268267
269− hax(ctx, b, &tar(ctx, subj, &c)?, &tar(ctx, subj, &d)?)
268+ let foo = tar(ctx, subj.clone(), &c)?;
269+ let bar = tar(ctx, subj, &d)?;
270+ hax(ctx, b, &foo, &bar)
270271 }
271272 11 => {
272273 let (b, d) = formula.as_cell()?;
273− // println!("{b}");
274274 match b.borrow() {
275275 Noun::Atom(_) => tar(ctx, subj, &d),
276− Noun::Cell { q: c, .. } => {
277− let foo = tar(ctx, subj, &c)?;
278− let bar = tar(ctx, subj, &d)?;
279− tar_u32(ctx, &cell(&foo, &bar), 0, &ctx.nouns.three)
276+ Noun::Cell { p, q, .. } => {
277+ if *p == ctx.nouns.memo {
278+ let hash = cell(&subj, formula).hash();
279+ match ctx.memo.get(&hash) {
280+ Some(target) => Some(target.clone()),
281+ None => {
282+ let foo = cell(
283+ &tar(ctx, subj.clone(), &q)?,
284+ &tar(ctx, subj.clone(), &d)?,
285+ );
286+ let target = tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())?;
287+ ctx.memo.insert(hash, target.clone());
288+ Some(target)
289+ }
290+ }
291+ } else {
292+ let foo = cell(&tar(ctx, subj.clone(), &q)?, &tar(ctx, subj.clone(), &d)?);
293+ tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())
294+ }
280295 }
281296 }
282297 }
@@ -284,11 +299,15 @@ fn tar_u32<'a>(
284299 }
285300}
286301
287−pub fn tar<'a>(ctx: &InterpreterContext, subj: &'a Noun, formula: &'a Noun) -> Option<Rc<Noun>> {
302+pub fn tar<'a>(
303+ ctx: &mut InterpreterContext,
304+ subj: Rc<Noun>,
305+ formula: &'a Noun,
306+) -> Option<Rc<Noun>> {
288307 let (op, formula) = formula.as_cell()?;
289308 match op.borrow() {
290309 Noun::Cell { .. } => {
291− let foo = tar(ctx, subj, &op)?;
310+ let foo = tar(ctx, subj.clone(), &op)?;
292311 let bar = tar(ctx, subj, &formula)?;
293312 Some(cell(&foo, &bar))
294313 }
@@ -305,27 +324,27 @@ pub fn tar<'a>(ctx: &InterpreterContext, subj: &'a Noun, formula: &'a Noun) -> O
305324 }
306325}
307326
308−pub fn eval_gate(ctx: &InterpreterContext, gate_factory: &Rc<Noun>) -> Option<Rc<Noun>> {
309− let pulled_gate = tar(ctx, &ctx.nouns.sig, &gate_factory)?;
310− eval_pulled_gate(ctx, &pulled_gate)
327+pub fn eval_gate(ctx: &mut InterpreterContext, gate_factory: &Rc<Noun>) -> Option<Rc<Noun>> {
328+ let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
329+ eval_pulled_gate(ctx, pulled_gate)
311330}
312331
313332pub fn slam(
314− ctx: &InterpreterContext,
333+ ctx: &mut InterpreterContext,
315334 gate_factory: &Rc<Noun>,
316335 sample: &Rc<Noun>,
317336) -> Option<Rc<Noun>> {
318− let gate = tar(ctx, &ctx.nouns.sig, &gate_factory)?;
337+ let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
319338
320− eval_pulled_gate(ctx, &replace_sample(&gate, sample)?)
339+ eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
321340}
322341
323342/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
324343/// Also for calling gates from within jets.
325−pub fn eval_pulled_gate(ctx: &InterpreterContext, gate: &Rc<Noun>) -> Option<Rc<Noun>> {
344+pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Option<Rc<Noun>> {
326345 tar(
327346 ctx,
328− &gate,
347+ gate,
329348 &cell(
330349 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
331350 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),
@@ -336,11 +355,11 @@ pub fn eval_pulled_gate(ctx: &InterpreterContext, gate: &Rc<Noun>) -> Option<Rc<
336355/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
337356/// Also for calling gates from within jets.
338357pub fn slam_pulled_gate(
339− ctx: &InterpreterContext,
358+ ctx: &mut InterpreterContext,
340359 gate: &Rc<Noun>,
341360 sample: &Rc<Noun>,
342361) -> Option<Rc<Noun>> {
343− eval_pulled_gate(ctx, &replace_sample(gate, sample)?)
362+ eval_pulled_gate(ctx, replace_sample(gate, sample)?)
344363}
345364
346365pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Option<Rc<Noun>> {