formality/
compiler.rs

1// >> THIS FILE IS A PROTOTYPE <<
2// This was built in a hurry to have some benchmarks for Devcon 4. It is not in a great shape.
3// Currently only lambdas, applications and non-polymorphic datatypes are supported. It supports
4// recursive definitions, even though those aren't typeable in Formality.
5
6extern crate sic;
7
8use term::*;
9use term::Vars;
10use term::Defs;
11use term::Term::*;
12use term::Context;
13
14pub fn term_to_lambda(term : &Term, defs : &Defs, scope : &mut Vec<Vec<u8>>, name_count : &mut u32, copy_count : &mut u32) -> sic::term::Term {
15    pub fn gen_name(name_count : &mut u32) -> Vec<u8> {
16        *name_count += 1;
17        sic::term::new_name(*name_count)
18    }
19    pub fn build(term : &Term, rec : &mut (Vec<u8>, Vec<u8>), defs : &Defs, scope : &mut Vec<Vec<u8>>, name_count : &mut u32, copy_count : &mut u32) -> sic::term::Term {
20        match term {
21            All{nam: _, typ: _, bod: _} => {
22                // TODO: implement properly
23                sic::term::Term::Set
24            },
25            Lam{nam: _, typ: _, bod} => {
26                let nam = gen_name(name_count);
27                scope.push(nam.clone());
28                let bod = Box::new(build(bod, rec, defs, scope, name_count, copy_count));
29                scope.pop();
30                sic::term::Term::Lam{nam, bod}
31            },
32            Var{idx} => {
33                sic::term::Term::Var{nam: scope[scope.len() - (*idx as usize) - 1].clone()}
34            },
35            App{fun, arg} => {
36                let fun = Box::new(build(fun, rec, defs, scope, name_count, copy_count));
37                let arg = Box::new(build(arg, rec, defs, scope, name_count, copy_count));
38                sic::term::Term::App{fun, arg}
39            },
40            Idt{nam: _, arg: _, par: _, typ: _, ctr: _} => {
41                // TODO: implement properly
42                sic::term::Term::Set
43            },
44            New{idt: _, ctr, bod} => {
45                let mut nams = Vec::new();
46
47                for _ in 0..ctr.len() {
48                    let nam = gen_name(name_count);
49                    scope.push(nam.clone());
50                    nams.push(nam);
51                }
52
53                let mut res = build(bod, rec, defs, scope, name_count, copy_count);
54
55                for _ in 0..ctr.len() {
56                    scope.pop();
57                }
58
59                for i in (0..ctr.len()).rev() {
60                    res = sic::term::Term::Lam{nam: nams[i].clone(), bod: Box::new(res)};
61                }
62
63                res
64            },
65            Cas{val, cas, ret: _} => {
66                // Checks if this pattern match folds.
67                let mut folds = false;
68                for (_, cas_typ, cas_bod) in cas {
69                    folds = folds || uses(cas_bod, cas_typ.len() as i32) > 0;
70                }
71
72                // Allocates names for fold variables.
73                let fold_a = if folds { gen_name(name_count) } else { Vec::new() };
74                let fold_b = if folds { gen_name(name_count) } else { Vec::new() };
75
76                // Builds the matching function body on SIC. For example:
77                // - This:    (case v | A  (x,  y) =>  P(x, fold(y))  | B => Q)
78                // - Becomes:      (v (λx. λy. λF.    (P x  (F   y))) (λF.   Q))
79                // Note that, if folds, each case includes a local fold argument `F`.
80
81                // Inits the matching function body as just the matched variable.
82                let var = gen_name(name_count);
83                let mut fun_bod = sic::term::Term::Var{nam: var.clone()};
84
85                // Then, for each case of the pattern match...
86                for (_cas_nam, cas_args, cas_bod) in cas {
87                    // Generates names for the local fold and each field, and extends the scope.
88                    let mut nams = Vec::new();
89                    let fold_nam = gen_name(name_count);
90                    scope.push(fold_nam.clone());
91                    for _ in 0..cas_args.len() {
92                        let field_nam = gen_name(name_count);
93                        scope.push(field_nam.clone());
94                        nams.push(field_nam);
95                    }
96                    if folds { nams.push(fold_nam.clone()); }
97
98                    // Builds the case body on SIC.
99                    let cas_bod = build(cas_bod, rec, defs, scope, name_count, copy_count);
100
101                    // Narrows the scope back.
102                    scope.pop();
103                    for _ in 0..cas_args.len() {
104                        scope.pop();
105                    }
106
107                    // Builds the case function on SIC by closing the body with generated names.
108                    let mut cas_fun = cas_bod;
109                    for i in 0..nams.len() {
110                        cas_fun = sic::term::Term::Lam{nam: nams[nams.len() - i - 1].clone(), bod: Box::new(cas_fun)}
111                    }
112
113                    // Extends the matching function body by applying it to this new case function.
114                    fun_bod = sic::term::Term::App{fun: Box::new(fun_bod), arg: Box::new(cas_fun)};
115                }
116
117                // Builds the matching function on SIC. It takes the matching function body and
118                // closes over the matched variable, turning the body into a lambda. Then, if it
119                // folds, it turns it recursive by applying it to a copy o itself.
120                let fun = if folds {
121                    sic::term::Term::Let{
122                        tag: *copy_count + 10,
123                        fst: fold_a.clone(),
124                        snd: fold_b.clone(),
125                        val: Box::new(sic::term::Term::Lam{
126                            nam: var,
127                            bod: Box::new(sic::term::Term::App{
128                                fun: Box::new(fun_bod),
129                                arg: Box::new(sic::term::Term::Var{nam: fold_a})
130                            })
131                        }),
132                        nxt: Box::new(sic::term::Term::Var{nam: fold_b.clone()})
133                    }
134                } else {
135                    sic::term::Term::Lam{
136                        nam: var,
137                        bod: Box::new(fun_bod)
138                    }
139                };
140
141                // Builds the matched value on SIC.
142                let val = build(val, rec, defs, scope, name_count, copy_count);
143
144                // The result is an application of the folding function to the matched value.
145                let res = sic::term::Term::App{
146                    fun: Box::new(fun),
147                    arg: Box::new(val)
148                };
149
150                res
151            },
152
153            Cpy{nam: _, val, bod} => {
154                let val = Box::new(build(val, rec, defs, scope, name_count, copy_count));
155
156                let nam_a = gen_name(name_count);
157                scope.push(nam_a.clone());
158
159                let nam_b = gen_name(name_count);
160                scope.push(nam_b.clone());
161
162                let bod = Box::new(build(bod, rec, defs, scope, name_count, copy_count));
163
164                scope.pop();
165
166                scope.pop();
167
168                *copy_count += 1;
169
170                let tag = *copy_count + 10;
171                let fst = nam_a;
172                let snd = nam_b;
173                let val = val;
174                let nxt = bod;
175                sic::term::Term::Let{tag, fst, snd, val, nxt}
176            },
177            Ref{nam} => {
178                if *nam == rec.0 {
179                    let nam = rec.1.clone();
180                    rec.1 = b"".to_vec();
181                    sic::term::Term::Var{nam}
182                } else {
183                    match defs.get(nam) {
184                        Some(term) => {
185                            *copy_count += 1;
186
187                            let mut nam_a = nam.clone();
188                            nam_a.extend_from_slice(b"$a$");
189                            nam_a.append(&mut copy_count.to_string().into_bytes());
190
191                            let mut nam_b = nam.clone();
192                            nam_b.extend_from_slice(b"$b$");
193                            nam_b.append(&mut copy_count.to_string().into_bytes());
194
195                            let mut rec = (nam.to_vec(), nam_b.clone());
196                            let tag = *copy_count + 10;
197                            let fst = nam_a.clone();
198                            let snd = nam_b.clone();
199                            let ter = build(&term, &mut rec, defs, scope, name_count, copy_count);
200                            if rec.1 == b"" {
201                                let val = Box::new(ter);
202                                let nxt = Box::new(sic::term::Term::Var{nam: nam_a});
203                                sic::term::Term::Let{tag, fst, snd, val, nxt}
204                            } else {
205                                ter
206                            }
207                        },
208                        None => panic!("Undefined variable.")
209                    }
210                }
211            },
212            Set => {
213                panic!("Not implemented.")
214            }
215        }
216    }
217    build(term, &mut (b"".to_vec(), b"".to_vec()), defs, scope, name_count, copy_count)
218}
219
220pub fn term_from_lambda(term : &sic::term::Term, typ : &Term, defs : &Defs, vars : &mut Vars, ctx : &mut Context) -> Term {
221    pub fn infer(term : &sic::term::Term, defs : &Defs, vars : &mut Vars, ctx : &mut Context) -> (Term, Term) {
222        match term {
223            sic::term::Term::Lam{nam: _, bod: _} => {
224                panic!("Not implemented.")
225            },
226            sic::term::Term::App{fun, arg} => {
227                let (fun_v, fun_t) = infer(fun, defs, vars, ctx);
228                match fun_t {
229                    All{nam: _, typ, bod} => {
230                        let fun = Box::new(fun_v);
231                        let arg = Box::new(term_from_lambda(arg, &typ, defs, vars, ctx));
232                        let mut bod = bod.clone();
233                        subs(&mut bod, &arg, 0);
234                        (App{fun, arg}, *bod)
235                    },
236                    t => panic!("Not implemented. {}", t)
237                }
238            },
239            sic::term::Term::Var{nam} => {
240                for i in (0..vars.len()).rev() {
241                    if *nam == vars[i] {
242                        let val = Var{idx: (vars.len() - i - 1) as i32};
243                        let typ = ctx[i].clone();
244                        return (val, typ);
245                    }
246                }
247                panic!("Not implemented.");
248            },
249            sic::term::Term::Set => {
250                (Set, Set)
251            },
252            _ => panic!("Not implemented. {}", term)
253        }
254    }
255    match term {
256        sic::term::Term::Lam{nam: term_nam, bod: term_bod} => {
257            let typ = weak_reduced(&typ, defs, true);
258            match &typ {
259                All{nam, typ, bod} => {
260                    let nam = nam.to_vec();
261                    let typ = typ.clone();
262                    extend_context(&shifted(&typ,1,0), ctx);
263                    vars.push(term_nam.clone());
264                    let bod = Box::new(term_from_lambda(term_bod, &bod, defs, vars, ctx));
265                    narrow_context(ctx);
266                    vars.pop();
267                    Lam{nam, typ, bod}
268                },
269                Idt{nam: _, arg: _, par: _, typ: _, ctr} => {
270                    // Extends the context with IDT's constructor types
271                    for i in 0..ctr.len() {
272                        let ctr_typ = &apply_idt_args(&typ).1[i].1;
273                        extend_context(&shifted(&ctr_typ, ctr.len() as i32, 0), ctx);
274                    }
275
276                    // Extracts the body of the Scott-encoded SIC term, appending var names
277                    let mut bod = term;
278                    for _ in 0..ctr.len() {
279                        bod = match bod {
280                            sic::term::Term::Lam{ref nam, ref bod} => {
281                                vars.push(nam.clone());
282                                bod
283                            },
284                            _ => panic!("Attempted to read wrongly shaped SIC term. This is probably a Formality bug.")
285                        }
286                    }
287
288                    // Converts body of the Scott-encoded SIC term to Formality
289                    let (res, _) = infer(bod, defs, vars, ctx);
290
291                    // Narrows the context and clears var names
292                    for _ in 0..ctr.len() {
293                        vars.pop();
294                        narrow_context(ctx);
295                    }
296
297                    // Completes the Formality instantiator term
298                    New {
299                        idt: Box::new(typ.clone()),
300                        ctr: ctr.iter().map(|c| c.0.clone()).collect(),
301                        bod: Box::new(res)
302                    }
303                },
304                t => panic!("Not implemented. {} : {}", term, t)
305            }
306        },
307        term => {
308            infer(term, defs, vars, ctx).0
309        }
310    }
311}
312
313pub fn eval(term : &Term, defs : &Defs) -> (sic::net::Stats, Term) {
314    let term_type = infer(&term, &defs, true).unwrap();
315    let lambda = term_to_lambda(&term, &defs, &mut Vec::new(), &mut 0, &mut 0);
316    let mut net = sic::term::to_net(&lambda);
317    let stats = sic::net::reduce(&mut net);
318    let lambda_nf = sic::term::from_net(&net); // TODO: correctly read-back lets (i.e., use sic::term::from_net)
319    let term_nf = term_from_lambda(&lambda_nf, &term_type, defs, &mut Vec::new(), &mut Vec::new());
320    (stats, term_nf)
321}
322
323pub fn partial_eval(term : &Term, defs : &Defs) -> (sic::net::Stats, sic::term::Term) {
324    let lambda = term_to_lambda(&term, &defs, &mut Vec::new(), &mut 0, &mut 0);
325    let mut net = sic::term::to_net(&lambda);
326    let stats = sic::net::reduce(&mut net);
327    let lambda_nf = sic::term::from_net(&net);
328    (stats, lambda_nf)
329}