ic/term/
conversion.rs

1// Converts Term to Nets, and back.
2
3use super::*;
4
5// Converts a term to an Interaction Combinator net. Both systems are directly isomorphic, so,
6// each node of the Interaction Calculus correspond to a single Interaction Combinator node.
7pub fn to_net(term : &Term) -> INet {
8  fn encode_term
9    ( net   : &mut INet
10    , term  : &Term
11    , up    : Port
12    , scope : &mut HashMap<Vec<u8>,u32>
13    , vars  : &mut Vec<(Vec<u8>,u32)>
14    ) -> Port {
15    match term {
16      // A lambda becomes to a con node. Ports:
17      // - 0: points to where the lambda occurs.
18      // - 1: points to the lambda variable.
19      // - 2: points to the lambda body.
20      //&Lam{ref nam, ref typ, ref bod} => {
21        //// TODO: handle typ
22        //let fun = new_node(net, CON);
23        //scope.insert(nam.to_vec(), port(fun, 1));
24        //// Also, if the variable is unused, crease an erase node.
25        //if nam == b"*" {
26          //let era = new_node(net, ERA);
27          //link(net, port(era, 1), port(era, 2));
28          //link(net, port(fun, 1), port(era, 0));
29        //}
30        //let bod = encode_term(net, bod, port(fun, 2), scope, vars);
31        //link(net, port(fun, 2), bod);
32        //port(fun, 0)
33      //},
34      &Lam { ref nam, ref typ, ref bod } => {
35        let fun = new_node(net, CON);
36        if let Some(ref typ) = typ {
37          let ann = new_node(net, ANN);
38          let typ = encode_term(net, typ, port(ann, 0), scope, vars);
39          link(net, port(ann, 0), typ);
40          link(net, port(fun, 1), port(ann, 1));
41          scope.insert(nam.to_vec(), port(ann, 2));
42        } else {
43          scope.insert(nam.to_vec(), port(fun, 1));
44        }
45        if nam == b"*" {
46          let era = new_node(net, ERA);
47          link(net, port(era, 1), port(era, 2));
48          link(net, port(fun, 1), port(era, 0));
49        }
50        let bod = encode_term(net, bod, port(fun, 2), scope, vars);
51        link(net, port(fun, 2), bod);
52        port(fun, 0)
53      },
54      // An application becomes to a con node too. Ports:
55      // - 0: points to the function being applied.
56      // - 1: points to the function's argument.
57      // - 2: points to where the application occurs.
58      &App{ref fun, ref arg} => {
59        let app = new_node(net, CON);
60        let fun = encode_term(net, fun, port(app, 0), scope, vars);
61        link(net, port(app, 0), fun);
62        let arg = encode_term(net, arg, port(app, 1), scope, vars);
63        link(net, port(app, 1), arg);
64        port(app, 2)
65      },
66      // An annotation becomes an ANN node. Ports:
67      // - 0: points to the type of the annotation.
68      // - 1: points to where the annotation occurs.
69      // - 2: points to the value being annotated.
70      &Ann{ref val, ref typ} => {
71        let ann = new_node(net, ANN);
72        let val = encode_term(net, val, port(ann, 2), scope, vars);
73        link(net, port(ann, 2), val);
74        let typ = encode_term(net, typ, port(ann, 0), scope, vars);
75        link(net, port(ann, 0), typ);
76        port(ann, 1)
77      },
78      // A pair becomes a dup node. Ports:
79      // - 0: points to where the pair occurs.
80      // - 1: points to the first value.
81      // - 2: points to the second value.
82      &Sup{tag, ref fst, ref snd} => {
83        let dup = new_node(net, DUP + tag);
84        let fst = encode_term(net, fst, port(dup, 1), scope, vars);
85        link(net, port(dup, 1), fst);
86        let snd = encode_term(net, snd, port(dup, 2), scope, vars);
87        link(net, port(dup, 2), snd);
88        port(dup, 0)
89      },
90      // A dup becomes a dup node too. Ports:
91      // - 0: points to the value projected.
92      // - 1: points to the occurrence of the first variable.
93      // - 2: points to the occurrence of the second variable.
94      &Dup{tag, ref fst, ref snd, ref val, ref nxt} => {
95        let dup = new_node(net, DUP + tag);
96        scope.insert(fst.to_vec(), port(dup, 1));
97        scope.insert(snd.to_vec(), port(dup, 2));
98        // If the first variable is unused, create an erase node.
99        if fst == b"*" {
100          let era = new_node(net, ERA);
101          link(net, port(era, 1), port(era, 2));
102          link(net, port(dup, 1), port(era, 0));
103        }
104        // If the second variable is unused, create an erase node.
105        if snd == b"*" {
106          let era = new_node(net, ERA);
107          link(net, port(era, 1), port(era, 2));
108          link(net, port(dup, 2), port(era, 0));
109        }
110        let val = encode_term(net, &val, port(dup, 0), scope, vars);
111        link(net, val, port(dup, 0));
112        encode_term(net, &nxt, up, scope, vars)
113      },
114      // A set is just an erase node stored in a place.
115      &Set => {
116        let set = new_node(net, ERA);
117        link(net, port(set, 1), port(set, 2));
118        port(set, 0)
119      },
120      Var{ref nam} => {
121        vars.push((nam.to_vec(), up));
122        up
123      }
124    }
125  }
126
127  let mut net = new_inet();
128  let mut vars = Vec::new();
129  let mut scope = HashMap::new();
130
131  // Encodes the main term.
132  let main = encode_term(&mut net, &term, ROOT, &mut scope, &mut vars);
133
134  // Links bound variables.
135  for i in 0..vars.len() {
136    let (ref nam, var) = vars[i];
137    match scope.get(nam) {
138      Some(next) => {
139        let next = *next;
140        if enter(&net, next) == next {
141          link(&mut net, var, next);
142        } else {
143          panic!("Variable used more than once: {}.", std::str::from_utf8(nam).unwrap());
144        }
145      },
146      None => panic!("Unbound variable: {}.", std::str::from_utf8(nam).unwrap())
147    }
148  }
149
150  // Connects unbound variables to erase nodes
151  for (_, addr) in scope {
152    if enter(&net, addr) == addr {
153      let era = new_node(&mut net, ERA);
154      link(&mut net, port(era, 1), port(era, 2));
155      link(&mut net, addr, port(era, 0));
156    }
157  }
158
159  // Links the term to the net's root.
160  link(&mut net, 1, main);
161
162  net
163}
164
165// Converts an Interaction-INet node to an Interaction Calculus term.
166pub fn from_net(net : &INet) -> Term {
167  // Given a port, returns its name, or assigns one if it wasn't named yet.
168  fn name_of(net : &INet, var_port : Port, var_name : &mut HashMap<u32, Vec<u8>>) -> Vec<u8> {
169    // If port is linked to an erase node, return an unused variable
170    if kind(net, addr(enter(net, var_port))) == ERA {
171      return b"*".to_vec();
172    }
173    if !var_name.contains_key(&var_port) {
174      let nam = index_to_name(var_name.len() as u32 + 1);
175      var_name.insert(var_port, nam.clone());
176    }
177    var_name.get(&var_port).unwrap().to_vec()
178  }
179
180  // Reads a term recursively by starting at root node.
181  fn read_term
182    ( net   : &INet
183    , next   : Port
184    , var_name : &mut HashMap<u32, Vec<u8>>
185    , dups_vec : &mut Vec<u32>
186    , dups_set : &mut HashSet<(u32)>
187    ) -> Term {
188    match kind(net, addr(next)) {
189      // If we're visiting a set...
190      ERA => Set,
191      // If we're visiting a con node...
192      CON => match slot(next) {
193        // If we're visiting a port 0, then it is a lambda.
194        0 => {
195          let nam = name_of(net, port(addr(next), 1), var_name);
196          let prt = enter(net, port(addr(next), 2));
197          let bod = read_term(net, prt, var_name, dups_vec, dups_set);
198          let ann = enter(net, port(addr(next), 1));
199          let typ = if kind(net, addr(ann)) == ANN && slot(ann) == 1 {
200            let ann_addr = addr(ann);
201            let typ_port = enter(net, port(ann_addr, 0));
202            Some(Box::new(read_term(net, typ_port, var_name, dups_vec, dups_set)))
203          } else {
204            None
205          };
206          let mut lam = Lam {
207            nam: nam,
208            typ: typ,
209            bod: Box::new(bod),
210          };
211          lam
212        },
213        // If we're visiting a port 1, then it is a variable.
214        1 => {
215          Var{nam: name_of(net, next, var_name)}
216        },
217        // If we're visiting a port 2, then it is an application.
218        _ => {
219          let prt = enter(net, port(addr(next), 0));
220          let fun = read_term(net, prt, var_name, dups_vec, dups_set);
221          let prt = enter(net, port(addr(next), 1));
222          let arg = read_term(net, prt, var_name, dups_vec, dups_set);
223          App{fun: Box::new(fun), arg: Box::new(arg)}
224        }
225      },
226      // If we're visiting an ANN node...
227      ANN => match slot(next) {
228        // If we're visiting a port 0, then it is an annotation...
229        0 => {
230          todo!();
231        },
232        // If we're visiting a port 1, then it is where the annotation occurs.
233        1 => {
234          let prt = enter(net, port(addr(next), 2));
235          let val = read_term(net, prt, var_name, dups_vec, dups_set);
236          let prt = enter(net, port(addr(next), 0));
237          let typ = read_term(net, prt, var_name, dups_vec, dups_set);
238          Ann{val: Box::new(val), typ: Box::new(typ)}
239        },
240        // If we're visiting a port 2, then it is the value being annotated.
241        _ => {
242          let prt = enter(net, port(addr(next), 1));
243          let val = read_term(net, prt, var_name, dups_vec, dups_set);
244          val
245          //let prt = enter(net, port(addr(next), 0));
246          //let typ = read_term(net, prt, var_name, dups_vec, dups_set);
247          //Ann{val: Box::new(val), typ: Box::new(typ)}
248        }
249      },
250
251      // If we're visiting a fan node...
252      tag => match slot(next) {
253        // If we're visiting a port 0, then it is a pair.
254        0 => {
255          let tag = tag - DUP;
256          let prt = enter(net, port(addr(next), 1));
257          let fst = read_term(net, prt, var_name, dups_vec, dups_set);
258          let prt = enter(net, port(addr(next), 2));
259          let snd = read_term(net, prt, var_name, dups_vec, dups_set);
260          Sup{tag, fst: Box::new(fst), snd: Box::new(snd)}
261        },
262        // If we're visiting a port 1 or 2, then it is a variable.
263        // Also, that means we found a dup, so we store it to read later.
264        _ => {
265          if !dups_set.contains(&addr(next)) {
266            dups_set.insert(addr(next));
267            dups_vec.push(addr(next));
268          }
269          let nam = name_of(net, next, var_name);
270          Var{nam}
271        }
272      }
273    }
274  }
275
276  // A hashmap linking ports to binder names. Those ports have names:
277  // Port 1 of a con node (λ), ports 1 and 2 of a fan node (let).
278  let mut binder_name = HashMap::new();
279
280  // Dup aren't scoped. We find them when we read one of the variables
281  // introduced by them. Thus, we must store the dups we find to read later.
282  // We have a vec for .pop(). and a set to avoid storing duplicates.
283  let mut dups_vec = Vec::new();
284  let mut dups_set = HashSet::new();
285
286  // Reads the main term from the net
287  let mut main = read_term(net, enter(net, ROOT), &mut binder_name, &mut dups_vec, &mut dups_set);
288
289  // Reads let founds by starting the read_term function from their 0 ports.
290  while dups_vec.len() > 0 {
291    let dup = dups_vec.pop().unwrap();
292    let val = read_term(net, enter(net,port(dup,0)), &mut binder_name, &mut dups_vec, &mut dups_set);
293    let tag = kind(net, dup) - DUP;
294    let fst = name_of(net, port(dup,1), &mut binder_name);
295    let snd = name_of(net, port(dup,2), &mut binder_name);
296    let val = Box::new(val);
297    let nxt = Box::new(main);
298    main = Dup{tag, fst, snd, val, nxt};
299  }
300  main
301}