summaryrefslogtreecommitdiff
path: root/dhall/src/binary.rs
blob: 0f09987eb4279668081e94b0c7d8c3f42f147ea1 (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
use dhall_core::*;
use itertools::*;
use serde_cbor::value::value as cbor;

type ParsedExpr = Expr<X, Import>;

#[derive(Debug)]
pub enum DecodeError {
    CBORError(serde_cbor::error::Error),
    WrongFormatError,
}

pub fn decode(data: &[u8]) -> Result<ParsedExpr, DecodeError> {
    match serde_cbor::de::from_slice(data) {
        Ok(v) => cbor_value_to_dhall(&v),
        Err(e) => Err(DecodeError::CBORError(e)),
    }
}

fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
    use cbor::Value::*;
    use dhall_core::{BinOp, Builtin, Const};
    use Expr::*;
    match data {
        String(s) => match Builtin::parse(s) {
            Some(b) => Ok(Expr::Builtin(b)),
            None => match s.as_str() {
                "True" => Ok(Expr::BoolLit(true)),
                "False" => Ok(Expr::BoolLit(false)),
                "Type" => Ok(Expr::Const(Const::Type)),
                "Kind" => Ok(Expr::Const(Const::Kind)),
                s => Ok(Expr::Var(V(Label::from(s), 0))),
            },
        },
        U64(n) => Ok(Expr::Var(V(Label::from("_"), *n as usize))),
        F64(x) => Ok(DoubleLit(*x)),
        Bool(b) => Ok(BoolLit(*b)),
        Array(vec) => match vec.as_slice() {
            [String(l), U64(n)] => {
                let l = Label::from(l.as_str());
                Ok(Expr::Var(V(l, *n as usize)))
            }
            [U64(0), f, args..] => {
                let f = cbor_value_to_dhall(&f)?;
                let args = args
                    .iter()
                    .map(cbor_value_to_dhall)
                    .collect::<Result<Vec<_>, _>>()?;
                Ok(args
                    .into_iter()
                    .fold(f, |acc, e| (Expr::App(bx(acc), bx(e)))))
            }
            [U64(1), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                Ok(Lam(Label::from("_"), x, y))
            }
            [U64(1), String(l), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                let l = Label::from(l.as_str());
                Ok(Lam(l, x, y))
            }
            [U64(2), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                Ok(Pi(Label::from("_"), x, y))
            }
            [U64(2), String(l), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                let l = Label::from(l.as_str());
                Ok(Pi(l, x, y))
            }
            [U64(3), U64(n), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                use BinOp::*;
                let op = match n {
                    0 => BoolOr,
                    1 => BoolAnd,
                    2 => BoolEQ,
                    3 => BoolNE,
                    4 => NaturalPlus,
                    5 => NaturalTimes,
                    6 => TextAppend,
                    7 => ListAppend,
                    8 => Combine,
                    9 => Prefer,
                    10 => CombineTypes,
                    11 => ImportAlt,
                    _ => Err(DecodeError::WrongFormatError)?,
                };
                Ok(BinOp(op, x, y))
            }
            [U64(4), t] => {
                let t = bx(cbor_value_to_dhall(&t)?);
                Ok(ListLit(Some(t), vec![]))
            }
            [U64(4), Null, rest..] => {
                let rest = rest
                    .iter()
                    .map(cbor_value_to_dhall)
                    .collect::<Result<Vec<_>, _>>()?;
                Ok(ListLit(None, rest))
            }
            [U64(5), t] => {
                let t = bx(cbor_value_to_dhall(&t)?);
                Ok(OptionalLit(Some(t), vec![]))
            }
            [U64(5), Null, x] => {
                let x = cbor_value_to_dhall(&x)?;
                Ok(OptionalLit(None, vec![x]))
            }
            [U64(5), t, x] => {
                let x = cbor_value_to_dhall(&x)?;
                let t = bx(cbor_value_to_dhall(&t)?);
                Ok(OptionalLit(Some(t), vec![x]))
            }
            [U64(6), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                Ok(Merge(x, y, None))
            }
            [U64(6), x, y, z] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                let z = bx(cbor_value_to_dhall(&z)?);
                Ok(Merge(x, y, Some(z)))
            }
            [U64(7), Object(map)] => {
                let map = cbor_map_to_dhall_map(map)?;
                Ok(Record(map))
            }
            [U64(8), Object(map)] => {
                let map = cbor_map_to_dhall_map(map)?;
                Ok(RecordLit(map))
            }
            [U64(9), x, String(l)] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let l = Label::from(l.as_str());
                Ok(Field(x, l))
            }
            [U64(11), Object(map)] => {
                let map = cbor_map_to_dhall_map(map)?;
                Ok(Union(map))
            }
            [U64(12), String(l), x, Object(map)] => {
                let map = cbor_map_to_dhall_map(map)?;
                let x = bx(cbor_value_to_dhall(&x)?);
                let l = Label::from(l.as_str());
                Ok(UnionLit(l, x, map))
            }
            [U64(14), x, y, z] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                let z = bx(cbor_value_to_dhall(&z)?);
                Ok(BoolIf(x, y, z))
            }
            [U64(15), U64(x)] => Ok(NaturalLit(*x as Natural)),
            [U64(16), U64(x)] => Ok(IntegerLit(*x as Integer)),
            [U64(16), I64(x)] => Ok(IntegerLit(*x as Integer)),
            [U64(18), String(first), _rest..] => {
                // TODO: interpolated string
                Ok(TextLit(first.clone()))
            }
            [U64(25), bindings..] => {
                let mut tuples = bindings.iter().tuples();
                let bindings = (&mut tuples)
                    .map(|(x, t, v)| {
                        let x = match x {
                            String(s) => Label::from(s.as_str()),
                            _ => Err(DecodeError::WrongFormatError)?,
                        };
                        let t = match t {
                            Null => None,
                            t => Some(bx(cbor_value_to_dhall(&t)?)),
                        };
                        let v = bx(cbor_value_to_dhall(&v)?);
                        Ok((x, t, v))
                    })
                    .collect::<Result<Vec<_>, _>>()?;
                let expr = tuples
                    .into_buffer()
                    .next()
                    .ok_or(DecodeError::WrongFormatError)?;
                let expr = cbor_value_to_dhall(expr)?;
                Ok(bindings
                    .into_iter()
                    .fold(expr, |acc, (x, t, v)| Let(x, t, v, bx(acc))))
            }
            [U64(26), x, y] => {
                let x = bx(cbor_value_to_dhall(&x)?);
                let y = bx(cbor_value_to_dhall(&y)?);
                Ok(Annot(x, y))
            }
            _ => Err(DecodeError::WrongFormatError),
        },
        _ => Err(DecodeError::WrongFormatError),
    }
}

fn cbor_map_to_dhall_map(
    map: &std::collections::BTreeMap<cbor::ObjectKey, cbor::Value>,
) -> Result<std::collections::BTreeMap<Label, ParsedExpr>, DecodeError> {
    map.iter()
        .map(|(k, v)| -> Result<(_, _), _> {
            let k = k.as_string().ok_or(DecodeError::WrongFormatError)?;
            let v = cbor_value_to_dhall(v)?;
            Ok((Label::from(k.as_ref()), v))
        })
        .collect::<Result<_, _>>()
}