yatima_core/
defs.rs

1use crate::{
2  anon::Anon,
3  embed_error::EmbedError,
4  name::Name,
5  package::{
6    import_alias,
7    Entry,
8    Import,
9  },
10  position::Pos,
11  term::Term,
12};
13
14use sp_cid::Cid;
15
16use sp_std::{
17  collections::btree_map::BTreeMap,
18  fmt,
19  rc::Rc,
20  vec::Vec,
21};
22
23use alloc::string::{
24  String,
25  ToString,
26};
27
28/// A type-annotated definition with content ids for the def and its
29/// data, represented as an AST
30#[derive(Clone, Debug)]
31pub struct Def {
32  pub pos: Pos,
33  pub def_cid: Cid,
34  pub ast_cid: Cid,
35  pub typ_: Term,
36  pub term: Term,
37}
38
39impl PartialEq for Def {
40  fn eq(&self, other: &Def) -> bool {
41    self.def_cid == other.def_cid
42      && self.ast_cid == other.ast_cid
43      && self.typ_ == other.typ_
44      && self.term == other.term
45  }
46}
47
48/// A map of content ids to defs, with content ids for the def
49#[derive(PartialEq, Clone, Debug)]
50pub struct Defs {
51  pub defs: BTreeMap<Cid, Def>,
52  pub names: BTreeMap<Name, Cid>,
53}
54
55impl Def {
56  /// Creates a def and a corresponding package entry
57  pub fn make(pos: Pos, typ_: Term, term: Term) -> (Self, Entry) {
58    let (type_anon, type_meta) = typ_.embed();
59    let (term_anon, term_meta) = term.embed();
60    let ast_cid = term_anon.cid();
61    let defn = Entry {
62      pos,
63      type_anon: type_anon.cid(),
64      type_meta,
65      term_anon: ast_cid,
66      term_meta,
67    };
68    let def = Def { pos, def_cid: defn.cid(), ast_cid, typ_, term };
69    (def, defn)
70  }
71
72  /// Embeds the def's data and type into a package entry
73  pub fn embed(&self) -> (Entry, Anon, Anon) {
74    let (type_anon, type_meta) = self.typ_.embed();
75    let (term_anon, term_meta) = self.term.embed();
76    let d = Entry {
77      pos: self.pos,
78      type_anon: type_anon.cid(),
79      term_anon: self.ast_cid,
80      type_meta,
81      term_meta,
82    };
83    (d, type_anon, term_anon)
84  }
85
86  /// Retrieves a def from a package and anonymous data
87  pub fn unembed(
88    def: Entry,
89    type_anon: Anon,
90    term_anon: Anon,
91  ) -> Result<Self, EmbedError> {
92    let typ_ = Term::unembed(&type_anon, &def.type_meta)?;
93    let term = Term::unembed(&term_anon, &def.term_meta)?;
94    Ok(Def {
95      pos: def.pos,
96      def_cid: def.cid(),
97      ast_cid: def.term_anon,
98      typ_,
99      term,
100    })
101  }
102
103  /// Formats the def for pretty-printing
104  pub fn pretty(&self, name: String, ind: bool) -> String {
105    format!(
106      "def {} : {} = {}",
107      name,
108      self.typ_.pretty(Some(&name), ind),
109      self.term.pretty(Some(&name), ind)
110    )
111  }
112}
113
114impl Defs {
115  /// Creates a new map of content ids to defs and names to content ids
116  pub fn new() -> Self {
117    Defs { defs: BTreeMap::new(), names: BTreeMap::new() }
118  }
119
120  /// Gets a list of the name keys in sorted order
121  pub fn names(&self) -> Vec<Name> {
122    self.names.keys().cloned().collect()
123  }
124
125  /// Gets a list of the named defs
126  pub fn named_defs(&self) -> Vec<(Name, Def)> {
127    let mut res = Vec::new();
128    for (n, cid) in &self.names {
129      res.push((n.clone(), self.defs.get(cid).unwrap().clone()))
130    }
131    res
132  }
133
134  /// Adds a def and its name to the defs
135  pub fn insert(&mut self, name: Name, def: Def) -> Option<Def> {
136    self.names.insert(name, def.def_cid);
137    self.defs.insert(def.def_cid, def)
138  }
139
140  /// Gets a def from the defs
141  pub fn get(&self, name: &Name) -> Option<&Def> {
142    let def_cid = self.names.get(name)?;
143    self.defs.get(def_cid)
144  }
145
146  /// Merges Defs from an Import
147  pub fn merge(self, other: Defs, import: &Import) -> Self {
148    let mut defs = self.defs;
149    for (k, v) in other.defs {
150      defs.insert(k, v);
151    }
152    let mut names = self.names;
153    for k in import.with.iter() {
154      let k = k.clone();
155      let v = other.names.get(&k).unwrap();
156      names.insert(import_alias(k, import), *v);
157    }
158    Defs { defs, names }
159  }
160
161  /// Merges Defs mutably at the same level like in a REPL env
162  pub fn flat_merge_mut(&mut self, other: Rc<Defs>) {
163    for (k, v) in other.defs.iter() {
164      self.defs.insert(*k, v.clone());
165    }
166    for (k, v) in other.names.iter() {
167      self.names.insert(k.clone(), *v);
168    }
169  }
170
171  /// Merges Defs at the same level like in a REPL env
172  pub fn flat_merge(self, other: Defs) -> Self {
173    let mut defs = self.defs;
174    for (k, v) in other.defs {
175      defs.insert(k, v);
176    }
177    let mut names = self.names;
178    for (k, v) in other.names.iter() {
179      names.insert(k.clone(), *v);
180    }
181    Defs { defs, names }
182  }
183}
184
185impl Default for Defs {
186  fn default() -> Self { Self::new() }
187}
188
189impl fmt::Display for Def {
190  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191    write!(f, "{}", self.pretty("#^".to_string(), false))
192  }
193}
194impl fmt::Display for Defs {
195  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196    for (k, v) in &self.names {
197      let def = self.defs.get(v).unwrap();
198      writeln!(f, "{}:", def.def_cid)?;
199      writeln!(
200        f,
201        "def {} : {} = {}",
202        k.clone(),
203        def.typ_.pretty(Some(&k.to_string()), false),
204        def.term.pretty(Some(&k.to_string()), false),
205      )?;
206      writeln!(f)?;
207    }
208    Ok(())
209  }
210}
211
212#[cfg(test)]
213pub mod tests {
214  use super::*;
215  use crate::term::tests::{
216    arbitrary_term,
217    test_defs,
218  };
219  use quickcheck::{
220    Arbitrary,
221    Gen,
222  };
223  use sp_im::Vector;
224
225  pub fn arbitrary_def(g: &mut Gen) -> (Def, Entry) {
226    let typ_: Term = Arbitrary::arbitrary(g);
227    let term = arbitrary_term(g, true, test_defs(), Vector::new());
228    Def::make(Pos::None, typ_, term)
229  }
230
231  impl Arbitrary for Def {
232    fn arbitrary(g: &mut Gen) -> Self { arbitrary_def(g).0 }
233  }
234
235  #[quickcheck]
236  fn def_embed_unembed(x: Def) -> bool {
237    let (d, ta, xa) = x.clone().embed();
238    match Def::unembed(d, ta, xa) {
239      Ok(y) => {
240        if x == y {
241          true
242        }
243        else {
244          //          println!("x: {:?}", x);
245          //          println!("y: {:?}", y);
246          false
247        }
248      }
249      _e => {
250        //        println!("x: {:?}", x);
251        //        println!("a: {:?}", a);
252        //        println!("m: {:?}", m);
253        //        println!("e: {:?}", e);
254        false
255      }
256    }
257  }
258}