diff options
Diffstat (limited to 'expr.v')
-rw-r--r-- | expr.v | 250 |
1 files changed, 250 insertions, 0 deletions
@@ -0,0 +1,250 @@ | |||
1 | Require Import Coq.Strings.String. | ||
2 | From stdpp Require Import gmap. | ||
3 | |||
4 | (* The Nix Expression Language *) | ||
5 | |||
6 | (** Selected operators from Dolsta and Löh, 2008. Newer definitions at | ||
7 | https://nixos.org/manual/nix/stable/language/operators *) | ||
8 | Variant op : Type := | ||
9 | | O_Eq (* = *) | ||
10 | | O_Lt (* < *) | ||
11 | | O_Plus (* + *) | ||
12 | | O_Min (* - *) | ||
13 | | O_Div (* / *) | ||
14 | | O_Upd. (* // *) | ||
15 | |||
16 | Hint Constructors op : core. | ||
17 | |||
18 | Variant nonempty A := Ne_Cons (head : A) (tail : list A). | ||
19 | Arguments Ne_Cons {A} _ _. | ||
20 | Hint Constructors nonempty : core. | ||
21 | |||
22 | Inductive expr : Type := | ||
23 | | X_V (v : value) (* v *) | ||
24 | | X_Id (x : string) (* x *) | ||
25 | | X_Attrset (bs : gmap string b_rhs) (* { bᵣ* } *) | ||
26 | | X_LetBinding (bs : gmap string b_rhs) (e : expr) (* let bᵣ* in e *) | ||
27 | | X_Select (e : expr) (xs : nonempty string) (* e.xs *) | ||
28 | | X_SelectOr (e : expr) (xs : nonempty string) (or : expr) (* e.xs or e *) | ||
29 | | X_Apply (e1 e2 : expr) (* e1 e2 *) | ||
30 | | X_Cond (e1 e2 e3 : expr) (* if e1 then e2 else e3 *) | ||
31 | | X_Incl (e1 e2 : expr) (* with e1; e2 *) | ||
32 | | X_Assert (e1 e2 : expr) (* assert e1; e2 *) | ||
33 | | X_Op (op : op) (e1 e2 : expr) (* e1 <op> e2 *) | ||
34 | | X_HasAttr (e1 : expr) (x : string) (* e ? x *) | ||
35 | | X_Force (e : expr) (* force e *) | ||
36 | | X_Closed (e : expr) (* closed(e) *) | ||
37 | | X_Placeholder (x : string) (e : expr) (* placeholderₓ(e) *) | ||
38 | with b_rhs := | ||
39 | | B_Rec (e : expr) (* := e *) | ||
40 | | B_Nonrec (e : expr) (* :=ᵣ e *) | ||
41 | with matcher := | ||
42 | | M_Matcher (ms : gmap string m_rhs) (strict : bool) | ||
43 | with m_rhs := | ||
44 | | M_Mandatory | ||
45 | | M_Optional (e : expr) (* ? e *) | ||
46 | with value := | ||
47 | | V_Bool (p : bool) : value (* true | false *) | ||
48 | | V_Null : value (* null *) | ||
49 | | V_Int (n : Z) : value (* n *) | ||
50 | | V_Str (s : string) : value (* s *) | ||
51 | | V_Fn (x : string) (e : expr) : value (* x: e *) | ||
52 | | V_AttrsetFn (m : matcher) (e : expr) : value (* { m }: e *) | ||
53 | | V_Attrset (bs : gmap string expr) : value. (* { b* } *) | ||
54 | |||
55 | Hint Constructors expr : core. | ||
56 | |||
57 | Instance Maybe_X_Attrset : Maybe X_Attrset := λ e, | ||
58 | match e with | ||
59 | | X_Attrset bs => Some bs | ||
60 | | _ => None | ||
61 | end. | ||
62 | |||
63 | Instance Maybe_B_Nonrec : Maybe B_Nonrec := λ rhs, | ||
64 | match rhs with | ||
65 | | B_Nonrec e => Some e | ||
66 | | _ => None | ||
67 | end. | ||
68 | |||
69 | Instance Maybe_B_Rec : Maybe B_Rec := λ rhs, | ||
70 | match rhs with | ||
71 | | B_Rec e => Some e | ||
72 | | _ => None | ||
73 | end. | ||
74 | |||
75 | Lemma maybe_b_rhs_excl b : | ||
76 | is_Some (maybe B_Nonrec b) → is_Some (maybe B_Rec b) → False. | ||
77 | Proof. intros [e2 Hnonrec] [e1 Hrec]. simplify_option_eq. Qed. | ||
78 | |||
79 | Lemma no_b_nonrec__b_rec b : | ||
80 | ¬ is_Some (maybe B_Nonrec b) → is_Some (maybe B_Rec b). | ||
81 | Proof. | ||
82 | destruct b; try by eauto. | ||
83 | simplify_eq/=. intros contra. apply is_Some_alt. eauto. | ||
84 | Qed. | ||
85 | |||
86 | Lemma no_b_rec__b_nonrec b : | ||
87 | ¬ is_Some (maybe B_Rec b) → is_Some (maybe B_Nonrec b). | ||
88 | Proof. | ||
89 | destruct b; try by eauto. | ||
90 | simplify_eq/=. intros contra. apply is_Some_alt. eauto. | ||
91 | Qed. | ||
92 | |||
93 | Instance Maybe_V_Attrset : Maybe V_Attrset := λ e, | ||
94 | match e with | ||
95 | | V_Attrset bs => Some bs | ||
96 | | _ => None | ||
97 | end. | ||
98 | |||
99 | Instance Maybe_V_Bool : Maybe V_Bool := λ e, | ||
100 | match e with | ||
101 | | V_Bool p => Some p | ||
102 | | _ => None | ||
103 | end. | ||
104 | |||
105 | Global Instance B_Nonrec_inj : Inj (=) (=) B_Nonrec. | ||
106 | Proof. intros [] [] ?; by simplify_eq. Qed. | ||
107 | |||
108 | Definition matcher_keys (m : matcher) : gset string := | ||
109 | match m with M_Matcher ms _ => dom ms end. | ||
110 | |||
111 | Definition matcher_map (f : expr → expr) (m : matcher) : matcher := | ||
112 | let map_m_rhs := λ rhs, | ||
113 | match rhs with | ||
114 | | M_Optional e => M_Optional (f e) | ||
115 | | _ => rhs | ||
116 | end in | ||
117 | match m with | ||
118 | | M_Matcher ms strict => M_Matcher (map_m_rhs <$> ms) strict | ||
119 | end. | ||
120 | |||
121 | Local Definition map_delete_all {K V} `{Countable K} | ||
122 | (ks : gset K) (m : gmap K V) : gmap K V := | ||
123 | set_fold (λ k m', map_delete k m') m ks. | ||
124 | |||
125 | Local Definition b_rhs_map (f g : expr → expr) (rhs : b_rhs) : b_rhs := | ||
126 | match rhs with | ||
127 | | B_Rec e => B_Rec (f e) | ||
128 | | B_Nonrec e => B_Nonrec (g e) | ||
129 | end. | ||
130 | |||
131 | (* See Dolstra (2006), §4.3.3 and fig. 4.6 (p. 75, PDF: p. 83) *) | ||
132 | Fixpoint subst (subs : gmap string expr) (e : expr) : expr := | ||
133 | let msubst subs' := b_rhs_map (subst subs') (subst subs) in | ||
134 | match e with | ||
135 | | X_V V_Null | X_V (V_Bool _) | X_V (V_Str _) | X_V (V_Int _) => e | ||
136 | | X_Id x | X_Placeholder x _ => default e (subs !! x) | ||
137 | | X_Attrset bs => | ||
138 | let subs' := map_delete_all (dom bs) subs in | ||
139 | X_Attrset (msubst subs' <$> bs) | ||
140 | | X_V (V_Attrset bs) => | ||
141 | X_V (V_Attrset (subst subs <$> bs)) | ||
142 | | X_LetBinding bs e' => | ||
143 | let subs' := map_delete_all (dom bs) subs in | ||
144 | X_LetBinding (msubst subs' <$> bs) (subst subs' e') | ||
145 | | X_Select e' x => X_Select (subst subs e') x | ||
146 | | X_SelectOr e' x or => X_SelectOr (subst subs e') x (subst subs or) | ||
147 | | X_V (V_Fn x e') => | ||
148 | let subs' := map_delete x subs in | ||
149 | X_V (V_Fn x (subst subs' e')) | ||
150 | | X_V (V_AttrsetFn (M_Matcher ms _ as m) e') => | ||
151 | let subs' := map_delete_all (matcher_keys m) subs in | ||
152 | X_V (V_AttrsetFn (matcher_map (subst subs') m) (subst subs' e')) | ||
153 | | X_Apply e1 e2 => X_Apply (subst subs e1) (subst subs e2) | ||
154 | | X_Cond e1 e2 e3 => X_Cond (subst subs e1) (subst subs e2) (subst subs e3) | ||
155 | | X_Incl e1 e2 => X_Incl (subst subs e1) (subst subs e2) | ||
156 | | X_Op op e1 e2 => X_Op op (subst subs e1) (subst subs e2) | ||
157 | | X_HasAttr e x => X_HasAttr (subst subs e) x | ||
158 | | X_Assert e1 e2 => X_Assert (subst subs e1) (subst subs e2) | ||
159 | | X_Closed e => X_Closed e | ||
160 | | X_Force e => X_Force (subst subs e) | ||
161 | end. | ||
162 | |||
163 | Definition closed (bs : gmap string expr) : gmap string expr := | ||
164 | X_Closed <$> bs. | ||
165 | |||
166 | Definition placeholders (bs : gmap string expr) : gmap string expr := | ||
167 | map_imap (λ (x : string) (e : expr), Some (X_Placeholder x e)) bs. | ||
168 | |||
169 | Definition nonempty_singleton {A} (a : A): nonempty A := Ne_Cons a nil. | ||
170 | |||
171 | Definition nonempty_cons {A} (a : A) (l : nonempty A) : nonempty A := | ||
172 | match l with Ne_Cons head tail => Ne_Cons a (head :: tail) end. | ||
173 | |||
174 | Definition indirect (bs : gmap string b_rhs) : gmap string expr := | ||
175 | map_imap (λ (x : string) (rhs : b_rhs), | ||
176 | Some (X_Select (X_Attrset bs) (nonempty_singleton x))) bs. | ||
177 | |||
178 | Definition rec_subst (bs : gmap string b_rhs) : gmap string expr := | ||
179 | let subs := indirect bs | ||
180 | in (λ b, match b with | ||
181 | | B_Rec e => subst (closed subs) e | ||
182 | | B_Nonrec e => e | ||
183 | end) <$> bs. | ||
184 | |||
185 | Inductive strong_value : Type := | ||
186 | | SV_Bool (b : bool) | ||
187 | | SV_Null | ||
188 | | SV_Int (n : Z) | ||
189 | | SV_Str (s : string) | ||
190 | | SV_Fn (x : string) (e : expr) | ||
191 | | SV_AttrsetFn (m : matcher) (e : expr) | ||
192 | | SV_Attrset (bs : gmap string strong_value). | ||
193 | |||
194 | Fixpoint value_from_strong_value (sv : strong_value) : value := | ||
195 | match sv with | ||
196 | | SV_Null => V_Null | ||
197 | | SV_Bool b => V_Bool b | ||
198 | | SV_Int n => V_Int n | ||
199 | | SV_Str s => V_Str s | ||
200 | | SV_Fn x e => V_Fn x e | ||
201 | | SV_AttrsetFn m e => V_AttrsetFn m e | ||
202 | | SV_Attrset bs => V_Attrset (X_V ∘ value_from_strong_value <$> bs) | ||
203 | end. | ||
204 | |||
205 | Global Instance X_V_inj : Inj (=) (=) X_V. | ||
206 | Proof. intros [] [] ?; by simplify_eq. Qed. | ||
207 | |||
208 | Definition expr_from_strong_value : strong_value → expr := | ||
209 | X_V ∘ value_from_strong_value. | ||
210 | |||
211 | (* Based on the fin_maps test from stdpp *) | ||
212 | Fixpoint sv_size (sv : strong_value) : nat := | ||
213 | match sv with | ||
214 | | SV_Null | SV_Bool _ | SV_Int _ | SV_Str _ | ||
215 | | SV_Fn _ _ | SV_AttrsetFn _ _ => 1 | ||
216 | | SV_Attrset bs => S (map_fold (λ _ sv', plus (sv_size sv')) 0 bs) | ||
217 | end. | ||
218 | |||
219 | (* Based on the fin_maps test from stdpp *) | ||
220 | Lemma strong_value_ind' : | ||
221 | ∀ P : strong_value → Prop, | ||
222 | P SV_Null → | ||
223 | (∀ b : bool, P (SV_Bool b)) → | ||
224 | (∀ n : Z, P (SV_Int n)) → | ||
225 | (∀ s : string, P (SV_Str s)) → | ||
226 | (∀ (x : string) (e : expr), P (SV_Fn x e)) → | ||
227 | (∀ (m : matcher) (e : expr), P (SV_AttrsetFn m e)) → | ||
228 | (∀ bs : gmap string strong_value, | ||
229 | map_Forall (λ i, P) bs → P (SV_Attrset bs)) → | ||
230 | ∀ s : strong_value, P s. | ||
231 | Proof. | ||
232 | intros P PNull PBool PInt PStr PFn PAttrsetFn PAttrset sv. | ||
233 | remember (sv_size sv) as n eqn:Hn. revert sv Hn. | ||
234 | induction (lt_wf n) as [n _ IH]; intros [| | | | | | bs] ->; simpl in *; try done. | ||
235 | apply PAttrset. revert bs IH. | ||
236 | apply (map_fold_ind (λ r bs, (∀ n', n' < S r → _) → map_Forall (λ _, P) bs)). | ||
237 | - intros IH. apply map_Forall_empty. | ||
238 | - intros k sv bs r ? IHbs IHsv. apply map_Forall_insert; [done|]. split. | ||
239 | + eapply IHsv; [|done]; lia. | ||
240 | + eapply IHbs. intros; eapply IHsv; [|done]; lia. | ||
241 | Qed. | ||
242 | |||
243 | Coercion X_Id : string >-> expr. | ||
244 | Coercion V_Int : Z >-> value. | ||
245 | (* Leaving this out for now: would conflict with X_Id and | ||
246 | therefore cause ambiguity *) | ||
247 | (* Coercion X_StrVal : string >-> expr. *) | ||
248 | Coercion V_Bool : bool >-> value. | ||
249 | Coercion X_V : value >-> expr. | ||
250 | Coercion value_from_strong_value : strong_value >-> value. | ||