sic/
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(snd, None, ctx);
177                extend(fst, None, ctx);
178                let (code, val) = parse_term(code, ctx, idx, comment);
179                let (code, nxt) = parse_term(code, ctx, idx, comment);
180                narrow(ctx);
181                narrow(ctx);
182                let tag = name_idx(&tag.to_vec());
183                let fst = fst.to_vec();
184                let snd = snd.to_vec();
185                let val = Box::new(val);
186                let nxt = Box::new(nxt);
187                (code, Let{tag, fst, snd, val, nxt})
188            },
189            // Definition
190            b'/' => {
191                let (code, nam) = parse_name(&code[1..]);
192                let (code, val) = parse_term(code, ctx, idx, comment);
193                extend(nam, Some(val), ctx);
194                let (code, bod) = parse_term(code, ctx, idx, comment);
195                narrow(ctx);
196                (code, bod)
197            },
198            // Set
199            b'*' => {
200                (&code[1..], Set)
201            },
202            // Variable
203            _ => {
204                let (code, nam) = parse_name(code);
205                let mut val : Option<Term> = None;
206                for i in (0..ctx.len()).rev() {
207                    if ctx[i].0 == nam {
208                        match ctx[i].1 {
209                            Some(ref term) => {
210                                let mut name = nam.clone().to_vec();
211                                val = Some(copy(&name, *idx, term));
212                                *idx += 1;
213                                break;
214                            },
215                            None => {
216                                break;
217                            }
218                        }
219                    }
220                }
221                let nam = nam.to_vec();
222                (code, match val { Some(term) => term, None => Var{nam} })
223            }
224        }
225    }
226}
227
228// Converts a source-code to a λ-term.
229pub fn from_string<'a>(code : &'a Str) -> Term {
230    let mut ctx = Vec::new();
231    let mut idx = 0;
232    parse_term(code, &mut ctx, &mut idx, 0).1
233}
234
235// Converts a λ-term back to a source-code.
236pub fn to_string(term : &Term) -> Vec<Chr> {
237    fn stringify_term(code : &mut Vec<u8>, term : &Term) {
238        match term {
239            &Lam{ref nam, ref bod} => {
240                code.extend_from_slice(b"#");
241                code.append(&mut nam.clone());
242                code.extend_from_slice(b" ");
243                stringify_term(code, &bod);
244            },
245            &App{ref fun, ref arg} => {
246                code.extend_from_slice(b":");
247                stringify_term(code, &fun);
248                code.extend_from_slice(b" ");
249                stringify_term(code, &arg);
250            },
251            &Par{tag, ref fst, ref snd} => {
252                code.extend_from_slice(b"&");
253                code.append(&mut new_name(tag));
254                code.extend_from_slice(b" ");
255                stringify_term(code, &fst);
256                code.extend_from_slice(b" ");
257                stringify_term(code, &snd);
258            },
259            &Let{tag, ref fst, ref snd, ref val, ref nxt} => {
260                code.extend_from_slice(b"=");
261                code.append(&mut new_name(tag));
262                code.extend_from_slice(b" ");
263                code.append(&mut fst.clone());
264                code.extend_from_slice(b" ");
265                code.append(&mut snd.clone());
266                code.extend_from_slice(b" ");
267                stringify_term(code, &val);
268                code.extend_from_slice(b"\n");
269                stringify_term(code, &nxt);
270            },
271            &Set => {
272                code.extend_from_slice(b"*");
273            },
274            &Var{ref nam} => {
275                code.append(&mut nam.clone());
276            },
277        }
278    }
279    let mut code = Vec::new();
280    stringify_term(&mut code, &term);
281    return code;
282}
283
284// Display macro.
285impl std::fmt::Display for Term {
286    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
287        write!(f, "{}", String::from_utf8_lossy(&to_string(&self)))
288    }
289}
290
291// Converts a term to an Interaction Combinator net. Both systems are directly isomorphic, so,
292// each node of the Abstract Calculus correspond to a single Interaction Combinator node.
293pub fn to_net(term : &Term) -> Net {
294    fn encode_term
295        ( net   : &mut Net
296        , term  : &Term
297        , up    : Port
298        , scope : &mut HashMap<Vec<u8>,u32>
299        , vars  : &mut Vec<(Vec<u8>,u32)>
300        ) -> Port {
301        match term {
302            // A lambda becomes to a con node. Ports:
303            // - 0: points to where the lambda occurs.
304            // - 1: points to the lambda variable.
305            // - 2: points to the lambda body.
306            &Lam{ref nam, ref bod} => {
307                let fun = new_node(net, CON);
308                scope.insert(nam.to_vec(), port(fun, 1));
309                // Also, if the variable is unused, crease an erase node.
310                if nam == b"-" {
311                    let era = new_node(net, ERA);
312                    link(net, port(era, 1), port(era, 2));
313                    link(net, port(fun, 1), port(era, 0));
314                }
315                let bod = encode_term(net, bod, port(fun, 2), scope, vars);
316                link(net, port(fun, 2), bod);
317                port(fun, 0)
318            },
319            // An application becomes to a con node too. Ports:
320            // - 0: points to the function being applied.
321            // - 1: points to the function's argument.
322            // - 2: points to where the application occurs.
323            &App{ref fun, ref arg} => {
324                let app = new_node(net, CON);
325                let fun = encode_term(net, fun, port(app, 0), scope, vars);
326                link(net, port(app, 0), fun);
327                let arg = encode_term(net, arg, port(app, 1), scope, vars);
328                link(net, port(app, 1), arg);
329                port(app, 2)
330            },
331            // A pair becomes a dup node. Ports:
332            // - 0: points to where the pair occurs.
333            // - 1: points to the first value.
334            // - 2: points to the second value.
335            &Par{tag, ref fst, ref snd} => {
336                let dup = new_node(net, FAN + tag);
337                let fst = encode_term(net, fst, port(dup, 1), scope, vars);
338                link(net, port(dup, 1), fst);
339                let snd = encode_term(net, snd, port(dup, 2), scope, vars);
340                link(net, port(dup, 2), snd);
341                port(dup, 0)
342            },
343            // A let becomes a dup node too. Ports:
344            // - 0: points to the value projected.
345            // - 1: points to the occurrence of the first variable.
346            // - 2: points to the occurrence of the second variable.
347            &Let{tag, ref fst, ref snd, ref val, ref nxt} => {
348                let dup = new_node(net, FAN + tag);
349                scope.insert(fst.to_vec(), port(dup, 1));
350                scope.insert(snd.to_vec(), port(dup, 2));
351                // If the first variable is unused, create an erase node.
352                if fst == b"-" {
353                    let era = new_node(net, ERA);
354                    link(net, port(era, 1), port(era, 2));
355                    link(net, port(dup, 1), port(era, 0));
356                }
357                // If the second variable is unused, create an erase node.
358                if snd == b"-" {
359                    let era = new_node(net, ERA);
360                    link(net, port(era, 1), port(era, 2));
361                    link(net, port(dup, 2), port(era, 0));
362                }
363                let val = encode_term(net, &val, port(dup, 0), scope, vars);
364                link(net, val, port(dup, 0));
365                encode_term(net, &nxt, up, scope, vars)
366            },
367            // A set is just an erase node stored in a place.
368            &Set => {
369                let set = new_node(net, ERA);
370                link(net, port(set, 1), port(set, 2));
371                port(set, 0)
372            },
373            Var{ref nam} => {
374                vars.push((nam.to_vec(), up));
375                up
376            }
377        }
378    }
379
380    // Initializes net with a root node.
381    let mut net = Net { nodes: vec![0,2,1,4], reuse: vec![] };
382    let mut vars = Vec::new();
383    let mut scope = HashMap::new();
384
385    // Encodes the main term.
386    let main = encode_term(&mut net, &term, 0, &mut scope, &mut vars);
387
388    // Links bound variables.
389    for i in 0..vars.len() {
390        let (ref nam, var) = vars[i];
391        match scope.get(nam) {
392            Some(next) => {
393                let next = *next;
394                if enter(&net, next) == next {
395                    link(&mut net, var, next);
396                } else {
397                    panic!("Variable used more than once: {}.", std::str::from_utf8(nam).unwrap());
398                }
399            },
400            None => panic!("Unbound variable: {}.", std::str::from_utf8(nam).unwrap())
401        }
402    }
403
404    // Connects unbound variables to erase nodes
405    for (_, addr) in scope {
406        if enter(&net, addr) == addr {
407            let era = new_node(&mut net, ERA);
408            link(&mut net, port(era, 1), port(era, 2));
409            link(&mut net, addr, port(era, 0));
410        }
411    }
412
413    // Links the term to the net's root.
414    link(&mut net, 0, main);
415
416    net
417}
418
419// Converts an Interaction-Net node to an Abstract Calculus term.
420pub fn from_net(net : &Net) -> Term {
421    // Given a port, returns its name, or assigns one if it wasn't named yet.
422    fn name_of(net : &Net, var_port : Port, var_name : &mut HashMap<u32, Vec<u8>>) -> Vec<u8> {
423        // If port is linked to an erase node, return an unused variable
424        if kind(net, addr(enter(net, var_port))) == ERA {
425            return b"-".to_vec();
426        }
427        if !var_name.contains_key(&var_port) {
428            let nam = new_name(var_name.len() as u32 + 1);
429            var_name.insert(var_port, nam.clone());
430        }
431        var_name.get(&var_port).unwrap().to_vec()
432    }
433
434    // Reads a term recursively by starting at root node.
435    fn read_term
436        ( net      : &Net
437        , next     : Port
438        , var_name : &mut HashMap<u32, Vec<u8>>
439        , lets_vec : &mut Vec<u32>
440        , lets_set : &mut HashSet<(u32)>
441        ) -> Term {
442        match kind(net, addr(next)) {
443            // If we're visiting a set...
444            ERA => Set,
445            // If we're visiting a con node...
446            CON => match slot(next) {
447                // If we're visiting a port 0, then it is a lambda.
448                0 => {
449                    let nam = name_of(net, port(addr(next),1), var_name);
450                    let prt = enter(net, port(addr(next), 2));
451                    let bod = read_term(net, prt, var_name, lets_vec, lets_set);
452                    let mut lam = Lam{nam: nam, bod: Box::new(bod)};
453                    lam
454                },
455                // If we're visiting a port 1, then it is a variable.
456                1 => {
457                    Var{nam: name_of(net, next, var_name)}
458                },
459                // If we're visiting a port 2, then it is an application.
460                _ => {
461                    let prt = enter(net, port(addr(next), 0));
462                    let fun = read_term(net, prt, var_name, lets_vec, lets_set);
463                    let prt = enter(net, port(addr(next), 1));
464                    let arg = read_term(net, prt, var_name, lets_vec, lets_set);
465                    App{fun: Box::new(fun), arg: Box::new(arg)}
466                }
467            },
468            // If we're visiting a fan node...
469            tag => match slot(next) {
470                // If we're visiting a port 0, then it is a pair.
471                0 => {
472                    let tag = tag - FAN;
473                    let prt = enter(net, port(addr(next), 1));
474                    let fst = read_term(net, prt, var_name, lets_vec, lets_set);
475                    let prt = enter(net, port(addr(next), 2));
476                    let snd = read_term(net, prt, var_name, lets_vec, lets_set);
477                    Par{tag, fst: Box::new(fst), snd: Box::new(snd)}
478                },
479                // If we're visiting a port 1 or 2, then it is a variable.
480                // Also, that means we found a let, so we store it to read later.
481                _ => {
482                    if !lets_set.contains(&addr(next)) {
483                        lets_set.insert(addr(next));
484                        lets_vec.push(addr(next));
485                    }
486                    let nam = name_of(net, next, var_name);
487                    Var{nam}
488                }
489            }
490        }
491    }
492
493    // A hashmap linking ports to binder names. Those ports have names:
494    // Port 1 of a con node (λ), ports 1 and 2 of a fan node (let).
495    let mut binder_name = HashMap::new();
496
497    // Lets aren't scoped. We find them when we read one of the variables
498    // introduced by them. Thus, we must store the lets we find to read later.
499    // We have a vec for .pop(). and a set to avoid storing duplicates.
500    let mut lets_vec = Vec::new();
501    let mut lets_set = HashSet::new();
502
503    // Reads the main term from the net
504    let mut main = read_term(net, enter(net, 0), &mut binder_name, &mut lets_vec, &mut lets_set);
505
506    // Reads let founds by starting the read_term function from their 0 ports.
507    while lets_vec.len() > 0 {
508        let dup = lets_vec.pop().unwrap();
509        let val = read_term(net, enter(net,port(dup,0)), &mut binder_name, &mut lets_vec, &mut lets_set);
510        let tag = kind(net, dup) - FAN;
511        let fst = name_of(net, port(dup,1), &mut binder_name);
512        let snd = name_of(net, port(dup,2), &mut binder_name);
513        let val = Box::new(val);
514        let nxt = Box::new(main);
515        main = Let{tag, fst, snd, val, nxt};
516    }
517    main
518}
519
520// Reduces an Abstract Calculus term through Interaction Combinators.
521pub fn reduce(term : &Term) -> Term {
522    let mut net : Net = to_net(&term);
523    ::net::reduce(&mut net);
524    from_net(&net)
525}