absal/
term.rs

1#![allow(dead_code)]
2
3use std::collections::*;
4use net::*;
5use std;
6
7// Terms of the Abstract Calculus.
8#[derive(Clone, Debug)]
9pub enum Term {
10    // Abstractions (affine functions).
11    Lam {nam: Vec<u8>, bod: Box<Term>},                               
12
13    // Applications.
14    App {fun: Box<Term>, arg: Box<Term>},
15
16    // Pairs.
17    Par {tag: u32, fst: Box<Term>, snd: Box<Term>},
18
19    // Definitions (let).
20    Let {tag: u32, fst: Vec<u8>, snd: Vec<u8>, val: Box<Term>, nxt: Box<Term>},
21
22    // Variable.
23    Var {nam: Vec<u8>}, 
24
25    // Set.
26    Set
27}
28use self::Term::{*};
29
30// Source code is Ascii-encoded.
31pub type Str = [u8];
32pub type Chr = u8;
33
34// Builds a var name from an index (0="a", 1="b", 26="aa"...).
35pub fn new_name(idx : u32) -> Vec<Chr> {
36    let mut name = Vec::new();
37    let mut idx = idx;
38    while idx > 0 {
39        idx = idx - 1;
40        name.push((97 + idx % 26) as u8);
41        idx = idx / 26;
42    }
43    return name;
44}
45
46pub fn name_idx(name : &Vec<Chr>) -> u32 {
47    let mut idx : u32 = 0;
48    for byte in name.iter().rev() {
49        idx = (idx * 26) + (*byte as u32 - 97) + 1;
50    }
51    return idx;
52}
53
54// A context is a vector of (name, value) assignments.
55type Context<'a> = Vec<(&'a Str, Option<Term>)>;
56
57// Extends a context with a (name, value) assignments.
58fn extend<'a,'b>(nam : &'a Str, val : Option<Term>, ctx : &'b mut Context<'a>) -> &'b mut Context<'a> {
59    ctx.push((nam,val));
60    ctx
61}
62
63// Removes an assignment from a context.
64fn narrow<'a,'b>(ctx : &'b mut Context<'a>) -> &'b mut Context<'a> {
65    ctx.pop();
66    ctx
67}
68
69
70// Parses a name, returns the remaining code and the name.
71fn parse_name(code : &Str) -> (&Str, &Str) {
72    let mut i : usize = 0;
73    while i < code.len() && !(code[i] == b' ' || code[i] == b'\n') {
74        i += 1;
75    }
76    (&code[i..], &code[0..i])
77}
78
79pub fn namespace(space : &Vec<u8>, idx : u32, var : &Vec<u8>) -> Vec<u8> {
80    if var != b"-" {
81        let mut nam = space.clone();
82        nam.extend_from_slice(b"/");
83        nam.append(&mut idx.to_string().as_bytes().to_vec());
84        nam.extend_from_slice(b"/");
85        nam.append(&mut var.clone());
86        nam
87    } else {
88        var.clone()
89    }
90}
91
92// Makes a namespaced copy of a term
93pub fn copy(space : &Vec<u8>, idx : u32, term : &Term) -> Term {
94    match term {
95        Lam{nam, bod} => {
96            let nam = namespace(space, idx, nam);
97            let bod = Box::new(copy(space, idx, bod));
98            Lam{nam, bod}
99        },
100        App{fun, arg} => {
101            let fun = Box::new(copy(space, idx, fun));
102            let arg = Box::new(copy(space, idx, arg));
103            App{fun, arg}
104        },
105        Par{tag, fst, snd} => {
106            let tag = *tag;
107            let fst = Box::new(copy(space, idx, fst));
108            let snd = Box::new(copy(space, idx, snd));
109            Par{tag, fst, snd}
110        },
111        Let{tag, fst, snd, val, nxt} => {
112            let tag = *tag;
113            let fst = namespace(space, idx, fst);
114            let snd = namespace(space, idx, snd);
115            let val = Box::new(copy(space, idx, val));
116            let nxt = Box::new(copy(space, idx, nxt));
117            Let{tag, fst, snd, val, nxt}
118        },
119        Var{nam} => {
120            let nam = namespace(space, idx, nam);
121            Var{nam}
122        },
123        Set => Set
124    }
125}
126
127// Parses a term, returns the remaining code and the term.
128pub fn parse_term<'a>(code : &'a Str, ctx : &mut Context<'a>, idx : &mut u32, comment : u32) -> (&'a Str, Term) {
129    if comment > 0 {
130        match code[0] {
131            b'(' => parse_term(&code[1..], ctx, idx, comment + 1),
132            b')' => parse_term(&code[1..], ctx, idx, comment - if comment == 0 { 0 } else { 1 }),
133            _    => parse_term(&code[1..], ctx, idx, comment)
134        }
135    } else {
136        match code[0] {
137            // Whitespace
138            b' ' => parse_term(&code[1..], ctx, idx, comment),
139            // Newline
140            b'\n' => parse_term(&code[1..], ctx, idx, comment),
141            // Comment
142            b'(' => parse_term(&code[1..], ctx, idx, comment + 1),
143            // Abstraction
144            b'#' => {
145                let (code, nam) = parse_name(&code[1..]);
146                extend(nam, None, ctx);
147                let (code, bod) = parse_term(code, ctx, idx, comment);
148                narrow(ctx);
149                let nam = nam.to_vec();
150                let bod = Box::new(bod);
151                (code, Lam{nam,bod})
152            },
153            // Application
154            b':' => {
155                let (code, fun) = parse_term(&code[1..], ctx, idx, comment);
156                let (code, arg) = parse_term(code, ctx, idx, comment);
157                let fun = Box::new(fun);
158                let arg = Box::new(arg);
159                (code, App{fun,arg})
160            },
161            // Pair
162            b'&' => {
163                let (code, tag) = parse_name(&code[1..]);
164                let (code, fst) = parse_term(code, ctx, idx, comment);
165                let (code, snd) = parse_term(code, ctx, idx, comment);
166                let tag = name_idx(&tag.to_vec());
167                let fst = Box::new(fst);
168                let snd = Box::new(snd);
169                (code, Par{tag,fst,snd})
170            },
171            // Let
172            b'=' => {
173                let (code, tag) = parse_name(&code[1..]);
174                let (code, fst) = parse_name(&code[1..]);
175                let (code, snd) = parse_name(&code[1..]);
176                extend(fst, None, extend(snd, None, ctx));
177                let (code, val) = parse_term(code, ctx, idx, comment);
178                let (code, nxt) = parse_term(code, ctx, idx, comment);
179                narrow(ctx);
180                let tag = name_idx(&tag.to_vec());
181                let fst = fst.to_vec();
182                let snd = snd.to_vec();
183                let val = Box::new(val);
184                let nxt = Box::new(nxt);
185                (code, Let{tag, fst, snd, val, nxt})
186            },
187            // Definition
188            b'/' => {
189                let (code, nam) = parse_name(&code[1..]);
190                let (code, val) = parse_term(code, ctx, idx, comment);
191                extend(nam, Some(val), ctx);
192                let (code, bod) = parse_term(code, ctx, idx, comment);
193                narrow(ctx);
194                (code, bod)
195            },
196            // Set
197            b'*' => {
198                (code, Set)
199            },
200            // Variable
201            _ => {
202                let (code, nam) = parse_name(code);
203                let mut val : Option<Term> = None;
204                for i in (0..ctx.len()).rev() {
205                    if ctx[i].0 == nam {
206                        match ctx[i].1 {
207                            Some(ref term) => {
208                                let mut name = nam.clone().to_vec();
209                                val = Some(copy(&name, *idx, term));
210                                *idx += 1;
211                                break;
212                            },
213                            None => {
214                                break;
215                            }
216                        }
217                    }
218                }
219                let nam = nam.to_vec();
220                (code, match val { Some(term) => term, None => Var{nam} })
221            }
222        }
223    }
224}
225
226// Converts a source-code to a λ-term.
227pub fn from_string<'a>(code : &'a Str) -> Term {
228    let mut ctx = Vec::new();
229    let mut idx = 0;
230    parse_term(code, &mut ctx, &mut idx, 0).1
231}
232
233// Converts a λ-term back to a source-code.
234pub fn to_string(term : &Term) -> Vec<Chr> {
235    fn stringify_term(code : &mut Vec<u8>, term : &Term) {
236        match term {
237            &Lam{ref nam, ref bod} => {
238                code.extend_from_slice(b"#");
239                code.append(&mut nam.clone());
240                code.extend_from_slice(b" ");
241                stringify_term(code, &bod);
242            },
243            &App{ref fun, ref arg} => {
244                code.extend_from_slice(b":");
245                stringify_term(code, &fun);
246                code.extend_from_slice(b" ");
247                stringify_term(code, &arg);
248            },
249            &Par{tag, ref fst, ref snd} => {
250                code.extend_from_slice(b"&");
251                code.append(&mut new_name(tag));
252                code.extend_from_slice(b" ");
253                stringify_term(code, &fst);
254                code.extend_from_slice(b" ");
255                stringify_term(code, &snd);
256            },
257            &Let{tag, ref fst, ref snd, ref val, ref nxt} => {
258                code.extend_from_slice(b"=");
259                code.append(&mut new_name(tag));
260                code.extend_from_slice(b" ");
261                code.append(&mut fst.clone());
262                code.extend_from_slice(b" ");
263                code.append(&mut snd.clone());
264                code.extend_from_slice(b" ");
265                stringify_term(code, &val);
266                code.extend_from_slice(b"\n");
267                stringify_term(code, &nxt);
268            },
269            &Set => {
270                code.extend_from_slice(b"*");
271            },
272            &Var{ref nam} => {
273                code.append(&mut nam.clone());
274            },
275        }
276    }
277    let mut code = Vec::new();
278    stringify_term(&mut code, &term);
279    return code;
280}
281
282// Display macro.
283impl std::fmt::Display for Term {
284    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
285        write!(f, "{}", String::from_utf8_lossy(&to_string(&self)))
286    }
287}
288
289// Converts a term to an Interaction Combinator net. Both systems are directly isomorphic, so,
290// each node of the Abstract Calculus correspond to a single Interaction Combinator node.
291pub fn to_net(term : &Term) -> Net {
292    fn encode_term
293        ( net   : &mut Net
294        , term  : &Term
295        , up    : Port
296        , scope : &mut HashMap<Vec<u8>,u32>
297        , vars  : &mut Vec<(Vec<u8>,u32)>
298        ) -> Port {
299        match term {
300            // A lambda becomes to a con node. Ports:
301            // - 0: points to where the lambda occurs.
302            // - 1: points to the lambda variable.
303            // - 2: points to the lambda body.
304            &Lam{ref nam, ref bod} => {
305                let fun = new_node(net, CON);
306                scope.insert(nam.to_vec(), port(fun, 1));
307                // Also, if the variable is unused, crease an erase node.
308                if nam == b"-" {
309                    let era = new_node(net, ERA);
310                    link(net, port(era, 1), port(era, 2));
311                    link(net, port(fun, 1), port(era, 0));
312                }
313                let bod = encode_term(net, bod, port(fun, 2), scope, vars);
314                link(net, port(fun, 2), bod);
315                port(fun, 0)
316            },
317            // An application becomes to a con node too. Ports:
318            // - 0: points to the function being applied.
319            // - 1: points to the function's argument.
320            // - 2: points to where the application occurs.
321            &App{ref fun, ref arg} => {
322                let app = new_node(net, CON);
323                let fun = encode_term(net, fun, port(app, 0), scope, vars);
324                link(net, port(app, 0), fun);
325                let arg = encode_term(net, arg, port(app, 1), scope, vars);
326                link(net, port(app, 1), arg);
327                port(app, 2)
328            },
329            // A pair becomes a dup node. Ports:
330            // - 0: points to where the pair occurs.
331            // - 1: points to the first value.
332            // - 2: points to the second value.
333            &Par{tag, ref fst, ref snd} => {
334                let dup = new_node(net, FAN + tag);
335                let fst = encode_term(net, fst, port(dup, 1), scope, vars);
336                link(net, port(dup, 1), fst);
337                let snd = encode_term(net, snd, port(dup, 2), scope, vars);
338                link(net, port(dup, 2), snd);
339                port(dup, 0)
340            },
341            // A let becomes a dup node too. Ports:
342            // - 0: points to the value projected.
343            // - 1: points to the occurrence of the first variable.
344            // - 2: points to the occurrence of the second variable.
345            &Let{tag, ref fst, ref snd, ref val, ref nxt} => {
346                let dup = new_node(net, FAN + tag);
347                scope.insert(fst.to_vec(), port(dup, 1));
348                scope.insert(snd.to_vec(), port(dup, 2));
349                // If the first variable is unused, create an erase node.
350                if fst == b"-" {
351                    let era = new_node(net, ERA);
352                    link(net, port(era, 1), port(era, 2));
353                    link(net, port(dup, 1), port(era, 0));
354                }
355                // If the second variable is unused, create an erase node.
356                if snd == b"-" {
357                    let era = new_node(net, ERA);
358                    link(net, port(era, 1), port(era, 2));
359                    link(net, port(dup, 2), port(era, 0));
360                }
361                let val = encode_term(net, &val, port(dup, 0), scope, vars);
362                link(net, val, port(dup, 0));
363                encode_term(net, &nxt, up, scope, vars)
364            },
365            // A set is just an erase node stored in a place.
366            &Set => {
367                let set = new_node(net, ERA);
368                link(net, port(set, 1), port(set, 2));
369                port(set, 0)
370            },
371            Var{ref nam} => {
372                vars.push((nam.to_vec(), up));
373                up
374            }
375        }
376    }
377
378    // Initializes net with a root node.
379    let mut net = Net { nodes: vec![0,2,1,4], reuse: vec![] };
380    let mut vars = Vec::new();
381    let mut scope = HashMap::new();
382
383    // Encodes the main term.
384    let main = encode_term(&mut net, &term, 0, &mut scope, &mut vars);
385
386    // Links bound variables.
387    for i in 0..vars.len() {
388        let (ref nam, var) = vars[i];
389        match scope.get(nam) {
390            Some(next) => {
391                let next = *next;
392                if enter(&net, next) == next {
393                    link(&mut net, var, next);
394                } else {
395                    panic!("Variable used more than once: {}.", std::str::from_utf8(nam).unwrap());
396                }
397            },
398            None => panic!("Unbound variable: {}.", std::str::from_utf8(nam).unwrap())
399        }
400    }
401
402    // Links the term to the net's root.
403    link(&mut net, 0, main);
404
405    net
406}
407
408// Converts an Interaction-Net node to an Abstract Calculus term.
409pub fn from_net(net : &Net) -> Term {
410    // Given a port, returns its name, or assigns one if it wasn't named yet.
411    fn name_of(net : &Net, var_port : Port, var_name : &mut HashMap<u32, Vec<u8>>) -> Vec<u8> {
412        // If port is linked to an erase node, return an unused variable
413        if kind(net, addr(enter(net, var_port))) == ERA {
414            return b"-".to_vec();
415        }
416        if !var_name.contains_key(&var_port) {
417            let nam = new_name(var_name.len() as u32 + 1);
418            var_name.insert(var_port, nam.clone());
419        }
420        var_name.get(&var_port).unwrap().to_vec()
421    }
422
423    // Reads a term recursively by starting at root node.
424    fn read_term
425        ( net      : &Net
426        , next     : Port
427        , var_name : &mut HashMap<u32, Vec<u8>>
428        , lets_vec : &mut Vec<u32>
429        , lets_set : &mut HashSet<(u32)>
430        ) -> Term {
431        match kind(net, addr(next)) {
432            // If we're visiting a set...
433            ERA => Set,
434            // If we're visiting a con node...
435            CON => match slot(next) {
436                // If we're visiting a port 0, then it is a lambda.
437                0 => {
438                    let nam = name_of(net, port(addr(next),1), var_name);
439                    let prt = enter(net, port(addr(next), 2));
440                    let bod = read_term(net, prt, var_name, lets_vec, lets_set);
441                    let mut lam = Lam{nam: nam, bod: Box::new(bod)};
442                    lam
443                },
444                // If we're visiting a port 1, then it is a variable.
445                1 => {
446                    Var{nam: name_of(net, next, var_name)}
447                },
448                // If we're visiting a port 2, then it is an application.
449                _ => {
450                    let prt = enter(net, port(addr(next), 0));
451                    let fun = read_term(net, prt, var_name, lets_vec, lets_set);
452                    let prt = enter(net, port(addr(next), 1));
453                    let arg = read_term(net, prt, var_name, lets_vec, lets_set);
454                    App{fun: Box::new(fun), arg: Box::new(arg)}
455                }
456            },
457            // If we're visiting a fan node...
458            tag => match slot(next) {
459                // If we're visiting a port 0, then it is a pair.
460                0 => {
461                    let tag = tag - FAN;
462                    let prt = enter(net, port(addr(next), 1));
463                    let fst = read_term(net, prt, var_name, lets_vec, lets_set);
464                    let prt = enter(net, port(addr(next), 2));
465                    let snd = read_term(net, prt, var_name, lets_vec, lets_set);
466                    Par{tag, fst: Box::new(fst), snd: Box::new(snd)}
467                },
468                // If we're visiting a port 1 or 2, then it is a variable.
469                // Also, that means we found a let, so we store it to read later.
470                _ => {
471                    if !lets_set.contains(&addr(next)) {
472                        lets_set.insert(addr(next));
473                        lets_vec.push(addr(next));
474                    }
475                    let nam = name_of(net, next, var_name);
476                    Var{nam}
477                }
478            }
479        }
480    }
481
482    // A hashmap linking ports to binder names. Those ports have names:
483    // Port 1 of a con node (λ), ports 1 and 2 of a fan node (let).
484    let mut binder_name = HashMap::new();
485
486    // Lets aren't scoped. We find them when we read one of the variables
487    // introduced by them. Thus, we must store the lets we find to read later.
488    // We have a vec for .pop(). and a set to avoid storing duplicates.
489    let mut lets_vec = Vec::new();
490    let mut lets_set = HashSet::new();
491
492    // Reads the main term from the net
493    let mut main = read_term(net, enter(net, 0), &mut binder_name, &mut lets_vec, &mut lets_set);
494
495    // Reads let founds by starting the read_term function from their 0 ports.
496    while lets_vec.len() > 0 {
497        let dup = lets_vec.pop().unwrap();
498        let val = read_term(net, enter(net,port(dup,0)), &mut binder_name, &mut lets_vec, &mut lets_set);
499        let tag = kind(net, dup) - FAN;
500        let fst = name_of(net, port(dup,1), &mut binder_name);
501        let snd = name_of(net, port(dup,2), &mut binder_name);
502        let val = Box::new(val);
503        let nxt = Box::new(main);
504        main = Let{tag, fst, snd, val, nxt};
505    }
506    main
507}
508
509// Reduces an Abstract Calculus term through Interaction Combinators.
510pub fn reduce(term : &Term) -> Term {
511    let mut net : Net = to_net(&term);
512    ::net::reduce(&mut net);
513    from_net(&net)
514}