summaryrefslogtreecommitdiff
path: root/dhall/src/syntax/ast/visitor.rs
blob: c361bc13513232898fc6e8a882ec254254401ad4 (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
105
106
107
108
109
110
111
112
113
use std::iter::FromIterator;

use crate::syntax::*;

fn vec<'a, T, U, Err>(
    x: &'a [T],
    f: impl FnMut(&'a T) -> Result<U, Err>,
) -> Result<Vec<U>, Err> {
    x.iter().map(f).collect()
}

fn opt<'a, T, U, Err>(
    x: &'a Option<T>,
    f: impl FnOnce(&'a T) -> Result<U, Err>,
) -> Result<Option<U>, Err> {
    Ok(match x {
        Some(x) => Some(f(x)?),
        None => None,
    })
}

fn dupmap<'a, SE1, SE2, T, Err>(
    x: impl IntoIterator<Item = (&'a Label, &'a SE1)>,
    mut f: impl FnMut(&'a SE1) -> Result<SE2, Err>,
) -> Result<T, Err>
where
    SE1: 'a,
    T: FromIterator<(Label, SE2)>,
{
    x.into_iter().map(|(k, x)| Ok((k.clone(), f(x)?))).collect()
}

fn optdupmap<'a, SE1, SE2, T, Err>(
    x: impl IntoIterator<Item = (&'a Label, &'a Option<SE1>)>,
    mut f: impl FnMut(&'a SE1) -> Result<SE2, Err>,
) -> Result<T, Err>
where
    SE1: 'a,
    T: FromIterator<(Label, Option<SE2>)>,
{
    x.into_iter()
        .map(|(k, x)| {
            Ok((
                k.clone(),
                match x {
                    Some(x) => Some(f(x)?),
                    None => None,
                },
            ))
        })
        .collect()
}

pub(crate) fn visit_ref<'a, F, SE1, SE2, Err>(
    input: &'a ExprKind<SE1>,
    mut f: F,
) -> Result<ExprKind<SE2>, Err>
where
    F: FnMut(Option<&'a Label>, &'a SE1) -> Result<SE2, Err>,
{
    // Can't use closures because of borrowing rules
    macro_rules! expr {
        ($e:expr) => {
            f(None, $e)
        };
        ($l:expr, $e:expr) => {
            f(Some($l), $e)
        };
    }

    use crate::syntax::ExprKind::*;
    Ok(match input {
        Var(v) => Var(v.clone()),
        Lam(l, t, e) => {
            let t = expr!(t)?;
            let e = expr!(l, e)?;
            Lam(l.clone(), t, e)
        }
        Pi(l, t, e) => {
            let t = expr!(t)?;
            let e = expr!(l, e)?;
            Pi(l.clone(), t, e)
        }
        Let(l, t, a, e) => {
            let t = opt(t, &mut |e| expr!(e))?;
            let a = expr!(a)?;
            let e = expr!(l, e)?;
            Let(l.clone(), t, a, e)
        }
        App(f, a) => App(expr!(f)?, expr!(a)?),
        Annot(x, t) => Annot(expr!(x)?, expr!(t)?),
        Const(k) => Const(*k),
        Builtin(v) => Builtin(*v),
        Lit(l) => Lit(l.clone()),
        TextLit(t) => TextLit(t.traverse_ref(|e| expr!(e))?),
        BinOp(o, x, y) => BinOp(*o, expr!(x)?, expr!(y)?),
        BoolIf(b, t, f) => BoolIf(expr!(b)?, expr!(t)?, expr!(f)?),
        EmptyListLit(t) => EmptyListLit(expr!(t)?),
        NEListLit(es) => NEListLit(vec(es, |e| expr!(e))?),
        SomeLit(e) => SomeLit(expr!(e)?),
        RecordType(kts) => RecordType(dupmap(kts, |e| expr!(e))?),
        RecordLit(kvs) => RecordLit(dupmap(kvs, |e| expr!(e))?),
        UnionType(kts) => UnionType(optdupmap(kts, |e| expr!(e))?),
        Merge(x, y, t) => Merge(expr!(x)?, expr!(y)?, opt(t, |e| expr!(e))?),
        ToMap(x, t) => ToMap(expr!(x)?, opt(t, |e| expr!(e))?),
        Field(e, l) => Field(expr!(e)?, l.clone()),
        Projection(e, ls) => Projection(expr!(e)?, ls.clone()),
        ProjectionByExpr(e, x) => ProjectionByExpr(expr!(e)?, expr!(x)?),
        Completion(e, x) => Completion(expr!(e)?, expr!(x)?),
        Assert(e) => Assert(expr!(e)?),
        Import(i) => Import(i.traverse_ref(|e| expr!(e))?),
    })
}