Module Qcert.Imp.Optim.ImpEJsonRewrite


Imp is a simpl imperative intermediate language.

Require Import String.
Require Import List.
Require Import Bool.
Require Import Arith.
Require Import ZArith.
Require Import Utils.
Require Import JsAst.JsNumber.
Require Import EJsonRuntime.
Require Import Imp.
Require Import ImpEJson.
Require Import ImpEJsonVars.
Require Import ImpEJsonEval.

Section ImpEJsonRewrite.
  Import ListNotations.

  Context {foreign_ejson_model:Set}.
  Context {fejson:foreign_ejson foreign_ejson_model}.
  Context {foreign_ejson_runtime_op : Set}.
  Context {fejruntime:foreign_ejson_runtime foreign_ejson_runtime_op}.

  Section ForLetRewrite.

    Definition imp_ejson_stmt_for_let_rewrite (stmt: @imp_ejson_stmt foreign_ejson_model foreign_ejson_runtime_op): imp_ejson_stmt :=
      match stmt with
      | ImpStmtFor v e s =>
        let avoid := v :: imp_ejson_stmt_free_vars s in
        let src_id := fresh_var "src" avoid in
        let src := ImpExprVar src_id in
        ImpStmtBlock
          [ (src_id, Some e) ]
          [ ImpStmtFor v src s ]
      | _ => stmt
      end.

  End ForLetRewrite.

  Section CorrectnessForLetRewrite.

    Lemma lookup_first_var A (i0 : A) (v:var) σ :
      lookup EquivDec.equiv_dec ((v, i0) :: σ) v = Some i0.
Proof.
      simpl.
      destruct (EquivDec.equiv_dec v v); try congruence.
    Qed.

    Lemma test1 h stmt v j σ σ':
      imp_ejson_stmt_eval h stmt
        ((fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), j) :: σ) = Some ((fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), j) :: σ') ->
      imp_ejson_stmt_eval h stmt σ = Some σ'.
Proof.
      imp_stmt_cases (destruct stmt) Case; simpl; intros.
      - admit.
      - admit.
      - admit.
      - admit.
      - admit.
    Admitted.

    Lemma test2 h stmt x1 v j σ:
      imp_ejson_stmt_eval h stmt
        (x1 :: (fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), Some j) :: σ) = None <->
      imp_ejson_stmt_eval h stmt (x1 :: σ) = None.
Proof.
      admit.
    Admitted.

    Lemma test3 h stmt v l σ σ' i0 :
      (fix for_fun
           (dl : list imp_ejson_model) (σ₁ : list (var * option imp_ejson_model)) {struct dl} :
         option (list (var * option imp_ejson_model)) :=
         match dl with
         | [] => Some σ₁
         | d :: dl' =>
           match imp_ejson_stmt_eval h stmt ((v, Some d) :: σ₁) with
           | Some (_ :: σ₂) => for_fun dl' σ₂
           | _ => None
           end
         end) l σ = Some σ' ->
      (fix for_fun
       (dl : list imp_ejson_model) (σ₁ : list (var * option imp_ejson_model)) {struct dl} :
         option (list (var * option imp_ejson_model)) :=
       match dl with
       | [] => Some σ₁
       | d :: dl' =>
           match imp_ejson_stmt_eval h stmt ((v, Some d) :: σ₁) with
           | Some (_ :: σ₂) => for_fun dl' σ₂
           | _ => None
           end
       end) l ((fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), Some i0) :: σ) = Some ((fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), Some i0) :: σ').
Proof.
      admit.
    Admitted.

    Lemma test4 h stmt v l σ i0 :
      (fix for_fun
           (dl : list imp_ejson_model) (σ₁ : list (var * option imp_ejson_model)) {struct dl} :
         option (list (var * option imp_ejson_model)) :=
         match dl with
         | [] => Some σ₁
         | d :: dl' =>
           match imp_ejson_stmt_eval h stmt ((v, Some d) :: σ₁) with
           | Some (_ :: σ₂) => for_fun dl' σ₂
           | _ => None
           end
         end) l σ = None ->
      (fix for_fun
       (dl : list imp_ejson_model) (σ₁ : list (var * option imp_ejson_model)) {struct dl} :
         option (list (var * option imp_ejson_model)) :=
       match dl with
       | [] => Some σ₁
       | d :: dl' =>
           match imp_ejson_stmt_eval h stmt ((v, Some d) :: σ₁) with
           | Some (_ :: σ₂) => for_fun dl' σ₂
           | _ => None
           end
       end) l ((fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), Some i0) :: σ) = None.
Proof.
      admit.
    Admitted.

    Lemma test5 h stmt v i0 i1 σ:
      imp_ejson_stmt_eval h stmt ((v, Some i1) :: σ) = None ->
      imp_ejson_stmt_eval h stmt
                          ((v, Some i1) :: (fresh_var "src" (v :: imp_ejson_stmt_free_vars stmt), Some i0) :: σ) = None.
Proof.
      admit.
    Admitted.
    
    Lemma imp_ejson_stmt_for_let_rewrite_correct h (σ : pd_jbindings) (stmt:imp_ejson_stmt) :
        imp_ejson_stmt_eval h stmt σ =
        imp_ejson_stmt_eval h (imp_ejson_stmt_for_let_rewrite stmt) σ.
Proof.
      destruct stmt; try reflexivity.
      simpl.
      unfold ImpEval.imp_decls_eval; unfold olift; simpl.
      generalize (@ImpEval.imp_expr_eval (@imp_ejson_model foreign_ejson_model)
        (@imp_ejson_constant foreign_ejson_model) imp_ejson_op
        (@imp_ejson_runtime_op foreign_ejson_runtime_op)
        (@imp_ejson_model_normalize foreign_ejson_model)
        (@imp_ejson_runtime_eval foreign_ejson_model fejson foreign_ejson_runtime_op fejruntime h)
        (@imp_ejson_op_eval foreign_ejson_model) σ i); intros; clear i.
      destruct o; try reflexivity.
      rewrite lookup_first_var.
      destruct (imp_ejson_model_to_list i); try reflexivity.
      admit.
    Admitted.

  End CorrectnessForLetRewrite.

  Section ForRewrite.

    Definition imp_ejson_stmt_for_rewrite (stmt: @imp_ejson_stmt foreign_ejson_model foreign_ejson_runtime_op): imp_ejson_stmt :=
      match stmt with
      | ImpStmtFor v (ImpExprVar src_id) s =>
        let avoid := imp_ejson_stmt_free_vars stmt in
        let i_id := fresh_var "i" avoid in
        let avoid := i_id :: avoid in
        let i := ImpExprVar i_id in
        ImpStmtForRange
          i_id
          (ImpExprConst (cejbigint 0))
          (ImpExprRuntimeCall
             EJsonRuntimeNatMinus [
               ImpExprRuntimeCall EJsonRuntimeArrayLength [ (ImpExprVar src_id) ]; ImpExprConst (cejbigint 1)
          ])
          (ImpStmtBlock
             [ (v, Some (ImpExprRuntimeCall EJsonRuntimeArrayAccess [ (ImpExprVar src_id); i ])) ]
             [ s ])
      | _ => stmt
      end.
  End ForRewrite.

  Section CorrectnessForRewrite.

    Lemma number_iterations A (l: list A):
      (ImpEval.nb_iter 0 (BinInt.Z.sub (BinInt.Z.of_nat (List.length l)) 1)) = length l.
Proof.
      unfold ImpEval.nb_iter; simpl.
      induction (Datatypes.length l); [ simpl; reflexivity | ].
      rewrite BinInt.Z.sub_1_r.
      rewrite Znat.Nat2Z.inj_succ.
      rewrite <- BinInt.Zpred_succ.
      case n; [ simpl; reflexivity | ].
      intros.
      rewrite <- BinInt.Zminus_0_l_reverse.
      rewrite Znat.Nat2Z.id.
      simpl; reflexivity.
    Qed.

    Fixpoint list_n_nat {A} (n:nat) (l:list A) :=
      match n with
      | 0 => nil
      | S n' =>
        match l with
        | nil => nil
        | x :: l' => x :: (list_n_nat n' l')
        end
      end.

    Definition list_tail_n_nat {A} n (l: list A) :=
      List.rev (list_n_nat n (List.rev l)).

    Lemma imp_ejson_stmt_for_rewrite_correct h (σ : pd_jbindings) (stmt:imp_ejson_stmt) :
        imp_ejson_stmt_eval h stmt σ =
        imp_ejson_stmt_eval h (imp_ejson_stmt_for_rewrite stmt) σ.
Proof.
      imp_stmt_cases (destruct stmt) Case; try reflexivity; intros.
      simpl.
      destruct i; try reflexivity; intros; simpl.
      destruct (@olift (option (@imp_ejson_model foreign_ejson_model))
        (@imp_ejson_model foreign_ejson_model)
        (fun x : option (@imp_ejson_model foreign_ejson_model) => x)
        (@lookup string (option (@imp_ejson_model foreign_ejson_model))
           (@EquivDec.equiv_dec string (@eq string) (@RelationClasses.eq_equivalence string)
              string_eqdec) σ v0)); try reflexivity.
      simpl.
      unfold imp_ejson_model_to_list.
      case i; simpl; try reflexivity; intros l; clear i.
      rewrite number_iterations.
      revert σ.
      induction l; [ simpl; reflexivity | ].
      intros.
      simpl.
      unfold olift.
      admit.
    Admitted.

  End CorrectnessForRewrite.

End ImpEJsonRewrite.