aboutsummaryrefslogtreecommitdiffstats
Require Import Coq.Strings.String.
From stdpp Require Import gmap.
From mininix Require Import binop expr matching relations.

Definition attrset := is_Some ∘ maybe V_Attrset.

Reserved Infix "-->base" (right associativity, at level 55).

Inductive base_step : expr → expr → Prop :=
  | E_Force (sv : strong_value) :
      X_Force sv -->base sv
  | E_Closed e :
      X_Closed e -->base e
  | E_Placeholder x e :
      X_Placeholder x e -->base e
  | E_MSelect bs x ys :
      X_Select (V_Attrset bs) (nonempty_cons x ys) -->base
      X_Select (X_Select (V_Attrset bs) (nonempty_singleton x)) ys
  | E_Select e bs x :
      X_Select (V_Attrset (<[x := e]>bs)) (nonempty_singleton x) -->base e
  | E_SelectOr bs x e :
      X_SelectOr (V_Attrset bs) (nonempty_singleton x) e -->base
        X_Cond (X_HasAttr (V_Attrset bs) x)
               (* if true *)
               (X_Select (V_Attrset bs) (nonempty_singleton x))
               (* if false *)
               e
  | E_MSelectOr bs x ys e :
      X_SelectOr (V_Attrset bs) (nonempty_cons x ys) e -->base
        X_Cond (X_HasAttr (V_Attrset bs) x)
               (* if true *)
               (X_SelectOr
                 (X_Select (V_Attrset bs) (nonempty_singleton x))
                 ys e)
               (* if false *)
               e
  | E_Rec bs :
      X_Attrset bs -->base V_Attrset (rec_subst bs)
  | E_Let e bs :
      X_LetBinding bs e -->base subst (closed (rec_subst bs)) e
  | E_With e bs :
      X_Incl (V_Attrset bs) e -->base subst (placeholders bs) e
  | E_WithNoAttrset v1 e2 :
      ¬ attrset v1 →
      X_Incl v1 e2 -->base e2
  | E_ApplySimple x e1 e2 :
      X_Apply (V_Fn x e1) e2 -->base subst {[x := X_Closed e2]} e1
  | E_ApplyAttrset m e bs bs' :
      bs ~ m ~> bs' →
      X_Apply (V_AttrsetFn m e) (V_Attrset bs) -->base
      X_LetBinding bs' e
  | E_ApplyFunctor e1 e2 bs :
      X_Apply (V_Attrset (<["__functor" := e2]>bs)) e1 -->base
      X_Apply (X_Apply e2 (V_Attrset (<["__functor" := e2]>bs))) e1
  | E_IfTrue e2 e3 :
      X_Cond true e2 e3 -->base e2
  | E_IfFalse e2 e3 :
      X_Cond false e2 e3 -->base e3
  | E_Op op v1 v2 u :
      v1 ⟦op⟧ v2 -⊚-> u →
      X_Op op v1 v2 -->base u
  | E_OpHasAttrTrue bs x :
      is_Some (bs !! x) →
      X_HasAttr (V_Attrset bs) x -->base true
  | E_OpHasAttrFalse bs x :
      bs !! x = None →
      X_HasAttr (V_Attrset bs) x -->base false
  | E_OpHasAttrNoAttrset v x :
      ¬ attrset v →
      X_HasAttr v x -->base false
  | E_Assert e2 :
      X_Assert true e2 -->base e2
where "e -->base e'" := (base_step e e').

Notation "e '-->base*' e'" := (rtc base_step e e')
                              (right associativity, at level 55).

Hint Constructors base_step : core.

Variant is_ctx_item : bool → bool → (expr → expr) → Prop :=
  | IsCtxItem_Select uf_ext xs :
      is_ctx_item uf_ext false (λ e1, X_Select e1 xs)
  | IsCtxItem_SelectOr uf_ext xs e2 :
      is_ctx_item uf_ext false (λ e1, X_SelectOr e1 xs e2)
  | IsCtxItem_Incl uf_ext e2 :
      is_ctx_item uf_ext false (λ e1, X_Incl e1 e2)
  | IsCtxItem_ApplyL uf_ext e2 :
      is_ctx_item uf_ext false (λ e1, X_Apply e1 e2)
  | IsCtxItem_ApplyAttrsetR uf_ext m e1 :
      is_ctx_item uf_ext false (λ e2, X_Apply (V_AttrsetFn m e1) e2)
  | IsCtxItem_CondL uf_ext e2 e3 :
      is_ctx_item uf_ext false (λ e1, X_Cond e1 e2 e3)
  | IsCtxItem_AssertL uf_ext e2 :
      is_ctx_item uf_ext false (λ e1, X_Assert e1 e2)
  | IsCtxItem_OpL uf_ext op e2 :
      is_ctx_item uf_ext false (λ e1, X_Op op e1 e2)
  | IsCtxItem_OpR uf_ext op v1 :
      is_ctx_item uf_ext false (λ e2, X_Op op (X_V v1) e2)
  | IsCtxItem_OpHasAttrL uf_ext x :
      is_ctx_item uf_ext false (λ e, X_HasAttr e x)
  | IsCtxItem_Force uf_ext :
      is_ctx_item uf_ext true (λ e, X_Force e)
  | IsCtxItem_ForceAttrset bs x :
      is_ctx_item true true (λ e, X_V (V_Attrset (<[x := e]>bs))).

Hint Constructors is_ctx_item : core.

Inductive is_ctx : bool → bool → (expr → expr) → Prop :=
  | IsCtx_Id uf : is_ctx uf uf id
  | IsCtx_Compose E1 E2 uf_int uf_aux uf_ext :
      is_ctx_item uf_ext uf_aux E1 →
      is_ctx uf_aux uf_int E2 →
      is_ctx uf_ext uf_int (E1 ∘ E2).

Hint Constructors is_ctx : core.

(* /--> This is required because the standard library definition of "-->"
   |    (in Coq.Classes.Morphisms, for `respectful`) defines that this operator
   |    uses right associativity. Our definition must match exactly, as Coq
   |    will give an error otherwise.
   \-------------------------------------\
                     |                   | *)
Reserved Infix "-->" (right associativity, at level 55).

Variant step : expr → expr → Prop :=
  E_Ctx e1 e2 E uf_int :
    is_ctx false uf_int E →
    e1 -->base e2 →
    E e1 --> E e2
where "e --> e'" := (step e e').

Hint Constructors step : core.

Notation "e '-->*' e'" := (rtc step e e') (right associativity, at level 55).

(** Theories for contexts *)

Lemma is_ctx_once uf_ext uf_int E :
  is_ctx_item uf_ext uf_int E → is_ctx uf_ext uf_int E.
Proof. intros. eapply IsCtx_Compose; [done | constructor]. Qed.

Lemma is_ctx_item_ext_imp E uf_int :
  is_ctx_item false uf_int E → is_ctx_item true uf_int E.
Proof. intros H. inv H; constructor. Qed.

Lemma is_ctx_ext_imp E1 E2 uf_aux uf_int :
  is_ctx_item false uf_aux E1 →
  is_ctx uf_aux uf_int E2 →
  is_ctx true uf_int (E1 ∘ E2).
Proof.
  intros H1 H2.
  revert E1 H1.
  induction H2; intros.
  - inv H1; eapply IsCtx_Compose; constructor.
  - eapply IsCtx_Compose.
    + by apply is_ctx_item_ext_imp in H1.
    + by eapply IsCtx_Compose.
Qed.

Lemma is_ctx_uf_false_impl_true E uf_int :
  is_ctx false uf_int E →
  is_ctx true uf_int E ∨ E = id.
Proof.
  intros Hctx. inv Hctx.
  - by right.
  - left. eapply is_ctx_ext_imp; [apply H | apply H0].
Qed.