Module Qcert.Translation.Lang.NNRSimptoImpData
Require Import String.
Require Import List.
Require Import Bool.
Require Import Arith.
Require Import EquivDec.
Require Import Morphisms.
Require Import Permutation.
Require Import Eqdep_dec.
Require Import Utils.
Require Import DataRuntime.
Require Import NNRSimpRuntime.
Require Import Imp.
Require Import ImpData.
Require Import ImpDataEval.
Section NNRSimptoImpData.
  
Import ListNotations.
  
Context {
fruntime:
foreign_runtime}.
Translation 
  Section Translation.
    
Fixpoint nnrs_imp_expr_to_imp_data (
constants: 
string) (
exp: 
nnrs_imp_expr): 
imp_data_expr :=
      
match exp with
      | 
NNRSimpGetConstant x =>
        
ImpExprOp (
DataOpUnary (
OpDot x)) [ 
ImpExprVar constants ]
      | 
NNRSimpVar x =>
        
ImpExprVar x
      | 
NNRSimpConst d =>
        
ImpExprConst d
      | 
NNRSimpBinop op e1 e2 =>
        
let e1' := 
nnrs_imp_expr_to_imp_data constants e1 in
        let e2' := 
nnrs_imp_expr_to_imp_data constants e2 in
        ImpExprOp (
DataOpBinary op) [
e1'; 
e2']
      | 
NNRSimpUnop op e =>
        
let e' := 
nnrs_imp_expr_to_imp_data constants e in
        ImpExprOp (
DataOpUnary op) [
e']
      | 
NNRSimpGroupBy g fields e =>
        
let e' := 
nnrs_imp_expr_to_imp_data constants e in
        ImpExprRuntimeCall (
DataRuntimeGroupby g fields) [ 
e' ]
      
end.
    
Fixpoint nnrs_imp_stmt_to_imp_data (
constants: 
string) (
stmt: 
nnrs_imp_stmt): 
imp_data_stmt :=
      
match stmt with
      | 
NNRSimpSkip =>
        @
ImpStmtBlock imp_data_model imp_data_op imp_data_runtime_op  [] []
      | 
NNRSimpSeq s1 s2 =>
        
ImpStmtBlock
          []
          [ 
nnrs_imp_stmt_to_imp_data constants s1;
              
nnrs_imp_stmt_to_imp_data constants s2 ]
      | 
NNRSimpLet x e s =>
        
ImpStmtBlock
          [ (
x, 
lift (
nnrs_imp_expr_to_imp_data constants) 
e) ]
          [ 
nnrs_imp_stmt_to_imp_data constants s ]
      | 
NNRSimpAssign x e =>
        
ImpStmtAssign x (
nnrs_imp_expr_to_imp_data constants e)
      | 
NNRSimpFor x e s =>
        
ImpStmtFor x (
nnrs_imp_expr_to_imp_data constants e) (
nnrs_imp_stmt_to_imp_data constants s)
      | 
NNRSimpIf e s1 s2 =>
        
ImpStmtIf
          (
nnrs_imp_expr_to_imp_data constants e)
          (
nnrs_imp_stmt_to_imp_data constants s1)
          (
nnrs_imp_stmt_to_imp_data constants s2)
      | 
NNRSimpEither e x1 s1 x2 s2 =>
        
let e' := 
nnrs_imp_expr_to_imp_data constants e in
        ImpStmtIf
          (
ImpExprRuntimeCall DataRuntimeEither [
e'])
          (
ImpStmtBlock 
             [ (
x1, 
Some (
ImpExprRuntimeCall DataRuntimeToLeft [
e'])) ]
             [ 
nnrs_imp_stmt_to_imp_data constants s1 ])
          (
ImpStmtBlock 
             [ (
x2, 
Some (
ImpExprRuntimeCall DataRuntimeToRight [
e'])) ]
             [ 
nnrs_imp_stmt_to_imp_data constants s2 ])
      
end.
    
Definition nnrs_imp_to_imp_data_function (
q: 
nnrs_imp): 
imp_function :=
      
let (
stmt, 
ret) := 
q in
      let constants :=
          
let fv := 
nnrs_imp_stmt_free_vars stmt in
          let bv := 
nnrs_imp_stmt_bound_vars stmt in
          fresh_var "
constants"%
string (
ret :: 
fv ++ 
bv)
      
in
      let body := 
nnrs_imp_stmt_to_imp_data constants stmt in
      ImpFun constants body ret.
    
Definition nnrs_imp_to_imp_data_top (
qname: 
string) (
q: 
nnrs_imp): 
imp :=
      
ImpLib [ (
qname, 
nnrs_imp_to_imp_data_function q) ].
  
End Translation.
  
Section Correctness.
    
Lemma nnrs_imp_expr_to_imp_data_correct h (σ
c:
bindings) (σ:
pd_bindings) (
exp:
nnrs_imp_expr) :
      
forall constants: 
string,
        
let σ0 : 
pd_bindings :=
            σ ++ [(
constants,  
Some (
drec σ
c))]
        
in
        ~ 
In constants (
nnrs_imp_expr_free_vars exp) ->
        
lookup equiv_dec σ 
constants = 
None ->
        
nnrs_imp_expr_eval h σ
c σ 
exp = 
imp_data_expr_eval h σ0 (
nnrs_imp_expr_to_imp_data constants exp).
Proof.
      intros constants.
      
nnrs_imp_expr_cases (
induction exp) 
Case; 
simpl.
      - 
Case "
NNRSimpGetConstant"%
string.
        
intros Hfv Hσ.
        
rewrite (
lookup_app equiv_dec constants).
        
unfold olift.
        
unfold Var.var.
        
unfold imp_data_model.
        
case_eq (
lookup equiv_dec σ 
constants); 
try congruence.
        
intros.
        
unfold lookup.
        
case (
equiv_dec constants constants); 
try congruence.
        
intros.
        
reflexivity.
      - 
Case "
NNRSimpVar"%
string.
        
intros Hfv Hσ.
        
rewrite (
lookup_app equiv_dec v).
        
unfold id.
        
unfold olift.
        
unfold Var.var.
        
unfold imp_data_model.
        
case_eq (
lookup equiv_dec σ 
v); 
try reflexivity.
        
intros Hv.
        
case_eq (
lookup equiv_dec [(
constants, 
Some (
drec σ
c))] 
v); 
try congruence.
        
intros.
        
simpl in H.
        
destruct Hfv.
        
left.
        
case_eq (
equiv_dec v constants); 
try congruence.
        
intros.
        
unfold Var.var in *.
        
rewrite H0 in H.
        
congruence.
      - 
Case "
NNRSimpConst"%
string.
        
reflexivity.
      - 
Case "
NNRSimpBinop"%
string.
        
intros Hfv Hσ.
        
simpl in *.
        
rewrite app_or_in_iff in Hfv.
        
apply notand in Hfv.
        
destruct Hfv as [ 
Hfv1 Hfv2 ].
        
rewrite <- (
IHexp1 Hfv1 Hσ).
        
rewrite <- (
IHexp2 Hfv2 Hσ).
        
match_destr. 
match_destr.
      - 
Case "
NNRSimpUnop"%
string. 
        
intros Hfv Hσ.
        
simpl in *.
        
rewrite <- 
IHexp; 
trivial.
        
match_destr.
      - 
Case "
NNRSimpGroupBy"%
string.
        
intros Hfv Hσ.
        
simpl in *.
        
rewrite <- 
IHexp; 
trivial.
        
match_destr.
    Qed.
 
    Lemma nnrs_imp_stmt_to_imp_data_correct h (σ
c:
bindings) (σ:
pd_bindings) (
stmt:
nnrs_imp_stmt) :
      
forall constants: 
string,
        
let σ0 : 
pd_bindings :=
            σ ++ [(
constants,  
Some (
drec σ
c))]
        
in
        ~ 
In constants (
nnrs_imp_stmt_free_vars stmt) ->
        ~ 
In constants (
nnrs_imp_stmt_bound_vars stmt) ->
        
lookup equiv_dec σ 
constants = 
None ->
        
olift (
fun σ
r => 
Some (σ
r ++ [(
constants,  
Some (
drec σ
c))]))
              (
nnrs_imp_stmt_eval h σ
c stmt σ) =
        
imp_data_stmt_eval h (
nnrs_imp_stmt_to_imp_data constants stmt) σ0.
Proof.
    Lemma nnrs_imp_to_imp_data_function_correct h (σ
c:
bindings) (
q:
nnrs_imp) :
      
olift id (
nnrs_imp_eval h (
rec_sort σ
c) 
q) =
      
imp_data_function_eval h (
nnrs_imp_to_imp_data_function q) (
drec (
rec_sort σ
c)).
Proof.
    Theorem nnrs_imp_to_imp_data_top_correct h (σ
c:
bindings) (
qname: 
string) (
q:
nnrs_imp) :
      
nnrs_imp_eval_top h σ
c q =
      
imp_data_eval_top h σ
c (
nnrs_imp_to_imp_data_top qname q).
Proof.
  End Correctness.
End NNRSimptoImpData.