diff options
| author | Rutger Broekhoff | 2024-06-26 20:50:18 +0200 | 
|---|---|---|
| committer | Rutger Broekhoff | 2024-06-26 20:50:18 +0200 | 
| commit | 73df1945b31c0beee88cf4476df4ccd09d31403b (patch) | |
| tree | ed00db26b711442e643f38b66888a3df56e33ebd /expr.v | |
| download | mininix-formalization-73df1945b31c0beee88cf4476df4ccd09d31403b.tar.gz mininix-formalization-73df1945b31c0beee88cf4476df4ccd09d31403b.zip | |
Import Coq project
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. | ||