Module statements

This file defines statements and program contexts. Program contexts are an extension of Huet's zipper (Huet, 1997). They annotate local variable declarations with their associated memory index, and keep track of the program's stack. In the operational semantics we will use the program context to traverse through the statement that is being executed. This approach makes it easy to keep track of which memory cells should be freed upon uses of non-local control flow (goto and return).
Program contexts may be seen as a generalization of continuations (as for example being used in Compcert's small step semantics). However, there are some notable differences.
Require Export expressions.

Substitution

We define an operational type class for substitution of the hole of a context.
Class Subst A B C := subst: ABC.
Arguments subst {_ _ _ _} !_ _ /.

Since contexts are generally defined as lists of singular contexts, this type class is useful to lift substitution to lists of contexts in a generic way.
Instance list_subst `{Subst A B B} : Subst (list A) B B :=
  fix go (l : list A) (b : B) : B :=
  let _ : Subst _ _ _ := @go in
  match l with
  | [] => b
  | a :: l => subst l (subst a b)
  end.
Lemma list_subst_app `{Subst A B B} (l1 l2 : list A) b :
  subst (l1 ++ l2) b = subst l2 (subst l1 b).
Proof. revert b. induction l1; simpl; auto. Qed.

Function names

We use Coq's type of binary natural numbers N for function names, and the Nmap implementation for efficient finite maps with function names as keys.
Definition funname := N.
Definition funmap := Nmap.

Instance funname_eq_dec: ∀ i1 i2: funname, Decision (i1 = i2) := decide_rel (=).
Instance funname_fresh `{FinCollection funname C} : Fresh funname C := _.
Instance funname_fresh_spec `{FinCollection funname C} :
  FreshSpec funname C := _.

Instance funmap_dec {A} `{∀ a1 a2 : A, Decision (a1 = a2)} :
  ∀ m1 m2 : funmap A, Decision (m1 = m2) := decide_rel (=).
Instance funmap_empty {A} : Empty (funmap A) := @empty (Nmap A) _.
Instance funmap_lookup {A} : Lookup funname A (funmap A) :=
  @lookup _ _ (Nmap A) _.
Instance funmap_partial_alter {A} : PartialAlter funname A (funmap A) :=
  @partial_alter _ _ (Nmap A) _.
Instance funmap_to_list {A} : FinMapToList funname A (funmap A) :=
  @finmap_to_list _ _ (funmap A) _.
Instance funmap_merge {A} : Merge A (funmap A) := @merge _ (Nmap A) _.
Instance funmap_fmap: FMap funmap := λ A B f, @fmap Nmap _ _ f _.
Instance: FinMap funname funmap := _.

Typeclasses Opaque funname funmap.

Labels and gotos

We use Coq's type of binary natural numbers N for label names. We define operational type classes to collect free occurrences of labels and labels used by gotos.
Definition label := N.
Class Gotos A := gotos: Alistset label.
Arguments gotos {_ _} !_ / : simpl nomatch.
Class Labels A := labels: Alistset label.
Arguments labels {_ _} !_ / : simpl nomatch.

We lift instances of the above type classes to lists of contexts.
Instance list_gotos `{Gotos A} : Gotos (list A) :=
  fix go (l : list A) :=
  let _ : Gotos _ := @go in
  match l with
  | [] => ∅
  | a :: l => gotos agotos l
  end.
Instance list_labels `{Labels A} : Labels (list A) :=
  fix go (l : list A) :=
  let _ : Labels _ := @go in
  match l with
  | [] => ∅
  | a :: l => labels alabels l
  end.

Statements

Since expressions cannot perform side effects, we extend function calls to assign the result: SCall (Some e) f es calls f with arguments es and assigns the result to e. The constructor SBlock represents a local variable declaration. Since we treat variables in De Bruijn style it does not include a name of the variable.
Inductive stmt : Type :=
  | SAssign : exprexprstmt
  | SCall : option exprfunnamelist exprstmt
  | SSkip : stmt
  | SGoto : labelstmt
  | SReturn : option exprstmt
  | SBlock : stmtstmt
  | SComp : stmtstmtstmt
  | SLabel : labelstmtstmt
  | SWhile : exprstmtstmt
  | SIf : exprstmtstmtstmt.
Notation funenv := (funmap stmt).

Instance stmt_eq_dec (s1 s2 : stmt) : Decision (s1 = s2).
Proof. solve_decision. Defined.

We use the scope stmt_scope for notations of statements.
Delimit Scope stmt_scope with S.
Bind Scope stmt_scope with stmt.
Open Scope stmt_scope.

Arguments SBlock _%S.
Arguments SComp _%S _%S.
Arguments SLabel _ _%S.
Arguments SWhile _%E _%S.
Arguments SIf _%E _%S _%S.

Infix "::=" := SAssign (at level 60) : stmt_scope.
Notation "'call' f @ es" := (SCall None f es%E) (at level 60) : stmt_scope.
Notation "e ::= 'call' f @ es" := (SCall (Some e%E) f es%E)
  (at level 60, format "e ::= 'call' f @ es") : stmt_scope.
Notation "'skip'" := SSkip : stmt_scope.
Notation "'goto' l" := (SGoto l) (at level 10) : stmt_scope.
Notation "'ret' e" := (SReturn e%E) (at level 10) : stmt_scope.
Notation "'block' s" := (SBlock s) (at level 10) : stmt_scope.

Infix ";;" := SComp (at level 80, right associativity) : stmt_scope.
Infix ":;" := SLabel (at level 81, right associativity) : stmt_scope.
Notation "'while' '(' e ')' s" := (SWhile e s)
  (at level 10, format "'while' '(' e ')' s") : stmt_scope.
Notation "'IF' e 'then' s1 'else' s2" := (SIf e s1 s2) : stmt_scope.

Instance: Injective (=) (=) SBlock.
Proof. congruence. Qed.

Instance stmt_gotos: Gotos stmt :=
  fix go (s : stmt) :=
  let _ : Gotos _ := @go in
  match s with
  | block s => gotos s
  | s1 ;; s2 => gotos s1gotos s2
  | _ :; s => gotos s
  | while (_) s => gotos s
  | (IF _ then s1 else s2) => gotos s1gotos s2
  | goto l => {[ l ]}
  | _ => ∅
  end.
Instance stmt_labels: Labels stmt :=
  fix go (s : stmt) :=
  let _ : Labels _ := @go in
  match s with
  | block s => labels s
  | s1 ;; s2 => labels s1labels s2
  | l :; s => {[ l ]} ∪ labels s
  | while (_) s => labels s
  | (IF _ then s1 else s2) => labels s1labels s2
  | _ => ∅
  end.

Program contexts

We first define the data type sctx_item of singular program contexts for all constructors of stmt that do not require additional annotations. That is, for all constructors besides local variable declarations SBlock.
Inductive sctx_item : Type :=
  | CCompL : stmtsctx_item
  | CCompR : stmtsctx_item
  | CLabel : labelsctx_item
  | CWhile : exprsctx_item
  | CIfL : exprstmtsctx_item
  | CIfR : exprstmtsctx_item.

Instance sctx_item_eq_dec (E1 E2 : sctx_item) : Decision (E1 = E2).
Proof. solve_decision. Defined.

Bind Scope stmt_scope with sctx_item.
Notation "s ;; □" := (CCompL s) (at level 80) : stmt_scope.
Notation "□ ;; s" := (CCompR s) (at level 80) : stmt_scope.
Notation "l :; □" := (CLabel l) (at level 81) : stmt_scope.
Notation "'while' ( e ) □" := (CWhile e)
  (at level 10, format "'while' '(' e ')' □") : stmt_scope.
Notation "'IF' e 'then' □ 'else' s2" := (CIfL e s2)
  (at level 200, right associativity) : stmt_scope.
Notation "'IF' e 'then' s1 'else' □" := (CIfR e s1)
  (at level 200, right associativity) : stmt_scope.

Instance sctx_item_subst: Subst sctx_item stmt stmt := λ E s,
  match E with
  | □ ;; s2 => s ;; s2
  | s1 ;; □ => s1 ;; s
  | l :; □ => l :; s
  | while (e) □ => while (e) s
  | (IF e thenelse s2) => IF e then s else s2
  | (IF e then s1 else □) => IF e then s1 else s
  end.

Instance: ∀ E : sctx_item, Injective (=) (=) (subst E).
Proof. by destruct E; repeat intro; simpl in *; simplify_equality. Qed.

Instance sctx_item_gotos: Gotos sctx_item := λ E,
  match E with
  | s2 ;; □ => gotos s2
  | □ ;; s1 => gotos s1
  | l :; □ => ∅
  | while (_) □ => ∅
  | (IF _ thenelse s2) => gotos s2
  | (IF _ then s1 else □) => gotos s1
  end.
Instance sctx_item_labels: Labels sctx_item := λ E,
  match E with
  | s2 ;; □ => labels s2
  | □ ;; s1 => labels s1
  | l :; □ => {[ l ]}
  | while (_) □ => ∅
  | (IF _ thenelse s2) => labels s2
  | (IF _ then s1 else □) => labels s1
  end.

Lemma elem_of_sctx_item_gotos (E : sctx_item) (s : stmt) l :
  lgotos (subst E s) ↔ lgotos Elgotos s.
Proof. destruct E; solve_elem_of. Qed.
Lemma sctx_item_gotos_spec (E : sctx_item) (s : stmt) :
  gotos (subst E s) ≡ gotos Egotos s.
Proof.
  apply elem_of_equiv. intros.
  rewrite elem_of_union. by apply elem_of_sctx_item_gotos.
Qed.


Lemma elem_of_sctx_item_labels (E : sctx_item) (s : stmt) l :
  llabels (subst E s) ↔ llabels Ellabels s.
Proof. destruct E; solve_elem_of. Qed.
Lemma sctx_item_labels_spec (E : sctx_item) (s : stmt) :
  labels (subst E s) ≡ labels Elabels s.
Proof.
  apply elem_of_equiv. intros.
  rewrite elem_of_union. by apply elem_of_sctx_item_labels.
Qed.


Now we define the type ctx_item which extends sctx_item with the following singular contexts: Program contexts ctx are then defined as lists of singular contexts.
Inductive ctx_item : Type :=
  | CItem : sctx_itemctx_item
  | CBlock : indexctx_item
  | CCall : option exprfunnamelist exprctx_item
  | CParams : list indexctx_item.
Notation ctx := (list ctx_item).
Bind Scope stmt_scope with ctx_item.

Instance ctx_item_eq_dec (E1 E2 : ctx_item) : Decision (E1 = E2).
Proof. solve_decision. Defined.
Instance ctx_eq_dec (k1 k2 : ctx) : Decision (k1 = k2).
Proof. solve_decision. Defined.

Given a context, we can construct a stack using the following erasure function.
Fixpoint get_stack (k : ctx) : stack :=
  match k with
  | [] => []
  | CItem _ :: k => get_stack k
  | CBlock b :: k => b :: get_stack k
  | CCall _ _ _ :: _ => []
  | CParams bs :: k => bs ++ get_stack k
  end.

Tactics

Ltac simplify_stmt_equality := simpl in *; repeat
  match goal with
  | _ => progress simplify_equality
  | H : @subst sctx_item stmt stmt _ ?E _ = _ |- _ =>
    is_var E; destruct E; simpl in H
  | H : _ = @subst sctx_item stmt stmt _ ?E _ |- _ =>
    is_var E; destruct E; simpl in H
  end.

Ltac unfold_stmt_elem_of := repeat
  match goal with
  | H : context [ _gotos (subst _ _) ] |- _ =>
    setoid_rewrite elem_of_sctx_item_gotos in H
  | H : context [ _labels (subst _ _) ] |- _ =>
    setoid_rewrite elem_of_sctx_item_labels in H
  | |- context [ _gotos (subst _ _) ] =>
    setoid_rewrite elem_of_sctx_item_gotos
  | |- context [ _labels (subst _ _) ] =>
    setoid_rewrite elem_of_sctx_item_labels
  end.
Ltac solve_stmt_elem_of :=
  simpl in *;
  unfold_stmt_elem_of;
  solve_elem_of.