summaryrefslogtreecommitdiff
path: root/dhall_generator/src/lib.rs
blob: d0d8d981bfbe895b37dd6fa06a250eb959841a38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
extern crate proc_macro;
use proc_macro2::TokenStream;
use proc_macro2::Literal;
use quote::quote;
use dhall_core::*;

#[proc_macro]
pub fn dhall(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input_str = input.to_string();
    let expr = parser::parse_expr_pest(&input_str).unwrap();
    let output = dhall_to_tokenstream(&expr);
    output.into()
}

// Returns an expression of type Expr<_, _>. Expects input variables
// to be of type Box<Expr<_, _>> (future-proof for structural sharing).
fn dhall_to_tokenstream(expr: &Expr<X, X>) -> TokenStream {
    use dhall_core::Expr::*;
    match expr {
        Var(V(s, _)) => {
            let v: TokenStream = s.parse().unwrap();
            quote!{ {
                let x: Expr<_, _> = (*#v).clone();
                x
            } }
        },
        Lam(x, ref t, ref b) => {
            let x = Literal::string(x);
            let t = dhall_to_tokenstream_bx(t);
            let b = dhall_to_tokenstream_bx(b);
            quote!{ Lam(#x, #t, #b) }
        }
        App(ref f, ref a) => {
            let f = dhall_to_tokenstream_bx(f);
            let a = dhall_to_tokenstream_bx(a);
            quote!{ App(#f, #a) }
        }
        Builtin(ref b) => {
            let b = builtin_to_tokenstream(b);
            quote!{ Builtin(#b) }
        },
        BinOp(ref o, ref a, ref b) => {
            let o = binop_to_tokenstream(o);
            let a = dhall_to_tokenstream_bx(a);
            let b = dhall_to_tokenstream_bx(b);
            quote!{ BinOp(#o, #a, #b) }
        }
        OptionalLit(ref t, ref es) => {
            let t = option_tks(t.as_ref().map(deref).map(dhall_to_tokenstream_bx));
            let es = vec_tks(es.into_iter().map(dhall_to_tokenstream));
            quote!{ OptionalLit(#t, #es) }
        }
        ListLit(ref t, ref es) => {
            let t = option_tks(t.as_ref().map(deref).map(dhall_to_tokenstream_bx));
            let es = vec_tks(es.into_iter().map(dhall_to_tokenstream));
            quote!{ ListLit(#t, #es) }
        }
        e => unimplemented!("{:?}", e),
    }
}

// Returns an expression of type Box<Expr<_, _>>
fn dhall_to_tokenstream_bx(expr: &Expr<X, X>) -> TokenStream {
    use dhall_core::Expr::*;
    match expr {
        Var(V(s, _)) => {
            let v: TokenStream = s.parse().unwrap();
            quote!{ {
                let x: Box<Expr<_, _>> = #v.clone();
                x
            } }
        },
        e => bx(dhall_to_tokenstream(e)),
    }
}

fn builtin_to_tokenstream(b: &Builtin) -> TokenStream {
    format!("{:?}", b).parse().unwrap()
}

fn binop_to_tokenstream(b: &BinOp) -> TokenStream {
    format!("{:?}", b).parse().unwrap()
}

fn deref<T>(x: &Box<T>) -> &T {
    &*x
}

fn bx(x: TokenStream) -> TokenStream {
    quote!{ bx(#x) }
}

fn option_tks(x: Option<TokenStream>) -> TokenStream {
    match x {
        Some(x) => quote!{ Some(#x) },
        None => quote!{ None },
    }
}

fn vec_tks<T>(x: T) -> TokenStream
where T: Iterator<Item=TokenStream>
{
    quote!{ vec![ #(#x),* ] }
}