Library Rustre.Minimp.Semantics

Require Import Coq.FSets.FMapPositive.
Require Import Rustre.Nelist.
Require Import List.

Require Import Rustre.Common.
Require Import Rustre.Memory.
Require Import Rustre.Minimp.Syntax.

Minimp semantics

The semantics of Minimp relies on a tree-structure memory, based on Rustre.Memory, to store object instances and a stack to keep track of local variables during method calls.

Definition heap: Type := memory const.
Definition stack : Set := PM.t const.

Implicit Type mmem: heap.
Implicit Type stack: stack.

Definition sempty: stack := PM.empty const.
Definition hempty: heap := empty_memory _.

Inductive exp_eval heap stack:
  expconstProp :=
| evar:
     x v,
      PM.find x stack = Some(v) →
      exp_eval heap stack (Var(x)) v
| estate:
     x v,
      mfind_mem x heap = Some(v) →
      exp_eval heap stack (State(x)) v
| econst:
     c ,
      exp_eval heap stack (Const(c)) c
| eop:
     op es cs c,
      Nelist.Forall2 (exp_eval heap stack) es cs
      apply_op op cs = Some c
      exp_eval heap stack (Op op es) c.

Lemma exps_eval_const:
   h s cs,
    Nelist.Forall2 (exp_eval h s) (Nelist.map Const cs) cs.
Proof.
  Hint Constructors exp_eval.
  intros h s cs. induction cs; constructor; eauto.
Qed.

Inductive stmt_eval :
    programheapstackstmtheap × stackProp :=
| Iassign:
     prog menv env x e v env´,
      exp_eval menv env e v
      PM.add x v env = env´
      stmt_eval prog menv env (Assign x e) (menv, env´)
| Iassignst:
     prog menv env x e v menv´,
      exp_eval menv env e v
      madd_mem x v menv = menv´
      stmt_eval prog menv env (AssignSt x e) (menv´, env)
| Istep:
     prog menv env es vs clsid o y menv´ env´ omenv omenv´ rv,
      mfind_inst o menv = Some(omenv) →
      Nelist.Forall2 (exp_eval menv env) es vs
      stmt_step_eval prog omenv clsid vs omenv´ rv
      madd_obj o omenv´ menv = menv´
      PM.add y rv env = env´
      stmt_eval prog menv env (Step_ap y clsid o es) (menv´, env´)
| Ireset:
     prog menv env o clsid omenv´ menv´,
      stmt_reset_eval prog clsid omenv´
      madd_obj o omenv´ menv = menv´
      stmt_eval prog menv env (Reset_ap clsid o) (menv´, env)
| Icomp:
     prog menv env a1 a2 env1 menv1 env2 menv2,
      stmt_eval prog menv env a1 (menv1, env1)
      stmt_eval prog menv1 env1 a2 (menv2, env2)
      stmt_eval prog menv env (Comp a1 a2) (menv2, env2)
| Iifte_true:
     prog menv env b ifTrue ifFalse env´ menv´,
      exp_eval menv env b (Cbool true) →
      stmt_eval prog menv env ifTrue (menv´, env´)
      stmt_eval prog menv env (Ifte b ifTrue ifFalse) (menv´, env´)
| Iifte_false:
     prog menv env b ifTrue ifFalse env´ menv´,
      exp_eval menv env b (Cbool false) →
      stmt_eval prog menv env ifFalse (menv´, env´)
      stmt_eval prog menv env (Ifte b ifTrue ifFalse) (menv´, env´)
| Iskip:
     prog menv env,
      stmt_eval prog menv env Skip (menv, env)

with stmt_step_eval :
       programheapidentnelist constheapconstProp :=
| Iestep:
     prog menv env clsid ivs prog´ menv´ ov cls env´,
      find_class clsid prog = Some(cls, prog´)
      env = adds cls.(c_input) ivs sempty
      stmt_eval prog´ menv env cls.(c_step)
                (menv´, env´)
      PM.find cls.(c_output) env´ = Some(ov) →
      stmt_step_eval prog menv clsid ivs menv´ ov

with stmt_reset_eval : programidentheapProp :=
| Iereset:
     prog clsid cls prog´ menv´ env´,
      find_class clsid prog = Some(cls, prog´)
      stmt_eval prog´ hempty sempty cls.(c_reset) (menv´, env´)
      stmt_reset_eval prog clsid menv´.

Scheme stmt_eval_mult := Induction for stmt_eval Sort Prop
with stmt_step_eval_mult := Induction for stmt_step_eval Sort Prop
with stmt_reset_eval_mult := Induction for stmt_reset_eval Sort Prop.

Determinism of semantics


Lemma exp_eval_det:
   menv env e v1 v2,
    exp_eval menv env e v1
    exp_eval menv env e v2
    v1 = v2.
Proof.
  induction e using exp_ind2;
    intros v1 v2 H1 H2;
    inversion H1 as [xa va Hv1|xa va Hv1|xa va Hv1| xa opa esa IHa Hv1];
    inversion H2 as [xb vb Hv2|xb vb Hv2|xb vb Hv2| xb opb esb IHb Hv2];
    try (rewrite Hv1 in Hv2; (injection Hv2; trivial) || apply Hv2).
  subst.
  assert (esa = esb).
  { clear H1 H2 H4 H8. revert esa esb Hv1 Hv2. induction es; intros esa esb Hv1 Hv2.
    × inversion_clear Hv1. inversion_clear Hv2. f_equal. inversion_clear IHes. now apply H1.
    × inversion_clear Hv1. inversion_clear Hv2. inversion_clear IHes. f_equal.
      + now apply H3.
      + now apply IHes0. }
  subst. rewrite H4 in ×. now inversion H8.
Qed.

Lemma stmt_eval_fold_left_shift:
   A prog f (xs:list A) iacc menv env menv´ env´,
    stmt_eval prog menv env
              (List.fold_left (fun i xComp (f x) i) xs iacc)
              (menv´, env´)
    
     menv´´ env´´,
      stmt_eval prog menv env
                (List.fold_left (fun i xComp (f x) i) xs Skip)
                (menv´´, env´´)
      
      stmt_eval prog menv´´ env´´ iacc (menv´, env´).
Proof.
  Hint Constructors stmt_eval.
  induction xs.
  - split; [ now eauto | ].
    intro H; do 2 destruct H.
    destruct H as [H0 H1].
    inversion_clear H0; apply H1.
  - intros.
    split.
    + intro H0.
      apply IHxs in H0.
      destruct H0 as [menv´´ H0].
      destruct H0 as [env´´ H0].
      destruct H0 as [H0 H1].
      inversion_clear H1.
       menv1. env1.
      split; try apply IHxs; eauto.
    + intros;
      repeat progress
             match goal with
             | H: _, _ |- _destruct H
             | H:_ _ |- _destruct H
             | H:stmt_eval _ _ _ (Comp _ Skip) _ |- _inversion_clear H
             | H:stmt_eval _ _ _ Skip _ |- _inversion H; subst
             | H:stmt_eval _ _ _ (List.fold_left _ _ _) _ |- _apply IHxs in H
             | _eauto
             end.
      apply IHxs; eauto.
Qed.

Lemma exp_evals_det:
   menv env es vs1 vs2,
    Nelist.Forall2 (exp_eval menv env) es vs1
    Nelist.Forall2 (exp_eval menv env) es vs2
    vs1 = vs2.
Proof.
  intros menv env es vs1 vs2 H1; generalize dependent vs2.
  induction H1 as [|e1 c1 es1 cs1]; intros vs2 H2;
  inversion_clear H2 as [|e2 c2 es2 cs2].
  - f_equal. eauto using exp_eval_det.
  - assert (c1 = c2) by eauto using exp_eval_det.
    assert (cs1 = cs2) by eauto using IHForall2.
    congruence.
Qed.

Lemma stmt_eval_det:
   prog s menv env renv1 renv2,
    stmt_eval prog menv env s renv1
    → stmt_eval prog menv env s renv2
    → renv1 = renv2.
Proof.
  intros prog s menv env renv1 renv2 Hs1.
  revert renv2.
  induction Hs1 using stmt_eval_mult
  with (P:=fun prog menv env s renv1 sev
              renv2, stmt_eval prog menv env s renv2renv1 = renv2)
       (P0:=fun prog menv clsid v menv´ rv ssev
               menv´´ rv´, stmt_step_eval prog menv clsid v menv´´ rv´
                                 → menv´ = menv´´ rv = rv´)
       (P1:=fun prog i menv srev
               menv´, stmt_reset_eval prog i menv´menv = menv´);
    inversion_clear 1;
    repeat progress match goal with
    | H: ?env = adds _ _ _ |- _subst env
    | Ht: exp_eval ?menv ?env ?e (Cbool true),
      Hf: exp_eval ?menv ?env ?e (Cbool false) |- _
      pose proof (exp_eval_det _ _ _ _ _ Ht Hf) as Hneq; discriminate
    | H1:exp_eval ?menv ?env ?e ?v1,
      H2:exp_eval ?menv ?env ?e ?v2 |- _
      pose proof (exp_eval_det _ _ _ _ _ H1 H2) as Heq;
        rewrite Heq in *; clear Heq H1 H2
    | H1: Nelist.Forall2 (exp_eval ?menv ?env) ?es ?vs1,
      H2: Nelist.Forall2 (exp_eval ?menv ?env) ?es ?vs2 |- _
      pose proof (exp_evals_det _ _ _ _ _ H1 H2) as Heq;
        rewrite Heq in *; clear Heq H1 H2
    | H1: PM.add ?x ?v ?env = ?env1,
      H2: PM.add ?x ?v ?env = ?env2 |- _
      rewrite H1 in H2; rewrite H2 in *; clear H1 H2
    | H1: madd_mem ?x ?v ?menv = ?menv1,
      H2: madd_mem ?x ?v ?menv = ?menv2 |- _
      rewrite H1 in H2; rewrite H2 in *; clear H1 H2
    | H1: mfind_inst ?o ?menv = Some ?omenv1,
      H2: mfind_inst ?o ?menv = Some ?omenv2 |- _
      rewrite H1 in H2; injection H2; intro Heq; rewrite Heq in *;
      clear H1 H2 Heq
    | H1: find_class ?clsid ?prog = _,
      H2: find_class ?clsid ?prog = _ |- _
      rewrite H1 in H2; injection H2;
      intros Heq1 Heq2; rewrite Heq1, Heq2 in *; clear H2 H2 Heq1 Heq2
    | H1: PM.find ?x ?env = ?rv1,
      H2: PM.find ?x ?env = ?rv2 |- _
      rewrite H1 in H2; injection H2; rewrite H2 in *; clear H1 H2
    | Hs: stmt_step_eval ?prog ?omenv ?clsid ?v _ _,
          IH: context[stmt_step_eval ?prog ?omenv ?clsid ?v _ __ = _ _ = _]
              |- _
      apply IH in Hs; destruct Hs as [Heq1 Heq2]; try rewrite Heq1 in *;
      try rewrite Heq2 in *; clear Heq1 Heq2
    | Hs: stmt_reset_eval ?prog ?clsid _,
      IH: context[stmt_reset_eval ?prog ?clsid __ = _] |- _
      apply IH in Hs; try rewrite Hs in *; clear Hs
    | Hs: stmt_eval ?prog ?menv ?env ?stmt _,
      IH: context[stmt_eval ?prog ?menv ?env ?stmt _(_, _) = _] |- _
      apply IH in Hs; injection Hs; intros Heq1 Heq2;
      try rewrite Heq1 in *; try rewrite Heq2 in *; clear Heq1 Heq2 Hs
    | H1: madd_obj ?o ?omenv ?menv = ?menv1,
      H2: madd_obj ?o ?omenv ?menv = ?menv2 |- _
      rewrite H1 in H2; rewrite H2 in *; clear H1 H2
    | _intuition
    end.
Qed.