diff options
Diffstat (limited to 'theories/nix/interp.v')
-rw-r--r-- | theories/nix/interp.v | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/theories/nix/interp.v b/theories/nix/interp.v new file mode 100644 index 0000000..bb4e815 --- /dev/null +++ b/theories/nix/interp.v | |||
@@ -0,0 +1,351 @@ | |||
1 | From Coq Require Import Ascii. | ||
2 | From mininix Require Export res nix.operational_props. | ||
3 | From stdpp Require Import options. | ||
4 | |||
5 | Section val. | ||
6 | Local Unset Elimination Schemes. | ||
7 | Inductive val := | ||
8 | | VLit (bl : base_lit) (Hbl : base_lit_ok bl) | ||
9 | | VClo (x : string) (E : gmap string (kind * thunk)) (e : expr) | ||
10 | | VCloMatch (E : gmap string (kind * thunk)) | ||
11 | (ms : gmap string (option expr)) | ||
12 | (strict : bool) (e : expr) | ||
13 | | VList (ts : list thunk) | ||
14 | | VAttr (ts : gmap string thunk) | ||
15 | with thunk := | ||
16 | | Forced (v : val) : thunk | ||
17 | | Thunk (E : gmap string (kind * thunk)) (e : expr) : thunk | ||
18 | | Indirect (x : string) | ||
19 | (E : gmap string (kind * thunk)) | ||
20 | (tαs : gmap string (expr + thunk)). | ||
21 | End val. | ||
22 | |||
23 | Notation VLitI bl := (VLit bl I). | ||
24 | |||
25 | Notation tattr := (expr + thunk)%type. | ||
26 | Notation env := (gmap string (kind * thunk)). | ||
27 | |||
28 | Definition maybe_VLit (v : val) : option base_lit := | ||
29 | if v is VLit bl _ then Some bl else None. | ||
30 | Global Instance maybe_VList : Maybe VList := λ v, | ||
31 | if v is VList ts then Some ts else None. | ||
32 | Global Instance maybe_VAttr : Maybe VAttr := λ v, | ||
33 | if v is VAttr ts then Some ts else None. | ||
34 | |||
35 | Fixpoint interp_eq_list_body (i : nat) (ts1 ts2 : list thunk) : expr := | ||
36 | match ts1, ts2 with | ||
37 | | [], [] => ELit (LitBool true) | ||
38 | | _ :: ts1, _ :: ts2 => | ||
39 | EIf (EBinOp EqOp (EId' ("1" +:+ pretty i)) (EId' ("2" +:+ pretty i))) | ||
40 | (interp_eq_list_body (S i) ts1 ts2) (ELit (LitBool false)) | ||
41 | | _, _ => ELit (LitBool false) | ||
42 | end. | ||
43 | |||
44 | Definition interp_eq_list (ts1 ts2 : list thunk) : thunk := | ||
45 | Thunk (kmap (λ n : nat, String "1" (pretty n)) ((ABS,.) <$> map_seq 0 ts1) ∪ | ||
46 | kmap (λ n : nat, String "2" (pretty n)) ((ABS,.) <$> map_seq 0 ts2)) $ | ||
47 | interp_eq_list_body 0 ts1 ts2. | ||
48 | |||
49 | Fixpoint interp_lt_list_body (i : nat) (ts1 ts2 : list thunk) : expr := | ||
50 | match ts1, ts2 with | ||
51 | | [], _ => ELit (LitBool true) | ||
52 | | _ :: ts1, _ :: ts2 => | ||
53 | EIf (EBinOp LtOp (EId' ("1" +:+ pretty i)) (EId' ("2" +:+ pretty i))) | ||
54 | (ELit (LitBool true)) | ||
55 | (EIf (EBinOp EqOp (EId' ("1" +:+ pretty i)) (EId' ("2" +:+ pretty i))) | ||
56 | (interp_lt_list_body (S i) ts1 ts2) (ELit (LitBool false))) | ||
57 | | _ :: _, [] => ELit (LitBool false) | ||
58 | end. | ||
59 | |||
60 | Definition interp_lt_list (ts1 ts2 : list thunk) : thunk := | ||
61 | Thunk (kmap (λ n : nat, String "1" (pretty n)) ((ABS,.) <$> map_seq 0 ts1) ∪ | ||
62 | kmap (λ n : nat, String "2" (pretty n)) ((ABS,.) <$> map_seq 0 ts2)) $ | ||
63 | interp_lt_list_body 0 ts1 ts2. | ||
64 | |||
65 | Definition interp_eq_attr (ts1 ts2 : gmap string thunk) : thunk := | ||
66 | Thunk (kmap (String "1") ((ABS,.) <$> ts1) ∪ | ||
67 | kmap (String "2") ((ABS,.) <$> ts2)) $ | ||
68 | sem_and_attr $ map_imap (λ x _, | ||
69 | Some (EBinOp EqOp (EId' ("1" +:+ x)) (EId' ("2" +:+ x)))) ts1. | ||
70 | |||
71 | Definition interp_eq (v1 v2 : val) : option thunk := | ||
72 | match v1, v2 with | ||
73 | | VLit bl1 _, VLit bl2 _ => | ||
74 | Some $ Forced $ VLitI (LitBool $ sem_eq_base_lit bl1 bl2) | ||
75 | | VClo _ _ _, VClo _ _ _ => None | ||
76 | | VList ts1, VList ts2 => Some $ | ||
77 | if decide (length ts1 = length ts2) then interp_eq_list ts1 ts2 | ||
78 | else Forced $ VLitI (LitBool false) | ||
79 | | VAttr ts1, VAttr ts2 => Some $ | ||
80 | if decide (dom ts1 = dom ts2) then interp_eq_attr ts1 ts2 | ||
81 | else Forced $ VLitI (LitBool false) | ||
82 | | _, _ => Some $ Forced $ VLitI (LitBool false) | ||
83 | end. | ||
84 | |||
85 | Definition type_of_val (v : val) : string := | ||
86 | match v with | ||
87 | | VLit bl _ => type_of_base_lit bl | ||
88 | | VClo _ _ _ | VCloMatch _ _ _ _ => "lambda" | ||
89 | | VList _ => "list" | ||
90 | | VAttr _ => "set" | ||
91 | end. | ||
92 | |||
93 | Global Instance val_inhabited : Inhabited val := populate (VLitI inhabitant). | ||
94 | Global Instance thunk_inhabited : Inhabited thunk := populate (Forced inhabitant). | ||
95 | |||
96 | Definition interp_bin_op (op : bin_op) (v1 : val) : option (val → option thunk) := | ||
97 | if decide (op = EqOp) then | ||
98 | Some (interp_eq v1) | ||
99 | else if decide (op = TypeOfOp) then | ||
100 | Some $ λ v2, | ||
101 | guard (maybe_VLit v2 = Some LitNull);; | ||
102 | Some $ Forced $ VLitI (LitString $ type_of_val v1) | ||
103 | else | ||
104 | match v1 with | ||
105 | | VLit (LitNum n1) Hn1 => | ||
106 | if maybe RoundOp op is Some m then | ||
107 | Some $ λ v2, | ||
108 | guard (maybe_VLit v2 = Some LitNull);; | ||
109 | Some $ Forced $ VLit | ||
110 | (LitNum $ NInt $ float_to_bounded_Z $ Float.round m $ num_to_float n1) | ||
111 | (float_to_bounded_Z_ok _) | ||
112 | else | ||
113 | '(f ↾ Hf) ← option_to_eq_Some (sem_bin_op_num op n1); | ||
114 | Some $ λ v2, | ||
115 | if v2 is VLit (LitNum n2) Hn2 then | ||
116 | '(bl ↾ Hbl) ← option_to_eq_Some (f n2); | ||
117 | Some $ Forced $ VLit bl (sem_bin_op_num_ok Hn1 Hn2 Hf Hbl) | ||
118 | else None | ||
119 | | VLit (LitString s1) _ => | ||
120 | match op with | ||
121 | | SingletonAttrOp => Some $ λ v2, | ||
122 | guard (maybe_VLit v2 = Some LitNull);; | ||
123 | Some $ Forced $ VClo "t" ∅ (EAttr {[ s1 := AttrN (EId' "t") ]}) | ||
124 | | MatchStringOp => Some $ λ v2, | ||
125 | guard (maybe_VLit v2 = Some LitNull);; | ||
126 | match s1 with | ||
127 | | EmptyString => Some $ Forced $ VAttr {[ | ||
128 | "empty" := Forced (VLitI (LitBool true)); | ||
129 | "head" := Forced (VLitI LitNull); | ||
130 | "tail" := Forced (VLitI LitNull) ]} | ||
131 | | String a s1 => Some $ Forced $ VAttr {[ | ||
132 | "empty" := Forced (VLitI (LitBool false)); | ||
133 | "head" := Forced (VLitI (LitString (String a EmptyString))); | ||
134 | "tail" := Forced (VLitI (LitString s1)) ]} | ||
135 | end | ||
136 | | _ => | ||
137 | '(f ↾ Hf) ← option_to_eq_Some (sem_bin_op_string op); | ||
138 | Some $ λ v2, | ||
139 | bl2 ← maybe_VLit v2; | ||
140 | s2 ← maybe LitString bl2; | ||
141 | Some $ Forced $ VLit (f s1 s2) (sem_bin_op_string_ok Hf) | ||
142 | end | ||
143 | | VClo _ _ _ => | ||
144 | match op with | ||
145 | | FunctionArgsOp => Some $ λ v2, | ||
146 | guard (maybe_VLit v2 = Some LitNull);; | ||
147 | Some (Forced (VAttr ∅)) | ||
148 | | _ => None | ||
149 | end | ||
150 | | VCloMatch _ ms _ _ => | ||
151 | match op with | ||
152 | | FunctionArgsOp => Some $ λ v2, | ||
153 | guard (maybe_VLit v2 = Some LitNull);; | ||
154 | Some $ Forced $ VAttr $ | ||
155 | (λ m, Forced $ VLitI (LitBool (from_option (λ _, true) false m))) <$> ms | ||
156 | | _ => None | ||
157 | end | ||
158 | | VList ts1 => | ||
159 | match op with | ||
160 | | LtOp => Some $ λ v2, | ||
161 | ts2 ← maybe VList v2; | ||
162 | Some (interp_lt_list ts1 ts2) | ||
163 | | MatchListOp => Some $ λ v2, | ||
164 | guard (maybe_VLit v2 = Some LitNull);; | ||
165 | match ts1 with | ||
166 | | [] => Some $ Forced $ VAttr {[ | ||
167 | "empty" := Forced (VLitI (LitBool true)); | ||
168 | "head" := Forced (VLitI LitNull); | ||
169 | "tail" := Forced (VLitI LitNull) ]} | ||
170 | | t :: ts1 => Some $ Forced $ VAttr {[ | ||
171 | "empty" := Forced (VLitI (LitBool false)); | ||
172 | "head" := t; | ||
173 | "tail" := Forced (VList ts1) ]} | ||
174 | end | ||
175 | | AppendListOp => Some $ λ v2, | ||
176 | ts2 ← maybe VList v2; | ||
177 | Some (Forced (VList (ts1 ++ ts2))) | ||
178 | | _ => None | ||
179 | end | ||
180 | | VAttr ts1 => | ||
181 | match op with | ||
182 | | SelectAttrOp => Some $ λ v2, | ||
183 | bl ← maybe_VLit v2; | ||
184 | x ← maybe LitString bl; | ||
185 | ts1 !! x | ||
186 | | UpdateAttrOp => Some $ λ v2, | ||
187 | ts2 ← maybe VAttr v2; | ||
188 | Some $ Forced $ VAttr $ ts2 ∪ ts1 | ||
189 | | HasAttrOp => Some $ λ v2, | ||
190 | bl ← maybe_VLit v2; | ||
191 | x ← maybe LitString bl; | ||
192 | Some $ Forced $ VLitI (LitBool $ bool_decide (is_Some (ts1 !! x))) | ||
193 | | DeleteAttrOp => Some $ λ v2, | ||
194 | bl ← maybe_VLit v2; | ||
195 | x ← maybe LitString bl; | ||
196 | Some $ Forced $ VAttr $ delete x ts1 | ||
197 | | MatchAttrOp => Some $ λ v2, | ||
198 | guard (maybe_VLit v2 = Some LitNull);; | ||
199 | match map_minimal_key attr_le ts1 with | ||
200 | | None => Some $ Forced $ VAttr {[ | ||
201 | "empty" := Forced (VLitI (LitBool true)); | ||
202 | "key" := Forced (VLitI LitNull); | ||
203 | "head" := Forced (VLitI LitNull); | ||
204 | "tail" := Forced (VLitI LitNull) ]} | ||
205 | | Some x => Some $ Forced $ VAttr {[ | ||
206 | "empty" := Forced (VLitI (LitBool false)); | ||
207 | "key" := Forced (VLitI (LitString x)); | ||
208 | "head" := ts1 !!! x; | ||
209 | "tail" := Forced (VAttr (delete x ts1)) ]} | ||
210 | end | ||
211 | | _ => None | ||
212 | end | ||
213 | | _ => None | ||
214 | end. | ||
215 | |||
216 | Definition interp_match | ||
217 | (ts : gmap string thunk) (mds : gmap string (option expr)) | ||
218 | (strict : bool) : option (gmap string tattr) := | ||
219 | map_mapM id $ merge (λ mt mmd, | ||
220 | (* Some (Some _) means keep, Some None means fail, None means skip *) | ||
221 | match mt, mmd with | ||
222 | | Some t, Some _ => Some $ Some (inr t) | ||
223 | | None, Some (Some e) => Some $ Some (inl e) | ||
224 | | None, Some _ => Some None (* bad *) | ||
225 | | Some _, None => guard strict;; Some None | ||
226 | | _, _ => None (* skip *) | ||
227 | end) ts mds. | ||
228 | |||
229 | Definition force_deep1 | ||
230 | (force_deep : val → res val) | ||
231 | (interp_thunk : thunk → res val) (v : val) : res val := | ||
232 | match v with | ||
233 | | VList ts => VList ∘ fmap Forced <$> | ||
234 | mapM (mbind force_deep ∘ interp_thunk) ts | ||
235 | | VAttr ts => VAttr ∘ fmap Forced <$> | ||
236 | map_mapM_sorted attr_le (mbind force_deep ∘ interp_thunk) ts | ||
237 | | _ => mret v | ||
238 | end. | ||
239 | |||
240 | Definition indirects_env (E : env) (tαs : gmap string tattr) : env := | ||
241 | map_imap (λ y _, Some (ABS, Indirect y E tαs)) tαs ∪ E. | ||
242 | |||
243 | Definition attr_to_tattr (E : env) (α : attr) : tattr := | ||
244 | from_attr inl (inr ∘ Thunk E) α. | ||
245 | |||
246 | Definition interp1 | ||
247 | (force_deep : val → res val) | ||
248 | (interp : env → expr → res val) | ||
249 | (interp_thunk : thunk → res val) | ||
250 | (interp_app : val → thunk → res val) | ||
251 | (E : env) (e : expr) : res val := | ||
252 | match e with | ||
253 | | ELit bl => | ||
254 | bl_ok ← guard (base_lit_ok bl); | ||
255 | mret (VLit bl bl_ok) | ||
256 | | EId x mke => | ||
257 | '(_,t) ← Res $ union_kinded (E !! x) (prod_map id (Thunk ∅) <$> mke); | ||
258 | interp_thunk t | ||
259 | | EAbs x e => mret (VClo x E e) | ||
260 | | EAbsMatch ms strict e => mret (VCloMatch E ms strict e) | ||
261 | | EApp e1 e2 => | ||
262 | v1 ← interp E e1; | ||
263 | interp_app v1 (Thunk E e2) | ||
264 | | ESeq μ' e1 e2 => | ||
265 | v ← interp E e1; | ||
266 | (if μ' is DEEP then force_deep else mret) v;; | ||
267 | interp E e2 | ||
268 | | EList es => mret (VList (Thunk E <$> es)) | ||
269 | | EAttr αs => | ||
270 | let E' := indirects_env E (attr_to_tattr E <$> αs) in | ||
271 | mret (VAttr (from_attr (Thunk E') (Thunk E) <$> αs)) | ||
272 | | ELetAttr k e1 e2 => | ||
273 | v1 ← interp E e1; | ||
274 | ts ← Res (maybe VAttr v1); | ||
275 | interp (union_kinded ((k,.) <$> ts) E) e2 | ||
276 | | EBinOp op e1 e2 => | ||
277 | v1 ← interp E e1; | ||
278 | f ← Res (interp_bin_op op v1); | ||
279 | v2 ← interp E e2; | ||
280 | t2 ← Res (f v2); | ||
281 | interp_thunk t2 | ||
282 | | EIf e1 e2 e3 => | ||
283 | v1 ← interp E e1; | ||
284 | '(b : bool) ← Res (maybe_VLit v1 ≫= maybe LitBool); | ||
285 | interp E (if b then e2 else e3) | ||
286 | end. | ||
287 | |||
288 | Definition interp_thunk1 | ||
289 | (interp : env → expr → res val) | ||
290 | (interp_thunk : thunk → res val) | ||
291 | (t : thunk) : res val := | ||
292 | match t with | ||
293 | | Forced v => mret v | ||
294 | | Thunk E e => interp E e | ||
295 | | Indirect x E tαs => | ||
296 | tα ← Res $ tαs !! x; | ||
297 | match tα with | ||
298 | | inl e => interp (indirects_env E tαs) e | ||
299 | | inr t => interp_thunk t | ||
300 | end | ||
301 | end. | ||
302 | |||
303 | Definition interp_app1 | ||
304 | (interp : env → expr → res val) | ||
305 | (interp_thunk : thunk → res val) | ||
306 | (interp_app : val → thunk → res val) | ||
307 | (v1 : val) (t2 : thunk) : res val := | ||
308 | match v1 with | ||
309 | | VClo x E e => | ||
310 | interp (<[x:=(ABS, t2)]> E) e | ||
311 | | VCloMatch E ms strict e => | ||
312 | vt ← interp_thunk t2; | ||
313 | ts ← Res (maybe VAttr vt); | ||
314 | tαs ← Res $ interp_match ts ms strict; | ||
315 | interp (indirects_env E tαs) e | ||
316 | | VAttr ts => | ||
317 | t ← Res (ts !! "__functor"); | ||
318 | vt ← interp_thunk t; | ||
319 | v ← interp_app vt (Forced v1); | ||
320 | interp_app v t2 | ||
321 | | _ => mfail | ||
322 | end. | ||
323 | |||
324 | Fixpoint force_deep (n : nat) (v : val) : res val := | ||
325 | match n with | ||
326 | | O => NoFuel | ||
327 | | S n => force_deep1 (force_deep n) (interp_thunk n) v | ||
328 | end | ||
329 | with interp (n : nat) (E : env) (e : expr) : res val := | ||
330 | match n with | ||
331 | | O => NoFuel | ||
332 | | S n => interp1 (force_deep n) (interp n) (interp_thunk n) (interp_app n) E e | ||
333 | end | ||
334 | with interp_thunk (n : nat) (t : thunk) : res val := | ||
335 | match n with | ||
336 | | O => NoFuel | ||
337 | | S n => interp_thunk1 (interp n) (interp_thunk n) t | ||
338 | end | ||
339 | with interp_app (n : nat) (v1 : val) (t2 : thunk) : res val := | ||
340 | match n with | ||
341 | | O => NoFuel | ||
342 | | S n => interp_app1 (interp n) (interp_thunk n) (interp_app n) v1 t2 | ||
343 | end. | ||
344 | |||
345 | Definition force_deep' (n : nat) (μ : mode) : val → res val := | ||
346 | match μ with SHALLOW => mret | DEEP => force_deep n end. | ||
347 | |||
348 | Definition interp' (n : nat) (μ : mode) (E : env) (e : expr) : res val := | ||
349 | interp n E e ≫= force_deep' n μ. | ||
350 | |||
351 | Global Opaque force_deep interp interp_thunk interp_app. | ||