Library syntax

Require Import base.
Require Import ZArith.
Require Import ZArith_dec.

Require Import nominal.

Inductive OPS :=
  | PLUS
  | MINUS
  | MULT
  | DIV
  | MOD
  | EQ
  | NEQ
  | LE
  | LT
  | GE
  | GT.

Inductive EXPR :=
  | const : Z -> EXPR
  | op : OPS -> EXPR -> EXPR -> EXPR
  | cond : EXPR -> EXPR -> EXPR -> EXPR
  | var : VAR -> EXPR
  | assign : VAR -> EXPR -> EXPR.

Fixpoint expr_idents (e:EXPR) : list VAR :=
  match e with
  | const _ => nil
  | op _ e1 e2 => expr_idents e1 ++ expr_idents e2
  | cond e1 e2 e3 => expr_idents e1 ++ expr_idents e2 ++ expr_idents e3
  | var v => v::nil
  | assign v e => v :: expr_idents e
  end.

Inductive STMT :=
  | expr : EXPR -> STMT
  | seq : STMT -> STMT -> STMT
  | local : VAR -> STMT -> STMT
  | ifte : EXPR -> STMT -> STMT -> STMT
  | while : EXPR -> STMT -> STMT.

Fixpoint stmt_free_idents (s:STMT) : list VAR :=
  match s with
  | expr e => expr_idents e
  | seq s1 s2 => stmt_free_idents s1 ++ stmt_free_idents s2
  | local v s => remove eq_nat_dec v (stmt_free_idents s)
  | ifte e s1 s2 => expr_idents e ++ stmt_free_idents s1 ++ stmt_free_idents s2
  | while e s => expr_idents e ++ stmt_free_idents s
  end.

Inductive var_state :=
| var_indeterm : var_state
| var_determ : Z -> var_state.

Inductive OBS :=
  | read : VAR -> var_state -> OBS
  | write : VAR -> var_state -> OBS
  | obs_val : Z -> OBS.

Inductive obs_complement (v:VAR) : OBS -> OBS -> Prop :=
  | obs_comp_rw : forall z, obs_complement v (read v z) (write v z)
  | obs_comp_wr : forall z, obs_complement v (write v z) (read v z).

Fixpoint expr_papp (p:perm) (e:EXPR) : EXPR :=
  match e with
  | const z => const z
  | op a e1 e2 => op a (expr_papp p e1) (expr_papp p e2)
  | cond e1 e2 e3 => cond (expr_papp p e1) (expr_papp p e2) (expr_papp p e3)
  | var v => var (perm_f p v)
  | assign v e => assign (perm_f p v) (expr_papp p e)
  end.

Lemma papp_expr_idents : forall e p,
  expr_idents (expr_papp p e) = papp p (expr_idents e).

Instance expr_nominal : Nominal EXPR eq :=
  {| papp := expr_papp
   ; support e v := In v (expr_idents e)
   |}.



Defined.

Fixpoint stmt_papp (p:perm) (s:STMT) : STMT :=
  match s with
  | expr e => expr (papp p e)
  | seq s1 s2 => seq (stmt_papp p s1) (stmt_papp p s2)
  | local v s => local (papp p v) (stmt_papp p s)
  | ifte e s1 s2 => ifte (papp p e) (stmt_papp p s1) (stmt_papp p s2)
  | while e s => while (papp p e) (stmt_papp p s)
  end.

Lemma papp_stmt_free_idents : forall s p,
  stmt_free_idents (stmt_papp p s) = papp p (stmt_free_idents s).

Definition alpha_eq (s1 s2:STMT) :=
  exists p,
    (forall v, In v (stmt_free_idents s1) -> perm_f p v = v) /\
    stmt_papp p s1 = s2.

Program Instance stmt_nominal : Nominal STMT alpha_eq :=
 {| papp := stmt_papp
  ; support s v := In v (stmt_free_idents s)
  |}.

Lemma alpha_eq_refl : forall s,
  alpha_eq s s.

Lemma alpha_eq_sym : forall s1 s2, alpha_eq s1 s2 -> alpha_eq s2 s1.

Lemma alpha_eq_trans : forall s1 s2 s3,
  alpha_eq s1 s2 -> alpha_eq s2 s3 -> alpha_eq s1 s3.

Instance obs_nominal : Nominal OBS eq :=
  {| papp p o :=
        match o with
        | read x v => read (papp p x) v
        | write x v => write (papp p x) v
        | obs_val z => obs_val z
        end
   ; support o v :=
        match o with
        | read x _ => x = v
        | write x _ => x = v
        | obs_val _ => False
        end
   |}.




Defined.