yatima_core/
dag.rs

1/// Bottom-up reduction of lambda DAGs. Based on the paper by Olin Shivers
2/// and Mitchel Wand "Bottom-up β-reduction: uplinks and λ-DAGs" (https://www.brics.dk/RS/04/38/BRICS-RS-04-38.pdf)
3use crate::{
4  defs::Def,
5  dll::*,
6  literal::{
7    LitType,
8    Literal,
9  },
10  name::Name,
11  position::Pos,
12  prim::Op,
13  term::Term,
14  uses::Uses,
15};
16
17use core::ptr::NonNull;
18
19use sp_std::{
20  boxed::Box,
21  collections::{
22    btree_map::BTreeMap,
23    btree_set::BTreeSet,
24  },
25  fmt,
26  mem,
27};
28
29use alloc::string::String;
30use sp_cid::Cid;
31
32/// A λ-DAG used to reduce Yatima terms. Acts like a directed acyclice graph,
33/// but has backpointers for the bottom-up reduction algorithm.
34pub struct DAG {
35  pub head: DAGPtr,
36}
37
38/// A top-down λ-DAG pointer. Keeps track of what kind of node it points to.
39/// Similar to the Term enum, except it uses a Fix for fixed-point recursion and
40/// keeps the Rec recursion marker as a field in Var
41#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
42pub enum DAGPtr {
43  Var(NonNull<Var>),
44  Lam(NonNull<Lam>),
45  App(NonNull<App>),
46  All(NonNull<All>),
47  Slf(NonNull<Slf>),
48  Fix(NonNull<Fix>),
49  Dat(NonNull<Dat>),
50  Cse(NonNull<Cse>),
51  Ref(NonNull<Ref>),
52  Let(NonNull<Let>),
53  Typ(NonNull<Typ>),
54  Ann(NonNull<Ann>),
55  Lit(NonNull<Lit>),
56  LTy(NonNull<LTy>),
57  Opr(NonNull<Opr>),
58}
59
60/// Doubly-linked list of parent nodes.
61pub type Parents = DLL<ParentPtr>;
62
63/// A bottom-up (parent) λ-DAG pointer. Keeps track of the relation between
64/// the child and the parent.
65#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
66pub enum ParentPtr {
67  Root,
68  LamBod(NonNull<Lam>),
69  SlfBod(NonNull<Slf>),
70  FixBod(NonNull<Fix>),
71  DatBod(NonNull<Dat>),
72  CseBod(NonNull<Cse>),
73  AppFun(NonNull<App>),
74  AppArg(NonNull<App>),
75  AllDom(NonNull<All>),
76  AllImg(NonNull<All>),
77  AnnTyp(NonNull<Ann>),
78  AnnExp(NonNull<Ann>),
79  LetTyp(NonNull<Let>),
80  LetExp(NonNull<Let>),
81  LetBod(NonNull<Let>),
82}
83
84#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
85pub enum BinderPtr {
86  Free,
87  Lam(NonNull<Lam>),
88  Slf(NonNull<Slf>),
89  Fix(NonNull<Fix>),
90}
91
92/// The λ-DAG nodes
93#[derive(Clone, Debug)]
94#[repr(C)]
95pub struct Var {
96  pub nam: Name,
97  // The field `rec` is only used to preserve the Term <-> DAG isomorphism for
98  // open Terms
99  pub rec: bool,
100  // The field `depth` is only used by the type checker to track free
101  // variables. Otherwise it is irrelevant.
102  pub dep: u64,
103  pub binder: BinderPtr,
104  pub parents: Option<NonNull<Parents>>,
105}
106
107#[repr(C)]
108pub struct Lam {
109  pub bod: DAGPtr,
110  pub bod_ref: Parents,
111  pub var: Var,
112  pub parents: Option<NonNull<Parents>>,
113}
114
115#[repr(C)]
116pub struct App {
117  pub fun: DAGPtr,
118  pub arg: DAGPtr,
119  pub fun_ref: Parents,
120  pub arg_ref: Parents,
121  // The field `copy` is used for copied DAG nodes during the upcopy operation
122  pub copy: Option<NonNull<App>>,
123  pub parents: Option<NonNull<Parents>>,
124}
125
126#[repr(C)]
127pub struct All {
128  pub uses: Uses,
129  pub dom: DAGPtr,
130  pub img: NonNull<Lam>,
131  pub dom_ref: Parents,
132  pub img_ref: Parents,
133  pub copy: Option<NonNull<All>>,
134  pub parents: Option<NonNull<Parents>>,
135}
136
137#[repr(C)]
138pub struct Slf {
139  pub bod: DAGPtr,
140  pub bod_ref: Parents,
141  pub var: Var,
142  pub parents: Option<NonNull<Parents>>,
143}
144
145#[repr(C)]
146pub struct Fix {
147  pub bod: DAGPtr,
148  pub bod_ref: Parents,
149  pub var: Var,
150  pub parents: Option<NonNull<Parents>>,
151}
152
153#[repr(C)]
154pub struct Dat {
155  pub bod: DAGPtr,
156  pub bod_ref: Parents,
157  pub parents: Option<NonNull<Parents>>,
158}
159
160#[repr(C)]
161pub struct Cse {
162  pub bod: DAGPtr,
163  pub bod_ref: Parents,
164  pub parents: Option<NonNull<Parents>>,
165}
166
167#[repr(C)]
168pub struct Ann {
169  pub typ: DAGPtr,
170  pub exp: DAGPtr,
171  pub typ_ref: Parents,
172  pub exp_ref: Parents,
173  pub copy: Option<NonNull<Ann>>,
174  pub parents: Option<NonNull<Parents>>,
175}
176
177#[repr(C)]
178pub struct Let {
179  pub uses: Uses,
180  pub typ: DAGPtr,
181  pub exp: DAGPtr,
182  pub bod: NonNull<Lam>,
183  pub typ_ref: Parents,
184  pub exp_ref: Parents,
185  pub bod_ref: Parents,
186  pub copy: Option<NonNull<Let>>,
187  pub parents: Option<NonNull<Parents>>,
188}
189
190#[repr(C)]
191pub struct Ref {
192  pub nam: Name,
193  pub rec: bool,
194  pub exp: Cid,
195  pub ast: Cid,
196  pub parents: Option<NonNull<Parents>>,
197}
198
199#[repr(C)]
200pub struct Typ {
201  pub parents: Option<NonNull<Parents>>,
202}
203
204#[repr(C)]
205pub struct Lit {
206  pub lit: Literal,
207  pub parents: Option<NonNull<Parents>>,
208}
209
210#[repr(C)]
211pub struct LTy {
212  pub lty: LitType,
213  pub parents: Option<NonNull<Parents>>,
214}
215
216#[repr(C)]
217pub struct Opr {
218  pub opr: Op,
219  pub parents: Option<NonNull<Parents>>,
220}
221
222/// Auxiliary allocation functions
223#[inline]
224pub fn alloc_val<T>(val: T) -> NonNull<T> {
225  NonNull::new(Box::leak(Box::new(val))).unwrap()
226}
227
228#[inline]
229pub fn alloc_lam(
230  var_nam: Name,
231  var_dep: u64,
232  bod: DAGPtr,
233  parents: Option<NonNull<Parents>>,
234) -> NonNull<Lam> {
235  unsafe {
236    let lam = alloc_val(Lam {
237      var: Var {
238        nam: var_nam,
239        rec: false,
240        dep: var_dep,
241        binder: mem::zeroed(),
242        parents: None,
243      },
244      bod,
245      bod_ref: mem::zeroed(),
246      parents,
247    });
248    (*lam.as_ptr()).var.binder = BinderPtr::Lam(lam);
249    (*lam.as_ptr()).bod_ref = DLL::singleton(ParentPtr::LamBod(lam));
250    lam
251  }
252}
253
254#[inline]
255pub fn alloc_slf(
256  var_nam: Name,
257  var_dep: u64,
258  bod: DAGPtr,
259  parents: Option<NonNull<Parents>>,
260) -> NonNull<Slf> {
261  unsafe {
262    let slf = alloc_val(Slf {
263      var: Var {
264        nam: var_nam,
265        rec: false,
266        dep: var_dep,
267        binder: mem::zeroed(),
268        parents: None,
269      },
270      bod,
271      bod_ref: mem::zeroed(),
272      parents,
273    });
274    (*slf.as_ptr()).var.binder = BinderPtr::Slf(slf);
275    (*slf.as_ptr()).bod_ref = DLL::singleton(ParentPtr::SlfBod(slf));
276    slf
277  }
278}
279
280#[inline]
281pub fn alloc_fix(
282  var_nam: Name,
283  var_dep: u64,
284  bod: DAGPtr,
285  parents: Option<NonNull<Parents>>,
286) -> NonNull<Fix> {
287  unsafe {
288    let fix = alloc_val(Fix {
289      var: Var {
290        nam: var_nam,
291        rec: false,
292        dep: var_dep,
293        binder: mem::zeroed(),
294        parents: None,
295      },
296      bod,
297      bod_ref: mem::zeroed(),
298      parents,
299    });
300    (*fix.as_ptr()).var.binder = BinderPtr::Fix(fix);
301    (*fix.as_ptr()).bod_ref = DLL::singleton(ParentPtr::FixBod(fix));
302    fix
303  }
304}
305
306#[inline]
307pub fn alloc_dat(
308  bod: DAGPtr,
309  parents: Option<NonNull<Parents>>,
310) -> NonNull<Dat> {
311  unsafe {
312    let dat = alloc_val(Dat { bod, bod_ref: mem::zeroed(), parents });
313    (*dat.as_ptr()).bod_ref = DLL::singleton(ParentPtr::DatBod(dat));
314    dat
315  }
316}
317
318#[inline]
319pub fn alloc_cse(
320  bod: DAGPtr,
321  parents: Option<NonNull<Parents>>,
322) -> NonNull<Cse> {
323  unsafe {
324    let cse = alloc_val(Cse { bod, bod_ref: mem::zeroed(), parents });
325    (*cse.as_ptr()).bod_ref = DLL::singleton(ParentPtr::CseBod(cse));
326    cse
327  }
328}
329
330#[inline]
331pub fn alloc_all(
332  uses: Uses,
333  dom: DAGPtr,
334  img: NonNull<Lam>,
335  parents: Option<NonNull<Parents>>,
336) -> NonNull<All> {
337  unsafe {
338    let all = alloc_val(All {
339      uses,
340      dom,
341      img,
342      copy: None,
343      dom_ref: mem::zeroed(),
344      img_ref: mem::zeroed(),
345      parents,
346    });
347    (*all.as_ptr()).dom_ref = DLL::singleton(ParentPtr::AllDom(all));
348    (*all.as_ptr()).img_ref = DLL::singleton(ParentPtr::AllImg(all));
349    all
350  }
351}
352
353#[inline]
354pub fn alloc_app(
355  fun: DAGPtr,
356  arg: DAGPtr,
357  parents: Option<NonNull<Parents>>,
358) -> NonNull<App> {
359  unsafe {
360    let app = alloc_val(App {
361      fun,
362      arg,
363      copy: None,
364      fun_ref: mem::zeroed(),
365      arg_ref: mem::zeroed(),
366      parents,
367    });
368    (*app.as_ptr()).fun_ref = DLL::singleton(ParentPtr::AppFun(app));
369    (*app.as_ptr()).arg_ref = DLL::singleton(ParentPtr::AppArg(app));
370    app
371  }
372}
373
374#[inline]
375pub fn alloc_ann(
376  typ: DAGPtr,
377  exp: DAGPtr,
378  parents: Option<NonNull<Parents>>,
379) -> NonNull<Ann> {
380  unsafe {
381    let ann = alloc_val(Ann {
382      typ,
383      exp,
384      copy: None,
385      typ_ref: mem::zeroed(),
386      exp_ref: mem::zeroed(),
387      parents,
388    });
389    (*ann.as_ptr()).typ_ref = DLL::singleton(ParentPtr::AnnTyp(ann));
390    (*ann.as_ptr()).exp_ref = DLL::singleton(ParentPtr::AnnExp(ann));
391    ann
392  }
393}
394
395#[inline]
396#[allow(clippy::too_many_arguments)]
397pub fn alloc_let(
398  uses: Uses,
399  typ: DAGPtr,
400  exp: DAGPtr,
401  bod: NonNull<Lam>,
402  parents: Option<NonNull<Parents>>,
403) -> NonNull<Let> {
404  unsafe {
405    let let_ = alloc_val(Let {
406      uses,
407      typ,
408      exp,
409      bod,
410      copy: None,
411      typ_ref: mem::zeroed(),
412      exp_ref: mem::zeroed(),
413      bod_ref: mem::zeroed(),
414      parents,
415    });
416    (*let_.as_ptr()).typ_ref = DLL::singleton(ParentPtr::LetTyp(let_));
417    (*let_.as_ptr()).exp_ref = DLL::singleton(ParentPtr::LetExp(let_));
418    (*let_.as_ptr()).bod_ref = DLL::singleton(ParentPtr::LetBod(let_));
419    let_
420  }
421}
422
423/// Auxiliary parent functions
424#[inline]
425pub fn get_parents(term: DAGPtr) -> Option<NonNull<Parents>> {
426  unsafe {
427    match term {
428      DAGPtr::Var(link) => (*link.as_ptr()).parents,
429      DAGPtr::Lam(link) => (*link.as_ptr()).parents,
430      DAGPtr::App(link) => (*link.as_ptr()).parents,
431      DAGPtr::All(link) => (*link.as_ptr()).parents,
432      DAGPtr::Slf(link) => (*link.as_ptr()).parents,
433      DAGPtr::Fix(link) => (*link.as_ptr()).parents,
434      DAGPtr::Dat(link) => (*link.as_ptr()).parents,
435      DAGPtr::Cse(link) => (*link.as_ptr()).parents,
436      DAGPtr::Ref(link) => (*link.as_ptr()).parents,
437      DAGPtr::Let(link) => (*link.as_ptr()).parents,
438      DAGPtr::Typ(link) => (*link.as_ptr()).parents,
439      DAGPtr::Ann(link) => (*link.as_ptr()).parents,
440      DAGPtr::Lit(link) => (*link.as_ptr()).parents,
441      DAGPtr::LTy(link) => (*link.as_ptr()).parents,
442      DAGPtr::Opr(link) => (*link.as_ptr()).parents,
443    }
444  }
445}
446
447#[inline]
448pub fn set_parents(term: DAGPtr, pref: Option<NonNull<Parents>>) {
449  unsafe {
450    match term {
451      DAGPtr::Var(link) => (*link.as_ptr()).parents = pref,
452      DAGPtr::Lam(link) => (*link.as_ptr()).parents = pref,
453      DAGPtr::App(link) => (*link.as_ptr()).parents = pref,
454      DAGPtr::All(link) => (*link.as_ptr()).parents = pref,
455      DAGPtr::Slf(link) => (*link.as_ptr()).parents = pref,
456      DAGPtr::Fix(link) => (*link.as_ptr()).parents = pref,
457      DAGPtr::Dat(link) => (*link.as_ptr()).parents = pref,
458      DAGPtr::Cse(link) => (*link.as_ptr()).parents = pref,
459      DAGPtr::Ref(link) => (*link.as_ptr()).parents = pref,
460      DAGPtr::Let(link) => (*link.as_ptr()).parents = pref,
461      DAGPtr::Typ(link) => (*link.as_ptr()).parents = pref,
462      DAGPtr::Ann(link) => (*link.as_ptr()).parents = pref,
463      DAGPtr::Lit(link) => (*link.as_ptr()).parents = pref,
464      DAGPtr::LTy(link) => (*link.as_ptr()).parents = pref,
465      DAGPtr::Opr(link) => (*link.as_ptr()).parents = pref,
466    }
467  }
468}
469
470/// Creates a child node by linking an existing pointer to a parent
471#[inline]
472pub fn install_child(parent: &mut ParentPtr, newchild: DAGPtr) {
473  unsafe {
474    match parent {
475      ParentPtr::LamBod(parent) => (*parent.as_ptr()).bod = newchild,
476      ParentPtr::SlfBod(parent) => (*parent.as_ptr()).bod = newchild,
477      ParentPtr::FixBod(parent) => (*parent.as_ptr()).bod = newchild,
478      ParentPtr::DatBod(parent) => (*parent.as_ptr()).bod = newchild,
479      ParentPtr::CseBod(parent) => (*parent.as_ptr()).bod = newchild,
480      ParentPtr::AppFun(parent) => (*parent.as_ptr()).fun = newchild,
481      ParentPtr::AppArg(parent) => (*parent.as_ptr()).arg = newchild,
482      ParentPtr::AllDom(parent) => (*parent.as_ptr()).dom = newchild,
483      ParentPtr::AllImg(parent) => match newchild {
484        DAGPtr::Lam(link) => (*parent.as_ptr()).img = link,
485        _ => panic!("Cannot install a non-lambda node as image"),
486      },
487      ParentPtr::AnnExp(parent) => (*parent.as_ptr()).exp = newchild,
488      ParentPtr::AnnTyp(parent) => (*parent.as_ptr()).typ = newchild,
489      ParentPtr::LetTyp(parent) => (*parent.as_ptr()).typ = newchild,
490      ParentPtr::LetExp(parent) => (*parent.as_ptr()).exp = newchild,
491      ParentPtr::LetBod(parent) => match newchild {
492        DAGPtr::Lam(link) => (*parent.as_ptr()).bod = link,
493        _ => panic!("Cannot install a non-lambda node as let body"),
494      },
495      ParentPtr::Root => (),
496    }
497  }
498}
499
500/// Replace one child w/another in the tree.
501pub fn replace_child(oldchild: DAGPtr, newchild: DAGPtr) {
502  unsafe {
503    let oldpref = get_parents(oldchild);
504    if let Some(old_parents) = oldpref {
505      let mut iter = (*old_parents.as_ptr()).iter();
506      let newpref = get_parents(newchild);
507      let mut last_old = None;
508      let first_new = newpref.map(DLL::first);
509      while let Some(parent) = iter.next() {
510        if iter.is_last() {
511          last_old = iter.this();
512          last_old.map_or((), |last_old| (*last_old.as_ptr()).next = first_new);
513        }
514        install_child(parent, newchild);
515      }
516      first_new.map_or((), |first_new| (*first_new.as_ptr()).prev = last_old);
517      set_parents(newchild, oldpref);
518    }
519    set_parents(oldchild, None);
520  }
521}
522
523/// Adds the node's parents to the DLL of parent nodes
524#[inline]
525pub fn add_to_parents(node: DAGPtr, plink: NonNull<Parents>) {
526  let parents = get_parents(node);
527  match parents {
528    Some(parents) => unsafe { (*parents.as_ptr()).merge(plink) },
529    None => set_parents(node, Some(plink)),
530  }
531}
532
533/// Free parentless nodes.
534pub fn free_dead_node(node: DAGPtr) {
535  unsafe {
536    match node {
537      DAGPtr::Lam(link) => {
538        let Lam { bod, bod_ref, .. } = &link.as_ref();
539        let new_bod_parents = bod_ref.unlink_node();
540        set_parents(*bod, new_bod_parents);
541        if new_bod_parents.is_none() {
542          free_dead_node(*bod)
543        }
544        Box::from_raw(link.as_ptr());
545      }
546      DAGPtr::Slf(mut link) => {
547        let Slf { bod, bod_ref, .. } = &link.as_mut();
548        let new_bod_parents = bod_ref.unlink_node();
549        set_parents(*bod, new_bod_parents);
550        if new_bod_parents.is_none() {
551          free_dead_node(*bod)
552        }
553        Box::from_raw(link.as_ptr());
554      }
555      DAGPtr::Fix(mut link) => {
556        let Fix { bod, bod_ref, .. } = &link.as_mut();
557        let new_bod_parents = bod_ref.unlink_node();
558        set_parents(*bod, new_bod_parents);
559        if new_bod_parents.is_none() {
560          free_dead_node(*bod)
561        }
562        Box::from_raw(link.as_ptr());
563      }
564      DAGPtr::Cse(link) => {
565        let Cse { bod, bod_ref, .. } = link.as_ref();
566        let new_bod_parents = bod_ref.unlink_node();
567        set_parents(*bod, new_bod_parents);
568        if new_bod_parents.is_none() {
569          free_dead_node(*bod)
570        }
571        Box::from_raw(link.as_ptr());
572      }
573      DAGPtr::Dat(link) => {
574        let Dat { bod, bod_ref, .. } = &link.as_ref();
575        let new_bod_parents = bod_ref.unlink_node();
576        set_parents(*bod, new_bod_parents);
577        if new_bod_parents.is_none() {
578          free_dead_node(*bod)
579        }
580        Box::from_raw(link.as_ptr());
581      }
582      DAGPtr::All(link) => {
583        let All { dom, img, dom_ref, img_ref, .. } = link.as_ref();
584        let img = DAGPtr::Lam(*img);
585        let new_dom_parents = dom_ref.unlink_node();
586        set_parents(*dom, new_dom_parents);
587        if new_dom_parents.is_none() {
588          free_dead_node(*dom)
589        }
590        let new_img_parents = img_ref.unlink_node();
591        set_parents(img, new_img_parents);
592        if new_img_parents.is_none() {
593          free_dead_node(img)
594        }
595        Box::from_raw(link.as_ptr());
596      }
597      DAGPtr::App(link) => {
598        let App { fun, arg, fun_ref, arg_ref, .. } = link.as_ref();
599        let new_fun_parents = fun_ref.unlink_node();
600        set_parents(*fun, new_fun_parents);
601        if new_fun_parents.is_none() {
602          free_dead_node(*fun)
603        }
604        let new_arg_parents = arg_ref.unlink_node();
605        set_parents(*arg, new_arg_parents);
606        if new_arg_parents.is_none() {
607          free_dead_node(*arg)
608        }
609        Box::from_raw(link.as_ptr());
610      }
611      DAGPtr::Ann(link) => {
612        let Ann { exp, typ, exp_ref, typ_ref, .. } = link.as_ref();
613        let new_exp_parents = exp_ref.unlink_node();
614        set_parents(*exp, new_exp_parents);
615        if new_exp_parents.is_none() {
616          free_dead_node(*exp)
617        }
618        let new_typ_parents = typ_ref.unlink_node();
619        set_parents(*typ, new_typ_parents);
620        if new_typ_parents.is_none() {
621          free_dead_node(*typ)
622        }
623        Box::from_raw(link.as_ptr());
624      }
625      DAGPtr::Let(link) => {
626        let Let { exp, typ, exp_ref, typ_ref, bod, bod_ref, .. } =
627          link.as_ref();
628        let bod = DAGPtr::Lam(*bod);
629        let new_exp_parents = exp_ref.unlink_node();
630        set_parents(*exp, new_exp_parents);
631        if new_exp_parents.is_none() {
632          free_dead_node(*exp)
633        }
634        let new_typ_parents = typ_ref.unlink_node();
635        set_parents(*typ, new_typ_parents);
636        if new_typ_parents.is_none() {
637          free_dead_node(*typ)
638        }
639        let new_bod_parents = bod_ref.unlink_node();
640        set_parents(bod, new_bod_parents);
641        if new_bod_parents.is_none() {
642          free_dead_node(bod)
643        }
644        Box::from_raw(link.as_ptr());
645      }
646      DAGPtr::Var(link) => {
647        let Var { binder, .. } = link.as_ref();
648        // only free Free variables, bound variables are freed with their binder
649        if let BinderPtr::Free = binder {
650          Box::from_raw(link.as_ptr());
651        }
652      }
653      DAGPtr::Ref(link) => {
654        Box::from_raw(link.as_ptr());
655      }
656      DAGPtr::Typ(link) => {
657        Box::from_raw(link.as_ptr());
658      }
659      DAGPtr::Lit(link) => {
660        Box::from_raw(link.as_ptr());
661      }
662      DAGPtr::LTy(link) => {
663        Box::from_raw(link.as_ptr());
664      }
665      DAGPtr::Opr(link) => {
666        Box::from_raw(link.as_ptr());
667      }
668    }
669  }
670}
671
672impl DAG {
673  /// Constructs a new DAG from an existing pointer
674  pub fn new(head: DAGPtr) -> DAG { DAG { head } }
675
676  /// Deallocates the DAG
677  pub fn free(self) {
678    match get_parents(self.head) {
679      None => (),
680      Some(pref) => unsafe {
681        Box::from_raw(pref.as_ptr());
682        set_parents(self.head, None);
683      },
684    }
685    free_dead_node(self.head)
686  }
687
688  /// Converts a DAG node into its Term equivalent
689  pub fn dag_ptr_to_term(
690    node: &DAGPtr,
691    map: &mut BTreeMap<*mut Var, u64>,
692    depth: u64,
693    re_rec: bool,
694  ) -> Term {
695    match node {
696      DAGPtr::Var(link) => {
697        let Var { nam, dep: var_depth, rec, .. } = unsafe { link.as_ref() };
698        if *rec && re_rec {
699          Term::Rec(Pos::None)
700        }
701        else if let Some(level) = map.get(&link.as_ptr()) {
702          Term::Var(Pos::None, nam.clone(), depth - level - 1)
703        }
704        else {
705          Term::Var(Pos::None, nam.clone(), *var_depth)
706        }
707      }
708      DAGPtr::Typ(_) => Term::Typ(Pos::None),
709      DAGPtr::LTy(link) => {
710        let LTy { lty, .. } = unsafe { link.as_ref() };
711        Term::LTy(Pos::None, *lty)
712      }
713      DAGPtr::Lit(link) => {
714        let Lit { lit, .. } = unsafe { link.as_ref() };
715        Term::Lit(Pos::None, lit.clone())
716      }
717      DAGPtr::Opr(link) => {
718        let Opr { opr, .. } = unsafe { link.as_ref() };
719        Term::Opr(Pos::None, opr.clone())
720      }
721      DAGPtr::Ref(link) => {
722        let Ref { nam, exp, ast, rec, .. } = unsafe { link.as_ref() };
723        if *rec && re_rec {
724          Term::Rec(Pos::None)
725        }
726        else {
727          Term::Ref(Pos::None, nam.clone(), *exp, *ast)
728        }
729      }
730      DAGPtr::Lam(link) => {
731        let Lam { var, bod, .. } = unsafe { &mut *link.as_ptr() };
732        let nam = var.nam.clone();
733        map.insert(var, depth);
734        let body = DAG::dag_ptr_to_term(bod, map, depth + 1, re_rec);
735        Term::Lam(Pos::None, nam, Box::new(body))
736      }
737      DAGPtr::Slf(link) => {
738        let Slf { var, bod, .. } = unsafe { &mut *link.as_ptr() };
739        let nam = var.nam.clone();
740        map.insert(var, depth);
741        let body = DAG::dag_ptr_to_term(bod, map, depth + 1, re_rec);
742        Term::Slf(Pos::None, nam, Box::new(body))
743      }
744      DAGPtr::Fix(_) => {
745        panic!("Fix conversion TODO")
746      }
747      DAGPtr::Cse(link) => {
748        let Cse { bod, .. } = unsafe { link.as_ref() };
749        Term::Cse(
750          Pos::None,
751          Box::new(DAG::dag_ptr_to_term(bod, map, depth, re_rec)),
752        )
753      }
754      DAGPtr::Dat(link) => {
755        let Dat { bod, .. } = unsafe { link.as_ref() };
756        Term::Dat(
757          Pos::None,
758          Box::new(DAG::dag_ptr_to_term(bod, map, depth, re_rec)),
759        )
760      }
761      DAGPtr::App(link) => {
762        let App { fun, arg, .. } = unsafe { link.as_ref() };
763        let fun_map = &mut map.clone();
764        Term::App(
765          Pos::None,
766          Box::new((
767            DAG::dag_ptr_to_term(fun, fun_map, depth, re_rec),
768            DAG::dag_ptr_to_term(arg, map, depth, re_rec),
769          )),
770        )
771      }
772      DAGPtr::Ann(link) => {
773        let Ann { typ, exp, .. } = unsafe { link.as_ref() };
774        let typ_map = &mut map.clone();
775        Term::Ann(
776          Pos::None,
777          Box::new((
778            DAG::dag_ptr_to_term(typ, typ_map, depth, re_rec),
779            DAG::dag_ptr_to_term(exp, map, depth, re_rec),
780          )),
781        )
782      }
783      DAGPtr::All(link) => {
784        let All { uses, dom, img: lam_link, .. } =
785          unsafe { &mut *link.as_ptr() };
786        let Lam { var, bod: img, .. } = unsafe { &mut *lam_link.as_ptr() };
787        let nam = var.nam.clone();
788        let dom_map = &mut map.clone();
789        map.insert(var, depth);
790        Term::All(
791          Pos::None,
792          *uses,
793          nam,
794          Box::new((
795            DAG::dag_ptr_to_term(dom, dom_map, depth, re_rec),
796            DAG::dag_ptr_to_term(img, map, depth + 1, re_rec),
797          )),
798        )
799      }
800      DAGPtr::Let(link) => {
801        let Let { uses, typ, exp, bod: lam_link, .. } =
802          unsafe { &mut *link.as_ptr() };
803        let Lam { var, bod, .. } = unsafe { &mut *lam_link.as_ptr() };
804        let nam = var.nam.clone();
805        let typ_map = &mut map.clone();
806        let exp_map = &mut map.clone();
807        let mut exp_depth = depth;
808        let (rec, exp) = match exp {
809          DAGPtr::Fix(link) => unsafe {
810            let Fix { var, bod, .. } = &mut *link.as_ptr();
811            exp_map.insert(var, depth);
812            exp_depth += 1;
813            (true, bod)
814          },
815          _ => (false, exp),
816        };
817        map.insert(var, depth);
818        Term::Let(
819          Pos::None,
820          rec,
821          *uses,
822          nam,
823          Box::new((
824            DAG::dag_ptr_to_term(typ, typ_map, depth, re_rec),
825            DAG::dag_ptr_to_term(exp, exp_map, exp_depth, re_rec),
826            DAG::dag_ptr_to_term(bod, map, depth + 1, re_rec),
827          )),
828        )
829      }
830    }
831  }
832
833  /// Converts the entire DAG into its Term equivalent
834  pub fn to_term(&self, re_rec: bool) -> Term {
835    let mut map = BTreeMap::new();
836    DAG::dag_ptr_to_term(&self.head, &mut map, 0, re_rec)
837  }
838
839  /// Converts a Term into a DAG
840  pub fn from_term(tree: &Term) -> Self {
841    let root = alloc_val(DLL::singleton(ParentPtr::Root));
842    DAG::new(DAG::from_term_inner(tree, 0, BTreeMap::new(), Some(root), None))
843  }
844
845  /// Converts a Def into a term and then into a DAG
846  pub fn from_def(def: &Def, name: Name) -> Self {
847    let root = alloc_val(DLL::singleton(ParentPtr::Root));
848    let (d, _, a) = def.embed();
849    let def_cid = d.cid();
850    let ast_cid = a.cid();
851    DAG::new(DAG::from_term_inner(
852      &def.term,
853      0,
854      BTreeMap::new(),
855      Some(root),
856      Some((name, def_cid, ast_cid)),
857    ))
858  }
859
860  pub fn from_ref(
861    def: &Def,
862    name: Name,
863    def_cid: Cid,
864    ast_cid: Cid,
865    parents: Option<NonNull<Parents>>,
866  ) -> DAGPtr {
867    DAG::from_term_inner(
868      &def.term,
869      0,
870      BTreeMap::new(),
871      parents,
872      Some((name, def_cid, ast_cid)),
873    )
874  }
875
876  /// Converts a Term into its DAG-node equivalent
877  pub fn from_term_inner(
878    tree: &Term,
879    depth: u64,
880    mut ctx: BTreeMap<usize, DAGPtr>,
881    parents: Option<NonNull<Parents>>,
882    rec_ref: Option<(Name, Cid, Cid)>,
883  ) -> DAGPtr {
884    match tree {
885      Term::Rec(_) => match rec_ref {
886        Some((nam, exp, ast)) => {
887          let ref_ = alloc_val(Ref { nam, rec: true, exp, ast, parents });
888          DAGPtr::Ref(ref_)
889        }
890        None => {
891          let var = alloc_val(Var {
892            nam: Name::from("#^"),
893            rec: true,
894            dep: depth,
895            binder: BinderPtr::Free,
896            parents,
897          });
898          DAGPtr::Var(var)
899        }
900      },
901      Term::Var(_, name, idx) => {
902        let dep = (depth - 1 - *idx) as usize;
903        match ctx.get(&dep) {
904          Some(val) => {
905            if let Some(parents) = parents {
906              DLL::concat(parents, get_parents(*val));
907              set_parents(*val, Some(parents));
908            }
909            *val
910          }
911          None => {
912            if depth < 1 + idx {
913              panic!("Negative index found.")
914            }
915            let var = alloc_val(Var {
916              nam: name.clone(),
917              rec: false,
918              dep: depth - 1 - idx,
919              binder: BinderPtr::Free,
920              parents,
921            });
922            DAGPtr::Var(var)
923          }
924        }
925      }
926      Term::Typ(_) => DAGPtr::Typ(alloc_val(Typ { parents })),
927      Term::LTy(_, lty) => DAGPtr::LTy(alloc_val(LTy { lty: *lty, parents })),
928      Term::Lit(_, lit) => {
929        DAGPtr::Lit(alloc_val(Lit { lit: lit.clone(), parents }))
930      }
931      Term::Opr(_, opr) => DAGPtr::Opr(alloc_val(Opr { opr: opr.clone(), parents })),
932      Term::Ref(_, nam, exp, ast) => DAGPtr::Ref(alloc_val(Ref {
933        nam: nam.clone(),
934        rec: false,
935        exp: *exp,
936        ast: *ast,
937        parents,
938      })),
939      Term::Lam(_, nam, bod) => unsafe {
940        let lam = alloc_lam(nam.clone(), 0, mem::zeroed(), parents);
941        let Lam { var, bod_ref, .. } = &mut *lam.as_ptr();
942        ctx.insert(depth as usize, DAGPtr::Var(NonNull::new(var).unwrap()));
943        let bod = DAG::from_term_inner(
944          &**bod,
945          depth + 1,
946          ctx,
947          NonNull::new(bod_ref),
948          rec_ref.clone(),
949        );
950        (*lam.as_ptr()).bod = bod;
951        DAGPtr::Lam(lam)
952      },
953      Term::Slf(_, nam, bod) => unsafe {
954        let slf = alloc_slf(nam.clone(), 0, mem::zeroed(), parents);
955        let Slf { var, bod_ref, .. } = &mut *slf.as_ptr();
956        ctx.insert(depth as usize, DAGPtr::Var(NonNull::new(var).unwrap()));
957        let bod = DAG::from_term_inner(
958          &**bod,
959          depth + 1,
960          ctx,
961          NonNull::new(bod_ref),
962          rec_ref.clone(),
963        );
964        (*slf.as_ptr()).bod = bod;
965        DAGPtr::Slf(slf)
966      },
967      Term::Dat(_, bod) => unsafe {
968        let dat = alloc_dat(mem::zeroed(), parents);
969        let Dat { bod_ref, .. } = &mut *dat.as_ptr();
970        let bod = DAG::from_term_inner(
971          &**bod,
972          depth,
973          ctx,
974          NonNull::new(bod_ref),
975          rec_ref.clone(),
976        );
977        (*dat.as_ptr()).bod = bod;
978        DAGPtr::Dat(dat)
979      },
980      Term::Cse(_, bod) => unsafe {
981        let cse = alloc_cse(mem::zeroed(), parents);
982        let Cse { bod_ref, .. } = &mut *cse.as_ptr();
983        let bod = DAG::from_term_inner(
984          &**bod,
985          depth,
986          ctx,
987          NonNull::new(bod_ref),
988          rec_ref.clone(),
989        );
990        (*cse.as_ptr()).bod = bod;
991        DAGPtr::Cse(cse)
992      },
993      Term::All(_, uses, nam, dom_img) => unsafe {
994        let (dom, img) = &**dom_img;
995        let all = alloc_all(*uses, mem::zeroed(), NonNull::dangling(), parents);
996        let All { dom_ref, img_ref, .. } = &mut *all.as_ptr();
997        let lam =
998          alloc_lam(nam.clone(), 0, mem::zeroed(), NonNull::new(img_ref));
999        let Lam { var, bod_ref, .. } = &mut *lam.as_ptr();
1000        let mut img_ctx = ctx.clone();
1001        let dom = DAG::from_term_inner(
1002          dom,
1003          depth,
1004          ctx,
1005          NonNull::new(dom_ref),
1006          rec_ref.clone(),
1007        );
1008        img_ctx.insert(depth as usize, DAGPtr::Var(NonNull::new(var).unwrap()));
1009        let img = DAG::from_term_inner(
1010          img,
1011          depth + 1,
1012          img_ctx,
1013          NonNull::new(bod_ref),
1014          rec_ref.clone(),
1015        );
1016        (*all.as_ptr()).dom = dom;
1017        (*all.as_ptr()).img = lam;
1018        (*lam.as_ptr()).bod = img;
1019        DAGPtr::All(all)
1020      },
1021      Term::App(_, fun_arg) => unsafe {
1022        let (fun, arg) = &**fun_arg;
1023        let app = alloc_app(mem::zeroed(), mem::zeroed(), parents);
1024        let App { fun_ref, arg_ref, .. } = &mut *app.as_ptr();
1025        let fun = DAG::from_term_inner(
1026          fun,
1027          depth,
1028          ctx.clone(),
1029          NonNull::new(fun_ref),
1030          rec_ref.clone(),
1031        );
1032        let arg = DAG::from_term_inner(
1033          arg,
1034          depth,
1035          ctx,
1036          NonNull::new(arg_ref),
1037          rec_ref.clone(),
1038        );
1039        (*app.as_ptr()).fun = fun;
1040        (*app.as_ptr()).arg = arg;
1041        DAGPtr::App(app)
1042      },
1043      Term::Ann(_, typ_exp) => unsafe {
1044        let (typ, exp) = &**typ_exp;
1045        let ann = alloc_ann(mem::zeroed(), mem::zeroed(), parents);
1046        let Ann { typ_ref, exp_ref, .. } = &mut *ann.as_ptr();
1047        let typ = DAG::from_term_inner(
1048          typ,
1049          depth,
1050          ctx.clone(),
1051          NonNull::new(typ_ref),
1052          rec_ref.clone(),
1053        );
1054        let exp = DAG::from_term_inner(
1055          exp,
1056          depth,
1057          ctx,
1058          NonNull::new(exp_ref),
1059          rec_ref.clone(),
1060        );
1061        (*ann.as_ptr()).typ = typ;
1062        (*ann.as_ptr()).exp = exp;
1063        DAGPtr::Ann(ann)
1064      },
1065      Term::Let(_, rec, uses, nam, typ_exp_bod) => unsafe {
1066        let (typ, exp, bod) = &**typ_exp_bod;
1067        // Allocates the `Let` node and a `Lam` node for `bod`
1068        let let_ = alloc_let(
1069          *uses,
1070          mem::zeroed(),
1071          mem::zeroed(),
1072          NonNull::dangling(),
1073          parents,
1074        );
1075        let Let { typ_ref, exp_ref, bod_ref, .. } = &mut *let_.as_ptr();
1076        let lam =
1077          alloc_lam(nam.clone(), 0, mem::zeroed(), NonNull::new(bod_ref));
1078        let Lam { var: lam_var, bod_ref: lam_bod_ref, .. } = &mut *lam.as_ptr();
1079        // Sets up the context for `typ` and `bod` conversion
1080        let typ_ctx = ctx.clone();
1081        let mut bod_ctx = ctx.clone();
1082        bod_ctx
1083          .insert(depth as usize, DAGPtr::Var(NonNull::new(lam_var).unwrap()));
1084        // Convert `typ` and `bod` to DAG and add it to the newly created `Let`
1085        // node
1086        let typ = DAG::from_term_inner(
1087          typ,
1088          depth,
1089          typ_ctx,
1090          NonNull::new(typ_ref),
1091          rec_ref.clone(),
1092        );
1093        let bod = DAG::from_term_inner(
1094          bod,
1095          depth + 1,
1096          bod_ctx,
1097          NonNull::new(lam_bod_ref),
1098          rec_ref.clone(),
1099        );
1100        (*let_.as_ptr()).typ = typ;
1101        (*let_.as_ptr()).bod = lam;
1102        (*lam.as_ptr()).bod = bod;
1103        // Do the same for `exp`, but set a `Fix` before if this is a recursive
1104        // `Let`
1105        if *rec {
1106          let fix =
1107            alloc_fix(nam.clone(), 0, mem::zeroed(), NonNull::new(exp_ref));
1108          let Fix { var: fix_var, bod_ref: fix_bod_ref, .. } =
1109            &mut *fix.as_ptr();
1110          ctx.insert(
1111            depth as usize,
1112            DAGPtr::Var(NonNull::new(fix_var).unwrap()),
1113          );
1114          let exp = DAG::from_term_inner(
1115            exp,
1116            depth + 1,
1117            ctx,
1118            NonNull::new(fix_bod_ref),
1119            rec_ref.clone(),
1120          );
1121          (*let_.as_ptr()).exp = DAGPtr::Fix(fix);
1122          (*fix.as_ptr()).bod = exp;
1123        }
1124        else {
1125          let exp = DAG::from_term_inner(
1126            exp,
1127            depth,
1128            ctx,
1129            NonNull::new(exp_ref),
1130            rec_ref.clone(),
1131          );
1132          (*let_.as_ptr()).exp = exp;
1133        }
1134        DAGPtr::Let(let_)
1135      },
1136    }
1137  }
1138
1139  /// Creates a new DAG from a subsection
1140  pub fn from_subdag(
1141    node: DAGPtr,
1142    map: &mut BTreeMap<DAGPtr, DAGPtr>,
1143    parents: Option<NonNull<Parents>>,
1144  ) -> DAGPtr {
1145    // If the node is in the hash map then it was already copied,
1146    // so we update the parent list and return the copy
1147    if let Some(copy) = (*map).get(&node) {
1148      if let Some(parents) = parents {
1149        DLL::concat(parents, get_parents(*copy));
1150        set_parents(*copy, Some(parents));
1151      }
1152      return *copy;
1153    }
1154    // Otherwise create a new DAG node and add it to the map
1155    let new_node = match node {
1156      DAGPtr::Var(link) => unsafe {
1157        let Var { nam, dep, rec, .. } = &*link.as_ptr();
1158        let var = alloc_val(Var {
1159          nam: nam.clone(),
1160          rec: *rec,
1161          dep: *dep,
1162          binder: BinderPtr::Free,
1163          parents,
1164        });
1165        DAGPtr::Var(var)
1166      },
1167      DAGPtr::Ref(link) => unsafe {
1168        let Ref { nam, exp, ast, rec, .. } = &*link.as_ptr();
1169        let node = alloc_val(Ref {
1170          nam: nam.clone(),
1171          rec: *rec,
1172          exp: *exp,
1173          ast: *ast,
1174          parents,
1175        });
1176        DAGPtr::Ref(node)
1177      },
1178      DAGPtr::Lam(link) => unsafe {
1179        let Lam { var, bod, .. } = &mut *link.as_ptr();
1180        let lam = alloc_lam(var.nam.clone(), var.dep, mem::zeroed(), parents);
1181        let Lam { var: new_var, bod: new_bod, bod_ref, .. } =
1182          &mut *lam.as_ptr();
1183        map.insert(
1184          DAGPtr::Var(NonNull::new(var).unwrap()),
1185          DAGPtr::Var(NonNull::new(new_var).unwrap()),
1186        );
1187        *new_bod = DAG::from_subdag(*bod, map, NonNull::new(bod_ref));
1188        DAGPtr::Lam(lam)
1189      },
1190      DAGPtr::Slf(link) => unsafe {
1191        let Slf { var, bod, .. } = &mut *link.as_ptr();
1192        let slf = alloc_slf(var.nam.clone(), var.dep, mem::zeroed(), parents);
1193        let Slf { var: new_var, bod: new_bod, bod_ref, .. } =
1194          &mut *slf.as_ptr();
1195        map.insert(
1196          DAGPtr::Var(NonNull::new(var).unwrap()),
1197          DAGPtr::Var(NonNull::new(new_var).unwrap()),
1198        );
1199        *new_bod = DAG::from_subdag(*bod, map, NonNull::new(bod_ref));
1200        DAGPtr::Slf(slf)
1201      },
1202      DAGPtr::Fix(link) => unsafe {
1203        let Fix { var, bod, .. } = &mut *link.as_ptr();
1204        let fix = alloc_fix(var.nam.clone(), var.dep, mem::zeroed(), parents);
1205        let Fix { var: new_var, bod: new_bod, bod_ref, .. } =
1206          &mut *fix.as_ptr();
1207        map.insert(
1208          DAGPtr::Var(NonNull::new(var).unwrap()),
1209          DAGPtr::Var(NonNull::new(new_var).unwrap()),
1210        );
1211        *new_bod = DAG::from_subdag(*bod, map, NonNull::new(bod_ref));
1212        DAGPtr::Fix(fix)
1213      },
1214      DAGPtr::Cse(link) => unsafe {
1215        let Cse { bod, .. } = &mut *link.as_ptr();
1216        let cse = alloc_cse(mem::zeroed(), parents);
1217        let Cse { bod: new_bod, bod_ref, .. } = &mut *cse.as_ptr();
1218        *new_bod = DAG::from_subdag(*bod, map, NonNull::new(bod_ref));
1219        DAGPtr::Cse(cse)
1220      },
1221      DAGPtr::Dat(link) => unsafe {
1222        let Dat { bod, .. } = &mut *link.as_ptr();
1223        let dat = alloc_dat(mem::zeroed(), parents);
1224        let Dat { bod: new_bod, bod_ref, .. } = &mut *dat.as_ptr();
1225        *new_bod = DAG::from_subdag(*bod, map, NonNull::new(bod_ref));
1226        DAGPtr::Dat(dat)
1227      },
1228      DAGPtr::App(link) => unsafe {
1229        let App { fun, arg, .. } = &mut *link.as_ptr();
1230        let app = alloc_app(mem::zeroed(), mem::zeroed(), parents);
1231        let App { fun: new_fun, fun_ref, arg: new_arg, arg_ref, .. } =
1232          &mut *app.as_ptr();
1233        *new_fun = DAG::from_subdag(*fun, map, NonNull::new(fun_ref));
1234        *new_arg = DAG::from_subdag(*arg, map, NonNull::new(arg_ref));
1235        DAGPtr::App(app)
1236      },
1237      DAGPtr::All(link) => unsafe {
1238        let All { uses, dom, img, .. } = &mut *link.as_ptr();
1239        let all = alloc_all(*uses, mem::zeroed(), NonNull::dangling(), parents);
1240        let All { dom: new_dom, dom_ref, img: new_img, img_ref, .. } =
1241          &mut *all.as_ptr();
1242        *new_dom = DAG::from_subdag(*dom, map, NonNull::new(dom_ref));
1243        *new_img =
1244          match DAG::from_subdag(DAGPtr::Lam(*img), map, NonNull::new(img_ref))
1245          {
1246            DAGPtr::Lam(link) => link,
1247            _ => panic!("Clone implementation incorrect"),
1248          };
1249        DAGPtr::All(all)
1250      },
1251      DAGPtr::Let(link) => unsafe {
1252        let Let { uses, typ, exp, bod, .. } = &mut *link.as_ptr();
1253        let let_ = alloc_let(
1254          *uses,
1255          mem::zeroed(),
1256          mem::zeroed(),
1257          NonNull::dangling(),
1258          parents,
1259        );
1260        let Let {
1261          typ: new_typ,
1262          typ_ref,
1263          exp: new_exp,
1264          exp_ref,
1265          bod: new_bod,
1266          bod_ref,
1267          ..
1268        } = &mut *let_.as_ptr();
1269        *new_exp = DAG::from_subdag(*exp, map, NonNull::new(exp_ref));
1270        *new_typ = DAG::from_subdag(*typ, map, NonNull::new(typ_ref));
1271        *new_bod =
1272          match DAG::from_subdag(DAGPtr::Lam(*bod), map, NonNull::new(bod_ref))
1273          {
1274            DAGPtr::Lam(link) => link,
1275            _ => panic!("Clone implementation incorrect"),
1276          };
1277        DAGPtr::Let(let_)
1278      },
1279      DAGPtr::Ann(link) => unsafe {
1280        let Ann { typ, exp, .. } = &mut *link.as_ptr();
1281        let ann = alloc_ann(mem::zeroed(), mem::zeroed(), parents);
1282        let Ann { typ: new_typ, typ_ref, exp: new_exp, exp_ref, .. } =
1283          &mut *ann.as_ptr();
1284        *new_typ = DAG::from_subdag(*typ, map, NonNull::new(typ_ref));
1285        *new_exp = DAG::from_subdag(*exp, map, NonNull::new(exp_ref));
1286        DAGPtr::Ann(ann)
1287      },
1288      DAGPtr::Lit(link) => unsafe {
1289        let Lit { lit, .. } = &*link.as_ptr();
1290        let node = alloc_val(Lit { lit: lit.clone(), parents });
1291        DAGPtr::Lit(node)
1292      },
1293      DAGPtr::LTy(link) => unsafe {
1294        let LTy { lty, .. } = *link.as_ptr();
1295        let node = alloc_val(LTy { lty, parents });
1296        DAGPtr::LTy(node)
1297      },
1298      DAGPtr::Opr(link) => unsafe {
1299        let Opr { opr, .. } = &*link.as_ptr();
1300        let node = alloc_val(Opr { opr: opr.clone(), parents });
1301        DAGPtr::Opr(node)
1302      },
1303      DAGPtr::Typ(_) => {
1304        let node = alloc_val(Typ { parents });
1305        DAGPtr::Typ(node)
1306      } // _ => panic!("TODO"),
1307    };
1308    // Map `node` to `new_node`
1309    map.insert(node, new_node);
1310    new_node
1311  }
1312
1313  /// Substitution of free variable
1314  pub fn subst(&mut self, idx: u64, val: DAGPtr) {
1315    pub fn go(node: DAGPtr, idx: u64, val: DAGPtr) {
1316      match node {
1317        DAGPtr::Var(link) => {
1318          let Var { dep, binder, .. } = unsafe { &*link.as_ptr() };
1319          if *dep == idx {
1320            match binder {
1321              BinderPtr::Free => (),
1322              _ => panic!("Variable not free"),
1323            }
1324            replace_child(node, val);
1325            free_dead_node(node);
1326          }
1327        }
1328        DAGPtr::Lam(link) => {
1329          let Lam { bod, .. } = unsafe { &*link.as_ptr() };
1330          go(*bod, idx, val)
1331        }
1332        DAGPtr::Slf(link) => {
1333          let Slf { bod, .. } = unsafe { &*link.as_ptr() };
1334          go(*bod, idx, val)
1335        }
1336        DAGPtr::Fix(link) => {
1337          let Fix { bod, .. } = unsafe { &*link.as_ptr() };
1338          go(*bod, idx, val)
1339        }
1340        DAGPtr::Cse(link) => {
1341          let Cse { bod, .. } = unsafe { &*link.as_ptr() };
1342          go(*bod, idx, val)
1343        }
1344        DAGPtr::Dat(link) => {
1345          let Dat { bod, .. } = unsafe { &*link.as_ptr() };
1346          go(*bod, idx, val)
1347        }
1348        DAGPtr::App(link) => {
1349          let App { fun, arg, .. } = unsafe { &*link.as_ptr() };
1350          go(*fun, idx, val);
1351          go(*arg, idx, val)
1352        }
1353        DAGPtr::All(link) => {
1354          let All { dom, img, .. } = unsafe { &*link.as_ptr() };
1355          go(*dom, idx, val);
1356          go(DAGPtr::Lam(*img), idx, val)
1357        }
1358        DAGPtr::Let(link) => {
1359          let Let { typ, exp, bod, .. } = unsafe { &*link.as_ptr() };
1360          go(*typ, idx, val);
1361          go(*exp, idx, val);
1362          go(DAGPtr::Lam(*bod), idx, val)
1363        }
1364        DAGPtr::Ann(link) => {
1365          let Ann { typ, exp, .. } = unsafe { &*link.as_ptr() };
1366          go(*typ, idx, val);
1367          go(*exp, idx, val)
1368        }
1369        _ => (),
1370      }
1371    }
1372    go(self.head, idx, val)
1373  }
1374}
1375
1376impl Clone for DAG {
1377  fn clone(&self) -> Self {
1378    let mut map: BTreeMap<DAGPtr, DAGPtr> = BTreeMap::new();
1379    let root = alloc_val(DLL::singleton(ParentPtr::Root));
1380    DAG::new(DAG::from_subdag(self.head, &mut map, Some(root)))
1381  }
1382}
1383
1384impl fmt::Debug for DAG {
1385  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1386    #[inline]
1387    fn format_uplink(p: ParentPtr) -> String {
1388      match p {
1389        ParentPtr::Root => String::from("ROOT"),
1390        ParentPtr::LamBod(link) => format!("LamBod<{:?}>", link.as_ptr()),
1391        ParentPtr::SlfBod(link) => format!("SlfBod<{:?}>", link.as_ptr()),
1392        ParentPtr::FixBod(link) => format!("FixBod<{:?}>", link.as_ptr()),
1393        ParentPtr::DatBod(link) => format!("DatBod<{:?}>", link.as_ptr()),
1394        ParentPtr::CseBod(link) => format!("CseBod<{:?}>", link.as_ptr()),
1395        ParentPtr::AppFun(link) => format!("AppFun<{:?}>", link.as_ptr()),
1396        ParentPtr::AppArg(link) => format!("AppArg<{:?}>", link.as_ptr()),
1397        ParentPtr::AllDom(link) => format!("AllDom<{:?}>", link.as_ptr()),
1398        ParentPtr::AllImg(link) => format!("AllImg<{:?}>", link.as_ptr()),
1399        ParentPtr::AnnExp(link) => format!("AnnExp<{:?}>", link.as_ptr()),
1400        ParentPtr::AnnTyp(link) => format!("AnnTyp<{:?}>", link.as_ptr()),
1401        ParentPtr::LetTyp(link) => format!("LetTyp<{:?}>", link.as_ptr()),
1402        ParentPtr::LetExp(link) => format!("LetExp<{:?}>", link.as_ptr()),
1403        ParentPtr::LetBod(link) => format!("LetBod<{:?}>", link.as_ptr()),
1404      }
1405    }
1406    #[inline]
1407    fn format_parents(dll: Option<NonNull<Parents>>) -> String {
1408      match dll {
1409        Some(dll) => unsafe {
1410          let mut iter = (*dll.as_ptr()).iter();
1411          let head =
1412            &iter.next().map_or(String::from(""), |head| format_uplink(*head));
1413          let mut msg = String::from("[ ") + head;
1414          for val in iter {
1415            msg = msg + " <-> " + &format_uplink(*val);
1416          }
1417          msg + " ]"
1418        },
1419        _ => String::from("[]"),
1420      }
1421    }
1422    fn go(term: DAGPtr, set: &mut BTreeSet<usize>) -> String {
1423      match term {
1424        DAGPtr::Var(link) => {
1425          let Var { nam, parents, binder, dep, .. } = unsafe { link.as_ref() };
1426          let binder = match binder {
1427            BinderPtr::Free => format!("Free<{}>", *dep),
1428            BinderPtr::Lam(link) => format!("Lam<{:?}>", link.as_ptr()),
1429            BinderPtr::Slf(link) => format!("Slf<{:?}>", link.as_ptr()),
1430            BinderPtr::Fix(link) => format!("Fix<{:?}>", link.as_ptr()),
1431          };
1432          if set.get(&(link.as_ptr() as usize)).is_none() {
1433            set.insert(link.as_ptr() as usize);
1434            format!(
1435              "\nVar<{:?}> {} bound at {} parents: {}",
1436              link.as_ptr(),
1437              binder,
1438              nam,
1439              format_parents(*parents)
1440            )
1441          }
1442          else {
1443            format!("\nSHARE<{:?}>", link.as_ptr())
1444          }
1445        }
1446        DAGPtr::Typ(link) => {
1447          let Typ { parents, .. } = unsafe { link.as_ref() };
1448          format!(
1449            "\nTyp<{:?}> parents: {}",
1450            (link.as_ptr()),
1451            format_parents(*parents)
1452          )
1453        }
1454        DAGPtr::LTy(link) => {
1455          let LTy { parents, .. } = unsafe { link.as_ref() };
1456          format!(
1457            "\nLTy<{:?}> parents: {}",
1458            (link.as_ptr()),
1459            format_parents(*parents)
1460          )
1461        }
1462        DAGPtr::Lit(link) => {
1463          let Lit { parents, .. } = unsafe { link.as_ref() };
1464          format!(
1465            "\nLit<{:?}> parents: {}",
1466            (link.as_ptr()),
1467            format_parents(*parents)
1468          )
1469        }
1470        DAGPtr::Opr(link) => {
1471          let Opr { parents, .. } = unsafe { link.as_ref() };
1472          format!(
1473            "\nOpr<{:?}> parents: {}",
1474            (link.as_ptr()),
1475            format_parents(*parents)
1476          )
1477        }
1478        DAGPtr::Ref(link) => {
1479          let Ref { nam, parents, .. } = unsafe { link.as_ref() };
1480          format!(
1481            "\nRef<{:?}> {} parents: {}",
1482            (link.as_ptr()),
1483            nam,
1484            format_parents(*parents)
1485          )
1486        }
1487        DAGPtr::Lam(link) => {
1488          if set.get(&(link.as_ptr() as usize)).is_none() {
1489            let Lam { var, parents, bod, .. } = unsafe { link.as_ref() };
1490            let name = var.nam.clone();
1491            set.insert(link.as_ptr() as usize);
1492            format!(
1493              "\nLam<{:?}> {} parents: {}{}",
1494              link.as_ptr(),
1495              name,
1496              format_parents(*parents),
1497              go(*bod, set)
1498            )
1499          }
1500          else {
1501            format!("\nSHARE<{:?}>", link.as_ptr())
1502          }
1503        }
1504        DAGPtr::Slf(link) => {
1505          if set.get(&(link.as_ptr() as usize)).is_none() {
1506            let Slf { var, parents, bod, .. } = unsafe { link.as_ref() };
1507            let name = var.nam.clone();
1508            set.insert(link.as_ptr() as usize);
1509            format!(
1510              "\nSlf<{:?}> {} parents: {}{}",
1511              link.as_ptr(),
1512              name,
1513              format_parents(*parents),
1514              go(*bod, set)
1515            )
1516          }
1517          else {
1518            format!("\nSHARE<{:?}>", link.as_ptr())
1519          }
1520        }
1521        DAGPtr::Fix(link) => {
1522          if set.get(&(link.as_ptr() as usize)).is_none() {
1523            let Fix { var, parents, bod, .. } = unsafe { link.as_ref() };
1524            let name = var.nam.clone();
1525            set.insert(link.as_ptr() as usize);
1526            format!(
1527              "\nFix<{:?}> {} parents: {}{}",
1528              link.as_ptr(),
1529              name,
1530              format_parents(*parents),
1531              go(*bod, set)
1532            )
1533          }
1534          else {
1535            format!("\nSHARE<{:?}>", link.as_ptr())
1536          }
1537        }
1538        DAGPtr::Dat(link) => {
1539          if set.get(&(link.as_ptr() as usize)).is_none() {
1540            let Dat { parents, bod, .. } = unsafe { link.as_ref() };
1541            set.insert(link.as_ptr() as usize);
1542            format!(
1543              "\nDat<{:?}> parents: {}{}",
1544              link.as_ptr(),
1545              format_parents(*parents),
1546              go(*bod, set)
1547            )
1548          }
1549          else {
1550            format!("\nSHARE<{:?}>", link.as_ptr())
1551          }
1552        }
1553        DAGPtr::Cse(link) => {
1554          if set.get(&(link.as_ptr() as usize)).is_none() {
1555            let Cse { parents, bod, .. } = unsafe { link.as_ref() };
1556            set.insert(link.as_ptr() as usize);
1557            format!(
1558              "\nCse<{:?}> parents: {}{}",
1559              link.as_ptr(),
1560              format_parents(*parents),
1561              go(*bod, set)
1562            )
1563          }
1564          else {
1565            format!("\nSHARE<{:?}>", link.as_ptr())
1566          }
1567        }
1568        DAGPtr::App(link) => {
1569          if set.get(&(link.as_ptr() as usize)).is_none() {
1570            set.insert(link.as_ptr() as usize);
1571            let App { fun, arg, parents, copy, .. } = unsafe { link.as_ref() };
1572            let copy = copy.map(|link| link.as_ptr() as usize);
1573            format!(
1574              "\nApp<{:?}> parents: {} copy: {:?}{}{}",
1575              link.as_ptr(),
1576              format_parents(*parents),
1577              copy,
1578              go(*fun, set),
1579              go(*arg, set)
1580            )
1581          }
1582          else {
1583            format!("\nSHARE<{}>", link.as_ptr() as usize)
1584          }
1585        }
1586        DAGPtr::Ann(link) => {
1587          if set.get(&(link.as_ptr() as usize)).is_none() {
1588            set.insert(link.as_ptr() as usize);
1589            let Ann { typ, exp, parents, copy, .. } = unsafe { link.as_ref() };
1590            let copy = copy.map(|link| link.as_ptr() as usize);
1591            format!(
1592              "\nAnn<{:?}> parents: {} copy: {:?}{}{}",
1593              link.as_ptr(),
1594              format_parents(*parents),
1595              copy,
1596              go(*typ, set),
1597              go(*exp, set),
1598            )
1599          }
1600          else {
1601            format!("\nSHARE<{:?}>", link.as_ptr())
1602          }
1603        }
1604        DAGPtr::All(link) => {
1605          if set.get(&(link.as_ptr() as usize)).is_none() {
1606            set.insert(link.as_ptr() as usize);
1607            let All { dom, img, parents, copy, .. } = unsafe { link.as_ref() };
1608            let copy = copy.map(|link| link.as_ptr() as usize);
1609            format!(
1610              "\nAll<{:?}> parents: {} copy: {:?}{}{}",
1611              link.as_ptr(),
1612              format_parents(*parents),
1613              copy,
1614              go(*dom, set),
1615              go(DAGPtr::Lam(*img), set),
1616            )
1617          }
1618          else {
1619            format!("\nSHARE<{:?}>", link.as_ptr())
1620          }
1621        }
1622        DAGPtr::Let(link) => {
1623          if set.get(&(link.as_ptr() as usize)).is_none() {
1624            set.insert(link.as_ptr() as usize);
1625            let Let { exp, typ, bod, parents, copy, .. } =
1626              unsafe { link.as_ref() };
1627            let copy = copy.map(|link| link.as_ptr() as usize);
1628            format!(
1629              "\nLet<{:?}> parents: {} copy: {:?}{}{}{}",
1630              link.as_ptr(),
1631              format_parents(*parents),
1632              copy,
1633              go(*typ, set),
1634              go(*exp, set),
1635              go(DAGPtr::Lam(*bod), set),
1636            )
1637          }
1638          else {
1639            format!("\nSHARE<{:?}>", link.as_ptr())
1640          }
1641        }
1642      }
1643    }
1644    write!(f, "{}", go(self.head, &mut BTreeSet::new()))
1645  }
1646}
1647
1648impl fmt::Display for DAG {
1649  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1650    write!(f, "{}", self.to_term(false))
1651  }
1652}
1653
1654impl fmt::Display for DAGPtr {
1655  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1656    write!(f, "{}", DAG::new(*self).to_term(false))
1657  }
1658}
1659
1660#[cfg(test)]
1661pub mod test {
1662  use super::*;
1663  // use crate::parse::term::parse;
1664
1665  //#[test]
1666  // fn test_cases() {
1667  //  let (_, x) = parse("λ _z => Type").unwrap();
1668  //  assert_eq!(x, DAG::to_term(&DAG::from_term(&x)));
1669  //  let (_, x) = parse("λ z => z").unwrap();
1670  //  assert_eq!(x, DAG::to_term(&DAG::from_term(&x)));
1671  //  let (_, x) =
1672  //    parse("λ _z => (λ _a => ∀ (1 _x: _a) -> #Natural) Type").unwrap();
1673  //  assert_eq!(x, DAG::to_term(&DAG::from_term(&x)));
1674  //}
1675
1676  #[quickcheck]
1677  fn dag_term_iso(x: Term) -> bool {
1678    // println!("x: {}", x);
1679    // println!("x: {:?}", x);
1680    let y = DAG::to_term(&DAG::from_term(&x), true);
1681    // println!("y: {}", y);
1682    // println!("y: {:?}", y);
1683    x == y
1684  }
1685
1686  #[quickcheck]
1687  fn dag_def_iso(x: Def) -> bool {
1688    let y = DAG::to_term(&DAG::from_def(&x, Name::from("test")), true);
1689    x.term == y
1690  }
1691}