summaryrefslogtreecommitdiff
path: root/contrib/correctness
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/correctness')
-rw-r--r--contrib/correctness/ArrayPermut.v175
-rw-r--r--contrib/correctness/Arrays.v78
-rw-r--r--contrib/correctness/Arrays_stuff.v16
-rw-r--r--contrib/correctness/Correctness.v25
-rw-r--r--contrib/correctness/Exchange.v95
-rw-r--r--contrib/correctness/ProgBool.v66
-rw-r--r--contrib/correctness/ProgInt.v19
-rw-r--r--contrib/correctness/ProgramsExtraction.v30
-rw-r--r--contrib/correctness/Programs_stuff.v13
-rw-r--r--contrib/correctness/Sorted.v202
-rw-r--r--contrib/correctness/Tuples.v98
-rw-r--r--contrib/correctness/examples/Handbook.v232
-rw-r--r--contrib/correctness/examples/exp.v204
-rw-r--r--contrib/correctness/examples/exp_int.v218
-rw-r--r--contrib/correctness/examples/extract.v43
-rw-r--r--contrib/correctness/examples/fact.v69
-rw-r--r--contrib/correctness/examples/fact_int.v195
-rw-r--r--contrib/correctness/past.mli97
-rw-r--r--contrib/correctness/pcic.ml231
-rw-r--r--contrib/correctness/pcic.mli24
-rw-r--r--contrib/correctness/pcicenv.ml118
-rw-r--r--contrib/correctness/pcicenv.mli38
-rw-r--r--contrib/correctness/pdb.ml165
-rw-r--r--contrib/correctness/pdb.mli25
-rw-r--r--contrib/correctness/peffect.ml159
-rw-r--r--contrib/correctness/peffect.mli42
-rw-r--r--contrib/correctness/penv.ml240
-rw-r--r--contrib/correctness/penv.mli87
-rw-r--r--contrib/correctness/perror.ml172
-rw-r--r--contrib/correctness/perror.mli47
-rw-r--r--contrib/correctness/pextract.ml473
-rw-r--r--contrib/correctness/pextract.mli17
-rw-r--r--contrib/correctness/pmisc.ml222
-rw-r--r--contrib/correctness/pmisc.mli81
-rw-r--r--contrib/correctness/pmlize.ml320
-rw-r--r--contrib/correctness/pmlize.mli20
-rw-r--r--contrib/correctness/pmonad.ml665
-rw-r--r--contrib/correctness/pmonad.mli106
-rw-r--r--contrib/correctness/pred.ml115
-rw-r--r--contrib/correctness/pred.mli26
-rw-r--r--contrib/correctness/prename.ml139
-rw-r--r--contrib/correctness/prename.mli57
-rw-r--r--contrib/correctness/preuves.v128
-rw-r--r--contrib/correctness/psyntax.ml41058
-rw-r--r--contrib/correctness/psyntax.mli25
-rw-r--r--contrib/correctness/ptactic.ml258
-rw-r--r--contrib/correctness/ptactic.mli22
-rw-r--r--contrib/correctness/ptype.mli73
-rw-r--r--contrib/correctness/ptyping.ml600
-rw-r--r--contrib/correctness/ptyping.mli36
-rw-r--r--contrib/correctness/putil.ml303
-rw-r--r--contrib/correctness/putil.mli72
-rw-r--r--contrib/correctness/pwp.ml347
-rw-r--r--contrib/correctness/pwp.mli18
54 files changed, 8404 insertions, 0 deletions
diff --git a/contrib/correctness/ArrayPermut.v b/contrib/correctness/ArrayPermut.v
new file mode 100644
index 00000000..b352045a
--- /dev/null
+++ b/contrib/correctness/ArrayPermut.v
@@ -0,0 +1,175 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ArrayPermut.v,v 1.3.2.1 2004/07/16 19:29:59 herbelin Exp $ *)
+
+(****************************************************************************)
+(* Permutations of elements in arrays *)
+(* Definition and properties *)
+(****************************************************************************)
+
+Require Import ProgInt.
+Require Import Arrays.
+Require Export Exchange.
+
+Require Import Omega.
+
+Set Implicit Arguments.
+
+(* We define "permut" as the smallest equivalence relation which contains
+ * transpositions i.e. exchange of two elements.
+ *)
+
+Inductive permut (n:Z) (A:Set) : array n A -> array n A -> Prop :=
+ | exchange_is_permut :
+ forall (t t':array n A) (i j:Z), exchange t t' i j -> permut t t'
+ | permut_refl : forall t:array n A, permut t t
+ | permut_sym : forall t t':array n A, permut t t' -> permut t' t
+ | permut_trans :
+ forall t t' t'':array n A, permut t t' -> permut t' t'' -> permut t t''.
+
+Hint Resolve exchange_is_permut permut_refl permut_sym permut_trans: v62
+ datatypes.
+
+(* We also define the permutation on a segment of an array, "sub_permut",
+ * the other parts of the array being unchanged
+ *
+ * One again we define it as the smallest equivalence relation containing
+ * transpositions on the given segment.
+ *)
+
+Inductive sub_permut (n:Z) (A:Set) (g d:Z) :
+array n A -> array n A -> Prop :=
+ | exchange_is_sub_permut :
+ forall (t t':array n A) (i j:Z),
+ (g <= i <= d)%Z ->
+ (g <= j <= d)%Z -> exchange t t' i j -> sub_permut g d t t'
+ | sub_permut_refl : forall t:array n A, sub_permut g d t t
+ | sub_permut_sym :
+ forall t t':array n A, sub_permut g d t t' -> sub_permut g d t' t
+ | sub_permut_trans :
+ forall t t' t'':array n A,
+ sub_permut g d t t' -> sub_permut g d t' t'' -> sub_permut g d t t''.
+
+Hint Resolve exchange_is_sub_permut sub_permut_refl sub_permut_sym
+ sub_permut_trans: v62 datatypes.
+
+(* To express that some parts of arrays are equal we introduce the
+ * property "array_id" which says that a segment is the same on two
+ * arrays.
+ *)
+
+Definition array_id (n:Z) (A:Set) (t t':array n A)
+ (g d:Z) := forall i:Z, (g <= i <= d)%Z -> #t [i] = #t' [i].
+
+(* array_id is an equivalence relation *)
+
+Lemma array_id_refl :
+ forall (n:Z) (A:Set) (t:array n A) (g d:Z), array_id t t g d.
+Proof.
+unfold array_id in |- *.
+auto with datatypes.
+Qed.
+
+Hint Resolve array_id_refl: v62 datatypes.
+
+Lemma array_id_sym :
+ forall (n:Z) (A:Set) (t t':array n A) (g d:Z),
+ array_id t t' g d -> array_id t' t g d.
+Proof.
+unfold array_id in |- *. intros.
+symmetry in |- *; auto with datatypes.
+Qed.
+
+Hint Resolve array_id_sym: v62 datatypes.
+
+Lemma array_id_trans :
+ forall (n:Z) (A:Set) (t t' t'':array n A) (g d:Z),
+ array_id t t' g d -> array_id t' t'' g d -> array_id t t'' g d.
+Proof.
+unfold array_id in |- *. intros.
+apply trans_eq with (y := #t' [i]); auto with datatypes.
+Qed.
+
+Hint Resolve array_id_trans: v62 datatypes.
+
+(* Outside the segment [g,d] the elements are equal *)
+
+Lemma sub_permut_id :
+ forall (n:Z) (A:Set) (t t':array n A) (g d:Z),
+ sub_permut g d t t' ->
+ array_id t t' 0 (g - 1) /\ array_id t t' (d + 1) (n - 1).
+Proof.
+intros n A t t' g d. simple induction 1; intros.
+elim H2; intros.
+unfold array_id in |- *; split; intros.
+apply H7; omega.
+apply H7; omega.
+auto with datatypes.
+decompose [and] H1; auto with datatypes.
+decompose [and] H1; decompose [and] H3; eauto with datatypes.
+Qed.
+
+Hint Resolve sub_permut_id.
+
+Lemma sub_permut_eq :
+ forall (n:Z) (A:Set) (t t':array n A) (g d:Z),
+ sub_permut g d t t' ->
+ forall i:Z, (0 <= i < g)%Z \/ (d < i < n)%Z -> #t [i] = #t' [i].
+Proof.
+intros n A t t' g d Htt' i Hi.
+elim (sub_permut_id Htt'). unfold array_id in |- *.
+intros.
+elim Hi; [ intro; apply H; omega | intro; apply H0; omega ].
+Qed.
+
+(* sub_permut is a particular case of permutation *)
+
+Lemma sub_permut_is_permut :
+ forall (n:Z) (A:Set) (t t':array n A) (g d:Z),
+ sub_permut g d t t' -> permut t t'.
+Proof.
+intros n A t t' g d. simple induction 1; intros; eauto with datatypes.
+Qed.
+
+Hint Resolve sub_permut_is_permut.
+
+(* If we have a sub-permutation on an empty segment, then we have a
+ * sub-permutation on any segment.
+ *)
+
+Lemma sub_permut_void :
+ forall (N:Z) (A:Set) (t t':array N A) (g g' d d':Z),
+ (d < g)%Z -> sub_permut g d t t' -> sub_permut g' d' t t'.
+Proof.
+intros N A t t' g g' d d' Hdg.
+simple induction 1; intros.
+absurd (g <= d)%Z; omega.
+auto with datatypes.
+auto with datatypes.
+eauto with datatypes.
+Qed.
+
+(* A sub-permutation on a segment may be extended to any segment that
+ * contains the first one.
+ *)
+
+Lemma sub_permut_extension :
+ forall (N:Z) (A:Set) (t t':array N A) (g g' d d':Z),
+ (g' <= g)%Z -> (d <= d')%Z -> sub_permut g d t t' -> sub_permut g' d' t t'.
+Proof.
+intros N A t t' g g' d d' Hgg' Hdd'.
+simple induction 1; intros.
+apply exchange_is_sub_permut with (i := i) (j := j);
+ [ omega | omega | assumption ].
+auto with datatypes.
+auto with datatypes.
+eauto with datatypes.
+Qed. \ No newline at end of file
diff --git a/contrib/correctness/Arrays.v b/contrib/correctness/Arrays.v
new file mode 100644
index 00000000..1659917a
--- /dev/null
+++ b/contrib/correctness/Arrays.v
@@ -0,0 +1,78 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Arrays.v,v 1.9.2.1 2004/07/16 19:29:59 herbelin Exp $ *)
+
+(**********************************************)
+(* Functional arrays, for use in Correctness. *)
+(**********************************************)
+
+(* This is an axiomatization of arrays.
+ *
+ * The type (array N T) is the type of arrays ranging from 0 to N-1
+ * which elements are of type T.
+ *
+ * Arrays are created with new, accessed with access and modified with store.
+ *
+ * Operations of accessing and storing are not guarded, but axioms are.
+ * So these arrays can be viewed as arrays where accessing and storing
+ * out of the bounds has no effect.
+ *)
+
+
+Require Export ProgInt.
+
+Set Implicit Arguments.
+
+
+(* The type of arrays *)
+
+Parameter array : Z -> Set -> Set.
+
+
+(* Functions to create, access and modify arrays *)
+
+Parameter new : forall (n:Z) (T:Set), T -> array n T.
+
+Parameter access : forall (n:Z) (T:Set), array n T -> Z -> T.
+
+Parameter store : forall (n:Z) (T:Set), array n T -> Z -> T -> array n T.
+
+
+(* Axioms *)
+
+Axiom
+ new_def :
+ forall (n:Z) (T:Set) (v0:T) (i:Z),
+ (0 <= i < n)%Z -> access (new n v0) i = v0.
+
+Axiom
+ store_def_1 :
+ forall (n:Z) (T:Set) (t:array n T) (v:T) (i:Z),
+ (0 <= i < n)%Z -> access (store t i v) i = v.
+
+Axiom
+ store_def_2 :
+ forall (n:Z) (T:Set) (t:array n T) (v:T) (i j:Z),
+ (0 <= i < n)%Z ->
+ (0 <= j < n)%Z -> i <> j -> access (store t i v) j = access t j.
+
+Hint Resolve new_def store_def_1 store_def_2: datatypes v62.
+
+(* A tactic to simplify access in arrays *)
+
+Ltac array_access i j H :=
+ elim (Z_eq_dec i j);
+ [ intro H; rewrite H; rewrite store_def_1
+ | intro H; rewrite store_def_2; [ idtac | idtac | idtac | exact H ] ].
+
+(* Symbolic notation for access *)
+
+Notation "# t [ c ]" := (access t c) (at level 0, t at level 0). \ No newline at end of file
diff --git a/contrib/correctness/Arrays_stuff.v b/contrib/correctness/Arrays_stuff.v
new file mode 100644
index 00000000..899d7007
--- /dev/null
+++ b/contrib/correctness/Arrays_stuff.v
@@ -0,0 +1,16 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Arrays_stuff.v,v 1.2.16.1 2004/07/16 19:29:59 herbelin Exp $ *)
+
+Require Export Exchange.
+Require Export ArrayPermut.
+Require Export Sorted.
+
diff --git a/contrib/correctness/Correctness.v b/contrib/correctness/Correctness.v
new file mode 100644
index 00000000..a2ad2f50
--- /dev/null
+++ b/contrib/correctness/Correctness.v
@@ -0,0 +1,25 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Correctness.v,v 1.6.2.1 2004/07/16 19:29:59 herbelin Exp $ *)
+
+(* Correctness is base on the tactic Refine (developped on purpose) *)
+
+Require Export Tuples.
+
+Require Export ProgInt.
+Require Export ProgBool.
+Require Export Zwf.
+
+Require Export Arrays.
+
+(*
+Token "'".
+*) \ No newline at end of file
diff --git a/contrib/correctness/Exchange.v b/contrib/correctness/Exchange.v
new file mode 100644
index 00000000..7dc5218e
--- /dev/null
+++ b/contrib/correctness/Exchange.v
@@ -0,0 +1,95 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Exchange.v,v 1.4.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+(****************************************************************************)
+(* Exchange of two elements in an array *)
+(* Definition and properties *)
+(****************************************************************************)
+
+Require Import ProgInt.
+Require Import Arrays.
+
+Set Implicit Arguments.
+
+(* Definition *)
+
+Inductive exchange (n:Z) (A:Set) (t t':array n A) (i j:Z) : Prop :=
+ exchange_c :
+ (0 <= i < n)%Z ->
+ (0 <= j < n)%Z ->
+ #t [i] = #t' [j] ->
+ #t [j] = #t' [i] ->
+ (forall k:Z, (0 <= k < n)%Z -> k <> i -> k <> j -> #t [k] = #t' [k]) ->
+ exchange t t' i j.
+
+(* Properties about exchanges *)
+
+Lemma exchange_1 :
+ forall (n:Z) (A:Set) (t:array n A) (i j:Z),
+ (0 <= i < n)%Z ->
+ (0 <= j < n)%Z -> #(store (store t i #t [j]) j #t [i]) [i] = #t [j].
+Proof.
+intros n A t i j H_i H_j.
+case (dec_eq j i).
+intro eq_i_j. rewrite eq_i_j.
+auto with datatypes.
+intro not_j_i.
+rewrite (store_def_2 (store t i #t [j]) #t [i] H_j H_i not_j_i).
+auto with datatypes.
+Qed.
+
+Hint Resolve exchange_1: v62 datatypes.
+
+
+Lemma exchange_proof :
+ forall (n:Z) (A:Set) (t:array n A) (i j:Z),
+ (0 <= i < n)%Z ->
+ (0 <= j < n)%Z -> exchange (store (store t i #t [j]) j #t [i]) t i j.
+Proof.
+intros n A t i j H_i H_j.
+apply exchange_c; auto with datatypes.
+intros k H_k not_k_i not_k_j.
+cut (j <> k); auto with datatypes. intro not_j_k.
+rewrite (store_def_2 (store t i #t [j]) #t [i] H_j H_k not_j_k).
+auto with datatypes.
+Qed.
+
+Hint Resolve exchange_proof: v62 datatypes.
+
+
+Lemma exchange_sym :
+ forall (n:Z) (A:Set) (t t':array n A) (i j:Z),
+ exchange t t' i j -> exchange t' t i j.
+Proof.
+intros n A t t' i j H1.
+elim H1. clear H1. intros.
+constructor 1; auto with datatypes.
+intros. rewrite (H3 k); auto with datatypes.
+Qed.
+
+Hint Resolve exchange_sym: v62 datatypes.
+
+
+Lemma exchange_id :
+ forall (n:Z) (A:Set) (t t':array n A) (i j:Z),
+ exchange t t' i j ->
+ i = j -> forall k:Z, (0 <= k < n)%Z -> #t [k] = #t' [k].
+Proof.
+intros n A t t' i j Hex Heq k Hk.
+elim Hex. clear Hex. intros.
+rewrite Heq in H1. rewrite Heq in H2.
+case (Z_eq_dec k j).
+ intro Heq'. rewrite Heq'. assumption.
+ intro Hnoteq. apply (H3 k); auto with datatypes. rewrite Heq. assumption.
+Qed.
+
+Hint Resolve exchange_id: v62 datatypes. \ No newline at end of file
diff --git a/contrib/correctness/ProgBool.v b/contrib/correctness/ProgBool.v
new file mode 100644
index 00000000..bce19870
--- /dev/null
+++ b/contrib/correctness/ProgBool.v
@@ -0,0 +1,66 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ProgBool.v,v 1.4.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+Require Import ZArith.
+Require Export Bool_nat.
+Require Export Sumbool.
+
+Definition annot_bool :
+ forall b:bool, {b' : bool | if b' then b = true else b = false}.
+Proof.
+intro b.
+exists b. case b; trivial.
+Qed.
+
+
+(* Logical connectives *)
+
+Definition spec_and (A B C D:Prop) (b:bool) := if b then A /\ C else B \/ D.
+
+Definition prog_bool_and :
+ forall Q1 Q2:bool -> Prop,
+ sig Q1 ->
+ sig Q2 ->
+ {b : bool | if b then Q1 true /\ Q2 true else Q1 false \/ Q2 false}.
+Proof.
+intros Q1 Q2 H1 H2.
+elim H1. intro b1. elim H2. intro b2.
+case b1; case b2; intros.
+exists true; auto.
+exists false; auto. exists false; auto. exists false; auto.
+Qed.
+
+Definition spec_or (A B C D:Prop) (b:bool) := if b then A \/ C else B /\ D.
+
+Definition prog_bool_or :
+ forall Q1 Q2:bool -> Prop,
+ sig Q1 ->
+ sig Q2 ->
+ {b : bool | if b then Q1 true \/ Q2 true else Q1 false /\ Q2 false}.
+Proof.
+intros Q1 Q2 H1 H2.
+elim H1. intro b1. elim H2. intro b2.
+case b1; case b2; intros.
+exists true; auto. exists true; auto. exists true; auto.
+exists false; auto.
+Qed.
+
+Definition spec_not (A B:Prop) (b:bool) := if b then B else A.
+
+Definition prog_bool_not :
+ forall Q:bool -> Prop, sig Q -> {b : bool | if b then Q false else Q true}.
+Proof.
+intros Q H.
+elim H. intro b.
+case b; intro.
+exists false; auto. exists true; auto.
+Qed.
diff --git a/contrib/correctness/ProgInt.v b/contrib/correctness/ProgInt.v
new file mode 100644
index 00000000..c26e3553
--- /dev/null
+++ b/contrib/correctness/ProgInt.v
@@ -0,0 +1,19 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ProgInt.v,v 1.2.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+Require Export ZArith.
+Require Export ZArith_dec.
+
+Theorem Znotzero : forall x:Z, {x <> 0%Z} + {x = 0%Z}.
+Proof.
+intro x. elim (Z_eq_dec x 0); auto.
+Qed. \ No newline at end of file
diff --git a/contrib/correctness/ProgramsExtraction.v b/contrib/correctness/ProgramsExtraction.v
new file mode 100644
index 00000000..40253f33
--- /dev/null
+++ b/contrib/correctness/ProgramsExtraction.v
@@ -0,0 +1,30 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ProgramsExtraction.v,v 1.2.16.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+Require Export Extraction.
+
+Extract Inductive unit => unit [ "()" ].
+Extract Inductive bool => bool [ true false ].
+Extract Inductive sumbool => bool [ true false ].
+
+Require Export Correctness.
+
+Declare ML Module "pextract".
+
+Grammar vernac vernac : ast :=
+ imperative_ocaml [ "Write" "Caml" "File" stringarg($file)
+ "[" ne_identarg_list($idl) "]" "." ]
+ -> [ (IMPERATIVEEXTRACTION $file (VERNACARGLIST ($LIST $idl))) ]
+
+| initialize [ "Initialize" identarg($id) "with" comarg($c) "." ]
+ -> [ (INITIALIZE $id $c) ]
+.
diff --git a/contrib/correctness/Programs_stuff.v b/contrib/correctness/Programs_stuff.v
new file mode 100644
index 00000000..1ca4b63e
--- /dev/null
+++ b/contrib/correctness/Programs_stuff.v
@@ -0,0 +1,13 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Programs_stuff.v,v 1.1.16.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+Require Export Arrays_stuff.
diff --git a/contrib/correctness/Sorted.v b/contrib/correctness/Sorted.v
new file mode 100644
index 00000000..2efe54a4
--- /dev/null
+++ b/contrib/correctness/Sorted.v
@@ -0,0 +1,202 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Library about sorted (sub-)arrays / Nicolas Magaud, July 1998 *)
+
+(* $Id: Sorted.v,v 1.7.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+Require Export Arrays.
+Require Import ArrayPermut.
+
+Require Import ZArithRing.
+Require Import Omega.
+Open Local Scope Z_scope.
+
+Set Implicit Arguments.
+
+(* Definition *)
+
+Definition sorted_array (N:Z) (A:array N Z) (deb fin:Z) :=
+ deb <= fin -> forall x:Z, x >= deb -> x < fin -> #A [x] <= #A [x + 1].
+
+(* Elements of a sorted sub-array are in increasing order *)
+
+(* one element and the next one *)
+
+Lemma sorted_elements_1 :
+ forall (N:Z) (A:array N Z) (n m:Z),
+ sorted_array A n m ->
+ forall k:Z,
+ k >= n -> forall i:Z, 0 <= i -> k + i <= m -> #A [k] <= #A [k + i].
+Proof.
+intros N A n m H_sorted k H_k i H_i.
+pattern i in |- *. apply natlike_ind.
+intro.
+replace (k + 0) with k; omega. (*** Ring `k+0` => BUG ***)
+
+intros.
+apply Zle_trans with (m := #A [k + x]).
+apply H0; omega.
+
+unfold Zsucc in |- *.
+replace (k + (x + 1)) with (k + x + 1).
+unfold sorted_array in H_sorted.
+apply H_sorted; omega.
+
+omega.
+
+assumption.
+Qed.
+
+(* one element and any of the following *)
+
+Lemma sorted_elements :
+ forall (N:Z) (A:array N Z) (n m k l:Z),
+ sorted_array A n m ->
+ k >= n -> l < N -> k <= l -> l <= m -> #A [k] <= #A [l].
+Proof.
+intros.
+replace l with (k + (l - k)).
+apply sorted_elements_1 with (n := n) (m := m);
+ [ assumption | omega | omega | omega ].
+omega.
+Qed.
+
+Hint Resolve sorted_elements: datatypes v62.
+
+(* A sub-array of a sorted array is sorted *)
+
+Lemma sub_sorted_array :
+ forall (N:Z) (A:array N Z) (deb fin i j:Z),
+ sorted_array A deb fin ->
+ i >= deb -> j <= fin -> i <= j -> sorted_array A i j.
+Proof.
+unfold sorted_array in |- *.
+intros.
+apply H; omega.
+Qed.
+
+Hint Resolve sub_sorted_array: datatypes v62.
+
+(* Extension on the left of the property of being sorted *)
+
+Lemma left_extension :
+ forall (N:Z) (A:array N Z) (i j:Z),
+ i > 0 ->
+ j < N ->
+ sorted_array A i j -> #A [i - 1] <= #A [i] -> sorted_array A (i - 1) j.
+Proof.
+intros; unfold sorted_array in |- *; intros.
+elim (Z_ge_lt_dec x i). (* (`x >= i`) + (`x < i`) *)
+intro Hcut.
+apply H1; omega.
+
+intro Hcut.
+replace x with (i - 1).
+replace (i - 1 + 1) with i; [ assumption | omega ].
+
+omega.
+Qed.
+
+(* Extension on the right *)
+
+Lemma right_extension :
+ forall (N:Z) (A:array N Z) (i j:Z),
+ i >= 0 ->
+ j < N - 1 ->
+ sorted_array A i j -> #A [j] <= #A [j + 1] -> sorted_array A i (j + 1).
+Proof.
+intros; unfold sorted_array in |- *; intros.
+elim (Z_lt_ge_dec x j).
+intro Hcut.
+apply H1; omega.
+
+intro HCut.
+replace x with j; [ assumption | omega ].
+Qed.
+
+(* Substitution of the leftmost value by a smaller value *)
+
+Lemma left_substitution :
+ forall (N:Z) (A:array N Z) (i j v:Z),
+ i >= 0 ->
+ j < N ->
+ sorted_array A i j -> v <= #A [i] -> sorted_array (store A i v) i j.
+Proof.
+intros N A i j v H_i H_j H_sorted H_v.
+unfold sorted_array in |- *; intros.
+
+cut (x = i \/ x > i).
+intro Hcut; elim Hcut; clear Hcut; intro.
+rewrite H2.
+rewrite store_def_1; try omega.
+rewrite store_def_2; try omega.
+apply Zle_trans with (m := #A [i]); [ assumption | apply H_sorted; omega ].
+
+rewrite store_def_2; try omega.
+rewrite store_def_2; try omega.
+apply H_sorted; omega.
+omega.
+Qed.
+
+(* Substitution of the rightmost value by a larger value *)
+
+Lemma right_substitution :
+ forall (N:Z) (A:array N Z) (i j v:Z),
+ i >= 0 ->
+ j < N ->
+ sorted_array A i j -> #A [j] <= v -> sorted_array (store A j v) i j.
+Proof.
+intros N A i j v H_i H_j H_sorted H_v.
+unfold sorted_array in |- *; intros.
+
+cut (x = j - 1 \/ x < j - 1).
+intro Hcut; elim Hcut; clear Hcut; intro.
+rewrite H2.
+replace (j - 1 + 1) with j; [ idtac | omega ]. (*** Ring `j-1+1`. => BUG ***)
+rewrite store_def_2; try omega.
+rewrite store_def_1; try omega.
+apply Zle_trans with (m := #A [j]).
+apply sorted_elements with (n := i) (m := j); try omega; assumption.
+assumption.
+
+rewrite store_def_2; try omega.
+rewrite store_def_2; try omega.
+apply H_sorted; omega.
+
+omega.
+Qed.
+
+(* Affectation outside of the sorted region *)
+
+Lemma no_effect :
+ forall (N:Z) (A:array N Z) (i j k v:Z),
+ i >= 0 ->
+ j < N ->
+ sorted_array A i j ->
+ 0 <= k < i \/ j < k < N -> sorted_array (store A k v) i j.
+Proof.
+intros.
+unfold sorted_array in |- *; intros.
+rewrite store_def_2; try omega.
+rewrite store_def_2; try omega.
+apply H1; assumption.
+Qed.
+
+Lemma sorted_array_id :
+ forall (N:Z) (t1 t2:array N Z) (g d:Z),
+ sorted_array t1 g d -> array_id t1 t2 g d -> sorted_array t2 g d.
+Proof.
+intros N t1 t2 g d Hsorted Hid.
+unfold array_id in Hid.
+unfold sorted_array in Hsorted. unfold sorted_array in |- *.
+intros Hgd x H1x H2x.
+rewrite <- (Hid x); [ idtac | omega ].
+rewrite <- (Hid (x + 1)); [ idtac | omega ].
+apply Hsorted; assumption.
+Qed. \ No newline at end of file
diff --git a/contrib/correctness/Tuples.v b/contrib/correctness/Tuples.v
new file mode 100644
index 00000000..e3fff08d
--- /dev/null
+++ b/contrib/correctness/Tuples.v
@@ -0,0 +1,98 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Tuples.v,v 1.2.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+(* Tuples *)
+
+Definition tuple_1 (X:Set) := X.
+Definition tuple_2 := prod.
+Definition Build_tuple_2 := pair.
+Definition proj_2_1 := fst.
+Definition proj_2_2 := snd.
+
+Record tuple_3 (T1 T2 T3:Set) : Set :=
+ {proj_3_1 : T1; proj_3_2 : T2; proj_3_3 : T3}.
+
+Record tuple_4 (T1 T2 T3 T4:Set) : Set :=
+ {proj_4_1 : T1; proj_4_2 : T2; proj_4_3 : T3; proj_4_4 : T4}.
+
+Record tuple_5 (T1 T2 T3 T4 T5:Set) : Set :=
+ {proj_5_1 : T1; proj_5_2 : T2; proj_5_3 : T3; proj_5_4 : T4; proj_5_5 : T5}.
+
+Record tuple_6 (T1 T2 T3 T4 T5 T6:Set) : Set :=
+ {proj_6_1 : T1;
+ proj_6_2 : T2;
+ proj_6_3 : T3;
+ proj_6_4 : T4;
+ proj_6_5 : T5;
+ proj_6_6 : T6}.
+
+Record tuple_7 (T1 T2 T3 T4 T5 T6 T7:Set) : Set :=
+ {proj_7_1 : T1;
+ proj_7_2 : T2;
+ proj_7_3 : T3;
+ proj_7_4 : T4;
+ proj_7_5 : T5;
+ proj_7_6 : T6;
+ proj_7_7 : T7}.
+
+
+(* Existentials *)
+
+Definition sig_1 := sig.
+Definition exist_1 := exist.
+
+Inductive sig_2 (T1 T2:Set) (P:T1 -> T2 -> Prop) : Set :=
+ exist_2 : forall (x1:T1) (x2:T2), P x1 x2 -> sig_2 T1 T2 P.
+
+Inductive sig_3 (T1 T2 T3:Set) (P:T1 -> T2 -> T3 -> Prop) : Set :=
+ exist_3 : forall (x1:T1) (x2:T2) (x3:T3), P x1 x2 x3 -> sig_3 T1 T2 T3 P.
+
+
+Inductive sig_4 (T1 T2 T3 T4:Set) (P:T1 -> T2 -> T3 -> T4 -> Prop) : Set :=
+ exist_4 :
+ forall (x1:T1) (x2:T2) (x3:T3) (x4:T4),
+ P x1 x2 x3 x4 -> sig_4 T1 T2 T3 T4 P.
+
+Inductive sig_5 (T1 T2 T3 T4 T5:Set) (P:T1 -> T2 -> T3 -> T4 -> T5 -> Prop) :
+Set :=
+ exist_5 :
+ forall (x1:T1) (x2:T2) (x3:T3) (x4:T4) (x5:T5),
+ P x1 x2 x3 x4 x5 -> sig_5 T1 T2 T3 T4 T5 P.
+
+Inductive sig_6 (T1 T2 T3 T4 T5 T6:Set)
+(P:T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> Prop) : Set :=
+ exist_6 :
+ forall (x1:T1) (x2:T2) (x3:T3) (x4:T4) (x5:T5)
+ (x6:T6), P x1 x2 x3 x4 x5 x6 -> sig_6 T1 T2 T3 T4 T5 T6 P.
+
+Inductive sig_7 (T1 T2 T3 T4 T5 T6 T7:Set)
+(P:T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> T7 -> Prop) : Set :=
+ exist_7 :
+ forall (x1:T1) (x2:T2) (x3:T3) (x4:T4) (x5:T5)
+ (x6:T6) (x7:T7),
+ P x1 x2 x3 x4 x5 x6 x7 -> sig_7 T1 T2 T3 T4 T5 T6 T7 P.
+
+Inductive sig_8 (T1 T2 T3 T4 T5 T6 T7 T8:Set)
+(P:T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> T7 -> T8 -> Prop) : Set :=
+ exist_8 :
+ forall (x1:T1) (x2:T2) (x3:T3) (x4:T4) (x5:T5)
+ (x6:T6) (x7:T7) (x8:T8),
+ P x1 x2 x3 x4 x5 x6 x7 x8 -> sig_8 T1 T2 T3 T4 T5 T6 T7 T8 P.
+
+Inductive dep_tuple_2 (T1 T2:Set) (P:T1 -> T2 -> Set) : Set :=
+ Build_dep_tuple_2 :
+ forall (x1:T1) (x2:T2), P x1 x2 -> dep_tuple_2 T1 T2 P.
+
+Inductive dep_tuple_3 (T1 T2 T3:Set) (P:T1 -> T2 -> T3 -> Set) : Set :=
+ Build_dep_tuple_3 :
+ forall (x1:T1) (x2:T2) (x3:T3), P x1 x2 x3 -> dep_tuple_3 T1 T2 T3 P.
+
diff --git a/contrib/correctness/examples/Handbook.v b/contrib/correctness/examples/Handbook.v
new file mode 100644
index 00000000..8c983a72
--- /dev/null
+++ b/contrib/correctness/examples/Handbook.v
@@ -0,0 +1,232 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: Handbook.v,v 1.3 2001/04/11 07:56:19 filliatr Exp $ *)
+
+(* This file contains proofs of programs taken from the
+ * "Handbook of Theoretical Computer Science", volume B,
+ * chapter "Methods and Logics for Proving Programs", by P. Cousot,
+ * pp 841--993, Edited by J. van Leeuwen (c) Elsevier Science Publishers B.V.
+ * 1990.
+ *
+ * Programs are refered to by numbers and pages.
+ *)
+
+Require Correctness.
+
+Require Sumbool.
+Require Omega.
+Require Zcomplements.
+Require Zpower.
+
+(****************************************************************************)
+
+(* program (2) page 853 to compute x^y (annotated version is (25) page 860) *)
+
+(* en attendant... *)
+Parameter Zdiv2 : Z->Z.
+
+Parameter Zeven_odd_dec : (x:Z){`x=2*(Zdiv2 x)`}+{`x=2*(Zdiv2 x)+1`}.
+Definition Zodd_dec := [z:Z](sumbool_not ? ? (Zeven_odd_dec z)).
+Definition Zodd_bool := [z:Z](bool_of_sumbool ? ? (Zodd_dec z)).
+
+Axiom axiom1 : (x,y:Z) `y>0` -> `x*(Zpower x (Zpred y)) = (Zpower x y)`.
+Axiom axiom2 : (x:Z)`x>0` -> `(Zdiv2 x)<x`.
+Axiom axiom3 : (x,y:Z) `y>=0` -> `(Zpower (x*x) (Zdiv2 y)) = (Zpower x y)`.
+
+Global Variable X : Z ref.
+Global Variable Y : Z ref.
+Global Variable Z_ : Z ref.
+
+Correctness pgm25
+ { `Y >= 0` }
+ begin
+ Z_ := 1;
+ while !Y <> 0 do
+ { invariant `Y >= 0` /\ `Z_ * (Zpower X Y) = (Zpower X@0 Y@0)`
+ variant Y }
+ if (Zodd_bool !Y) then begin
+ Y := (Zpred !Y);
+ Z_ := (Zmult !Z_ !X)
+ end else begin
+ Y := (Zdiv2 !Y);
+ X := (Zmult !X !X)
+ end
+ done
+ end
+ { Z_ = (Zpower X@ Y@) }.
+Proof.
+Split.
+Unfold Zpred; Unfold Zwf; Omega.
+Split.
+Unfold Zpred; Omega.
+Decompose [and] Pre2.
+Rewrite <- H0.
+Replace `Z_1*X0*(Zpower X0 (Zpred Y0))` with `Z_1*(X0*(Zpower X0 (Zpred Y0)))`.
+Apply f_equal with f := (Zmult Z_1).
+Apply axiom1.
+Omega.
+
+Auto.
+Symmetry.
+Apply Zmult_assoc_r.
+
+Split.
+Unfold Zwf.
+Repeat (Apply conj).
+Omega.
+
+Omega.
+
+Apply axiom2. Omega.
+
+Split.
+Omega.
+
+Decompose [and] Pre2.
+Rewrite <- H0.
+Apply f_equal with f:=(Zmult Z_1).
+Apply axiom3. Omega.
+
+Omega.
+
+Decompose [and] Post6.
+Rewrite <- H2.
+Rewrite H0.
+Simpl.
+Omega.
+
+Save.
+
+
+(****************************************************************************)
+
+(* program (178) page 934 to compute the factorial using global variables
+ * annotated version is (185) page 939
+ *)
+
+Parameter Zfact : Z -> Z.
+
+Axiom axiom4 : `(Zfact 0) = 1`.
+Axiom axiom5 : (x:Z) `x>0` -> `(Zfact (x-1))*x=(Zfact x)`.
+
+Correctness pgm178
+let rec F (u:unit) : unit { variant X } =
+ { `X>=0` }
+ (if !X = 0 then
+ Y := 1
+ else begin
+ label L;
+ X := (Zpred !X);
+ (F tt);
+ X := (Zs !X);
+ Y := (Zmult !Y !X)
+ end)
+ { `X=X@` /\ `Y=(Zfact X@)` }.
+Proof.
+Rewrite Test1. Rewrite axiom4. Auto.
+Unfold Zwf. Unfold Zpred. Omega.
+Unfold Zpred. Omega.
+Unfold Zs. Unfold Zpred in Post3. Split.
+Omega.
+Decompose [and] Post3.
+Rewrite H.
+Replace `X0+(-1)+1` with X0.
+Rewrite H0.
+Replace `X0+(-1)` with `X0-1`.
+Apply axiom5.
+Omega.
+Omega.
+Omega.
+Save.
+
+
+(****************************************************************************)
+
+(* program (186) page 939 "showing the usefulness of auxiliary variables" ! *)
+
+Global Variable N : Z ref.
+Global Variable S : Z ref.
+
+Correctness pgm186
+let rec F (u:unit) : unit { variant N } =
+ { `N>=0` }
+ (if !N > 0 then begin
+ label L;
+ N := (Zpred !N);
+ (F tt);
+ S := (Zs !S);
+ (F tt);
+ N := (Zs !N)
+ end)
+ { `N=N@` /\ `S=S@+(Zpower 2 N@)-1` }.
+Proof.
+Unfold Zwf. Unfold Zpred. Omega.
+Unfold Zpred. Omega.
+Decompose [and] Post5. Rewrite H. Unfold Zwf. Unfold Zpred. Omega.
+Decompose [and] Post5. Rewrite H. Unfold Zpred. Omega.
+Split.
+Unfold Zpred in Post5. Omega.
+Decompose [and] Post4. Rewrite H0.
+Decompose [and] Post5. Rewrite H2. Rewrite H1.
+Replace `(Zpower 2 N0)` with `2*(Zpower 2 (Zpred N0))`. Omega.
+Symmetry.
+Replace `(Zpower 2 N0)` with `(Zpower 2 (1+(Zpred N0)))`.
+Replace `2*(Zpower 2 (Zpred N0))` with `(Zpower 2 1)*(Zpower 2 (Zpred N0))`.
+Apply Zpower_exp.
+Omega.
+Unfold Zpred. Omega.
+Auto.
+Replace `(1+(Zpred N0))` with N0; [ Auto | Unfold Zpred; Omega ].
+Split.
+Auto.
+Replace N0 with `0`; Simpl; Omega.
+Save.
+
+
+(****************************************************************************)
+
+(* program (196) page 944 (recursive factorial procedure with value-result
+ * parameters)
+ *)
+
+Correctness pgm196
+let rec F (U:Z) (V:Z ref) : unit { variant U } =
+ { `U >= 0` }
+ (if U = 0 then
+ V := 1
+ else begin
+ (F (Zpred U) V);
+ V := (Zmult !V U)
+ end)
+ { `V = (Zfact U)` }.
+Proof.
+Symmetry. Rewrite Test1. Apply axiom4.
+Unfold Zwf. Unfold Zpred. Omega.
+Unfold Zpred. Omega.
+Rewrite Post3.
+Unfold Zpred. Replace `U0+(-1)` with `U0-1`. Apply axiom5.
+Omega.
+Omega.
+Save.
+
+(****************************************************************************)
+
+(* program (197) page 945 (L_4 subset of Pascal) *)
+
+(*
+procedure P(X:Z; procedure Q(Z:Z));
+ procedure L(X:Z); begin Q(X-1) end;
+ begin if X>0 then P(X-1,L) else Q(X) end;
+
+procedure M(N:Z);
+ procedure R(X:Z); begin writeln(X) (* => RES := !X *) end;
+ begin P(N,R) end.
+*)
diff --git a/contrib/correctness/examples/exp.v b/contrib/correctness/examples/exp.v
new file mode 100644
index 00000000..dcfcec87
--- /dev/null
+++ b/contrib/correctness/examples/exp.v
@@ -0,0 +1,204 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(*i $Id: exp.v,v 1.3 2001/04/11 07:56:19 filliatr Exp $ i*)
+
+(* Efficient computation of X^n using
+ *
+ * X^(2n) = (X^n) ^ 2
+ * X^(2n+1) = X . (X^n) ^ 2
+ *
+ * Proofs of both fonctional and imperative programs.
+ *)
+
+Require Even.
+Require Div2.
+Require Correctness.
+Require ArithRing.
+Require ZArithRing.
+
+(* The specification uses the traditional definition of X^n *)
+
+Fixpoint power [x,n:nat] : nat :=
+ Cases n of
+ O => (S O)
+ | (S n') => (mult x (power x n'))
+ end.
+
+Definition square := [n:nat](mult n n).
+
+
+(* Three lemmas are necessary to establish the forthcoming proof obligations *)
+
+(* n = 2*(n/2) => (x^(n/2))^2 = x^n *)
+
+Lemma exp_div2_0 : (x,n:nat)
+ n=(double (div2 n))
+ -> (square (power x (div2 n)))=(power x n).
+Proof.
+Unfold square.
+Intros x n. Pattern n. Apply ind_0_1_SS.
+Auto.
+
+Intro. (Absurd (1)=(double (0)); Auto).
+
+Intros. Simpl.
+Cut n0=(double (div2 n0)).
+Intro. Rewrite <- (H H1).
+Ring.
+
+Simpl in H0.
+Unfold double in H0.
+Simpl in H0.
+Rewrite <- (plus_n_Sm (div2 n0) (div2 n0)) in H0.
+(Injection H0; Auto).
+Save.
+
+(* n = 2*(n/2)+1 => x*(x^(n/2))^2 = x^n *)
+
+Lemma exp_div2_1 : (x,n:nat)
+ n=(S (double (div2 n)))
+ -> (mult x (square (power x (div2 n))))=(power x n).
+Proof.
+Unfold square.
+Intros x n. Pattern n. Apply ind_0_1_SS.
+
+Intro. (Absurd (0)=(S (double (0))); Auto).
+
+Auto.
+
+Intros. Simpl.
+Cut n0=(S (double (div2 n0))).
+Intro. Rewrite <- (H H1).
+Ring.
+
+Simpl in H0.
+Unfold double in H0.
+Simpl in H0.
+Rewrite <- (plus_n_Sm (div2 n0) (div2 n0)) in H0.
+(Injection H0; Auto).
+Save.
+
+(* x^(2*n) = (x^2)^n *)
+
+Lemma power_2n : (x,n:nat)(power x (double n))=(power (square x) n).
+Proof.
+Unfold double. Unfold square.
+Induction n.
+Auto.
+
+Intros.
+Simpl.
+Rewrite <- H.
+Rewrite <- (plus_n_Sm n0 n0).
+Simpl.
+Auto with arith.
+Save.
+
+Hints Resolve exp_div2_0 exp_div2_1.
+
+
+(* Functional version.
+ *
+ * Here we give the functional program as an incomplete CIC term,
+ * using the tactic Refine.
+ *
+ * On this example, it really behaves as the tactic Program.
+ *)
+
+(*
+Lemma f_exp : (x,n:nat) { y:nat | y=(power x n) }.
+Proof.
+Refine [x:nat]
+ (well_founded_induction nat lt lt_wf
+ [n:nat]{y:nat | y=(power x n) }
+ [n:nat]
+ [f:(p:nat)(lt p n)->{y:nat | y=(power x p) }]
+ Cases (zerop n) of
+ (left _) => (exist ? ? (S O) ?)
+ | (right _) =>
+ let (y,H) = (f (div2 n) ?) in
+ Cases (even_odd_dec n) of
+ (left _) => (exist ? ? (mult y y) ?)
+ | (right _) => (exist ? ? (mult x (mult y y)) ?)
+ end
+ end).
+Proof.
+Rewrite a. Auto.
+Exact (lt_div2 n a).
+Change (square y)=(power x n). Rewrite H. Auto with arith.
+Change (mult x (square y))=(power x n). Rewrite H. Auto with arith.
+Save.
+*)
+
+(* Imperative version. *)
+
+Definition even_odd_bool := [x:nat](bool_of_sumbool ? ? (even_odd_dec x)).
+
+Correctness i_exp
+ fun (x:nat)(n:nat) ->
+ let y = ref (S O) in
+ let m = ref x in
+ let e = ref n in
+ begin
+ while (notzerop_bool !e) do
+ { invariant (power x n)=(mult y (power m e)) as Inv
+ variant e for lt }
+ (if not (even_odd_bool !e) then y := (mult !y !m))
+ { (power x n) = (mult y (power m (double (div2 e)))) as Q };
+ m := (square !m);
+ e := (div2 !e)
+ done;
+ !y
+ end
+ { result=(power x n) }
+.
+Proof.
+Rewrite (odd_double e0 Test1) in Inv. Rewrite Inv. Simpl. Auto with arith.
+
+Rewrite (even_double e0 Test1) in Inv. Rewrite Inv. Reflexivity.
+
+Split.
+Exact (lt_div2 e0 Test2).
+
+Rewrite Q. Unfold double. Unfold square.
+Simpl.
+Change (mult y1 (power m0 (double (div2 e0))))
+ = (mult y1 (power (square m0) (div2 e0))).
+Rewrite (power_2n m0 (div2 e0)). Reflexivity.
+
+Auto with arith.
+
+Decompose [and] Inv.
+Rewrite H. Rewrite H0.
+Auto with arith.
+Save.
+
+
+(* Recursive version. *)
+
+Correctness r_exp
+ let rec exp (x:nat) (n:nat) : nat { variant n for lt} =
+ (if (zerop_bool n) then
+ (S O)
+ else
+ let y = (exp x (div2 n)) in
+ if (even_odd_bool n) then
+ (mult y y)
+ else
+ (mult x (mult y y))
+ ) { result=(power x n) }
+.
+Proof.
+Rewrite Test2. Auto.
+Exact (lt_div2 n0 Test2).
+Change (square y)=(power x0 n0). Rewrite Post7. Auto with arith.
+Change (mult x0 (square y))=(power x0 n0). Rewrite Post7. Auto with arith.
+Save.
diff --git a/contrib/correctness/examples/exp_int.v b/contrib/correctness/examples/exp_int.v
new file mode 100644
index 00000000..accd60c2
--- /dev/null
+++ b/contrib/correctness/examples/exp_int.v
@@ -0,0 +1,218 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: exp_int.v,v 1.4 2001/04/11 07:56:19 filliatr Exp $ *)
+
+(* Efficient computation of X^n using
+ *
+ * X^(2n) = (X^n) ^ 2
+ * X^(2n+1) = X . (X^n) ^ 2
+ *
+ * Proofs of both fonctional and imperative programs.
+ *)
+
+Require Zpower.
+Require Zcomplements.
+
+Require Correctness.
+Require ZArithRing.
+Require Omega.
+
+Definition Zdouble := [n:Z]`2*n`.
+
+Definition Zsquare := [n:Z](Zmult n n).
+
+(* Some auxiliary lemmas about Zdiv2 are necessary *)
+
+Lemma Zdiv2_ge_0 : (x:Z) `x >= 0` -> `(Zdiv2 x) >= 0`.
+Proof.
+Destruct x; Auto with zarith.
+Destruct p; Auto with zarith.
+Simpl. Omega.
+Intros. (Absurd `(NEG p) >= 0`; Red; Auto with zarith).
+Save.
+
+Lemma Zdiv2_lt : (x:Z) `x > 0` -> `(Zdiv2 x) < x`.
+Proof.
+Destruct x.
+Intro. Absurd `0 > 0`; [ Omega | Assumption ].
+Destruct p; Auto with zarith.
+
+Simpl.
+Intro p0.
+Replace (POS (xI p0)) with `2*(POS p0)+1`.
+Omega.
+Simpl. Auto with zarith.
+
+Intro p0.
+Simpl.
+Replace (POS (xO p0)) with `2*(POS p0)`.
+Omega.
+Simpl. Auto with zarith.
+
+Simpl. Omega.
+
+Intros.
+Absurd `(NEG p) > 0`; Red; Auto with zarith.
+Elim p; Auto with zarith.
+Omega.
+Save.
+
+(* A property of Zpower: x^(2*n) = (x^2)^n *)
+
+Lemma Zpower_2n :
+ (x,n:Z)`n >= 0` -> (Zpower x (Zdouble n))=(Zpower (Zsquare x) n).
+Proof.
+Unfold Zdouble.
+Intros x n Hn.
+Replace `2*n` with `n+n`.
+Rewrite Zpower_exp.
+Pattern n.
+Apply natlike_ind.
+
+Simpl. Auto with zarith.
+
+Intros.
+Unfold Zs.
+Rewrite Zpower_exp.
+Rewrite Zpower_exp.
+Replace (Zpower x `1`) with x.
+Replace (Zpower (Zsquare x) `1`) with (Zsquare x).
+Rewrite <- H0.
+Unfold Zsquare.
+Ring.
+
+Unfold Zpower; Unfold Zpower_pos; Simpl. Omega.
+
+Unfold Zpower; Unfold Zpower_pos; Simpl. Omega.
+
+Omega.
+Omega.
+Omega.
+Omega.
+Omega.
+Assumption.
+Assumption.
+Omega.
+Save.
+
+
+(* The program *)
+
+Correctness i_exp
+ fun (x:Z)(n:Z) ->
+ { `n >= 0` }
+ (let y = ref 1 in
+ let m = ref x in
+ let e = ref n in
+ begin
+ while !e > 0 do
+ { invariant (Zpower x n)=(Zmult y (Zpower m e)) /\ `e>=0` as Inv
+ variant e }
+ (if not (Zeven_odd_bool !e) then y := (Zmult !y !m))
+ { (Zpower x n) = (Zmult y (Zpower m (Zdouble (Zdiv2 e)))) as Q };
+ m := (Zsquare !m);
+ e := (Zdiv2 !e)
+ done;
+ !y
+ end)
+ { result=(Zpower x n) }
+.
+Proof.
+(* Zodd *)
+Decompose [and] Inv.
+Rewrite (Zodd_div2 e0 H0 Test1) in H. Rewrite H.
+Rewrite Zpower_exp.
+Unfold Zdouble.
+Replace (Zpower m0 `1`) with m0.
+Ring.
+Unfold Zpower; Unfold Zpower_pos; Simpl; Ring.
+Generalize (Zdiv2_ge_0 e0); Omega.
+Omega.
+(* Zeven *)
+Decompose [and] Inv.
+Rewrite (Zeven_div2 e0 Test1) in H. Rewrite H.
+Auto with zarith.
+Split.
+(* Zwf *)
+Unfold Zwf.
+Repeat Split.
+Generalize (Zdiv2_ge_0 e0); Omega.
+Omega.
+Exact (Zdiv2_lt e0 Test2).
+(* invariant *)
+Split.
+Rewrite Q. Unfold Zdouble. Unfold Zsquare.
+Rewrite (Zpower_2n).
+Trivial.
+Generalize (Zdiv2_ge_0 e0); Omega.
+Generalize (Zdiv2_ge_0 e0); Omega.
+Split; [ Ring | Assumption ].
+(* exit fo loop *)
+Decompose [and] Inv.
+Cut `e0 = 0`. Intro.
+Rewrite H1. Rewrite H.
+Simpl; Ring.
+Omega.
+Save.
+
+
+(* Recursive version. *)
+
+Correctness r_exp
+ let rec exp (x:Z) (n:Z) : Z { variant n } =
+ { `n >= 0` }
+ (if n = 0 then
+ 1
+ else
+ let y = (exp x (Zdiv2 n)) in
+ (if (Zeven_odd_bool n) then
+ (Zmult y y)
+ else
+ (Zmult x (Zmult y y))) { result=(Zpower x n) as Q }
+ )
+ { result=(Zpower x n) }
+.
+Proof.
+Rewrite Test2. Auto with zarith.
+(* w.f. *)
+Unfold Zwf.
+Repeat Split.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Omega.
+Generalize (Zdiv2_lt n0) ; Omega.
+(* rec. call *)
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+(* invariant: case even *)
+Generalize (Zeven_div2 n0 Test1).
+Intro Heq. Rewrite Heq.
+Rewrite Post4.
+Replace `2*(Zdiv2 n0)` with `(Zdiv2 n0)+(Zdiv2 n0)`.
+Rewrite Zpower_exp.
+Auto with zarith.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Omega.
+(* invariant: cas odd *)
+Generalize (Zodd_div2 n0 Pre1 Test1).
+Intro Heq. Rewrite Heq.
+Rewrite Post4.
+Rewrite Zpower_exp.
+Replace `2*(Zdiv2 n0)` with `(Zdiv2 n0)+(Zdiv2 n0)`.
+Rewrite Zpower_exp.
+Replace `(Zpower x0 1)` with x0.
+Ring.
+Unfold Zpower; Unfold Zpower_pos; Simpl. Omega.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Omega.
+Generalize (Zdiv2_ge_0 n0) ; Omega.
+Omega.
+Save.
diff --git a/contrib/correctness/examples/extract.v b/contrib/correctness/examples/extract.v
new file mode 100644
index 00000000..e225ba18
--- /dev/null
+++ b/contrib/correctness/examples/extract.v
@@ -0,0 +1,43 @@
+
+(* Tests d'extraction *)
+
+Require ProgramsExtraction.
+Save State Ici "test extraction".
+
+(* exp *)
+
+Require exp.
+Write Caml File "exp" [ i_exp r_exp ].
+
+(* exp_int *)
+
+Restore State Ici.
+Require exp_int.
+Write Caml File "exp_int" [ i_exp r_exp ].
+
+(* fact *)
+
+Restore State Ici.
+Require fact.
+Initialize x with (S (S (S O))).
+Initialize y with O.
+Write Caml File "fact" [ factorielle ].
+
+(* fact_int *)
+
+Restore State Ici.
+Require fact_int.
+Initialize x with `3`.
+Initialize y with `0`.
+Write Caml File "fact_int" [ factorielle ].
+
+(* Handbook *)
+
+Restore State Ici.
+Require Handbook.
+Initialize X with `3`.
+Initialize Y with `3`.
+Initialize Z with `3`.
+Initialize N with `3`.
+Initialize S with `3`.
+Write Caml File "Handbook" [ pgm178 pgm186 pgm196 ].
diff --git a/contrib/correctness/examples/fact.v b/contrib/correctness/examples/fact.v
new file mode 100644
index 00000000..e480c806
--- /dev/null
+++ b/contrib/correctness/examples/fact.v
@@ -0,0 +1,69 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: fact.v,v 1.3 2001/04/11 07:56:19 filliatr Exp $ *)
+
+(* Proof of an imperative program computing the factorial (over type nat) *)
+
+Require Correctness.
+Require Omega.
+Require Arith.
+
+Fixpoint fact [n:nat] : nat :=
+ Cases n of
+ O => (S O)
+ | (S p) => (mult n (fact p))
+ end.
+
+(* (x * y) * (x-1)! = y * x! *)
+
+Lemma fact_rec : (x,y:nat)(lt O x) ->
+ (mult (mult x y) (fact (pred x))) = (mult y (fact x)).
+Proof.
+Intros x y H.
+Generalize (mult_sym x y). Intro H1. Rewrite H1.
+Generalize (mult_assoc_r y x (fact (pred x))). Intro H2. Rewrite H2.
+Apply (f_equal nat nat [x:nat](mult y x)).
+Generalize H. Elim x; Auto with arith.
+Save.
+
+
+(* we declare two variables x and y *)
+
+Global Variable x : nat ref.
+Global Variable y : nat ref.
+
+(* we give the annotated program *)
+
+Correctness factorielle
+ begin
+ y := (S O);
+ while (notzerop_bool !x) do
+ { invariant (mult y (fact x)) = (fact x@0) as I
+ variant x for lt }
+ y := (mult !x !y);
+ x := (pred !x)
+ done
+ end
+ { y = (fact x@0) }.
+Proof.
+Split.
+(* decreasing of the variant *)
+Omega.
+(* preservation of the invariant *)
+Rewrite <- I. Exact (fact_rec x0 y1 Test1).
+(* entrance of loop *)
+Auto with arith.
+(* exit of loop *)
+Elim I. Intros H1 H2.
+Rewrite H2 in H1.
+Rewrite <- H1.
+Auto with arith.
+Save.
diff --git a/contrib/correctness/examples/fact_int.v b/contrib/correctness/examples/fact_int.v
new file mode 100644
index 00000000..cb2b0460
--- /dev/null
+++ b/contrib/correctness/examples/fact_int.v
@@ -0,0 +1,195 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: fact_int.v,v 1.3 2001/04/11 07:56:19 filliatr Exp $ *)
+
+(* Proof of an imperative program computing the factorial (over type Z) *)
+
+Require Correctness.
+Require Omega.
+Require ZArithRing.
+
+(* We define the factorial as a relation... *)
+
+Inductive fact : Z -> Z -> Prop :=
+ fact_0 : (fact `0` `1`)
+ | fact_S : (z,f:Z) (fact z f) -> (fact (Zs z) (Zmult (Zs z) f)).
+
+(* ...and then we prove that it contains a function *)
+
+Lemma fact_function : (z:Z) `0 <= z` -> (EX f:Z | (fact z f)).
+Proof.
+Intros.
+Apply natlike_ind with P:=[z:Z](EX f:Z | (fact z f)).
+Split with `1`.
+Exact fact_0.
+
+Intros.
+Elim H1.
+Intros.
+Split with `(Zs x)*x0`.
+Exact (fact_S x x0 H2).
+
+Assumption.
+Save.
+
+(* This lemma should belong to the ZArith library *)
+
+Lemma Z_mult_1 : (x,y:Z)`x>=1`->`y>=1`->`x*y>=1`.
+Proof.
+Intros.
+Generalize H.
+Apply natlike_ind with P:=[x:Z]`x >= 1`->`x*y >= 1`.
+Omega.
+
+Intros.
+Simpl.
+Elim (Z_le_lt_eq_dec `0` x0 H1).
+Simpl.
+Unfold Zs.
+Replace `(x0+1)*y` with `x0*y+y`.
+Generalize H2.
+Generalize `x0*y`.
+Intro.
+Intros.
+Omega.
+
+Ring.
+
+Intros.
+Rewrite <- b.
+Omega.
+
+Omega.
+Save.
+
+(* (fact x f) implies x>=0 and f>=1 *)
+
+Lemma fact_pos : (x,f:Z)(fact x f)-> `x>=0` /\ `f>=1`.
+Proof.
+Intros.
+(Elim H; Auto).
+Omega.
+
+Intros.
+(Split; Try Omega).
+(Apply Z_mult_1; Try Omega).
+Save.
+
+(* (fact 0 x) implies x=1 *)
+
+Lemma fact_0_1 : (x:Z)(fact `0` x) -> `x=1`.
+Proof.
+Intros.
+Inversion H.
+Reflexivity.
+
+Elim (fact_pos z f H1).
+Intros.
+(Absurd `z >= 0`; Omega).
+Save.
+
+
+(* We define the loop invariant : y * x! = x0! *)
+
+Inductive invariant [y,x,x0:Z] : Prop :=
+ c_inv : (f,f0:Z)(fact x f)->(fact x0 f0)->(Zmult y f)=f0
+ -> (invariant y x x0).
+
+(* The following lemma is used to prove the preservation of the invariant *)
+
+Lemma fact_rec : (x0,x,y:Z)`0 < x` ->
+ (invariant y x x0)
+ -> (invariant `x*y` (Zpred x) x0).
+Proof.
+Intros x0 x y H H0.
+Elim H0.
+Intros.
+Generalize H H0 H3.
+Elim H1.
+Intros.
+Absurd `0 < 0`; Omega.
+
+Intros.
+Apply c_inv with f:=f1 f0:=f0.
+Cut `z+1+-1 = z`. Intro eq_z. Rewrite <- eq_z in H4.
+Assumption.
+
+Omega.
+
+Assumption.
+
+Rewrite (Zmult_sym (Zs z) y).
+Rewrite (Zmult_assoc_r y (Zs z) f1).
+Auto.
+Save.
+
+
+(* This one is used to prove the proof obligation at the exit of the loop *)
+
+Lemma invariant_0 : (x,y:Z)(invariant y `0` x)->(fact x y).
+Proof.
+Intros.
+Elim H.
+Intros.
+Generalize (fact_0_1 f H0).
+Intro.
+Rewrite H3 in H2.
+Simpl in H2.
+Replace y with `y*1`.
+Rewrite H2.
+Assumption.
+
+Omega.
+Save.
+
+
+(* At last we come to the proof itself *************************************)
+
+(* we declare two variable x and y *)
+
+Global Variable x : Z ref.
+Global Variable y : Z ref.
+
+(* and we give the annotated program *)
+
+Correctness factorielle
+ { `0 <= x` }
+ begin
+ y := 1;
+ while !x <> 0 do
+ { invariant `0 <= x` /\ (invariant y x x@0) as Inv
+ variant x for (Zwf ZERO) }
+ y := (Zmult !x !y);
+ x := (Zpred !x)
+ done
+ end
+ { (fact x@0 y) }.
+Proof.
+Split.
+(* decreasing *)
+Unfold Zwf. Unfold Zpred. Omega.
+(* preservation of the invariant *)
+Split.
+ Unfold Zpred; Omega.
+ Cut `0 < x0`. Intro Hx0.
+ Decompose [and] Inv.
+ Exact (fact_rec x x0 y1 Hx0 H0).
+ Omega.
+(* entrance of the loop *)
+Split; Auto.
+Elim (fact_function x Pre1). Intros.
+Apply c_inv with f:=x0 f0:=x0; Auto.
+Omega.
+(* exit of the loop *)
+Decompose [and] Inv.
+Rewrite H0 in H2.
+Exact (invariant_0 x y1 H2).
+Save.
diff --git a/contrib/correctness/past.mli b/contrib/correctness/past.mli
new file mode 100644
index 00000000..1cc7164e
--- /dev/null
+++ b/contrib/correctness/past.mli
@@ -0,0 +1,97 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: past.mli,v 1.7.6.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+(*s Abstract syntax of imperative programs. *)
+
+open Names
+open Ptype
+open Topconstr
+
+type termination =
+ | RecArg of int
+ | Wf of constr_expr * constr_expr
+
+type variable = identifier
+
+type pattern =
+ | PatVar of identifier
+ | PatConstruct of identifier * ((kernel_name * int) * int)
+ | PatAlias of pattern * identifier
+ | PatPair of pattern * pattern
+ | PatApp of pattern list
+
+type epattern =
+ | ExnConstant of identifier
+ | ExnBind of identifier * identifier
+
+type ('a, 'b) block_st =
+ | Label of string
+ | Assert of 'b Ptype.assertion
+ | Statement of 'a
+
+type ('a, 'b) block = ('a, 'b) block_st list
+
+type ('a, 'b) t = {
+ desc : ('a, 'b) t_desc;
+ pre : 'b Ptype.precondition list;
+ post : 'b Ptype.postcondition option;
+ loc : Util.loc;
+ info : 'a
+}
+
+and ('a, 'b) t_desc =
+ | Variable of variable
+ | Acc of variable
+ | Aff of variable * ('a, 'b) t
+ | TabAcc of bool * variable * ('a, 'b) t
+ | TabAff of bool * variable * ('a, 'b) t * ('a, 'b) t
+ | Seq of (('a, 'b) t, 'b) block
+ | While of ('a, 'b) t * 'b Ptype.assertion option * ('b * 'b) *
+ (('a, 'b) t, 'b) block
+ | If of ('a, 'b) t * ('a, 'b) t * ('a, 'b) t
+ | Lam of 'b Ptype.ml_type_v Ptype.binder list * ('a, 'b) t
+ | Apply of ('a, 'b) t * ('a, 'b) arg list
+ | SApp of ('a, 'b) t_desc list * ('a, 'b) t list
+ | LetRef of variable * ('a, 'b) t * ('a, 'b) t
+ | Let of variable * ('a, 'b) t * ('a, 'b) t
+ | LetRec of variable * 'b Ptype.ml_type_v Ptype.binder list *
+ 'b Ptype.ml_type_v * ('b * 'b) * ('a, 'b) t
+ | PPoint of string * ('a, 'b) t_desc
+ | Expression of Term.constr
+ | Debug of string * ('a, 'b) t
+
+and ('a, 'b) arg =
+ | Term of ('a, 'b) t
+ | Refarg of variable
+ | Type of 'b Ptype.ml_type_v
+
+type program = (unit, Topconstr.constr_expr) t
+
+(*s Intermediate type for CC terms. *)
+
+type cc_type = Term.constr
+
+type cc_bind_type =
+ | CC_typed_binder of cc_type
+ | CC_untyped_binder
+
+type cc_binder = variable * cc_bind_type
+
+type cc_term =
+ | CC_var of variable
+ | CC_letin of bool * cc_type * cc_binder list * cc_term * cc_term
+ | CC_lam of cc_binder list * cc_term
+ | CC_app of cc_term * cc_term list
+ | CC_tuple of bool * cc_type list * cc_term list
+ | CC_case of cc_type * cc_term * cc_term list
+ | CC_expr of Term.constr
+ | CC_hole of cc_type
diff --git a/contrib/correctness/pcic.ml b/contrib/correctness/pcic.ml
new file mode 100644
index 00000000..e87ba70c
--- /dev/null
+++ b/contrib/correctness/pcic.ml
@@ -0,0 +1,231 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pcic.ml,v 1.23.2.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+open Util
+open Names
+open Nameops
+open Libnames
+open Term
+open Termops
+open Nametab
+open Declarations
+open Indtypes
+open Sign
+open Rawterm
+open Typeops
+open Entries
+open Topconstr
+
+open Pmisc
+open Past
+
+
+(* Here we translate intermediates terms (cc_term) into CCI terms (constr) *)
+
+let make_hole c = mkCast (isevar, c)
+
+(* Tuples are defined in file Tuples.v
+ * and their constructors are called Build_tuple_n or exists_n,
+ * wether they are dependant (last element only) or not.
+ * If necessary, tuples are generated ``on the fly''. *)
+
+let tuple_exists id =
+ try let _ = Nametab.locate (make_short_qualid id) in true
+ with Not_found -> false
+
+let ast_set = CSort (dummy_loc,RProp Pos)
+
+let tuple_n n =
+ let id = make_ident "tuple_" (Some n) in
+ let l1n = Util.interval 1 n in
+ let params =
+ List.map (fun i ->
+ (LocalRawAssum ([dummy_loc,Name (make_ident "T" (Some i))], ast_set)))
+ l1n in
+ let fields =
+ List.map
+ (fun i ->
+ let id = make_ident ("proj_" ^ string_of_int n ^ "_") (Some i) in
+ let id' = make_ident "T" (Some i) in
+ (false, Vernacexpr.AssumExpr ((dummy_loc,Name id), mkIdentC id')))
+ l1n
+ in
+ let cons = make_ident "Build_tuple_" (Some n) in
+ Record.definition_structure
+ ((false, (dummy_loc,id)), params, fields, cons, mk_Set)
+
+(*s [(sig_n n)] generates the inductive
+ \begin{verbatim}
+ Inductive sig_n [T1,...,Tn:Set; P:T1->...->Tn->Prop] : Set :=
+ exist_n : (x1:T1)...(xn:Tn)(P x1 ... xn) -> (sig_n T1 ... Tn P).
+ \end{verbatim} *)
+
+let sig_n n =
+ let id = make_ident "sig_" (Some n) in
+ let l1n = Util.interval 1 n in
+ let lT = List.map (fun i -> make_ident "T" (Some i)) l1n in
+ let lx = List.map (fun i -> make_ident "x" (Some i)) l1n in
+ let idp = make_ident "P" None in
+ let params =
+ let typ = List.fold_right (fun _ c -> mkArrow (mkRel n) c) lT mkProp in
+ (idp, LocalAssum typ) ::
+ (List.rev_map (fun id -> (id, LocalAssum mkSet)) lT)
+ in
+ let lc =
+ let app_sig = mkApp(mkRel (2*n+3),
+ Array.init (n+1) (fun i -> mkRel (2*n+2-i))) in
+ let app_p = mkApp(mkRel (n+1),
+ Array.init n (fun i -> mkRel (n-i))) in
+ let c = mkArrow app_p app_sig in
+ List.fold_right (fun id c -> mkProd (Name id, mkRel (n+1), c)) lx c
+ in
+ let cname = make_ident "exist_" (Some n) in
+ Declare.declare_mind
+ { mind_entry_finite = true;
+ mind_entry_inds =
+ [ { mind_entry_params = params;
+ mind_entry_typename = id;
+ mind_entry_arity = mkSet;
+ mind_entry_consnames = [ cname ];
+ mind_entry_lc = [ lc ] } ] }
+
+(*s On the fly generation of needed (possibly dependent) tuples. *)
+
+let check_product_n n =
+ if n > 2 then
+ let s = Printf.sprintf "tuple_%d" n in
+ if not (tuple_exists (id_of_string s)) then tuple_n n
+
+let check_dep_product_n n =
+ if n > 1 then
+ let s = Printf.sprintf "sig_%d" n in
+ if not (tuple_exists (id_of_string s)) then ignore (sig_n n)
+
+(*s Constructors for the tuples. *)
+
+let pair = ConstructRef ((coq_constant ["Init"; "Datatypes"] "prod",0),1)
+let exist = ConstructRef ((coq_constant ["Init"; "Specif"] "sig",0),1)
+
+let tuple_ref dep n =
+ if n = 2 & not dep then
+ pair
+ else
+ let n = n - (if dep then 1 else 0) in
+ if dep then
+ if n = 1 then
+ exist
+ else begin
+ let id = make_ident "exist_" (Some n) in
+ if not (tuple_exists id) then ignore (sig_n n);
+ Nametab.locate (make_short_qualid id)
+ end
+ else begin
+ let id = make_ident "Build_tuple_" (Some n) in
+ if not (tuple_exists id) then tuple_n n;
+ Nametab.locate (make_short_qualid id)
+ end
+
+(* Binders. *)
+
+let trad_binder avoid nenv id = function
+ | CC_untyped_binder -> RHole (dummy_loc,BinderType (Name id))
+ | CC_typed_binder ty -> Detyping.detype (false,Global.env()) avoid nenv ty
+
+let rec push_vars avoid nenv = function
+ | [] -> ([],avoid,nenv)
+ | (id,b) :: bl ->
+ let b' = trad_binder avoid nenv id b in
+ let bl',avoid',nenv' =
+ push_vars (id :: avoid) (add_name (Name id) nenv) bl
+ in
+ ((id,b') :: bl', avoid', nenv')
+
+let rec raw_lambda bl v = match bl with
+ | [] ->
+ v
+ | (id,ty) :: bl' ->
+ RLambda (dummy_loc, Name id, ty, raw_lambda bl' v)
+
+(* The translation itself is quite easy.
+ letin are translated into Cases constructions *)
+
+let rawconstr_of_prog p =
+ let rec trad avoid nenv = function
+ | CC_var id ->
+ RVar (dummy_loc, id)
+
+ (*i optimisation : let x = <constr> in e2 => e2[x<-constr]
+ | CC_letin (_,_,[id,_],CC_expr c,e2) ->
+ real_subst_in_constr [id,c] (trad e2)
+ | CC_letin (_,_,([_] as b),CC_expr e1,e2) ->
+ let (b',avoid',nenv') = push_vars avoid nenv b in
+ let c1 = Detyping.detype avoid nenv e1
+ and c2 = trad avoid' nenv' e2 in
+ let id = Name (fst (List.hd b')) in
+ RLetIn (dummy_loc, id, c1, c2)
+ i*)
+
+ | CC_letin (_,_,([_] as b),e1,e2) ->
+ let (b',avoid',nenv') = push_vars avoid nenv b in
+ let c1 = trad avoid nenv e1
+ and c2 = trad avoid' nenv' e2 in
+ RApp (dummy_loc, raw_lambda b' c2, [c1])
+
+ | CC_letin (dep,ty,bl,e1,e2) ->
+ let (bl',avoid',nenv') = push_vars avoid nenv bl in
+ let c1 = trad avoid nenv e1
+ and c2 = trad avoid' nenv' e2 in
+ ROrderedCase (dummy_loc, LetStyle, None, c1, [| raw_lambda bl' c2 |], ref None)
+
+ | CC_lam (bl,e) ->
+ let bl',avoid',nenv' = push_vars avoid nenv bl in
+ let c = trad avoid' nenv' e in
+ raw_lambda bl' c
+
+ | CC_app (f,args) ->
+ let c = trad avoid nenv f
+ and cargs = List.map (trad avoid nenv) args in
+ RApp (dummy_loc, c, cargs)
+
+ | CC_tuple (_,_,[e]) ->
+ trad avoid nenv e
+
+ | CC_tuple (false,_,[e1;e2]) ->
+ let c1 = trad avoid nenv e1
+ and c2 = trad avoid nenv e2 in
+ RApp (dummy_loc, RRef (dummy_loc,pair),
+ [RHole (dummy_loc,ImplicitArg (pair,1));
+ RHole (dummy_loc,ImplicitArg (pair,2));c1;c2])
+
+ | CC_tuple (dep,tyl,l) ->
+ let n = List.length l in
+ let cl = List.map (trad avoid nenv) l in
+ let tuple = tuple_ref dep n in
+ let tyl = List.map (Detyping.detype (false,Global.env()) avoid nenv) tyl in
+ let args = tyl @ cl in
+ RApp (dummy_loc, RRef (dummy_loc, tuple), args)
+
+ | CC_case (ty,b,el) ->
+ let c = trad avoid nenv b in
+ let cl = List.map (trad avoid nenv) el in
+ let ty = Detyping.detype (false,Global.env()) avoid nenv ty in
+ ROrderedCase (dummy_loc, RegularStyle, Some ty, c, Array.of_list cl, ref None)
+
+ | CC_expr c ->
+ Detyping.detype (false,Global.env()) avoid nenv c
+
+ | CC_hole c ->
+ RCast (dummy_loc, RHole (dummy_loc, QuestionMark),
+ Detyping.detype (false,Global.env()) avoid nenv c)
+
+ in
+ trad [] empty_names_context p
diff --git a/contrib/correctness/pcic.mli b/contrib/correctness/pcic.mli
new file mode 100644
index 00000000..89731472
--- /dev/null
+++ b/contrib/correctness/pcic.mli
@@ -0,0 +1,24 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(*i $Id: pcic.mli,v 1.3.16.1 2004/07/16 19:30:00 herbelin Exp $ i*)
+
+open Past
+open Rawterm
+
+(* On-the-fly generation of needed (possibly dependent) tuples. *)
+
+val check_product_n : int -> unit
+val check_dep_product_n : int -> unit
+
+(* transforms intermediate functional programs into (raw) CIC terms *)
+
+val rawconstr_of_prog : cc_term -> rawconstr
+
diff --git a/contrib/correctness/pcicenv.ml b/contrib/correctness/pcicenv.ml
new file mode 100644
index 00000000..cc15c8f3
--- /dev/null
+++ b/contrib/correctness/pcicenv.ml
@@ -0,0 +1,118 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pcicenv.ml,v 1.5.14.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+open Names
+open Term
+open Sign
+
+open Pmisc
+open Putil
+open Ptype
+open Past
+
+(* on redéfinit add_sign pour éviter de construire des environnements
+ * avec des doublons (qui font planter la résolution des implicites !) *)
+
+(* VERY UGLY!! find some work around *)
+let modify_sign id t s =
+ fold_named_context
+ (fun ((x,b,ty) as d) sign ->
+ if x=id then add_named_decl (x,b,t) sign else add_named_decl d sign)
+ s ~init:empty_named_context
+
+let add_sign (id,t) s =
+ try
+ let _ = lookup_named id s in
+ modify_sign id t s
+ with Not_found ->
+ add_named_decl (id,None,t) s
+
+let cast_set c = mkCast (c, mkSet)
+
+let set = mkCast (mkSet, mkType Univ.prop_univ)
+
+(* [cci_sign_of env] construit un environnement pour CIC ne comprenant que
+ * les objets fonctionnels de l'environnement de programes [env]
+ *)
+
+let cci_sign_of ren env =
+ Penv.fold_all
+ (fun (id,v) sign ->
+ match v with
+ | Penv.TypeV (Ref _ | Array _) -> sign
+ | Penv.TypeV v ->
+ let ty = Pmonad.trad_ml_type_v ren env v in
+ add_sign (id,cast_set ty) sign
+ | Penv.Set -> add_sign (id,set) sign)
+ env (Global.named_context ())
+
+(* [sign_meta ren env fadd ini]
+ * construit un environnement pour CIC qui prend en compte les variables
+ * de programme.
+ * pour cela, cette fonction parcours tout l'envrionnement (global puis
+ * local [env]) et pour chaque déclaration, ajoute ce qu'il faut avec la
+ * fonction [fadd] s'il s'agit d'un mutable et directement sinon,
+ * en partant de [ini].
+ *)
+
+let sign_meta ren env fast ini =
+ Penv.fold_all
+ (fun (id,v) sign ->
+ match v with
+ | Penv.TypeV (Ref _ | Array _ as v) ->
+ let ty = Pmonad.trad_imp_type ren env v in
+ fast sign id ty
+ | Penv.TypeV v ->
+ let ty = Pmonad.trad_ml_type_v ren env v in
+ add_sign (id,cast_set ty) sign
+ | Penv.Set -> add_sign (id,set) sign)
+ env ini
+
+let add_sign_d dates (id,c) sign =
+ let sign =
+ List.fold_left (fun sign d -> add_sign (at_id id d,c) sign) sign dates
+ in
+ add_sign (id,c) sign
+
+let sign_of add ren env =
+ sign_meta ren env
+ (fun sign id c -> let c = cast_set c in add (id,c) sign)
+ (Global.named_context ())
+
+let result_of sign = function
+ None -> sign
+ | Some (id,c) -> add_sign (id, cast_set c) sign
+
+let before_after_result_sign_of res ren env =
+ let dates = "" :: Prename.all_dates ren in
+ result_of (sign_of (add_sign_d dates) ren env) res
+
+let before_after_sign_of ren =
+ let dates = "" :: Prename.all_dates ren in
+ sign_of (add_sign_d dates) ren
+
+let before_sign_of ren =
+ let dates = Prename.all_dates ren in
+ sign_of (add_sign_d dates) ren
+
+let now_sign_of =
+ sign_of (add_sign_d [])
+
+
+(* environnement aprčs traduction *)
+
+let trad_sign_of ren =
+ sign_of
+ (fun (id,c) sign -> add_sign (Prename.current_var ren id,c) sign)
+ ren
+
+
diff --git a/contrib/correctness/pcicenv.mli b/contrib/correctness/pcicenv.mli
new file mode 100644
index 00000000..fc4fa0b9
--- /dev/null
+++ b/contrib/correctness/pcicenv.mli
@@ -0,0 +1,38 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pcicenv.mli,v 1.2.16.1 2004/07/16 19:30:00 herbelin Exp $ *)
+
+open Penv
+open Names
+open Term
+open Sign
+
+(* Translation of local programs environments into Coq signatures.
+ * It is mainly used to type the pre/post conditions in the good
+ * environment *)
+
+(* cci_sign_of: uniquement les objets purement fonctionnels de l'env. *)
+val cci_sign_of : Prename.t -> local_env -> named_context
+
+(* env. Coq avec seulement les variables X de l'env. *)
+val now_sign_of : Prename.t -> local_env -> named_context
+
+(* + les variables X@d pour toutes les dates de l'env. *)
+val before_sign_of : Prename.t -> local_env -> named_context
+
+(* + les variables `avant' X@ *)
+val before_after_sign_of : Prename.t -> local_env -> named_context
+val before_after_result_sign_of : ((identifier * constr) option)
+ -> Prename.t -> local_env -> named_context
+
+(* env. des programmes traduits, avec les variables rennomées *)
+val trad_sign_of : Prename.t -> local_env -> named_context
+
diff --git a/contrib/correctness/pdb.ml b/contrib/correctness/pdb.ml
new file mode 100644
index 00000000..302db871
--- /dev/null
+++ b/contrib/correctness/pdb.ml
@@ -0,0 +1,165 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pdb.ml,v 1.8.2.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+open Term
+open Termops
+open Nametab
+open Constrintern
+
+open Ptype
+open Past
+open Penv
+
+let cci_global id =
+ try
+ global_reference id
+ with
+ _ -> raise Not_found
+
+let lookup_var ids locop id =
+ if List.mem id ids then
+ None
+ else begin
+ try Some (cci_global id)
+ with Not_found -> Perror.unbound_variable id locop
+ end
+
+let check_ref idl loc id =
+ if (not (List.mem id idl)) & (not (Penv.is_global id)) then
+ Perror.unbound_reference id loc
+
+(* db types : only check the references for the moment *)
+
+let rec check_type_v refs = function
+ | Ref v ->
+ check_type_v refs v
+ | Array (c,v) ->
+ check_type_v refs v
+ | Arrow (bl,c) ->
+ check_binder refs c bl
+ | TypePure _ ->
+ ()
+
+and check_type_c refs ((_,v),e,_,_) =
+ check_type_v refs v;
+ List.iter (check_ref refs None) (Peffect.get_reads e);
+ List.iter (check_ref refs None) (Peffect.get_writes e)
+ (* TODO: check_condition on p and q *)
+
+and check_binder refs c = function
+ | [] ->
+ check_type_c refs c
+ | (id, BindType (Ref _ | Array _ as v)) :: bl ->
+ check_type_v refs v;
+ check_binder (id :: refs) c bl
+ | (_, BindType v) :: bl ->
+ check_type_v refs v;
+ check_binder refs c bl
+ | _ :: bl ->
+ check_binder refs c bl
+
+(* db binders *)
+
+let rec db_binders ((tids,pids,refs) as idl) = function
+ | [] ->
+ idl, []
+ | (id, BindType (Ref _ | Array _ as v)) as b :: rem ->
+ check_type_v refs v;
+ let idl',rem' = db_binders (tids,pids,id::refs) rem in
+ idl', b :: rem'
+ | (id, BindType v) as b :: rem ->
+ check_type_v refs v;
+ let idl',rem' = db_binders (tids,id::pids,refs) rem in
+ idl', b :: rem'
+ | ((id, BindSet) as t) :: rem ->
+ let idl',rem' = db_binders (id::tids,pids,refs) rem in
+ idl', t :: rem'
+ | a :: rem ->
+ let idl',rem' = db_binders idl rem in idl', a :: rem'
+
+
+(* db programs *)
+
+let db_prog e =
+ (* tids = type identifiers, ids = variables, refs = references and arrays *)
+ let rec db_desc ((tids,ids,refs) as idl) = function
+ | (Variable x) as t ->
+ (match lookup_var ids (Some e.loc) x with
+ None -> t
+ | Some c -> Expression c)
+ | (Acc x) as t ->
+ check_ref refs (Some e.loc) x;
+ t
+ | Aff (x,e1) ->
+ check_ref refs (Some e.loc) x;
+ Aff (x, db idl e1)
+ | TabAcc (b,x,e1) ->
+ check_ref refs (Some e.loc) x;
+ TabAcc(b,x,db idl e1)
+ | TabAff (b,x,e1,e2) ->
+ check_ref refs (Some e.loc) x;
+ TabAff (b,x, db idl e1, db idl e2)
+ | Seq bl ->
+ Seq (List.map (function
+ Statement p -> Statement (db idl p)
+ | x -> x) bl)
+ | If (e1,e2,e3) ->
+ If (db idl e1, db idl e2, db idl e3)
+ | While (b,inv,var,bl) ->
+ let bl' = List.map (function
+ Statement p -> Statement (db idl p)
+ | x -> x) bl in
+ While (db idl b, inv, var, bl')
+
+ | Lam (bl,e) ->
+ let idl',bl' = db_binders idl bl in Lam(bl', db idl' e)
+ | Apply (e1,l) ->
+ Apply (db idl e1, List.map (db_arg idl) l)
+ | SApp (dl,l) ->
+ SApp (dl, List.map (db idl) l)
+ | LetRef (x,e1,e2) ->
+ LetRef (x, db idl e1, db (tids,ids,x::refs) e2)
+ | Let (x,e1,e2) ->
+ Let (x, db idl e1, db (tids,x::ids,refs) e2)
+
+ | LetRec (f,bl,v,var,e) ->
+ let (tids',ids',refs'),bl' = db_binders idl bl in
+ check_type_v refs' v;
+ LetRec (f, bl, v, var, db (tids',f::ids',refs') e)
+
+ | Debug (s,e1) ->
+ Debug (s, db idl e1)
+
+ | Expression _ as x -> x
+ | PPoint (s,d) -> PPoint (s, db_desc idl d)
+
+ and db_arg ((tids,_,refs) as idl) = function
+ | Term ({ desc = Variable id } as t) ->
+ if List.mem id refs then Refarg id else Term (db idl t)
+ | Term t -> Term (db idl t)
+ | Type v as ty -> check_type_v refs v; ty
+ | Refarg _ -> assert false
+
+ and db idl e =
+ { desc = db_desc idl e.desc ;
+ pre = e.pre; post = e.post;
+ loc = e.loc; info = e.info }
+
+ in
+ let ids = Termops.ids_of_named_context (Global.named_context ()) in
+ (* TODO: separer X:Set et x:V:Set
+ virer le reste (axiomes, etc.) *)
+ let vars,refs = all_vars (), all_refs () in
+ db ([],vars@ids,refs) e
+;;
+
diff --git a/contrib/correctness/pdb.mli b/contrib/correctness/pdb.mli
new file mode 100644
index 00000000..a0df29bd
--- /dev/null
+++ b/contrib/correctness/pdb.mli
@@ -0,0 +1,25 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pdb.mli,v 1.2.16.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Ptype
+open Past
+
+
+(* Here we separate local and global variables, we check the use of
+ * references and arrays w.r.t the local and global environments, etc.
+ * These functions directly raise UserError exceptions on bad programs.
+ *)
+
+val check_type_v : Names.identifier list -> 'a ml_type_v -> unit
+
+val db_prog : program -> program
+
diff --git a/contrib/correctness/peffect.ml b/contrib/correctness/peffect.ml
new file mode 100644
index 00000000..08d6b002
--- /dev/null
+++ b/contrib/correctness/peffect.ml
@@ -0,0 +1,159 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: peffect.ml,v 1.3.14.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+open Nameops
+open Pmisc
+
+(* The type of effects.
+ *
+ * An effect is composed of two lists (r,w) of variables.
+ * The first one is the list of read-only variables
+ * and the second one is the list of read-write variables.
+ *
+ * INVARIANT: 1. each list is sorted in decreasing order for Pervasives.compare
+ * 2. there are no duplicate elements in each list
+ * 3. the two lists are disjoint
+ *)
+
+type t = identifier list * identifier list
+
+
+(* the empty effect *)
+
+let bottom = ([], [])
+
+(* basic operations *)
+
+let push x l =
+ let rec push_rec = function
+ [] -> [x]
+ | (y::rem) as l ->
+ if x = y then l else if x > y then x::l else y :: push_rec rem
+ in
+ push_rec l
+
+let basic_remove x l =
+ let rec rem_rec = function
+ [] -> []
+ | y::l -> if x = y then l else y :: rem_rec l
+ in
+ rem_rec l
+
+let mem x (r,w) = (List.mem x r) or (List.mem x w)
+
+let rec basic_union = function
+ [], s2 -> s2
+ | s1, [] -> s1
+ | ((v1::l1) as s1), ((v2::l2) as s2) ->
+ if v1 > v2 then
+ v1 :: basic_union (l1,s2)
+ else if v1 < v2 then
+ v2 :: basic_union (s1,l2)
+ else
+ v1 :: basic_union (l1,l2)
+
+(* adds reads and writes variables *)
+
+let add_read id ((r,w) as e) =
+ (* if the variable is already a RW it is ok, otherwise adds it as a RO. *)
+ if List.mem id w then
+ e
+ else
+ push id r, w
+
+let add_write id (r,w) =
+ (* if the variable is a RO then removes it from RO. Adds it to RW. *)
+ if List.mem id r then
+ basic_remove id r, push id w
+ else
+ r, push id w
+
+(* access *)
+
+let get_reads = basic_union
+let get_writes = snd
+let get_repr e = (get_reads e, get_writes e)
+
+(* tests *)
+
+let is_read (r,_) id = List.mem id r
+let is_write (_,w) id = List.mem id w
+
+(* union and disjunction *)
+
+let union (r1,w1) (r2,w2) = basic_union (r1,r2), basic_union (w1,w2)
+
+let rec diff = function
+ [], s2 -> []
+ | s1, [] -> s1
+ | ((v1::l1) as s1), ((v2::l2) as s2) ->
+ if v1 > v2 then
+ v1 :: diff (l1,s2)
+ else if v1 < v2 then
+ diff (s1,l2)
+ else
+ diff (l1,l2)
+
+let disj (r1,w1) (r2,w2) =
+ let w1_w2 = diff (w1,w2) and w2_w1 = diff (w2,w1) in
+ let r = basic_union (basic_union (r1,r2), basic_union (w1_w2,w2_w1))
+ and w = basic_union (w1,w2) in
+ r,w
+
+(* comparison relation *)
+
+let le e1 e2 = failwith "effects: le: not yet implemented"
+
+let inf e1 e2 = failwith "effects: inf: not yet implemented"
+
+(* composition *)
+
+let compose (r1,w1) (r2,w2) =
+ let r = basic_union (r1, diff (r2,w1)) in
+ let w = basic_union (w1,w2) in
+ r,w
+
+(* remove *)
+
+let remove (r,w) name = basic_remove name r, basic_remove name w
+
+(* substitution *)
+
+let subst_list (x,x') l =
+ if List.mem x l then push x' (basic_remove x l) else l
+
+let subst_one (r,w) s = subst_list s r, subst_list s w
+
+let subst s e = List.fold_left subst_one e s
+
+(* pretty-print *)
+
+open Pp
+open Util
+open Himsg
+
+let pp (r,w) =
+ hov 0 (if r<>[] then
+ (str"reads " ++
+ prlist_with_sep (fun () -> (str"," ++ spc ())) pr_id r)
+ else (mt ()) ++
+ spc () ++
+ if w<>[] then
+ (str"writes " ++
+ prlist_with_sep (fun ()-> (str"," ++ spc ())) pr_id w)
+ else (mt ())
+)
+
+let ppr e =
+ Pp.pp (pp e)
+
diff --git a/contrib/correctness/peffect.mli b/contrib/correctness/peffect.mli
new file mode 100644
index 00000000..d6d0ce22
--- /dev/null
+++ b/contrib/correctness/peffect.mli
@@ -0,0 +1,42 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: peffect.mli,v 1.1.16.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+
+(* The abstract type of effects *)
+
+type t
+
+val bottom : t
+val add_read : identifier -> t -> t
+val add_write : identifier -> t -> t
+
+val get_reads : t -> identifier list
+val get_writes : t -> identifier list
+val get_repr : t -> (identifier list) * (identifier list)
+
+val is_read : t -> identifier -> bool (* read-only *)
+val is_write : t -> identifier -> bool (* read-write *)
+
+val compose : t -> t -> t
+
+val union : t -> t -> t
+val disj : t -> t -> t
+
+val remove : t -> identifier -> t
+
+val subst : (identifier * identifier) list -> t -> t
+
+
+val pp : t -> Pp.std_ppcmds
+val ppr : t -> unit
+
diff --git a/contrib/correctness/penv.ml b/contrib/correctness/penv.ml
new file mode 100644
index 00000000..820d1cf0
--- /dev/null
+++ b/contrib/correctness/penv.ml
@@ -0,0 +1,240 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: penv.ml,v 1.10.2.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Pmisc
+open Past
+open Ptype
+open Names
+open Nameops
+open Libobject
+open Library
+open Term
+
+(* Environments for imperative programs.
+ *
+ * An environment of programs is an association tables
+ * from identifiers (Names.identifier) to types of values with effects
+ * (ProgAst.ml_type_v), together with a list of these associations, since
+ * the order is relevant (we have dependent types e.g. [x:nat; t:(array x T)])
+ *)
+
+module Env = struct
+ type 'a t = ('a Idmap.t)
+ * ((identifier * 'a) list)
+ * ((identifier * (identifier * variant)) list)
+ let empty = Idmap.empty, [], []
+ let add id v (m,l,r) = (Idmap.add id v m, (id,v)::l, r)
+ let find id (m,_,_) = Idmap.find id m
+ let fold f (_,l,_) x0 = List.fold_right f l x0
+ let add_rec (id,var) (m,l,r) = (m,l,(id,var)::r)
+ let find_rec id (_,_,r) = List.assoc id r
+end
+
+(* Local environments *)
+
+type type_info = Set | TypeV of type_v
+
+type local_env = type_info Env.t
+
+let empty = (Env.empty : local_env)
+
+let add (id,v) = Env.add id (TypeV v)
+
+let add_set id = Env.add id Set
+
+let find id env =
+ match Env.find id env with TypeV v -> v | Set -> raise Not_found
+
+let is_local env id =
+ try
+ match Env.find id env with TypeV _ -> true | Set -> false
+ with
+ Not_found -> false
+
+let is_local_set env id =
+ try
+ match Env.find id env with TypeV _ -> false | Set -> true
+ with
+ Not_found -> false
+
+
+(* typed programs *)
+
+type typing_info = {
+ env : local_env;
+ kappa : constr ml_type_c
+}
+
+type typed_program = (typing_info, constr) t
+
+
+(* The global environment.
+ *
+ * We have a global typing environment env
+ * We also keep a table of programs for extraction purposes
+ * and a table of initializations (still for extraction)
+ *)
+
+let (env : type_info Env.t ref) = ref Env.empty
+
+let (pgm_table : (typed_program option) Idmap.t ref) = ref Idmap.empty
+
+let (init_table : constr Idmap.t ref) = ref Idmap.empty
+
+let freeze () = (!env, !pgm_table, !init_table)
+let unfreeze (e,p,i) = env := e; pgm_table := p; init_table := i
+let init () =
+ env := Env.empty; pgm_table := Idmap.empty; init_table := Idmap.empty
+;;
+
+Summary.declare_summary "programs-environment"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
+ Summary.survive_module = false;
+ Summary.survive_section = false }
+;;
+
+(* Operations on the global environment. *)
+
+let add_pgm id p = pgm_table := Idmap.add id p !pgm_table
+
+let cache_global (_,(id,v,p)) =
+ env := Env.add id v !env; add_pgm id p
+
+let type_info_app f = function Set -> Set | TypeV v -> TypeV (f v)
+
+let subst_global (_,s,(id,v,p)) = (id, type_info_app (type_v_knsubst s) v, p)
+
+let (inProg,outProg) =
+ declare_object { object_name = "programs-objects";
+ cache_function = cache_global;
+ load_function = (fun _ -> cache_global);
+ open_function = (fun _ _ -> ());
+ classify_function = (fun (_,x) -> Substitute x);
+ subst_function = subst_global;
+ export_function = (fun x -> Some x) }
+
+let is_mutable = function Ref _ | Array _ -> true | _ -> false
+
+let add_global id v p =
+ try
+ let _ = Env.find id !env in
+ Perror.clash id None
+ with
+ Not_found -> begin
+ let id' =
+ if is_mutable v then id
+ else id_of_string ("prog_" ^ (string_of_id id))
+ in
+ Lib.add_leaf id' (inProg (id,TypeV v,p))
+ end
+
+let add_global_set id =
+ try
+ let _ = Env.find id !env in
+ Perror.clash id None
+ with
+ Not_found -> Lib.add_leaf id (inProg (id,Set,None))
+
+let is_global id =
+ try
+ match Env.find id !env with TypeV _ -> true | Set -> false
+ with
+ Not_found -> false
+
+let is_global_set id =
+ try
+ match Env.find id !env with TypeV _ -> false | Set -> true
+ with
+ Not_found -> false
+
+
+let lookup_global id =
+ match Env.find id !env with TypeV v -> v | Set -> raise Not_found
+
+let find_pgm id = Idmap.find id !pgm_table
+
+let all_vars () =
+ Env.fold
+ (fun (id,v) l -> match v with TypeV (Arrow _|TypePure _) -> id::l | _ -> l)
+ !env []
+
+let all_refs () =
+ Env.fold
+ (fun (id,v) l -> match v with TypeV (Ref _ | Array _) -> id::l | _ -> l)
+ !env []
+
+(* initializations *)
+
+let cache_init (_,(id,c)) =
+ init_table := Idmap.add id c !init_table
+
+let subst_init (_,s,(id,c)) = (id, subst_mps s c)
+
+let (inInit,outInit) =
+ declare_object { object_name = "programs-objects-init";
+ cache_function = cache_init;
+ load_function = (fun _ -> cache_init);
+ open_function = (fun _ _-> ());
+ classify_function = (fun (_,x) -> Substitute x);
+ subst_function = subst_init;
+ export_function = (fun x -> Some x) }
+
+let initialize id c = Lib.add_anonymous_leaf (inInit (id,c))
+
+let find_init id = Idmap.find id !init_table
+
+
+(* access in env, local then global *)
+
+let type_in_env env id =
+ try find id env with Not_found -> lookup_global id
+
+let is_in_env env id =
+ (is_global id) or (is_local env id)
+
+let fold_all f lenv x0 =
+ let x1 = Env.fold f !env x0 in
+ Env.fold f lenv x1
+
+
+(* recursions *)
+
+let add_recursion = Env.add_rec
+
+let find_recursion = Env.find_rec
+
+
+(* We also maintain a table of the currently edited proofs of programs
+ * in order to add them in the environnement when the user does Save *)
+
+open Pp
+open Himsg
+
+let (edited : (type_v * typed_program) Idmap.t ref) = ref Idmap.empty
+
+let new_edited id v =
+ edited := Idmap.add id v !edited
+
+let is_edited id =
+ try let _ = Idmap.find id !edited in true with Not_found -> false
+
+let register id id' =
+ try
+ let (v,p) = Idmap.find id !edited in
+ let _ = add_global id' v (Some p) in
+ Options.if_verbose
+ msgnl (hov 0 (str"Program " ++ pr_id id' ++ spc () ++ str"is defined"));
+ edited := Idmap.remove id !edited
+ with Not_found -> ()
+
diff --git a/contrib/correctness/penv.mli b/contrib/correctness/penv.mli
new file mode 100644
index 00000000..ef2e4c6e
--- /dev/null
+++ b/contrib/correctness/penv.mli
@@ -0,0 +1,87 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: penv.mli,v 1.3.8.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Ptype
+open Past
+open Names
+open Libnames
+open Term
+
+(* Environment for imperative programs.
+ *
+ * Here we manage the global environment, which is imperative,
+ * and we provide a functional local environment.
+ *
+ * The most important functions, is_in_env, type_in_env and fold_all
+ * first look in the local environment then in the global one.
+ *)
+
+(* local environments *)
+
+type local_env
+
+val empty : local_env
+val add : (identifier * type_v) -> local_env -> local_env
+val add_set : identifier -> local_env -> local_env
+val is_local : local_env -> identifier -> bool
+val is_local_set : local_env -> identifier -> bool
+
+(* typed programs *)
+
+type typing_info = {
+ env : local_env;
+ kappa : constr ml_type_c
+}
+
+type typed_program = (typing_info, constr) t
+
+(* global environment *)
+
+val add_global : identifier -> type_v -> typed_program option -> object_name
+val add_global_set : identifier -> object_name
+val is_global : identifier -> bool
+val is_global_set : identifier -> bool
+val lookup_global : identifier -> type_v
+
+val all_vars : unit -> identifier list
+val all_refs : unit -> identifier list
+
+(* a table keeps the program (for extraction) *)
+
+val find_pgm : identifier -> typed_program option
+
+(* a table keeps the initializations of mutable objects *)
+
+val initialize : identifier -> constr -> unit
+val find_init : identifier -> constr
+
+(* access in env (local then global) *)
+
+val type_in_env : local_env -> identifier -> type_v
+val is_in_env : local_env -> identifier -> bool
+
+type type_info = Set | TypeV of type_v
+val fold_all : (identifier * type_info -> 'a -> 'a) -> local_env -> 'a -> 'a
+
+(* local environnements also contains a list of recursive functions
+ * with the associated variant *)
+
+val add_recursion : identifier * (identifier*variant) -> local_env -> local_env
+val find_recursion : identifier -> local_env -> identifier * variant
+
+(* We also maintain a table of the currently edited proofs of programs
+ * in order to add them in the environnement when the user does Save *)
+
+val new_edited : identifier -> type_v * typed_program -> unit
+val is_edited : identifier -> bool
+val register : identifier -> identifier -> unit
+
diff --git a/contrib/correctness/perror.ml b/contrib/correctness/perror.ml
new file mode 100644
index 00000000..40fe4c98
--- /dev/null
+++ b/contrib/correctness/perror.ml
@@ -0,0 +1,172 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: perror.ml,v 1.9.2.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Nameops
+open Term
+open Himsg
+
+open Ptype
+open Past
+
+let is_mutable = function Ref _ | Array _ -> true | _ -> false
+let is_pure = function TypePure _ -> true | _ -> false
+
+let raise_with_loc = function
+ | None -> raise
+ | Some loc -> Stdpp.raise_with_loc loc
+
+let unbound_variable id loc =
+ raise_with_loc loc
+ (UserError ("Perror.unbound_variable",
+ (hov 0 (str"Unbound variable" ++ spc () ++ pr_id id ++ fnl ()))))
+
+let unbound_reference id loc =
+ raise_with_loc loc
+ (UserError ("Perror.unbound_reference",
+ (hov 0 (str"Unbound reference" ++ spc () ++ pr_id id ++ fnl ()))))
+
+let clash id loc =
+ raise_with_loc loc
+ (UserError ("Perror.clash",
+ (hov 0 (str"Clash with previous constant" ++ spc () ++
+ str(string_of_id id) ++ fnl ()))))
+
+let not_defined id =
+ raise
+ (UserError ("Perror.not_defined",
+ (hov 0 (str"The object" ++ spc () ++ pr_id id ++ spc () ++
+ str"is not defined" ++ fnl ()))))
+
+let check_for_reference loc id = function
+ Ref _ -> ()
+ | _ -> Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_reference",
+ hov 0 (pr_id id ++ spc () ++
+ str"is not a reference")))
+
+let check_for_array loc id = function
+ Array _ -> ()
+ | _ -> Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_array",
+ hov 0 (pr_id id ++ spc () ++
+ str"is not an array")))
+
+let is_constant_type s = function
+ TypePure c ->
+ let id = id_of_string s in
+ let c' = Constrintern.global_reference id in
+ Reductionops.is_conv (Global.env()) Evd.empty c c'
+ | _ -> false
+
+let check_for_index_type loc v =
+ let is_index = is_constant_type "Z" v in
+ if not is_index then
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_index",
+ hov 0 (str"This expression is an index" ++ spc () ++
+ str"and should have type int (Z)")))
+
+let check_no_effect loc ef =
+ if not (Peffect.get_writes ef = []) then
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_no_effect",
+ hov 0 (str"A boolean should not have side effects"
+)))
+
+let should_be_boolean loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.should_be_boolean",
+ hov 0 (str"This expression is a test:" ++ spc () ++
+ str"it should have type bool")))
+
+let test_should_be_annotated loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.test_should_be_annotated",
+ hov 0 (str"This test should be annotated")))
+
+let if_branches loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.if_branches",
+ hov 0 (str"The two branches of an `if' expression" ++ spc () ++
+ str"should have the same type")))
+
+let check_for_not_mutable loc v =
+ if is_mutable v then
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_not_mutable",
+ hov 0 (str"This expression cannot be a mutable")))
+
+let check_for_pure_type loc v =
+ if not (is_pure v) then
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_pure_type",
+ hov 0 (str"This expression must be pure" ++ spc () ++
+ str"(neither a mutable nor a function)")))
+
+let check_for_let_ref loc v =
+ if not (is_pure v) then
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.check_for_let_ref",
+ hov 0 (str"References can only be bound in pure terms")))
+
+let informative loc s =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.variant_informative",
+ hov 0 (str s ++ spc () ++ str"must be informative")))
+
+let variant_informative loc = informative loc "Variant"
+let should_be_informative loc = informative loc "This term"
+
+let app_of_non_function loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.app_of_non_function",
+ hov 0 (str"This term cannot be applied" ++ spc () ++
+ str"(either it is not a function" ++ spc () ++
+ str"or it is applied to non pure arguments)")))
+
+let partial_app loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.partial_app",
+ hov 0 (str"This function does not have" ++
+ spc () ++ str"the right number of arguments")))
+
+let expected_type loc s =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.expected_type",
+ hov 0 (str"Argument is expected to have type" ++ spc () ++ s)))
+
+let expects_a_type id loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.expects_a_type",
+ hov 0 (str"The argument " ++ pr_id id ++ spc () ++
+ str"in this application is supposed to be a type")))
+
+let expects_a_term id =
+ raise
+ (UserError ("Perror.expects_a_type",
+ hov 0 (str"The argument " ++ pr_id id ++ spc () ++
+ str"in this application is supposed to be a term")))
+
+let should_be_a_variable loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.should_be_a_variable",
+ hov 0 (str"Argument should be a variable")))
+
+let should_be_a_reference loc =
+ Stdpp.raise_with_loc loc
+ (UserError ("Perror.should_be_a_reference",
+ hov 0 (str"Argument of function should be a reference")))
+
+
diff --git a/contrib/correctness/perror.mli b/contrib/correctness/perror.mli
new file mode 100644
index 00000000..40b2d25c
--- /dev/null
+++ b/contrib/correctness/perror.mli
@@ -0,0 +1,47 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: perror.mli,v 1.2.6.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Ptype
+open Past
+
+val unbound_variable : identifier -> loc option -> 'a
+val unbound_reference : identifier -> loc option -> 'a
+
+val clash : identifier -> loc option -> 'a
+val not_defined : identifier -> 'a
+
+val check_for_reference : loc -> identifier -> type_v -> unit
+val check_for_array : loc -> identifier -> type_v -> unit
+
+val check_for_index_type : loc -> type_v -> unit
+val check_no_effect : loc -> Peffect.t -> unit
+val should_be_boolean : loc -> 'a
+val test_should_be_annotated : loc -> 'a
+val if_branches : loc -> 'a
+
+val check_for_not_mutable : loc -> type_v -> unit
+val check_for_pure_type : loc -> type_v -> unit
+val check_for_let_ref : loc -> type_v -> unit
+
+val variant_informative : loc -> 'a
+val should_be_informative : loc -> 'a
+
+val app_of_non_function : loc -> 'a
+val partial_app : loc -> 'a
+val expected_type : loc -> std_ppcmds -> 'a
+val expects_a_type : identifier -> loc -> 'a
+val expects_a_term : identifier -> 'a
+val should_be_a_variable : loc -> 'a
+val should_be_a_reference : loc -> 'a
diff --git a/contrib/correctness/pextract.ml b/contrib/correctness/pextract.ml
new file mode 100644
index 00000000..2a35d471
--- /dev/null
+++ b/contrib/correctness/pextract.ml
@@ -0,0 +1,473 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pextract.ml,v 1.5.6.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Pp_control
+open Pp
+open Util
+open System
+open Names
+open Term
+open Himsg
+open Reduction
+
+open Putil
+open Ptype
+open Past
+open Penv
+open Putil
+
+let extraction env c =
+ let ren = initial_renaming env in
+ let sign = Pcicenv.now_sign_of ren env in
+ let fsign = Mach.fsign_of_sign (Evd.mt_evd()) sign in
+ match Mach.infexecute (Evd.mt_evd()) (sign,fsign) c with
+ | (_,Inf j) -> j._VAL
+ | (_,Logic) -> failwith "Prog_extract.pp: should be informative"
+
+(* les tableaux jouent un role particulier, puisqu'ils seront extraits
+ * vers des tableaux ML *)
+
+let sp_access = coq_constant ["correctness"; "Arrays"] "access"
+let access = ConstRef sp_access
+
+let has_array = ref false
+
+let pp_conversions () =
+ (str"\
+let rec int_of_pos = function
+ XH -> 1
+ | XI p -> 2 * (int_of_pos p) + 1
+ | XO p -> 2 * (int_of_pos p)
+ ++ ++
+
+let int_of_z = function
+ ZERO -> 0
+ | POS p -> int_of_pos p
+ | NEG p -> -(int_of_pos p)
+ ++ ++
+") (* '"' *)
+
+(* collect all section-path in a CIC constant *)
+
+let spset_of_cci env c =
+ let spl = Fw_env.collect (extraction env c) in
+ let sps = List.fold_left (fun e x -> SpSet.add x e) SpSet.empty spl in
+ has_array := !has_array or (SpSet.mem sp_access sps) ++
+ SpSet.remove sp_access sps
+
+
+(* collect all Coq constants and all pgms appearing in a given program *)
+
+let add_id env ((sp,ids) as s) id =
+ if is_local env id then
+ s
+ else if is_global id then
+ (sp,IdSet.add id ids)
+ else
+ try (SpSet.add (Nametab.sp_of_id FW id) sp,ids) with Not_found -> s
+
+let collect env =
+ let rec collect_desc env s = function
+ | Var x -> add_id env s x
+ | Acc x -> add_id env s x
+ | Aff (x,e1) -> add_id env (collect_rec env s e1) x
+ | TabAcc (_,x,e1) ->
+ has_array := true ++
+ add_id env (collect_rec env s e1) x
+ | TabAff (_,x,e1,e2) ->
+ has_array := true ++
+ add_id env (collect_rec env (collect_rec env s e1) e2) x
+ | Seq bl ->
+ List.fold_left (fun s st -> match st with
+ Statement p -> collect_rec env s p
+ | _ -> s) s bl
+ | If (e1,e2,e3) ->
+ collect_rec env (collect_rec env (collect_rec env s e1) e2) e3
+ | While (b,_,_,bl) ->
+ let s = List.fold_left (fun s st -> match st with
+ Statement p -> collect_rec env s p
+ | _ -> s) s bl in
+ collect_rec env s b
+ | Lam (bl,e) ->
+ collect_rec (traverse_binders env bl) s e
+ | App (e1,l) ->
+ let s = List.fold_left (fun s a -> match a with
+ Term t -> collect_rec env s t
+ | Type _ | Refarg _ -> s) s l in
+ collect_rec env s e1
+ | SApp (_,l) ->
+ List.fold_left (fun s a -> collect_rec env s a) s l
+ | LetRef (x,e1,e2) ->
+ let (_,v),_,_,_ = e1.info.kappa in
+ collect_rec (add (x,Ref v) env) (collect_rec env s e1) e2
+ | LetIn (x,e1,e2) ->
+ let (_,v),_,_,_ = e1.info.kappa in
+ collect_rec (add (x,v) env) (collect_rec env s e1) e2
+ | LetRec (f,bl,_,_,e) ->
+ let env' = traverse_binders env bl in
+ let env'' = add (f,make_arrow bl e.info.kappa) env' in
+ collect_rec env'' s e
+ | Debug (_,e1) -> collect_rec env s e1
+ | PPoint (_,d) -> collect_desc env s d
+ | Expression c ->
+ let (sp,ids) = s in
+ let sp' = spset_of_cci env c in
+ SpSet.fold
+ (fun s (es,ei) ->
+ let id = basename s in
+ if is_global id then (*SpSet.add s*)es,IdSet.add id ei
+ else SpSet.add s es,ei)
+ sp' (sp,ids)
+
+ and collect_rec env s p = collect_desc env s p.desc
+
+ in
+ collect_rec env (SpSet.empty,IdSet.empty)
+
+
+(* On a besoin de faire du renommage, tout comme pour l'extraction des
+ * termes Coq. En ce qui concerne les globaux, on utilise la table de
+ * Fwtoml. Pour les objects locaux, on introduit la structure de
+ * renommage rename_struct
+ *)
+
+module Ocaml_ren = Ocaml.OCaml_renaming
+
+let rename_global id =
+ let id' = Ocaml_ren.rename_global_term !Fwtoml.globals (Name id) in
+ Fwtoml.add_global_renaming (id,id') ++
+ id'
+
+type rename_struct = { rn_map : identifier IdMap.t;
+ rn_avoid : identifier list }
+
+let rn_empty = { rn_map = IdMap.empty; rn_avoid = [] }
+
+let rename_local rn id =
+ let id' = Ocaml_ren.rename_term (!Fwtoml.globals@rn.rn_avoid) (Name id) in
+ { rn_map = IdMap.add id id' rn.rn_map; rn_avoid = id' :: rn.rn_avoid },
+ id'
+
+let get_local_name rn id = IdMap.find id rn.rn_map
+
+let get_name env rn id =
+ if is_local env id then
+ get_local_name rn id
+ else
+ Fwtoml.get_global_name id
+
+let rec rename_binders rn = function
+ | [] -> rn
+ | (id,_) :: bl -> let rn',_ = rename_local rn id in rename_binders rn' bl
+
+(* on a bespoin d'un pretty-printer de constr particulier, qui reconnaisse
+ * les acces a des references et dans des tableaux, et qui de plus n'imprime
+ * pas de GENTERM lorsque des identificateurs ne sont pas visibles.
+ * Il est simplifie dans la mesure ou l'on a ici que des constantes et
+ * des applications.
+ *)
+
+let putpar par s =
+ if par then (str"(" ++ s ++ str")") else s
+
+let is_ref env id =
+ try
+ (match type_in_env env id with Ref _ -> true | _ -> false)
+ with
+ Not_found -> false
+
+let rec pp_constr env rn = function
+ | VAR id ->
+ if is_ref env id then
+ (str"!" ++ pID (get_name env rn id))
+ else
+ pID (get_name env rn id)
+ | DOPN((Const _|MutInd _|MutConstruct _) as oper, _) ->
+ pID (Fwtoml.name_of_oper oper)
+ | DOPN(AppL,v) ->
+ if Array.length v = 0 then
+ (mt ())
+ else begin
+ match v.(0) with
+ DOPN(Const sp,_) when sp = sp_access ->
+ (pp_constr env rn v.(3) ++
+ str".(int_of_z " ++ pp_constr env rn v.(4) ++ str")")
+ | _ ->
+ hov 2 (putpar true (prvect_with_sep (fun () -> (spc ()))
+ (pp_constr env rn) v))
+ end
+ | DOP2(Cast,c,_) -> pp_constr env rn c
+ | _ -> failwith "Prog_extract.pp_constr: unexpected constr"
+
+
+(* pretty-print of imperative programs *)
+
+let collect_lambda =
+ let rec collect acc p = match p.desc with
+ | Lam(bl,t) -> collect (bl@acc) t
+ | x -> acc,p
+ in
+ collect []
+
+let pr_binding rn =
+ prlist_with_sep (fun () -> (mt ()))
+ (function
+ | (id,(Untyped | BindType _)) ->
+ (str" " ++ pID (get_local_name rn id))
+ | (id,BindSet) -> (mt ()))
+
+let pp_prog id =
+ let rec pp_d env rn par = function
+ | Var x -> pID (get_name env rn x)
+ | Acc x -> (str"!" ++ pID (get_name env rn x))
+ | Aff (x,e1) -> (pID (get_name env rn x) ++
+ str" := " ++ hov 0 (pp env rn false e1))
+ | TabAcc (_,x,e1) ->
+ (pID (get_name env rn x) ++
+ str".(int_of_z " ++ hov 0 (pp env rn true e1) ++ str")")
+ | TabAff (_,x,e1,e2) ->
+ (pID (get_name env rn x) ++
+ str".(int_of_z " ++ hov 0 (pp env rn true e1) ++ str")" ++
+ str" <-" ++ spc () ++ hov 2 (pp env rn false e2))
+ | Seq bl ->
+ (str"begin" ++ fnl () ++
+ str" " ++ hov 0 (pp_block env rn bl) ++ fnl () ++
+ str"end")
+ | If (e1,e2,e3) ->
+ putpar par (str"if " ++ (pp env rn false e1) ++
+ str" then" ++ fnl () ++
+ str" " ++ hov 0 (pp env rn false e2) ++ fnl () ++
+ str"else" ++ fnl () ++
+ str" " ++ hov 0 (pp env rn false e3))
+ (* optimisations : then begin .... end else begin ... end *)
+ | While (b,inv,_,bl) ->
+ (str"while " ++ (pp env rn false b) ++ str" do" ++ fnl () ++
+ str" " ++
+ hov 0 ((match inv with
+ None -> (mt ())
+ | Some c -> (str"(* invariant: " ++ pTERM c.a_value ++
+ str" *)" ++ fnl ())) ++
+ pp_block env rn bl) ++ fnl () ++
+ str"done")
+ | Lam (bl,e) ->
+ let env' = traverse_binders env bl in
+ let rn' = rename_binders rn bl in
+ putpar par
+ (hov 2 (str"fun" ++ pr_binding rn' bl ++ str" ->" ++
+ spc () ++ pp env' rn' false e))
+ | SApp ((Var id)::_, [e1; e2])
+ when id = connective_and or id = connective_or ->
+ let conn = if id = connective_and then "&" else "or" in
+ putpar par
+ (hov 0 (pp env rn true e1 ++ spc () ++ str conn ++ spc () ++
+ pp env rn true e2))
+ | SApp ((Var id)::_, [e]) when id = connective_not ->
+ putpar par
+ (hov 0 (str"not" ++ spc () ++ pp env rn true e))
+ | SApp _ ->
+ invalid_arg "Prog_extract.pp_prog (SApp)"
+ | App(e1,[]) ->
+ hov 0 (pp env rn false e1)
+ | App (e1,l) ->
+ putpar true
+ (hov 2 (pp env rn true e1 ++
+ prlist (function
+ Term p -> (spc () ++ pp env rn true p)
+ | Refarg x -> (spc () ++ pID (get_name env rn x))
+ | Type _ -> (mt ()))
+ l))
+ | LetRef (x,e1,e2) ->
+ let (_,v),_,_,_ = e1.info.kappa in
+ let env' = add (x,Ref v) env in
+ let rn',x' = rename_local rn x in
+ putpar par
+ (hov 0 (str"let " ++ pID x' ++ str" = ref " ++ pp env rn false e1 ++
+ str" in" ++ fnl () ++ pp env' rn' false e2))
+ | LetIn (x,e1,e2) ->
+ let (_,v),_,_,_ = e1.info.kappa in
+ let env' = add (x,v) env in
+ let rn',x' = rename_local rn x in
+ putpar par
+ (hov 0 (str"let " ++ pID x' ++ str" = " ++ pp env rn false e1 ++
+ str" in" ++ fnl () ++ pp env' rn' false e2))
+ | LetRec (f,bl,_,_,e) ->
+ let env' = traverse_binders env bl in
+ let rn' = rename_binders rn bl in
+ let env'' = add (f,make_arrow bl e.info.kappa) env' in
+ let rn'',f' = rename_local rn' f in
+ putpar par
+ (hov 0 (str"let rec " ++ pID f' ++ pr_binding rn' bl ++ str" =" ++ fnl () ++
+ str" " ++ hov 0 (pp env'' rn'' false e) ++ fnl () ++
+ str"in " ++ pID f'))
+ | Debug (_,e1) -> pp env rn par e1
+ | PPoint (_,d) -> pp_d env rn par d
+ | Expression c ->
+ pp_constr env rn (extraction env c)
+
+ and pp_block env rn bl =
+ let bl =
+ map_succeed (function Statement p -> p | _ -> failwith "caught") bl
+ in
+ prlist_with_sep (fun () -> (str";" ++ fnl ()))
+ (fun p -> hov 0 (pp env rn false p)) bl
+
+ and pp env rn par p =
+ (pp_d env rn par p.desc)
+
+ and pp_mut v c = match v with
+ | Ref _ ->
+ (str"ref " ++ pp_constr empty rn_empty (extraction empty c))
+ | Array (n,_) ->
+ (str"Array.create " ++ cut () ++
+ putpar true
+ (str"int_of_z " ++
+ pp_constr empty rn_empty (extraction empty n)) ++
+ str" " ++ pp_constr empty rn_empty (extraction empty c))
+ | _ -> invalid_arg "pp_mut"
+ in
+ let v = lookup_global id in
+ let id' = rename_global id in
+ if is_mutable v then
+ try
+ let c = find_init id in
+ hov 0 (str"let " ++ pID id' ++ str" = " ++ pp_mut v c)
+ with Not_found ->
+ errorlabstrm "Prog_extract.pp_prog"
+ (str"The variable " ++ pID id ++
+ str" must be initialized first !")
+ else
+ match find_pgm id with
+ | None ->
+ errorlabstrm "Prog_extract.pp_prog"
+ (str"The program " ++ pID id ++
+ str" must be realized first !")
+ | Some p ->
+ let bl,p = collect_lambda p in
+ let rn = rename_binders rn_empty bl in
+ let env = traverse_binders empty bl in
+ hov 0 (str"let " ++ pID id' ++ pr_binding rn bl ++ str" =" ++ fnl () ++
+ str" " ++ hov 2 (pp env rn false p))
+
+(* extraction des programmes impératifs/fonctionnels vers ocaml *)
+
+(* Il faut parfois importer des modules non ouverts, sinon
+ * Ocaml.OCaml_pp_file.pp echoue en disant "machin is not a defined
+ * informative object". Cela dit, ce n'est pas tres satisfaisant, vu que
+ * la constante existe quand meme: il vaudrait mieux contourner l'echec
+ * de ml_import.fwsp_of_id
+ *)
+
+let import sp = match repr_path sp with
+ | [m],_,_ ->
+ begin
+ try Library.import_export_module m true
+ with _ -> ()
+ end
+ | _ -> ()
+
+let pp_ocaml file prm =
+ has_array := false ++
+ (* on separe objects Coq et programmes *)
+ let cic,pgms =
+ List.fold_left
+ (fun (sp,ids) id ->
+ if is_global id then (sp,IdSet.add id ids) else (IdSet.add id sp,ids))
+ (IdSet.empty,IdSet.empty) prm.needed
+ in
+ (* on met les programmes dans l'ordre et pour chacun on recherche les
+ * objects Coq necessaires, que l'on rajoute a l'ensemble cic *)
+ let cic,_,pgms =
+ let o_pgms = fold_all (fun (id,_) l -> id::l) empty [] in
+ List.fold_left
+ (fun (cic,pgms,pl) id ->
+ if IdSet.mem id pgms then
+ let spl,pgms' =
+ try
+ (match find_pgm id with
+ | Some p -> collect empty p
+ | None ->
+ (try
+ let c = find_init id in
+ spset_of_cci empty c,IdSet.empty
+ with Not_found ->
+ SpSet.empty,IdSet.empty))
+ with Not_found -> SpSet.empty,IdSet.empty
+ in
+ let cic' =
+ SpSet.fold
+ (fun sp cic -> import sp ++ IdSet.add (basename sp) cic)
+ spl cic
+ in
+ (cic',IdSet.union pgms pgms',id::pl)
+ else
+ (cic,pgms,pl))
+ (cic,pgms,[]) o_pgms
+ in
+ let cic = IdSet.elements cic in
+ (* on pretty-print *)
+ let prm' = { needed = cic ++ expand = prm.expand ++
+ expansion = prm.expansion ++ exact = prm.exact }
+ in
+ let strm = (Ocaml.OCaml_pp_file.pp_recursive prm' ++
+ fnl () ++ fnl () ++
+ if !has_array then pp_conversions() else (mt ()) ++
+ prlist (fun p -> (pp_prog p ++ fnl () ++ str";;" ++ fnl () ++ fnl ()))
+ pgms
+)
+ in
+ (* puis on ecrit dans le fichier *)
+ let chan = open_trapping_failure open_out file ".ml" in
+ let ft = with_output_to chan in
+ begin
+ try pP_with ft strm ++ pp_flush_with ft ()
+ with e -> pp_flush_with ft () ++ close_out chan ++ raise e
+ end ++
+ close_out chan
+
+
+(* Initializations of mutable objects *)
+
+let initialize id com =
+ let loc = Ast.loc com in
+ let c = constr_of_com (Evd.mt_evd()) (initial_sign()) com in
+ let ty =
+ Reductionops.nf_betaiota (type_of (Evd.mt_evd()) (initial_sign()) c) in
+ try
+ let v = lookup_global id in
+ let ety = match v with
+ | Ref (TypePure c) -> c | Array (_,TypePure c) -> c
+ | _ -> raise Not_found
+ in
+ if conv (Evd.mt_evd()) ty ety then
+ initialize id c
+ else
+ errorlabstrm "Prog_extract.initialize"
+ (str"Not the expected type for the mutable " ++ pID id)
+ with Not_found ->
+ errorlabstrm "Prog_extract.initialize"
+ (pr_id id ++ str" is not a mutable")
+
+(* grammaire *)
+
+open Vernacinterp
+
+let _ = vinterp_add "IMPERATIVEEXTRACTION"
+ (function
+ | VARG_STRING file :: rem ->
+ let prm = parse_param rem in (fun () -> pp_ocaml file prm)
+ | _ -> assert false)
+
+let _ = vinterp_add "INITIALIZE"
+ (function
+ | [VARG_IDENTIFIER id; VARG_COMMAND com] ->
+ (fun () -> initialize id com)
+ | _ -> assert false)
diff --git a/contrib/correctness/pextract.mli b/contrib/correctness/pextract.mli
new file mode 100644
index 00000000..dc5b4124
--- /dev/null
+++ b/contrib/correctness/pextract.mli
@@ -0,0 +1,17 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pextract.mli,v 1.2.16.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+
+val pp_ocaml : string -> unit
+
+
diff --git a/contrib/correctness/pmisc.ml b/contrib/correctness/pmisc.ml
new file mode 100644
index 00000000..aed8c5cb
--- /dev/null
+++ b/contrib/correctness/pmisc.ml
@@ -0,0 +1,222 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmisc.ml,v 1.18.2.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Nameops
+open Term
+open Libnames
+open Topconstr
+
+(* debug *)
+
+let deb_mess s =
+ if !Options.debug then begin
+ msgnl s; pp_flush()
+ end
+
+let deb_print f x =
+ if !Options.debug then begin
+ msgnl (f x); pp_flush()
+ end
+
+let list_of_some = function
+ None -> []
+ | Some x -> [x]
+
+let difference l1 l2 =
+ let rec diff = function
+ [] -> []
+ | a::rem -> if List.mem a l2 then diff rem else a::(diff rem)
+ in
+ diff l1
+
+(* TODO: these functions should be moved in the code of Coq *)
+
+let reraise_with_loc loc f x =
+ try f x with Util.UserError (_,_) as e -> Stdpp.raise_with_loc loc e
+
+
+(* functions on names *)
+
+let at = if !Options.v7 then "@" else "'at'"
+
+let at_id id d = id_of_string ((string_of_id id) ^ at ^ d)
+
+let is_at id =
+ try
+ let _ = string_index_from (string_of_id id) 0 at in true
+ with Not_found ->
+ false
+
+let un_at id =
+ let s = string_of_id id in
+ try
+ let n = string_index_from s 0 at in
+ id_of_string (String.sub s 0 n),
+ String.sub s (n + String.length at)
+ (String.length s - n - String.length at)
+ with Not_found ->
+ invalid_arg "un_at"
+
+let renaming_of_ids avoid ids =
+ let rec rename avoid = function
+ [] -> [], avoid
+ | x::rem ->
+ let al,avoid = rename avoid rem in
+ let x' = next_ident_away x avoid in
+ (x,x')::al, x'::avoid
+ in
+ rename avoid ids
+
+let result_id = id_of_string "result"
+
+let adr_id id = id_of_string ("adr_" ^ (string_of_id id))
+
+(* hypotheses names *)
+
+let next s r = function
+ Anonymous -> incr r; id_of_string (s ^ string_of_int !r)
+ | Name id -> id
+
+let reset_names,pre_name,post_name,inv_name,
+ test_name,bool_name,var_name,phi_name,for_name,label_name =
+ let pre = ref 0 in
+ let post = ref 0 in
+ let inv = ref 0 in
+ let test = ref 0 in
+ let bool = ref 0 in
+ let var = ref 0 in
+ let phi = ref 0 in
+ let forr = ref 0 in
+ let label = ref 0 in
+ (fun () ->
+ pre := 0; post := 0; inv := 0; test := 0;
+ bool := 0; var := 0; phi := 0; label := 0),
+ (next "Pre" pre),
+ (next "Post" post),
+ (next "Inv" inv),
+ (next "Test" test),
+ (fun () -> next "Bool" bool Anonymous),
+ (next "Variant" var),
+ (fun () -> next "rphi" phi Anonymous),
+ (fun () -> next "for" forr Anonymous),
+ (fun () -> string_of_id (next "Label" label Anonymous))
+
+let default = id_of_string "x_"
+let id_of_name = function Name id -> id | Anonymous -> default
+
+
+(* functions on CIC terms *)
+
+let isevar = Evarutil.new_evar_in_sign (Global.env ())
+
+(* Substitutions of variables by others. *)
+let subst_in_constr alist =
+ let alist' = List.map (fun (id,id') -> (id, mkVar id')) alist in
+ replace_vars alist'
+
+(*
+let subst_in_ast alist ast =
+ let rec subst = function
+ Nvar(l,s) -> Nvar(l,try List.assoc s alist with Not_found -> s)
+ | Node(l,s,args) -> Node(l,s,List.map subst args)
+ | Slam(l,so,a) -> Slam(l,so,subst a) (* TODO:enlever so de alist ? *)
+ | x -> x
+ in
+ subst ast
+*)
+(*
+let subst_ast_in_ast alist ast =
+ let rec subst = function
+ Nvar(l,s) as x -> (try List.assoc s alist with Not_found -> x)
+ | Node(l,s,args) -> Node(l,s,List.map subst args)
+ | Slam(l,so,a) -> Slam(l,so,subst a) (* TODO:enlever so de alist ? *)
+ | x -> x
+ in
+ subst ast
+*)
+
+let rec subst_in_ast alist = function
+ | CRef (Ident (loc,id)) ->
+ CRef (Ident (loc,(try List.assoc id alist with Not_found -> id)))
+ | x -> map_constr_expr_with_binders subst_in_ast List.remove_assoc alist x
+
+let rec subst_ast_in_ast alist = function
+ | CRef (Ident (_,id)) as x -> (try List.assoc id alist with Not_found -> x)
+ | x ->
+ map_constr_expr_with_binders subst_ast_in_ast List.remove_assoc alist x
+
+(* subst. of variables by constr *)
+let real_subst_in_constr = replace_vars
+
+(* Coq constants *)
+
+let coq_constant d s =
+ Libnames.encode_kn
+ (make_dirpath (List.rev (List.map id_of_string ("Coq"::d))))
+ (id_of_string s)
+
+let bool_sp = coq_constant ["Init"; "Datatypes"] "bool"
+let coq_true = mkConstruct ((bool_sp,0),1)
+let coq_false = mkConstruct ((bool_sp,0),2)
+
+let constant s =
+ let id = Constrextern.id_of_v7_string s in
+ Constrintern.global_reference id
+
+let connective_and = id_of_string "prog_bool_and"
+let connective_or = id_of_string "prog_bool_or"
+let connective_not = id_of_string "prog_bool_not"
+
+let is_connective id =
+ id = connective_and or id = connective_or or id = connective_not
+
+(* [conj i s] constructs the conjunction of two constr *)
+
+let conj i s = Term.applist (constant "and", [i; s])
+
+(* [n_mkNamedProd v [xn,tn;...;x1,t1]] constructs the type
+ [(x1:t1)...(xn:tn)v] *)
+
+let rec n_mkNamedProd v = function
+ | [] -> v
+ | (id,ty) :: rem -> n_mkNamedProd (Term.mkNamedProd id ty v) rem
+
+(* [n_lambda v [xn,tn;...;x1,t1]] constructs the type [x1:t1]...[xn:tn]v *)
+
+let rec n_lambda v = function
+ | [] -> v
+ | (id,ty) :: rem -> n_lambda (Term.mkNamedLambda id ty v) rem
+
+(* [abstract env idl c] constructs [x1]...[xn]c where idl = [x1;...;xn] *)
+
+let abstract ids c = n_lambda c (List.rev ids)
+
+(* substitutivity (of kernel names, for modules management) *)
+
+open Ptype
+
+let rec type_v_knsubst s = function
+ | Ref v -> Ref (type_v_knsubst s v)
+ | Array (c, v) -> Array (subst_mps s c, type_v_knsubst s v)
+ | Arrow (bl, c) -> Arrow (List.map (binder_knsubst s) bl, type_c_knsubst s c)
+ | TypePure c -> TypePure (subst_mps s c)
+
+and type_c_knsubst s ((id,v),e,pl,q) =
+ ((id, type_v_knsubst s v), e,
+ List.map (fun p -> { p with p_value = subst_mps s p.p_value }) pl,
+ option_app (fun q -> { q with a_value = subst_mps s q.a_value }) q)
+
+and binder_knsubst s (id,b) =
+ (id, match b with BindType v -> BindType (type_v_knsubst s v) | _ -> b)
diff --git a/contrib/correctness/pmisc.mli b/contrib/correctness/pmisc.mli
new file mode 100644
index 00000000..ec7521cc
--- /dev/null
+++ b/contrib/correctness/pmisc.mli
@@ -0,0 +1,81 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmisc.mli,v 1.9.6.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+open Term
+open Ptype
+open Topconstr
+
+(* Some misc. functions *)
+
+val reraise_with_loc : Util.loc -> ('a -> 'b) -> 'a -> 'b
+
+val list_of_some : 'a option -> 'a list
+val difference : 'a list -> 'a list -> 'a list
+
+val at_id : identifier -> string -> identifier
+val un_at : identifier -> identifier * string
+val is_at : identifier -> bool
+
+val result_id : identifier
+val adr_id : identifier -> identifier
+
+val renaming_of_ids : identifier list -> identifier list
+ -> (identifier * identifier) list * identifier list
+
+val reset_names : unit -> unit
+val pre_name : name -> identifier
+val post_name : name -> identifier
+val inv_name : name -> identifier
+val test_name : name -> identifier
+val bool_name : unit -> identifier
+val var_name : name -> identifier
+val phi_name : unit -> identifier
+val for_name : unit -> identifier
+val label_name : unit -> string
+
+val id_of_name : name -> identifier
+
+(* CIC terms *)
+
+val isevar : constr
+
+val subst_in_constr : (identifier * identifier) list -> constr -> constr
+val subst_in_ast : (identifier * identifier) list -> constr_expr -> constr_expr
+val subst_ast_in_ast :
+ (identifier * constr_expr) list -> constr_expr -> constr_expr
+val real_subst_in_constr : (identifier * constr) list -> constr -> constr
+
+val constant : string -> constr
+val coq_constant : string list -> string -> kernel_name
+val conj : constr -> constr -> constr
+
+val coq_true : constr
+val coq_false : constr
+
+val connective_and : identifier
+val connective_or : identifier
+val connective_not : identifier
+val is_connective : identifier -> bool
+
+val n_mkNamedProd : constr -> (identifier * constr) list -> constr
+val n_lambda : constr -> (identifier * constr) list -> constr
+val abstract : (identifier * constr) list -> constr -> constr
+
+val type_v_knsubst : substitution -> type_v -> type_v
+val type_c_knsubst : substitution -> type_c -> type_c
+
+(* for debugging purposes *)
+
+val deb_mess : Pp.std_ppcmds -> unit
+val deb_print : ('a -> Pp.std_ppcmds) -> 'a -> unit
+
diff --git a/contrib/correctness/pmlize.ml b/contrib/correctness/pmlize.ml
new file mode 100644
index 00000000..f899366d
--- /dev/null
+++ b/contrib/correctness/pmlize.ml
@@ -0,0 +1,320 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmlize.ml,v 1.7.2.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Names
+open Term
+open Termast
+open Pattern
+open Matching
+
+open Pmisc
+open Ptype
+open Past
+open Putil
+open Prename
+open Penv
+open Peffect
+open Ptyping
+open Pmonad
+
+
+let has_proof_part ren env c =
+ let sign = Pcicenv.trad_sign_of ren env in
+ let ty = Typing.type_of (Global.env_of_context sign) Evd.empty c in
+ Hipattern.is_matching_sigma (Reductionops.nf_betaiota ty)
+
+(* main part: translation of imperative programs into functional ones.
+ *
+ * [env] is the environment
+ * [ren] is the current renamings of variables
+ * [t] is the imperative program to translate, annotated with type+effects
+ *
+ * we return the translated program in type cc_term
+ *)
+
+let rec trad ren t =
+ let env = t.info.env in
+ trad_desc ren env t.info.kappa t.desc
+
+and trad_desc ren env ct d =
+ let (_,tt),eft,pt,qt = ct in
+ match d with
+
+ | Expression c ->
+ let ids = get_reads eft in
+ let al = current_vars ren ids in
+ let c' = subst_in_constr al c in
+ if has_proof_part ren env c' then
+ CC_expr c'
+ else
+ let ty = trad_ml_type_v ren env tt in
+ make_tuple [ CC_expr c',ty ] qt ren env (current_date ren)
+
+ | Variable id ->
+ if is_mutable_in_env env id then
+ invalid_arg "Mlise.trad_desc"
+ else if is_local env id then
+ CC_var id
+ else
+ CC_expr (constant (string_of_id id))
+
+ | Acc _ ->
+ failwith "Mlise.trad: pure terms are supposed to be expressions"
+
+ | TabAcc (check, x, e1) ->
+ let _,ty_elem,_ = array_info ren env x in
+ let te1 = trad ren e1 in
+ let (_,ef1,p1,q1) = e1.info.kappa in
+ let w = get_writes ef1 in
+ let ren' = next ren w in
+ let id = id_of_string "index" in
+ let access =
+ make_raw_access ren' env (x,current_var ren' x) (mkVar id)
+ in
+ let t,ty = result_tuple ren' (current_date ren) env
+ (CC_expr access, ty_elem) (eft,qt) in
+ let t =
+ if check then
+ let h = make_pre_access ren env x (mkVar id) in
+ let_in_pre ty (anonymous_pre true h) t
+ else
+ t
+ in
+ make_let_in ren env te1 p1
+ (current_vars ren' w,q1) (id,constant "Z") (t,ty)
+
+ | Aff (x, e1) ->
+ let tx = trad_type_in_env ren env x in
+ let te1 = trad ren e1 in
+ let (_,ef1,p1,q1) = e1.info.kappa in
+ let w1 = get_writes ef1 in
+ let ren' = next ren (x::w1) in
+ let t_ty = result_tuple ren' (current_date ren) env
+ (CC_expr (constant "tt"), constant "unit") (eft,qt)
+ in
+ make_let_in ren env te1 p1
+ (current_vars ren' w1,q1) (current_var ren' x,tx) t_ty
+
+ | TabAff (check, x, e1, e2) ->
+ let _,ty_elem,ty_array = array_info ren env x in
+ let te1 = trad ren e1 in
+ let (_,ef1,p1,q1) = e1.info.kappa in
+ let w1 = get_writes ef1 in
+ let ren' = next ren w1 in
+ let te2 = trad ren' e2 in
+ let (_,ef2,p2,q2) = e2.info.kappa in
+ let w2 = get_writes ef2 in
+ let ren'' = next ren' w2 in
+ let id1 = id_of_string "index" in
+ let id2 = id_of_string "v" in
+ let ren''' = next ren'' [x] in
+ let t,ty = result_tuple ren''' (current_date ren) env
+ (CC_expr (constant "tt"), constant "unit") (eft,qt) in
+ let store = make_raw_store ren'' env (x,current_var ren'' x) (mkVar id1)
+ (mkVar id2) in
+ let t = make_let_in ren'' env (CC_expr store) [] ([],None)
+ (current_var ren''' x,ty_array) (t,ty) in
+ let t = make_let_in ren' env te2 p2
+ (current_vars ren'' w2,q2) (id2,ty_elem) (t,ty) in
+ let t =
+ if check then
+ let h = make_pre_access ren' env x (mkVar id1) in
+ let_in_pre ty (anonymous_pre true h) t
+ else
+ t
+ in
+ make_let_in ren env te1 p1
+ (current_vars ren' w1,q1) (id1,constant "Z") (t,ty)
+
+ | Seq bl ->
+ let before = current_date ren in
+ let finish ren = function
+ Some (id,ty) ->
+ result_tuple ren before env (CC_var id, ty) (eft,qt)
+ | None ->
+ failwith "a block should contain at least one statement"
+ in
+ let bl = trad_block ren env bl in
+ make_block ren env finish bl
+
+ | If (b, e1, e2) ->
+ let tb = trad ren b in
+ let _,efb,_,_ = b.info.kappa in
+ let ren' = next ren (get_writes efb) in
+ let te1 = trad ren' e1 in
+ let te2 = trad ren' e2 in
+ make_if ren env (tb,b.info.kappa) ren' (te1,e1.info.kappa)
+ (te2,e2.info.kappa) ct
+
+ (* Translation of the while. *)
+
+ | While (b, inv, var, bl) ->
+ let ren' = next ren (get_writes eft) in
+ let tb = trad ren' b in
+ let tbl = trad_block ren' env bl in
+ let var' = typed_var ren env var in
+ make_while ren env var' (tb,b.info.kappa) tbl (inv,ct)
+
+ | Lam (bl, e) ->
+ let bl' = trad_binders ren env bl in
+ let env' = traverse_binders env bl in
+ let ren' = initial_renaming env' in
+ let te = trans ren' e in
+ CC_lam (bl', te)
+
+ | SApp ([Variable id; Expression q1; Expression q2], [e1; e2])
+ when id = connective_and or id = connective_or ->
+ let c = constant (string_of_id id) in
+ let te1 = trad ren e1
+ and te2 = trad ren e2 in
+ let q1' = apply_post ren env (current_date ren) (anonymous q1)
+ and q2' = apply_post ren env (current_date ren) (anonymous q2) in
+ CC_app (CC_expr c, [CC_expr q1'.a_value; CC_expr q2'.a_value; te1; te2])
+
+ | SApp ([Variable id; Expression q], [e]) when id = connective_not ->
+ let c = constant (string_of_id id) in
+ let te = trad ren e in
+ let q' = apply_post ren env (current_date ren) (anonymous q) in
+ CC_app (CC_expr c, [CC_expr q'.a_value; te])
+
+ | SApp _ ->
+ invalid_arg "mlise.trad (SApp)"
+
+ | Apply (f, args) ->
+ let trad_arg (ren,args) = function
+ | Term a ->
+ let ((_,tya),efa,_,_) as ca = a.info.kappa in
+ let ta = trad ren a in
+ let w = get_writes efa in
+ let ren' = next ren w in
+ ren', ta::args
+ | Refarg _ ->
+ ren, args
+ | Type v ->
+ let c = trad_ml_type_v ren env v in
+ ren, (CC_expr c)::args
+ in
+ let ren',targs = List.fold_left trad_arg (ren,[]) args in
+ let tf = trad ren' f in
+ let cf = f.info.kappa in
+ let c,(s,_,_),capp = effect_app ren env f args in
+ let tc_args =
+ List.combine
+ (List.rev targs)
+ (Util.map_succeed
+ (function
+ | Term x -> x.info.kappa
+ | Refarg _ -> failwith "caught"
+ | Type _ ->
+ (result_id,TypePure mkSet),Peffect.bottom,[],None)
+ args)
+ in
+ make_app env ren tc_args ren' (tf,cf) (c,s,capp) ct
+
+ | LetRef (x, e1, e2) ->
+ let (_,v1),ef1,p1,q1 = e1.info.kappa in
+ let te1 = trad ren e1 in
+ let tv1 = trad_ml_type_v ren env v1 in
+ let env' = add (x,Ref v1) env in
+ let ren' = next ren [x] in
+ let (_,v2),ef2,p2,q2 = e2.info.kappa in
+ let tv2 = trad_ml_type_v ren' env' v2 in
+ let te2 = trad ren' e2 in
+ let ren'' = next ren' (get_writes ef2) in
+ let t,ty = result_tuple ren'' (current_date ren) env
+ (CC_var result_id, tv2) (eft,qt) in
+ let t = make_let_in ren' env' te2 p2
+ (current_vars ren'' (get_writes ef2),q2)
+ (result_id,tv2) (t,ty) in
+ let t = make_let_in ren env te1 p1
+ (current_vars ren' (get_writes ef1),q1) (x,tv1) (t,ty)
+ in
+ t
+
+ | Let (x, e1, e2) ->
+ let (_,v1),ef1,p1,q1 = e1.info.kappa in
+ let te1 = trad ren e1 in
+ let tv1 = trad_ml_type_v ren env v1 in
+ let env' = add (x,v1) env in
+ let ren' = next ren (get_writes ef1) in
+ let (_,v2),ef2,p2,q2 = e2.info.kappa in
+ let tv2 = trad_ml_type_v ren' env' v2 in
+ let te2 = trad ren' e2 in
+ let ren'' = next ren' (get_writes ef2) in
+ let t,ty = result_tuple ren'' (current_date ren) env
+ (CC_var result_id, tv2) (eft,qt) in
+ let t = make_let_in ren' env' te2 p2
+ (current_vars ren'' (get_writes ef2),q2)
+ (result_id,tv2) (t,ty) in
+ let t = make_let_in ren env te1 p1
+ (current_vars ren' (get_writes ef1),q1) (x,tv1) (t,ty)
+ in
+ t
+
+ | LetRec (f,bl,v,var,e) ->
+ let (_,ef,_,_) as c =
+ match tt with Arrow(_,c) -> c | _ -> assert false in
+ let bl' = trad_binders ren env bl in
+ let env' = traverse_binders env bl in
+ let ren' = initial_renaming env' in
+ let (phi0,var') = find_recursion f e.info.env in
+ let te = trad ren' e in
+ let t = make_letrec ren' env' (phi0,var') f bl' (te,e.info.kappa) c in
+ CC_lam (bl', t)
+
+ | PPoint (s,d) ->
+ let ren' = push_date ren s in
+ trad_desc ren' env ct d
+
+ | Debug _ -> failwith "Mlise.trad: Debug: not implemented"
+
+
+and trad_binders ren env = function
+ | [] ->
+ []
+ | (_,BindType (Ref _ | Array _))::bl ->
+ trad_binders ren env bl
+ | (id,BindType v)::bl ->
+ let tt = trad_ml_type_v ren env v in
+ (id, CC_typed_binder tt) :: (trad_binders ren env bl)
+ | (id,BindSet)::bl ->
+ (id, CC_typed_binder mkSet) :: (trad_binders ren env bl)
+ | (_,Untyped)::_ -> invalid_arg "trad_binders"
+
+
+and trad_block ren env = function
+ | [] ->
+ []
+ | (Assert c)::block ->
+ (Assert c)::(trad_block ren env block)
+ | (Label s)::block ->
+ let ren' = push_date ren s in
+ (Label s)::(trad_block ren' env block)
+ | (Statement e)::block ->
+ let te = trad ren e in
+ let _,efe,_,_ = e.info.kappa in
+ let w = get_writes efe in
+ let ren' = next ren w in
+ (Statement (te,e.info.kappa))::(trad_block ren' env block)
+
+
+and trans ren e =
+ let env = e.info.env in
+ let _,ef,p,_ = e.info.kappa in
+ let ty = trad_ml_type_c ren env e.info.kappa in
+ let ids = get_reads ef in
+ let al = current_vars ren ids in
+ let c = trad ren e in
+ let c = abs_pre ren env (c,ty) p in
+ let bl = binding_of_alist ren env al in
+ make_abs (List.rev bl) c
+
diff --git a/contrib/correctness/pmlize.mli b/contrib/correctness/pmlize.mli
new file mode 100644
index 00000000..95f74ef9
--- /dev/null
+++ b/contrib/correctness/pmlize.mli
@@ -0,0 +1,20 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmlize.mli,v 1.2.16.1 2004/07/16 19:30:01 herbelin Exp $ *)
+
+open Past
+open Penv
+open Names
+
+(* translation of imperative programs into intermediate functional programs *)
+
+val trans : Prename.t -> typed_program -> cc_term
+
diff --git a/contrib/correctness/pmonad.ml b/contrib/correctness/pmonad.ml
new file mode 100644
index 00000000..b8b39353
--- /dev/null
+++ b/contrib/correctness/pmonad.ml
@@ -0,0 +1,665 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmonad.ml,v 1.6.16.1 2004/07/16 19:30:02 herbelin Exp $ *)
+
+open Util
+open Names
+open Term
+open Termast
+
+open Pmisc
+open Putil
+open Ptype
+open Past
+open Prename
+open Penv
+open Pcic
+open Peffect
+
+
+(* [product ren [y1,z1;...;yk,zk] q] constructs
+ * the (possibly dependent) tuple type
+ *
+ * z1 x ... x zk if no post-condition
+ * or \exists. y1:z1. ... yk:zk. (Q x1 ... xn) otherwise
+ *
+ * where the xi are given by the renaming [ren].
+ *)
+
+let product_name = function
+ | 2 -> "prod"
+ | n -> check_product_n n; Printf.sprintf "tuple_%d" n
+
+let dep_product_name = function
+ | 1 -> "sig"
+ | n -> check_dep_product_n n; Printf.sprintf "sig_%d" n
+
+let product ren env before lo = function
+ | None -> (* non dependent case *)
+ begin match lo with
+ | [_,v] -> v
+ | _ ->
+ let s = product_name (List.length lo) in
+ Term.applist (constant s, List.map snd lo)
+ end
+ | Some q -> (* dependent case *)
+ let s = dep_product_name (List.length lo) in
+ let a' = apply_post ren env before q in
+ Term.applist (constant s, (List.map snd lo) @ [a'.a_value])
+
+(* [arrow ren v pl] abstracts the term v over the pre-condition if any
+ * i.e. computes
+ *
+ * (P1 x1 ... xn) -> ... -> (Pk x1 ... xn) -> v
+ *
+ * where the xi are given by the renaming [ren].
+ *)
+
+let arrow ren env v pl =
+ List.fold_left
+ (fun t p ->
+ if p.p_assert then t else Term.mkArrow (apply_pre ren env p).p_value t)
+ v pl
+
+(* [abstract_post ren env (e,q) (res,v)] abstract a post-condition q
+ * over the write-variables of e *)
+
+let rec abstract_post ren env (e,q) =
+ let after_id id = id_of_string ((string_of_id id) ^ "'") in
+ let (_,go) = Peffect.get_repr e in
+ let al = List.map (fun id -> (id,after_id id)) go in
+ let q = option_app (named_app (subst_in_constr al)) q in
+ let tgo = List.map (fun (id,aid) -> (aid, trad_type_in_env ren env id)) al in
+ option_app (named_app (abstract tgo)) q
+
+(* Translation of effects types in cic types.
+ *
+ * [trad_ml_type_v] and [trad_ml_type_c] translate types with effects
+ * into cic types.
+ *)
+
+and prod ren env g =
+ List.map
+ (fun id -> (current_var ren id, trad_type_in_env ren env id))
+ g
+
+and input ren env e =
+ let i,_ = Peffect.get_repr e in
+ prod ren env i
+
+and output ren env ((id,v),e) =
+ let tv = trad_ml_type_v ren env v in
+ let _,o = Peffect.get_repr e in
+ (prod ren env o) @ [id,tv]
+
+and input_output ren env c =
+ let ((res,v),e,_,_) = c in
+ input ren env e, output ren env ((res,v),e)
+
+(* The function t -> \barre{t} on V and C. *)
+
+and trad_ml_type_c ren env c =
+ let ((res,v),e,p,q) = c in
+ let q = abstract_post ren env (e,q) in
+ let lo = output ren env ((res,v),e) in
+ let ty = product ren env (current_date ren) lo q in
+ let ty = arrow ren env ty p in
+ let li = input ren env e in
+ n_mkNamedProd ty li
+
+and trad_ml_type_v ren env = function
+
+ | Ref _ | Array _ -> invalid_arg "Monad.trad_ml_type_v"
+
+ | Arrow (bl, c) ->
+ let bl',ren',env' =
+ List.fold_left
+ (fun (bl,ren,env) b -> match b with
+ | (id,BindType ((Ref _ | Array _) as v)) ->
+ let env' = add (id,v) env in
+ let ren' = initial_renaming env' in
+ (bl,ren',env')
+ | (id,BindType v) ->
+ let tt = trad_ml_type_v ren env v in
+ let env' = add (id,v) env in
+ let ren' = initial_renaming env' in
+ (id,tt)::bl,ren',env'
+ | (id, BindSet) ->
+ (id,mkSet) :: bl,ren,env
+ | _ -> failwith "Monad: trad_ml_type_v: not yet implemented"
+ )
+ ([],ren,env) bl
+ in
+ n_mkNamedProd (trad_ml_type_c ren' env' c) bl'
+
+ | TypePure c ->
+ (apply_pre ren env (anonymous_pre false c)).p_value
+
+and trad_imp_type ren env = function
+ | Ref v -> trad_ml_type_v ren env v
+ | Array (c,v) -> Term.applist (constant "array",
+ [c; trad_ml_type_v ren env v])
+ | _ -> invalid_arg "Monad.trad_imp_type"
+
+and trad_type_in_env ren env id =
+ let v = type_in_env env id in trad_imp_type ren env v
+
+
+
+(* bindings *)
+
+let binding_of_alist ren env al =
+ List.map
+ (fun (id,id') -> (id', CC_typed_binder (trad_type_in_env ren env id)))
+ al
+
+
+(* [make_abs bl t p] abstracts t w.r.t binding list bl., that is
+ * [x1:t1]...[xn:tn]t. Returns t if the binding is empty. *)
+
+let make_abs bl t = match bl with
+ | [] -> t
+ | _ -> CC_lam (bl, t)
+
+
+(* [result_tuple ren before env (res,v) (ef,q)] constructs the tuple
+ *
+ * (y1,...,yn,res,?::(q/ren y1 ... yn res))
+ *
+ * where the yi are the values of the output of ef.
+ * if there is no yi and no post-condition, it is simplified in res itself.
+ *)
+
+let simple_constr_of_prog = function
+ | CC_expr c -> c
+ | CC_var id -> mkVar id
+ | _ -> assert false
+
+let make_tuple l q ren env before = match l with
+ | [e,_] when q = None ->
+ e
+ | _ ->
+ let tl = List.map snd l in
+ let dep,h,th = match q with
+ | None -> false,[],[]
+ | Some c ->
+ let args = List.map (fun (e,_) -> simple_constr_of_prog e) l in
+ let c = apply_post ren env before c in
+ true,
+ [ CC_hole (Term.applist (c.a_value, args)) ], (* hole *)
+ [ c.a_value ] (* type of the hole *)
+ in
+ CC_tuple (dep, tl @ th, (List.map fst l) @ h)
+
+let result_tuple ren before env (res,v) (ef,q) =
+ let ids = get_writes ef in
+ let lo =
+ (List.map (fun id ->
+ let id' = current_var ren id in
+ CC_var id', trad_type_in_env ren env id) ids)
+ @ [res,v]
+ in
+ let q = abstract_post ren env (ef,q) in
+ make_tuple lo q ren env before,
+ product ren env before lo q
+
+
+(* [make_let_in ren env fe p (vo,q) (res,v) t] constructs the term
+
+ [ let h1 = ?:P1 in ... let hn = ?:Pm in ]
+ let y1,y2,...,yn, res [,q] = fe in
+ t
+
+ vo=[_,y1;...;_,ym] are list of renamings.
+ v is the type of res
+ *)
+
+let let_in_pre ty p t =
+ let h = p.p_value in
+ CC_letin (false, ty, [pre_name p.p_name,CC_typed_binder h], CC_hole h, t)
+
+let multiple_let_in_pre ty hl t =
+ List.fold_left (fun t h -> let_in_pre ty h t) t hl
+
+let make_let_in ren env fe p (vo,q) (res,tyres) (t,ty) =
+ let b = [res, CC_typed_binder tyres] in
+ let b',dep = match q with
+ | None -> [],false
+ | Some q -> [post_name q.a_name, CC_untyped_binder],true
+ in
+ let bl = (binding_of_alist ren env vo) @ b @ b' in
+ let tyapp =
+ let n = succ (List.length vo) in
+ let name = match q with None -> product_name n | _ -> dep_product_name n in
+ constant name
+ in
+ let t = CC_letin (dep, ty, bl, fe, t) in
+ multiple_let_in_pre ty (List.map (apply_pre ren env) p) t
+
+
+(* [abs_pre ren env (t,ty) pl] abstracts a term t with respect to the
+ * list of pre-conditions [pl]. Some of them are real pre-conditions
+ * and others are assertions, according to the boolean field p_assert,
+ * so we construct the term
+ * [h1:P1]...[hn:Pn]let h'1 = ?:P'1 in ... let H'm = ?:P'm in t
+ *)
+
+let abs_pre ren env (t,ty) pl =
+ List.fold_left
+ (fun t p ->
+ if p.p_assert then
+ let_in_pre ty (apply_pre ren env p) t
+ else
+ let h = pre_name p.p_name in
+ CC_lam ([h,CC_typed_binder (apply_pre ren env p).p_value],t))
+ t pl
+
+
+(* [make_block ren env finish bl] builds the translation of a block
+ * finish is the function that is applied to the result at the end of the
+ * block. *)
+
+let make_block ren env finish bl =
+ let rec rec_block ren result = function
+ | [] ->
+ finish ren result
+ | (Assert c) :: block ->
+ let t,ty = rec_block ren result block in
+ let c = apply_assert ren env c in
+ let p = { p_assert = true; p_name = c.a_name; p_value = c.a_value } in
+ let_in_pre ty p t, ty
+ | (Label s) :: block ->
+ let ren' = push_date ren s in
+ rec_block ren' result block
+ | (Statement (te,info)) :: block ->
+ let (_,tye),efe,pe,qe = info in
+ let w = get_writes efe in
+ let ren' = next ren w in
+ let id = result_id in
+ let tye = trad_ml_type_v ren env tye in
+ let t = rec_block ren' (Some (id,tye)) block in
+ make_let_in ren env te pe (current_vars ren' w,qe) (id,tye) t,
+ snd t
+ in
+ let t,_ = rec_block ren None bl in
+ t
+
+
+(* [make_app env ren args ren' (tf,cf) (cb,s,capp) c]
+ * constructs the application of [tf] to [args].
+ * capp is the effect of application, after substitution (s) and cb before
+ *)
+
+let eq ty e1 e2 =
+ Term.applist (constant "eq", [ty; e1; e2])
+
+let lt r e1 e2 =
+ Term.applist (r, [e1; e2])
+
+let is_recursive env = function
+ | CC_var x ->
+ (try let _ = find_recursion x env in true with Not_found -> false)
+ | _ -> false
+
+let if_recursion env f = function
+ | CC_var x ->
+ (try let v = find_recursion x env in (f v x) with Not_found -> [])
+ | _ -> []
+
+let dec_phi ren env s svi =
+ if_recursion env
+ (fun (phi0,(cphi,r,_)) f ->
+ let phi = subst_in_constr svi (subst_in_constr s cphi) in
+ let phi = (apply_pre ren env (anonymous_pre true phi)).p_value in
+ [CC_expr phi; CC_hole (lt r phi (mkVar phi0))])
+
+let eq_phi ren env s svi =
+ if_recursion env
+ (fun (phi0,(cphi,_,a)) f ->
+ let phi = subst_in_constr svi (subst_in_constr s cphi) in
+ let phi = (apply_pre ren env (anonymous_pre true phi)).p_value in
+ [CC_hole (eq a phi phi)])
+
+let is_ref_binder = function
+ | (_,BindType (Ref _ | Array _)) -> true
+ | _ -> false
+
+let make_app env ren args ren' (tf,cf) ((bl,cb),s,capp) c =
+ let ((_,tvf),ef,pf,qf) = cf in
+ let (_,eapp,papp,qapp) = capp in
+ let ((_,v),e,p,q) = c in
+ let bl = List.filter (fun b -> not (is_ref_binder b)) bl in
+ let recur = is_recursive env tf in
+ let before = current_date ren in
+ let ren'' = next ren' (get_writes ef) in
+ let ren''' = next ren'' (get_writes eapp) in
+ let res = result_id in
+ let vi,svi =
+ let ids = List.map fst bl in
+ let s = fresh (avoid ren ids) ids in
+ List.map snd s, s
+ in
+ let tyres = subst_in_constr svi (trad_ml_type_v ren env v) in
+ let t,ty = result_tuple ren''' before env (CC_var res, tyres) (e,q) in
+ let res_f = id_of_string "vf" in
+ let inf,outf =
+ let i,o = let _,e,_,_ = cb in get_reads e, get_writes e in
+ let apply_s = List.map (fun id -> try List.assoc id s with _ -> id) in
+ apply_s i, apply_s o
+ in
+ let fe =
+ let xi = List.rev (List.map snd (current_vars ren'' inf)) in
+ let holes = List.map (fun x -> (apply_pre ren'' env x).p_value)
+ (List.map (pre_app (subst_in_constr svi)) papp) in
+ CC_app ((if recur then tf else CC_var res_f),
+ (dec_phi ren'' env s svi tf)
+ @(List.map (fun id -> CC_var id) (vi @ xi))
+ @(eq_phi ren'' env s svi tf)
+ @(List.map (fun c -> CC_hole c) holes))
+ in
+ let qapp' = option_app (named_app (subst_in_constr svi)) qapp in
+ let t =
+ make_let_in ren'' env fe [] (current_vars ren''' outf,qapp')
+ (res,tyres) (t,ty)
+ in
+ let t =
+ if recur then
+ t
+ else
+ make_let_in ren' env tf pf
+ (current_vars ren'' (get_writes ef),qf)
+ (res_f,trad_ml_type_v ren env tvf) (t,ty)
+ in
+ let rec eval_args ren = function
+ | [] -> t
+ | (vx,(ta,((_,tva),ea,pa,qa)))::args ->
+ let w = get_writes ea in
+ let ren' = next ren w in
+ let t' = eval_args ren' args in
+ make_let_in ren env ta pa (current_vars ren' (get_writes ea),qa)
+ (vx,trad_ml_type_v ren env tva) (t',ty)
+ in
+ eval_args ren (List.combine vi args)
+
+
+(* [make_if ren env (tb,cb) ren' (t1,c1) (t2,c2)]
+ * constructs the term corresponding to a if expression, i.e
+ *
+ * [p] let o1, b [,q1] = m1 [?::p1] in
+ * Cases b of
+ * R => let o2, v2 [,q2] = t1 [?::p2] in
+ * (proj (o1,o2)), v2 [,?::q]
+ * | S => let o2, v2 [,q2] = t2 [?::p2] in
+ * (proj (o1,o2)), v2 [,?::q]
+ *)
+
+let make_if_case ren env ty (b,qb) (br1,br2) =
+ let id_b,ty',ty1,ty2 = match qb with
+ | Some q ->
+ let q = apply_post ren env (current_date ren) q in
+ let (name,t1,t2) = Term.destLambda q.a_value in
+ q.a_name,
+ Term.mkLambda (name, t1, mkArrow t2 ty),
+ Term.mkApp (q.a_value, [| coq_true |]),
+ Term.mkApp (q.a_value, [| coq_false |])
+ | None -> assert false
+ in
+ let n = test_name Anonymous in
+ CC_app (CC_case (ty', b, [CC_lam ([n,CC_typed_binder ty1], br1);
+ CC_lam ([n,CC_typed_binder ty2], br2)]),
+ [CC_var (post_name id_b)])
+
+let make_if ren env (tb,cb) ren' (t1,c1) (t2,c2) c =
+ let ((_,tvb),eb,pb,qb) = cb in
+ let ((_,tv1),e1,p1,q1) = c1 in
+ let ((_,tv2),e2,p2,q2) = c2 in
+ let ((_,t),e,p,q) = c in
+
+ let wb = get_writes eb in
+ let resb = id_of_string "resultb" in
+ let res = result_id in
+ let tyb = trad_ml_type_v ren' env tvb in
+ let tt = trad_ml_type_v ren env t in
+
+ (* une branche de if *)
+ let branch (tv_br,e_br,p_br,q_br) f_br =
+ let w_br = get_writes e_br in
+ let ren'' = next ren' w_br in
+ let t,ty = result_tuple ren'' (current_date ren') env
+ (CC_var res,tt) (e,q) in
+ make_let_in ren' env f_br p_br (current_vars ren'' w_br,q_br)
+ (res,tt) (t,ty),
+ ty
+ in
+ let t1,ty1 = branch c1 t1 in
+ let t2,ty2 = branch c2 t2 in
+ let ty = ty1 in
+ let qb = force_bool_name qb in
+ let t = make_if_case ren env ty (CC_var resb,qb) (t1,t2) in
+ make_let_in ren env tb pb (current_vars ren' wb,qb) (resb,tyb) (t,ty)
+
+
+(* [make_while ren env (cphi,r,a) (tb,cb) (te,ce) c]
+ * constructs the term corresponding to the while, i.e.
+ *
+ * [h:(I x)](well_founded_induction
+ * A R ?::(well_founded A R)
+ * [Phi:A] (x) Phi=phi(x)->(I x)-> \exists x'.res.(I x')/\(S x')
+ * [Phi_0:A][w:(Phi:A)(Phi<Phi_0)-> ...]
+ * [x][eq:Phi_0=phi(x)][h:(I x)]
+ * Cases (b x) of
+ * (left HH) => (x,?::(IS x))
+ * | (right HH) => let x1,_,_ = (e x ?) in
+ * (w phi(x1) ? x1 ? ?)
+ * phi(x) x ? ?)
+ *)
+
+let id_phi = id_of_string "phi"
+let id_phi0 = id_of_string "phi0"
+
+let make_body_while ren env phi_of a r id_phi0 id_w (tb,cb) tbl (i,c) =
+ let ((_,tvb),eb,pb,qb) = cb in
+ let (_,ef,_,is) = c in
+
+ let ren' = next ren (get_writes ef) in
+ let before = current_date ren in
+
+ let ty =
+ let is = abstract_post ren' env (ef,is) in
+ let _,lo = input_output ren env c in
+ product ren env before lo is
+ in
+ let resb = id_of_string "resultb" in
+ let tyb = trad_ml_type_v ren' env tvb in
+ let wb = get_writes eb in
+
+ (* premičre branche: le test est vrai => e;w *)
+ let t1 =
+ make_block ren' env
+ (fun ren'' result -> match result with
+ | Some (id,_) ->
+ let v = List.rev (current_vars ren'' (get_writes ef)) in
+ CC_app (CC_var id_w,
+ [CC_expr (phi_of ren'');
+ CC_hole (lt r (phi_of ren'') (mkVar id_phi0))]
+ @(List.map (fun (_,id) -> CC_var id) v)
+ @(CC_hole (eq a (phi_of ren'') (phi_of ren'')))
+ ::(match i with
+ | None -> []
+ | Some c ->
+ [CC_hole (apply_assert ren'' env c).a_value])),
+ ty
+ | None -> failwith "a block should contain at least one statement")
+ tbl
+ in
+
+ (* deuxičme branche: le test est faux => on sort de la boucle *)
+ let t2,_ =
+ result_tuple ren' before env
+ (CC_expr (constant "tt"),constant "unit") (ef,is)
+ in
+
+ let b_al = current_vars ren' (get_reads eb) in
+ let qb = force_bool_name qb in
+ let t = make_if_case ren' env ty (CC_var resb,qb) (t1,t2) in
+ let t =
+ make_let_in ren' env tb pb (current_vars ren' wb,qb) (resb,tyb) (t,ty)
+ in
+ let t =
+ let pl = List.map (pre_of_assert false) (list_of_some i) in
+ abs_pre ren' env (t,ty) pl
+ in
+ let t =
+ CC_lam ([var_name Anonymous,
+ CC_typed_binder (eq a (mkVar id_phi0) (phi_of ren'))],t)
+ in
+ let bl = binding_of_alist ren env (current_vars ren' (get_writes ef)) in
+ make_abs (List.rev bl) t
+
+
+let make_while ren env (cphi,r,a) (tb,cb) tbl (i,c) =
+ let (_,ef,_,is) = c in
+ let phi_of ren = (apply_pre ren env (anonymous_pre true cphi)).p_value in
+ let wf_a_r = Term.applist (constant "well_founded", [a; r]) in
+
+ let before = current_date ren in
+ let ren' = next ren (get_writes ef) in
+ let al = current_vars ren' (get_writes ef) in
+ let v =
+ let _,lo = input_output ren env c in
+ let is = abstract_post ren' env (ef,is) in
+ match i with
+ | None -> product ren' env before lo is
+ | Some ci ->
+ Term.mkArrow (apply_assert ren' env ci).a_value
+ (product ren' env before lo is)
+ in
+ let v = Term.mkArrow (eq a (mkVar id_phi) (phi_of ren')) v in
+ let v =
+ n_mkNamedProd v
+ (List.map (fun (id,id') -> (id',trad_type_in_env ren env id)) al)
+ in
+ let tw =
+ Term.mkNamedProd id_phi a
+ (Term.mkArrow (lt r (mkVar id_phi) (mkVar id_phi0)) v)
+ in
+ let id_w = id_of_string "loop" in
+ let vars = List.rev (current_vars ren (get_writes ef)) in
+ let body =
+ make_body_while ren env phi_of a r id_phi0 id_w (tb,cb) tbl (i,c)
+ in
+ CC_app (CC_expr (constant "well_founded_induction"),
+ [CC_expr a; CC_expr r;
+ CC_hole wf_a_r;
+ CC_expr (Term.mkNamedLambda id_phi a v);
+ CC_lam ([id_phi0, CC_typed_binder a;
+ id_w, CC_typed_binder tw],
+ body);
+ CC_expr (phi_of ren)]
+ @(List.map (fun (_,id) -> CC_var id) vars)
+ @(CC_hole (eq a (phi_of ren) (phi_of ren)))
+ ::(match i with
+ | None -> []
+ | Some c -> [CC_hole (apply_assert ren env c).a_value]))
+
+
+(* [make_letrec ren env (phi0,(cphi,r,a)) bl (te,ce) c]
+ * constructs the term corresponding to the let rec i.e.
+ *
+ * [x][h:P(x)](well_founded_induction
+ * A R ?::(well_founded A R)
+ * [Phi:A] (bl) (x) Phi=phi(x)->(P x)-> \exists x'.res.(Q x x')
+ * [Phi_0:A][w:(Phi:A)(Phi<Phi_0)-> ...]
+ * [bl][x][eq:Phi_0=phi(x)][h:(P x)]te
+ * phi(x) bl x ? ?)
+ *)
+
+let make_letrec ren env (id_phi0,(cphi,r,a)) idf bl (te,ce) c =
+ let (_,ef,p,q) = c in
+ let phi_of ren = (apply_pre ren env (anonymous_pre true cphi)).p_value in
+ let wf_a_r = Term.applist (constant "well_founded", [a; r]) in
+
+ let before = current_date ren in
+ let al = current_vars ren (get_reads ef) in
+ let v =
+ let _,lo = input_output ren env c in
+ let q = abstract_post ren env (ef,q) in
+ arrow ren env (product ren env (current_date ren) lo q) p
+ in
+ let v = Term.mkArrow (eq a (mkVar id_phi) (phi_of ren)) v in
+ let v =
+ n_mkNamedProd v
+ (List.map (fun (id,id') -> (id',trad_type_in_env ren env id)) al)
+ in
+ let v =
+ n_mkNamedProd v
+ (List.map (function (id,CC_typed_binder c) -> (id,c)
+ | _ -> assert false) (List.rev bl))
+ in
+ let tw =
+ Term.mkNamedProd id_phi a
+ (Term.mkArrow (lt r (mkVar id_phi) (mkVar id_phi0)) v)
+ in
+ let vars = List.rev (current_vars ren (get_reads ef)) in
+ let body =
+ let al = current_vars ren (get_reads ef) in
+ let bod = abs_pre ren env (te,v) p in
+ let bod = CC_lam ([var_name Anonymous,
+ CC_typed_binder (eq a (mkVar id_phi0) (phi_of ren))],
+ bod)
+ in
+ let bl' = binding_of_alist ren env al in
+ make_abs (bl@(List.rev bl')) bod
+ in
+ let t =
+ CC_app (CC_expr (constant "well_founded_induction"),
+ [CC_expr a; CC_expr r;
+ CC_hole wf_a_r;
+ CC_expr (Term.mkNamedLambda id_phi a v);
+ CC_lam ([id_phi0, CC_typed_binder a;
+ idf, CC_typed_binder tw],
+ body);
+ CC_expr (phi_of ren)]
+ @(List.map (fun (id,_) -> CC_var id) bl)
+ @(List.map (fun (_,id) -> CC_var id) vars)
+ @[CC_hole (eq a (phi_of ren) (phi_of ren))]
+ )
+ in
+ (* on abstrait juste par rapport aux variables de ef *)
+ let al = current_vars ren (get_reads ef) in
+ let bl = binding_of_alist ren env al in
+ make_abs (List.rev bl) t
+
+
+(* [make_access env id c] Access in array id.
+ *
+ * Constructs [t:(array s T)](access_g s T t c ?::(lt c s)).
+ *)
+
+let array_info ren env id =
+ let ty = type_in_env env id in
+ let size,v = dearray_type ty in
+ let ty_elem = trad_ml_type_v ren env v in
+ let ty_array = trad_imp_type ren env ty in
+ size,ty_elem,ty_array
+
+let make_raw_access ren env (id,id') c =
+ let size,ty_elem,_ = array_info ren env id in
+ Term.applist (constant "access", [size; ty_elem; mkVar id'; c])
+
+let make_pre_access ren env id c =
+ let size,_,_ = array_info ren env id in
+ conj (lt (constant "Zle") (constant "ZERO") c)
+ (lt (constant "Zlt") c size)
+
+let make_raw_store ren env (id,id') c1 c2 =
+ let size,ty_elem,_ = array_info ren env id in
+ Term.applist (constant "store", [size; ty_elem; mkVar id'; c1; c2])
diff --git a/contrib/correctness/pmonad.mli b/contrib/correctness/pmonad.mli
new file mode 100644
index 00000000..e1400fcb
--- /dev/null
+++ b/contrib/correctness/pmonad.mli
@@ -0,0 +1,106 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pmonad.mli,v 1.1.16.1 2004/07/16 19:30:02 herbelin Exp $ *)
+
+open Names
+open Term
+
+open Ptype
+open Past
+open Penv
+
+(* Main part of the translation of imperative programs into functional ones
+ * (with mlise.ml) *)
+
+(* Here we translate the specification into a CIC specification *)
+
+val trad_ml_type_v : Prename.t -> local_env -> type_v -> constr
+val trad_ml_type_c : Prename.t -> local_env -> type_c -> constr
+val trad_imp_type : Prename.t -> local_env -> type_v -> constr
+val trad_type_in_env : Prename.t -> local_env -> identifier -> constr
+
+val binding_of_alist : Prename.t -> local_env
+ -> (identifier * identifier) list
+ -> cc_binder list
+val make_abs : cc_binder list -> cc_term -> cc_term
+val abs_pre : Prename.t -> local_env -> cc_term * constr ->
+ constr precondition list -> cc_term
+
+(* The following functions translate the main constructions *)
+
+val make_tuple : (cc_term * cc_type) list -> predicate option
+ -> Prename.t -> local_env -> string
+ -> cc_term
+
+val result_tuple : Prename.t -> string -> local_env
+ -> (cc_term * constr) -> (Peffect.t * predicate option)
+ -> cc_term * constr
+
+val let_in_pre : constr -> constr precondition -> cc_term -> cc_term
+
+val make_let_in : Prename.t -> local_env -> cc_term
+ -> constr precondition list
+ -> ((identifier * identifier) list * predicate option)
+ -> identifier * constr
+ -> cc_term * constr -> cc_term
+
+val make_block : Prename.t -> local_env
+ -> (Prename.t -> (identifier * constr) option -> cc_term * constr)
+ -> (cc_term * type_c, constr) block
+ -> cc_term
+
+val make_app : local_env
+ -> Prename.t -> (cc_term * type_c) list
+ -> Prename.t -> cc_term * type_c
+ -> ((type_v binder list) * type_c)
+ * ((identifier*identifier) list)
+ * type_c
+ -> type_c
+ -> cc_term
+
+val make_if : Prename.t -> local_env
+ -> cc_term * type_c
+ -> Prename.t
+ -> cc_term * type_c
+ -> cc_term * type_c
+ -> type_c
+ -> cc_term
+
+val make_while : Prename.t -> local_env
+ -> (constr * constr * constr) (* typed variant *)
+ -> cc_term * type_c
+ -> (cc_term * type_c, constr) block
+ -> constr assertion option * type_c
+ -> cc_term
+
+val make_letrec : Prename.t -> local_env
+ -> (identifier * (constr * constr * constr)) (* typed variant *)
+ -> identifier (* the name of the function *)
+ -> (cc_binder list)
+ -> (cc_term * type_c)
+ -> type_c
+ -> cc_term
+
+(* Functions to translate array operations *)
+
+val array_info :
+ Prename.t -> local_env -> identifier -> constr * constr * constr
+
+val make_raw_access :
+ Prename.t -> local_env -> identifier * identifier -> constr -> constr
+
+val make_raw_store :
+ Prename.t -> local_env -> identifier * identifier
+ -> constr -> constr -> constr
+
+val make_pre_access :
+ Prename.t -> local_env -> identifier -> constr -> constr
+
diff --git a/contrib/correctness/pred.ml b/contrib/correctness/pred.ml
new file mode 100644
index 00000000..732dcf08
--- /dev/null
+++ b/contrib/correctness/pred.ml
@@ -0,0 +1,115 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pred.ml,v 1.6.14.1 2004/07/16 19:30:05 herbelin Exp $ *)
+
+open Pp
+open Past
+open Pmisc
+
+let rec cc_subst subst = function
+ | CC_var id as c ->
+ (try CC_expr (List.assoc id subst) with Not_found -> c)
+ | CC_letin (b,ty,bl,c1,c2) ->
+ CC_letin (b, real_subst_in_constr subst ty, cc_subst_binders subst bl,
+ cc_subst subst c1, cc_subst (cc_cross_binders subst bl) c2)
+ | CC_lam (bl, c) ->
+ CC_lam (cc_subst_binders subst bl,
+ cc_subst (cc_cross_binders subst bl) c)
+ | CC_app (c, cl) ->
+ CC_app (cc_subst subst c, List.map (cc_subst subst) cl)
+ | CC_tuple (b, tl, cl) ->
+ CC_tuple (b, List.map (real_subst_in_constr subst) tl,
+ List.map (cc_subst subst) cl)
+ | CC_case (ty, c, cl) ->
+ CC_case (real_subst_in_constr subst ty, cc_subst subst c,
+ List.map (cc_subst subst) cl)
+ | CC_expr c ->
+ CC_expr (real_subst_in_constr subst c)
+ | CC_hole ty ->
+ CC_hole (real_subst_in_constr subst ty)
+
+and cc_subst_binders subst = List.map (cc_subst_binder subst)
+
+and cc_subst_binder subst = function
+ | id,CC_typed_binder c -> id,CC_typed_binder (real_subst_in_constr subst c)
+ | b -> b
+
+and cc_cross_binders subst = function
+ | [] -> subst
+ | (id,_) :: bl -> cc_cross_binders (List.remove_assoc id subst) bl
+
+(* here we only perform eta-reductions on programs to eliminate
+ * redexes of the kind
+ *
+ * let (x1,...,xn) = e in (x1,...,xn) --> e
+ *
+ *)
+
+let is_eta_redex bl al =
+ try
+ List.for_all2
+ (fun (id,_) t -> match t with CC_var id' -> id=id' | _ -> false)
+ bl al
+ with
+ Invalid_argument("List.for_all2") -> false
+
+let rec red = function
+ | CC_letin (_, _, [id,_], CC_expr c1, e2) ->
+ red (cc_subst [id,c1] e2)
+ | CC_letin (dep, ty, bl, e1, e2) ->
+ begin match red e2 with
+ | CC_tuple (false,tl,al) ->
+ if is_eta_redex bl al then
+ red e1
+ else
+ CC_letin (dep, ty, bl, red e1,
+ CC_tuple (false,tl,List.map red al))
+ | e -> CC_letin (dep, ty, bl, red e1, e)
+ end
+ | CC_lam (bl, e) ->
+ CC_lam (bl, red e)
+ | CC_app (e, al) ->
+ CC_app (red e, List.map red al)
+ | CC_case (ty, e1, el) ->
+ CC_case (ty, red e1, List.map red el)
+ | CC_tuple (dep, tl, al) ->
+ CC_tuple (dep, tl, List.map red al)
+ | e -> e
+
+
+(* How to reduce uncomplete proof terms when they have become constr *)
+
+open Term
+open Reductionops
+
+(* Il ne faut pas reduire de redexe (beta/iota) qui impliquerait
+ * la substitution d'une métavariable.
+ *
+ * On commence par rendre toutes les applications binaire (strong bin_app)
+ * puis on applique la reduction spéciale programmes définie dans
+ * typing/reduction *)
+
+(*i
+let bin_app = function
+ | DOPN(AppL,v) as c ->
+ (match Array.length v with
+ | 1 -> v.(0)
+ | 2 -> c
+ | n ->
+ let f = DOPN(AppL,Array.sub v 0 (pred n)) in
+ DOPN(AppL,[|f;v.(pred n)|]))
+ | c -> c
+i*)
+
+let red_cci c =
+ (*i let c = strong bin_app c in i*)
+ strong whd_programs (Global.env ()) Evd.empty c
+
diff --git a/contrib/correctness/pred.mli b/contrib/correctness/pred.mli
new file mode 100644
index 00000000..2f43f4ad
--- /dev/null
+++ b/contrib/correctness/pred.mli
@@ -0,0 +1,26 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pred.mli,v 1.1.16.1 2004/07/16 19:30:05 herbelin Exp $ *)
+
+open Term
+open Past
+
+(* reduction on intermediate programs
+ * get rid of redexes of the kind let (x1,...,xn) = e in (x1,...,xn) *)
+
+val red : cc_term -> cc_term
+
+
+(* Ad-hoc reduction on partial proof terms *)
+
+val red_cci : constr -> constr
+
+
diff --git a/contrib/correctness/prename.ml b/contrib/correctness/prename.ml
new file mode 100644
index 00000000..864f6abd
--- /dev/null
+++ b/contrib/correctness/prename.ml
@@ -0,0 +1,139 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: prename.ml,v 1.3.14.1 2004/07/16 19:30:05 herbelin Exp $ *)
+
+open Names
+open Nameops
+open Util
+open Pp
+open Himsg
+open Pmisc
+
+(* Variables names management *)
+
+type date = string
+
+(* The following data structure keeps the successive names of the variables
+ * as we traverse the program. A each step a ``date'' and a
+ * collection of new names is (possibly) given, and updates the
+ * previous renaming.
+ *
+ * Then, we can ask for the name of a variable, at current date or
+ * at a given date.
+ *
+ * It is easily represented by a list of date x assoc list, most recent coming
+ * first i.e. as follows:
+ *
+ * [ date (= current), [ (x,xi); ... ];
+ * date , [ (z,zk); ... ];
+ * ...
+ * date (= initial), [ (x,xj); (y,yi); ... ]
+ *
+ * We also keep a list of all names already introduced, in order to
+ * quickly get fresh names.
+ *)
+
+type t =
+ { levels : (date * (identifier * identifier) list) list;
+ avoid : identifier list;
+ cpt : int }
+
+
+let empty_ren = { levels = []; avoid = []; cpt = 0 }
+
+let update r d ids =
+ let al,av = renaming_of_ids r.avoid ids in
+ { levels = (d,al) :: r.levels; avoid = av; cpt = r.cpt }
+
+let push_date r d = update r d []
+
+let next r ids =
+ let al,av = renaming_of_ids r.avoid ids in
+ let n = succ r.cpt in
+ let d = string_of_int n in
+ { levels = (d,al) :: r.levels; avoid = av; cpt = n }
+
+
+let find r x =
+ let rec find_in_one = function
+ [] -> raise Not_found
+ | (y,v)::rem -> if y = x then v else find_in_one rem
+ in
+ let rec find_in_all = function
+ [] -> raise Not_found
+ | (_,l)::rem -> try find_in_one l with Not_found -> find_in_all rem
+ in
+ find_in_all r.levels
+
+
+let current_var = find
+
+let current_vars r ids = List.map (fun id -> id,current_var r id) ids
+
+
+let avoid r ids = { levels = r.levels; avoid = r.avoid @ ids; cpt = r.cpt }
+
+let fresh r ids = fst (renaming_of_ids r.avoid ids)
+
+
+let current_date r =
+ match r.levels with
+ [] -> invalid_arg "Renamings.current_date"
+ | (d,_)::_ -> d
+
+let all_dates r = List.map fst r.levels
+
+let rec valid_date da r =
+ let rec valid = function
+ [] -> false
+ | (d,_)::rem -> (d=da) or (valid rem)
+ in
+ valid r.levels
+
+(* [until d r] selects the part of the renaming [r] starting from date [d] *)
+let rec until da r =
+ let rec cut = function
+ [] -> invalid_arg "Renamings.until"
+ | (d,_)::rem as r -> if d=da then r else cut rem
+ in
+ { avoid = r.avoid; levels = cut r.levels; cpt = r.cpt }
+
+let var_at_date r d id =
+ try
+ find (until d r) id
+ with Not_found ->
+ raise (UserError ("Renamings.var_at_date",
+ hov 0 (str"Variable " ++ pr_id id ++ str" is unknown" ++ spc () ++
+ str"at date " ++ str d)))
+
+let vars_at_date r d ids =
+ let r' = until d r in List.map (fun id -> id,find r' id) ids
+
+
+(* pretty-printers *)
+
+open Pp
+open Util
+open Himsg
+
+let pp r =
+ hov 2 (prlist_with_sep (fun () -> (fnl ()))
+ (fun (d,l) ->
+ (str d ++ str": " ++
+ prlist_with_sep (fun () -> (spc ()))
+ (fun (id,id') ->
+ (str"(" ++ pr_id id ++ str"," ++ pr_id id' ++ str")"))
+ l))
+ r.levels)
+
+let ppr e =
+ Pp.pp (pp e)
+
diff --git a/contrib/correctness/prename.mli b/contrib/correctness/prename.mli
new file mode 100644
index 00000000..88b49d2c
--- /dev/null
+++ b/contrib/correctness/prename.mli
@@ -0,0 +1,57 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: prename.mli,v 1.1.16.1 2004/07/16 19:30:05 herbelin Exp $ *)
+
+open Names
+
+(* Abstract type for renamings
+ *
+ * Records the names of the mutables objets (ref, arrays) at the different
+ * moments of the evaluation, called dates
+ *)
+
+type t
+
+type date = string
+
+
+val empty_ren : t
+val update : t -> date -> identifier list -> t
+ (* assign new names for the given variables, associated to a new date *)
+val next : t -> identifier list -> t
+ (* assign new names for the given variables, associated to a new
+ * date which is generated from an internal counter *)
+val push_date : t -> date -> t
+ (* put a new date on top of the stack *)
+
+val valid_date : date -> t -> bool
+val current_date : t -> date
+val all_dates : t -> date list
+
+val current_var : t -> identifier -> identifier
+val current_vars : t -> identifier list -> (identifier * identifier) list
+ (* gives the current names of some variables *)
+
+val avoid : t -> identifier list -> t
+val fresh : t -> identifier list -> (identifier * identifier) list
+ (* introduces new names to avoid and renames some given variables *)
+
+val var_at_date : t -> date -> identifier -> identifier
+ (* gives the name of a variable at a given date *)
+val vars_at_date : t -> date -> identifier list
+ -> (identifier * identifier) list
+ (* idem for a list of variables *)
+
+(* pretty-printers *)
+
+val pp : t -> Pp.std_ppcmds
+val ppr : t -> unit
+
diff --git a/contrib/correctness/preuves.v b/contrib/correctness/preuves.v
new file mode 100644
index 00000000..33659b43
--- /dev/null
+++ b/contrib/correctness/preuves.v
@@ -0,0 +1,128 @@
+
+(* Quelques preuves sur des programmes simples,
+ * juste histoire d'avoir un petit bench.
+ *)
+
+Require Correctness.
+Require Omega.
+
+Global Variable x : Z ref.
+Global Variable y : Z ref.
+Global Variable z : Z ref.
+Global Variable i : Z ref.
+Global Variable j : Z ref.
+Global Variable n : Z ref.
+Global Variable m : Z ref.
+Variable r : Z.
+Variable N : Z.
+Global Variable t : array N of Z.
+
+(**********************************************************************)
+
+Require Exchange.
+Require ArrayPermut.
+
+Correctness swap
+ fun (N:Z)(t:array N of Z)(i,j:Z) ->
+ { `0 <= i < N` /\ `0 <= j < N` }
+ (let v = t[i] in
+ begin
+ t[i] := t[j];
+ t[j] := v
+ end)
+ { (exchange t t@ i j) }.
+Proof.
+Auto with datatypes.
+Save.
+
+Correctness downheap
+ let rec downheap (N:Z)(t:array N of Z) : unit { variant `0` } =
+ (swap N t 0 0) { True }
+.
+
+(**********************************************************************)
+
+Global Variable x : Z ref.
+Debug on.
+Correctness assign0 (x := 0) { `x=0` }.
+Save.
+
+(**********************************************************************)
+
+Global Variable i : Z ref.
+Debug on.
+Correctness assign1 { `0 <= i` } (i := !i + 1) { `0 < i` }.
+Omega.
+Save.
+
+(**********************************************************************)
+
+Global Variable i : Z ref.
+Debug on.
+Correctness if0 { `0 <= i` } (if !i>0 then i:=!i-1 else tt) { `0 <= i` }.
+Omega.
+Save.
+
+(**********************************************************************)
+
+Global Variable i : Z ref.
+Debug on.
+Correctness assert0 { `0 <= i` } begin assert { `i=2` }; i:=!i-1 end { `i=1` }.
+
+(**********************************************************************)
+
+Correctness echange
+ { `0 <= i < N` /\ `0 <= j < N` }
+ begin
+ label B;
+ x := t[!i]; t[!i] := t[!j]; t[!j] := !x;
+ assert { #t[i] = #t@B[j] /\ #t[j] = #t@B[i] }
+ end.
+Proof.
+Auto with datatypes.
+Save.
+
+
+(**********************************************************************)
+
+(*
+ * while x <= y do x := x+1 done { y < x }
+ *)
+
+Correctness incrementation
+ while !x < !y do
+ { invariant True variant `(Zs y)-x` }
+ x := !x + 1
+ done
+ { `y < x` }.
+Proof.
+Exact (Zwf_well_founded `0`).
+Unfold Zwf. Omega.
+Exact I.
+Save.
+
+
+(************************************************************************)
+
+Correctness pivot1
+ begin
+ while (Z_lt_ge_dec !i r) do
+ { invariant True variant (Zminus (Zs r) i) } i := (Zs !i)
+ done;
+ while (Z_lt_ge_dec r !j) do
+ { invariant True variant (Zminus (Zs j) r) } j := (Zpred !j)
+ done
+ end
+ { `j <= r` /\ `r <= i` }.
+Proof.
+Exact (Zwf_well_founded `0`).
+Unfold Zwf. Omega.
+Exact I.
+Exact (Zwf_well_founded `0`).
+Unfold Zwf. Unfold Zpred. Omega.
+Exact I.
+Omega.
+Save.
+
+
+
diff --git a/contrib/correctness/psyntax.ml4 b/contrib/correctness/psyntax.ml4
new file mode 100644
index 00000000..c1f00a3d
--- /dev/null
+++ b/contrib/correctness/psyntax.ml4
@@ -0,0 +1,1058 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: psyntax.ml4,v 1.29.2.1 2004/07/16 19:30:05 herbelin Exp $ *)
+
+(*i camlp4deps: "parsing/grammar.cma" i*)
+
+open Options
+open Util
+open Names
+open Nameops
+open Vernacentries
+open Reduction
+open Term
+open Libnames
+open Topconstr
+
+open Prename
+open Pmisc
+open Putil
+open Ptype
+open Past
+open Penv
+open Pmonad
+open Vernacexpr
+
+
+(* We define new entries for programs, with the use of this module
+ * Programs. These entries are named Programs.<foo>
+ *)
+
+module Gram = Pcoq.Gram
+module Constr = Pcoq.Constr
+module Tactic = Pcoq.Tactic
+
+module Programs =
+ struct
+ let gec s = Gram.Entry.create ("Programs."^s)
+ (* types *)
+ let type_v = gec "type_v"
+ let type_v0 = gec "type_v0"
+ let type_v1 = gec "type_v1"
+ let type_v2 = gec "type_v2"
+ let type_v3 = gec "type_v3"
+ let type_v_app = gec "type_v_app"
+ let type_c = gec "type_c"
+ let effects = gec "effects"
+ let reads = gec "reads"
+ let writes = gec "writes"
+ let pre_condition = gec "pre_condition"
+ let post_condition = gec "post_condition"
+ (* binders *)
+ let binder = gec "binder"
+ let binder_type = gec "binder_type"
+ let binders = gec "binders"
+ (* programs *)
+ let program = gec "program"
+ let prog1 = gec "prog1"
+ let prog2 = gec "prog2"
+ let prog3 = gec "prog3"
+ let prog4 = gec "prog4"
+ let prog5 = gec "prog5"
+ let prog6 = gec "prog6"
+ let prog7 = gec "prog7"
+ let ast1 = gec "ast1"
+ let ast2 = gec "ast2"
+ let ast3 = gec "ast3"
+ let ast4 = gec "ast4"
+ let ast5 = gec "ast5"
+ let ast6 = gec "ast6"
+ let ast7 = gec "ast7"
+ let arg = gec "arg"
+ let block = gec "block"
+ let block_statement = gec "block_statement"
+ let relation = gec "relation"
+ let variable = gec "variable"
+ let invariant = gec "invariant"
+ let variant = gec "variant"
+ let assertion = gec "assertion"
+ let precondition = gec "precondition"
+ let postcondition = gec "postcondition"
+ let predicate = gec "predicate"
+ let name = gec "name"
+ end
+
+open Programs
+
+let ast_of_int n =
+ CDelimiters
+ (dummy_loc, "Z", CNumeral (dummy_loc, Bignat.POS (Bignat.of_string n)))
+
+let constr_of_int n =
+ Constrintern.interp_constr Evd.empty (Global.env ()) (ast_of_int n)
+
+open Util
+open Coqast
+
+let mk_id loc id = mkRefC (Ident (loc, id))
+let mk_ref loc s = mk_id loc (Constrextern.id_of_v7_string s)
+let mk_appl loc1 loc2 f args =
+ CApp (join_loc loc1 loc2, (None,mk_ref loc1 f), List.map (fun a -> a,None) args)
+
+let conj_assert {a_name=n;a_value=a} {a_value=b} =
+ let loc1 = constr_loc a in
+ let loc2 = constr_loc a in
+ { a_value = mk_appl loc1 loc2 "and" [a;b]; a_name = n }
+
+let conj = function
+ None,None -> None
+ | None,b -> b
+ | a,None -> a
+ | Some a,Some b -> Some (conj_assert a b)
+
+let without_effect loc d =
+ { desc = d; pre = []; post = None; loc = loc; info = () }
+
+let isevar = Expression isevar
+
+let bin_op op loc e1 e2 =
+ without_effect loc
+ (Apply (without_effect loc (Expression (constant op)),
+ [ Term e1; Term e2 ]))
+
+let un_op op loc e =
+ without_effect loc
+ (Apply (without_effect loc (Expression (constant op)), [Term e]))
+
+let bool_bin op loc a1 a2 =
+ let w = without_effect loc in
+ let d = SApp ( [Variable op], [a1; a2]) in
+ w d
+
+let bool_or loc = bool_bin connective_or loc
+let bool_and loc = bool_bin connective_and loc
+
+let bool_not loc a =
+ let w = without_effect loc in
+ let d = SApp ( [Variable connective_not ], [a]) in
+ w d
+
+let ast_zwf_zero loc = mk_appl loc loc "Zwf" [mk_ref loc "ZERO"]
+
+(* program -> Coq AST *)
+
+let bdize c =
+ let env =
+ Global.env_of_context (Pcicenv.cci_sign_of Prename.empty_ren Penv.empty)
+ in
+ Constrextern.extern_constr true env c
+
+let rec coqast_of_program loc = function
+ | Variable id -> mk_id loc id
+ | Acc id -> mk_id loc id
+ | Apply (f,l) ->
+ let f = coqast_of_program f.loc f.desc in
+ let args = List.map
+ (function Term t -> (coqast_of_program t.loc t.desc,None)
+ | _ -> invalid_arg "coqast_of_program") l
+ in
+ CApp (dummy_loc, (None,f), args)
+ | Expression c -> bdize c
+ | _ -> invalid_arg "coqast_of_program"
+
+(* The construction `for' is syntactic sugar.
+ *
+ * for i = v1 to v2 do { invariant Inv } block done
+ *
+ * ==> (let rec f i { variant v2+1-i } =
+ * { i <= v2+1 /\ Inv(i) }
+ * (if i > v2 then tt else begin block; (f (i+1)) end)
+ * { Inv(v2+1) }
+ * in (f v1)) { Inv(v2+1) }
+ *)
+
+let ast_plus_un loc ast =
+ let un = ast_of_int "1" in
+ mk_appl loc loc "Zplus" [ast;un]
+
+let make_ast_for loc i v1 v2 inv block =
+ let f = for_name() in
+ let id_i = id_of_string i in
+ let var_i = without_effect loc (Variable id_i) in
+ let var_f = without_effect loc (Variable f) in
+ let succ_v2 =
+ let a_v2 = coqast_of_program v2.loc v2.desc in
+ ast_plus_un loc a_v2 in
+ let post = named_app (subst_ast_in_ast [ id_i, succ_v2 ]) inv in
+ let e1 =
+ let test = bin_op "Z_gt_le_bool" loc var_i v2 in
+ let br_t = without_effect loc (Expression (constant "tt")) in
+ let br_f =
+ let un = without_effect loc (Expression (constr_of_int "1")) in
+ let succ_i = bin_op "Zplus" loc var_i un in
+ let f_succ_i = without_effect loc (Apply (var_f, [Term succ_i])) in
+ without_effect loc (Seq (block @ [Statement f_succ_i]))
+ in
+ let inv' =
+ let i_le_sv2 = mk_appl loc loc "Zle" [mk_ref loc i; succ_v2] in
+ conj_assert {a_value=i_le_sv2;a_name=inv.a_name} inv
+ in
+ { desc = If(test,br_t,br_f); loc = loc;
+ pre = [pre_of_assert false inv']; post = Some post; info = () }
+ in
+ let bl =
+ let typez = mk_ref loc "Z" in
+ [(id_of_string i, BindType (TypePure typez))]
+ in
+ let fv1 = without_effect loc (Apply (var_f, [Term v1])) in
+ let v = TypePure (mk_ref loc "unit") in
+ let var =
+ let a = mk_appl loc loc "Zminus" [succ_v2;mk_ref loc i] in
+ (a, ast_zwf_zero loc)
+ in
+ Let (f, without_effect loc (LetRec (f,bl,v,var,e1)), fv1)
+
+let mk_prog loc p pre post =
+ { desc = p.desc;
+ pre = p.pre @ pre;
+ post = conj (p.post,post);
+ loc = loc;
+ info = () }
+
+if !Options.v7 then
+GEXTEND Gram
+
+ (* Types ******************************************************************)
+ type_v:
+ [ [ t = type_v0 -> t ] ]
+ ;
+ type_v0:
+ [ [ t = type_v1 -> t ] ]
+ ;
+ type_v1:
+ [ [ t = type_v2 -> t ] ]
+ ;
+ type_v2:
+ [ LEFTA
+ [ v = type_v2; IDENT "ref" -> Ref v
+ | t = type_v3 -> t ] ]
+ ;
+ type_v3:
+ [ [ IDENT "array"; size = Constr.constr; "of"; v = type_v0 ->
+ Array (size,v)
+ | IDENT "fun"; bl = binders; c = type_c -> make_arrow bl c
+ | c = Constr.constr -> TypePure c
+ ] ]
+ ;
+ type_c:
+ [ [ IDENT "returns"; id = IDENT; ":"; v = type_v;
+ e = effects; p = OPT pre_condition; q = OPT post_condition; "end" ->
+ ((id_of_string id, v), e, list_of_some p, q)
+ ] ]
+ ;
+ effects:
+ [ [ r = OPT reads; w = OPT writes ->
+ let r' = match r with Some l -> l | _ -> [] in
+ let w' = match w with Some l -> l | _ -> [] in
+ List.fold_left (fun e x -> Peffect.add_write x e)
+ (List.fold_left (fun e x -> Peffect.add_read x e) Peffect.bottom r')
+ w'
+ ] ]
+ ;
+ reads:
+ [ [ IDENT "reads"; l = LIST0 IDENT SEP "," -> List.map id_of_string l ] ]
+ ;
+ writes:
+ [ [ IDENT "writes"; l=LIST0 IDENT SEP "," -> List.map id_of_string l ] ]
+ ;
+ pre_condition:
+ [ [ IDENT "pre"; c = predicate -> pre_of_assert false c ] ]
+ ;
+ post_condition:
+ [ [ IDENT "post"; c = predicate -> c ] ]
+ ;
+
+ (* Binders (for both types and programs) **********************************)
+ binder:
+ [ [ "("; sl = LIST1 IDENT SEP ","; ":"; t = binder_type ; ")" ->
+ List.map (fun s -> (id_of_string s, t)) sl
+ ] ]
+ ;
+ binder_type:
+ [ [ "Set" -> BindSet
+ | v = type_v -> BindType v
+ ] ]
+ ;
+ binders:
+ [ [ bl = LIST0 binder -> List.flatten bl ] ]
+ ;
+
+ (* annotations *)
+ predicate:
+ [ [ c = Constr.constr; n = name -> { a_name = n; a_value = c } ] ]
+ ;
+ name:
+ [ [ "as"; s = IDENT -> Name (id_of_string s)
+ | -> Anonymous
+ ] ]
+ ;
+
+ (* Programs ***************************************************************)
+ variable:
+ [ [ s = IDENT -> id_of_string s ] ]
+ ;
+ assertion:
+ [ [ "{"; c = predicate; "}" -> c ] ]
+ ;
+ precondition:
+ [ [ "{"; c = predicate; "}" -> pre_of_assert false c ] ]
+ ;
+ postcondition:
+ [ [ "{"; c = predicate; "}" -> c ] ]
+ ;
+ program:
+ [ [ p = prog1 -> p ] ]
+ ;
+ prog1:
+ [ [ pre = LIST0 precondition; ast = ast1; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog2:
+ [ [ pre = LIST0 precondition; ast = ast2; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog3:
+ [ [ pre = LIST0 precondition; ast = ast3; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog4:
+ [ [ pre = LIST0 precondition; ast = ast4; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog5:
+ [ [ pre = LIST0 precondition; ast = ast5; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog6:
+ [ [ pre = LIST0 precondition; ast = ast6; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+
+ ast1:
+ [ [ x = prog2; IDENT "or"; y = prog1 -> bool_or loc x y
+ | x = prog2; IDENT "and"; y = prog1 -> bool_and loc x y
+ | x = prog2 -> x
+ ] ]
+ ;
+ ast2:
+ [ [ IDENT "not"; x = prog3 -> bool_not loc x
+ | x = prog3 -> x
+ ] ]
+ ;
+ ast3:
+ [ [ x = prog4; rel = relation; y = prog4 -> bin_op rel loc x y
+ | x = prog4 -> x
+ ] ]
+ ;
+ ast4:
+ [ [ x = prog5; "+"; y = prog4 -> bin_op "Zplus" loc x y
+ | x = prog5; "-"; y = prog4 -> bin_op "Zminus" loc x y
+ | x = prog5 -> x
+ ] ]
+ ;
+ ast5:
+ [ [ x = prog6; "*"; y = prog5 -> bin_op "Zmult" loc x y
+ | x = prog6 -> x
+ ] ]
+ ;
+ ast6:
+ [ [ "-"; x = prog6 -> un_op "Zopp" loc x
+ | x = ast7 -> without_effect loc x
+ ] ]
+ ;
+ ast7:
+ [ [ v = variable ->
+ Variable v
+ | n = INT ->
+ Expression (constr_of_int n)
+ | "!"; v = variable ->
+ Acc v
+ | "?" ->
+ isevar
+ | v = variable; ":="; p = program ->
+ Aff (v,p)
+ | v = variable; "["; e = program; "]" -> TabAcc (true,v,e)
+ | v = variable; "#"; "["; e = program; "]" -> TabAcc (true,v,e)
+ | v = variable; "["; e = program; "]"; ":="; p = program ->
+ TabAff (true,v,e,p)
+ | v = variable; "#"; "["; e = program; "]"; ":="; p = program ->
+ TabAff (true,v,e,p)
+ | IDENT "if"; e1 = program; IDENT "then"; e2 = program;
+ IDENT "else"; e3 = program ->
+ If (e1,e2,e3)
+ | IDENT "if"; e1 = program; IDENT "then"; e2 = program ->
+ If (e1,e2,without_effect loc (Expression (constant "tt")))
+ | IDENT "while"; b = program; IDENT "do";
+ "{"; inv = OPT invariant; IDENT "variant"; wf = variant; "}";
+ bl = block; IDENT "done" ->
+ While (b, inv, wf, bl)
+ | IDENT "for"; i = IDENT; "="; v1 = program; IDENT "to"; v2 = program;
+ IDENT "do"; "{"; inv = invariant; "}";
+ bl = block; IDENT "done" ->
+ make_ast_for loc i v1 v2 inv bl
+ | IDENT "let"; v = variable; "="; IDENT "ref"; p1 = program;
+ "in"; p2 = program ->
+ LetRef (v, p1, p2)
+ | IDENT "let"; v = variable; "="; p1 = program; "in"; p2 = program ->
+ Let (v, p1, p2)
+ | IDENT "begin"; b = block; "end" ->
+ Seq b
+ | IDENT "fun"; bl = binders; "->"; p = program ->
+ Lam (bl,p)
+ | IDENT "let"; IDENT "rec"; f = variable;
+ bl = binders; ":"; v = type_v;
+ "{"; IDENT "variant"; var = variant; "}"; "="; p = program ->
+ LetRec (f,bl,v,var,p)
+ | IDENT "let"; IDENT "rec"; f = variable;
+ bl = binders; ":"; v = type_v;
+ "{"; IDENT "variant"; var = variant; "}"; "="; p = program;
+ "in"; p2 = program ->
+ Let (f, without_effect loc (LetRec (f,bl,v,var,p)), p2)
+
+ | "@"; s = STRING; p = program ->
+ Debug (s,p)
+
+ | "("; p = program; args = LIST0 arg; ")" ->
+ match args with
+ [] ->
+ if p.pre<>[] or p.post<>None then
+ Pp.warning "Some annotations are lost";
+ p.desc
+ | _ ->
+ Apply(p,args)
+ ] ]
+ ;
+ arg:
+ [ [ "'"; t = type_v -> Type t
+ | p = program -> Term p
+ ] ]
+ ;
+ block:
+ [ [ s = block_statement; ";"; b = block -> s::b
+ | s = block_statement -> [s] ] ]
+ ;
+ block_statement:
+ [ [ IDENT "label"; s = IDENT -> Label s
+ | IDENT "assert"; c = assertion -> Assert c
+ | p = program -> Statement p ] ]
+ ;
+ relation:
+ [ [ "<" -> "Z_lt_ge_bool"
+ | "<=" -> "Z_le_gt_bool"
+ | ">" -> "Z_gt_le_bool"
+ | ">=" -> "Z_ge_lt_bool"
+ | "=" -> "Z_eq_bool"
+ | "<>" -> "Z_noteq_bool" ] ]
+ ;
+
+ (* Other entries (invariants, etc.) ***************************************)
+ invariant:
+ [ [ IDENT "invariant"; c = predicate -> c ] ]
+ ;
+ variant:
+ [ [ c = Constr.constr; IDENT "for"; r = Constr.constr -> (c, r)
+ | c = Constr.constr -> (c, ast_zwf_zero loc) ] ]
+ ;
+ END
+else
+GEXTEND Gram
+ GLOBAL: type_v program;
+
+ (* Types ******************************************************************)
+ type_v:
+ [ [ t = type_v0 -> t ] ]
+ ;
+ type_v0:
+ [ [ t = type_v1 -> t ] ]
+ ;
+ type_v1:
+ [ [ t = type_v2 -> t ] ]
+ ;
+ type_v2:
+ [ LEFTA
+ [ v = type_v2; IDENT "ref" -> Ref v
+ | t = type_v3 -> t ] ]
+ ;
+ type_v3:
+ [ [ IDENT "array"; size = Constr.constr; IDENT "of"; v = type_v0 ->
+ Array (size,v)
+ | "fun"; bl = binders; c = type_c -> make_arrow bl c
+ | c = Constr.constr -> TypePure c
+ ] ]
+ ;
+ type_c:
+ [ [ IDENT "returns"; id = IDENT; ":"; v = type_v;
+ e = effects; p = OPT pre_condition; q = OPT post_condition; "end" ->
+ ((id_of_string id, v), e, list_of_some p, q)
+ ] ]
+ ;
+ effects:
+ [ [ r = OPT reads; w = OPT writes ->
+ let r' = match r with Some l -> l | _ -> [] in
+ let w' = match w with Some l -> l | _ -> [] in
+ List.fold_left (fun e x -> Peffect.add_write x e)
+ (List.fold_left (fun e x -> Peffect.add_read x e) Peffect.bottom r')
+ w'
+ ] ]
+ ;
+ reads:
+ [ [ IDENT "reads"; l = LIST0 IDENT SEP "," -> List.map id_of_string l ] ]
+ ;
+ writes:
+ [ [ IDENT "writes"; l=LIST0 IDENT SEP "," -> List.map id_of_string l ] ]
+ ;
+ pre_condition:
+ [ [ IDENT "pre"; c = predicate -> pre_of_assert false c ] ]
+ ;
+ post_condition:
+ [ [ IDENT "post"; c = predicate -> c ] ]
+ ;
+
+ (* Binders (for both types and programs) **********************************)
+ binder:
+ [ [ "("; sl = LIST1 IDENT SEP ","; ":"; t = binder_type ; ")" ->
+ List.map (fun s -> (id_of_string s, t)) sl
+ ] ]
+ ;
+ binder_type:
+ [ [ "Set" -> BindSet
+ | v = type_v -> BindType v
+ ] ]
+ ;
+ binders:
+ [ [ bl = LIST0 binder -> List.flatten bl ] ]
+ ;
+
+ (* annotations *)
+ predicate:
+ [ [ c = Constr.constr; n = name -> { a_name = n; a_value = c } ] ]
+ ;
+ dpredicate:
+ [ [ c = Constr.lconstr; n = name -> { a_name = n; a_value = c } ] ]
+ ;
+ name:
+ [ [ "as"; s = IDENT -> Name (id_of_string s)
+ | -> Anonymous
+ ] ]
+ ;
+
+ (* Programs ***************************************************************)
+ variable:
+ [ [ s = IDENT -> id_of_string s ] ]
+ ;
+ assertion:
+ [ [ "{"; c = dpredicate; "}" -> c ] ]
+ ;
+ precondition:
+ [ [ "{"; c = dpredicate; "}" -> pre_of_assert false c ] ]
+ ;
+ postcondition:
+ [ [ "{"; c = dpredicate; "}" -> c ] ]
+ ;
+ program:
+ [ [ p = prog1 -> p ] ]
+ ;
+ prog1:
+ [ [ pre = LIST0 precondition; ast = ast1; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog2:
+ [ [ pre = LIST0 precondition; ast = ast2; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog3:
+ [ [ pre = LIST0 precondition; ast = ast3; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog4:
+ [ [ pre = LIST0 precondition; ast = ast4; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog5:
+ [ [ pre = LIST0 precondition; ast = ast5; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+ prog6:
+ [ [ pre = LIST0 precondition; ast = ast6; post = OPT postcondition ->
+ mk_prog loc ast pre post ] ]
+ ;
+
+ ast1:
+ [ [ x = prog2; IDENT "or"; y = prog1 -> bool_or loc x y
+ | x = prog2; IDENT "and"; y = prog1 -> bool_and loc x y
+ | x = prog2 -> x
+ ] ]
+ ;
+ ast2:
+ [ [ IDENT "not"; x = prog3 -> bool_not loc x
+ | x = prog3 -> x
+ ] ]
+ ;
+ ast3:
+ [ [ x = prog4; rel = relation; y = prog4 -> bin_op rel loc x y
+ | x = prog4 -> x
+ ] ]
+ ;
+ ast4:
+ [ [ x = prog5; "+"; y = prog4 -> bin_op "Zplus" loc x y
+ | x = prog5; "-"; y = prog4 -> bin_op "Zminus" loc x y
+ | x = prog5 -> x
+ ] ]
+ ;
+ ast5:
+ [ [ x = prog6; "*"; y = prog5 -> bin_op "Zmult" loc x y
+ | x = prog6 -> x
+ ] ]
+ ;
+ ast6:
+ [ [ "-"; x = prog6 -> un_op "Zopp" loc x
+ | x = ast7 -> without_effect loc x
+ ] ]
+ ;
+ ast7:
+ [ [ v = variable ->
+ Variable v
+ | n = INT ->
+ Expression (constr_of_int n)
+ | "!"; v = variable ->
+ Acc v
+ | "?" ->
+ isevar
+ | v = variable; ":="; p = program ->
+ Aff (v,p)
+ | v = variable; "["; e = program; "]" -> TabAcc (true,v,e)
+ | v = variable; "#"; "["; e = program; "]" -> TabAcc (true,v,e)
+ | v = variable; "["; e = program; "]"; ":="; p = program ->
+ TabAff (true,v,e,p)
+ | v = variable; "#"; "["; e = program; "]"; ":="; p = program ->
+ TabAff (true,v,e,p)
+ | "if"; e1 = program; "then"; e2 = program; "else"; e3 = program ->
+ If (e1,e2,e3)
+ | "if"; e1 = program; "then"; e2 = program ->
+ If (e1,e2,without_effect loc (Expression (constant "tt")))
+ | IDENT "while"; b = program; IDENT "do";
+ "{"; inv = OPT invariant; IDENT "variant"; wf = variant; "}";
+ bl = block; IDENT "done" ->
+ While (b, inv, wf, bl)
+ | "for"; i = IDENT; "="; v1 = program; IDENT "to"; v2 = program;
+ IDENT "do"; "{"; inv = invariant; "}";
+ bl = block; IDENT "done" ->
+ make_ast_for loc i v1 v2 inv bl
+ | "let"; v = variable; "="; IDENT "ref"; p1 = program;
+ "in"; p2 = program ->
+ LetRef (v, p1, p2)
+ | "let"; v = variable; "="; p1 = program; "in"; p2 = program ->
+ Let (v, p1, p2)
+ | IDENT "begin"; b = block; "end" ->
+ Seq b
+ | "fun"; bl = binders; "=>"; p = program ->
+ Lam (bl,p)
+ | "let"; IDENT "rec"; f = variable;
+ bl = binders; ":"; v = type_v;
+ "{"; IDENT "variant"; var = variant; "}"; "="; p = program ->
+ LetRec (f,bl,v,var,p)
+ | "let"; IDENT "rec"; f = variable;
+ bl = binders; ":"; v = type_v;
+ "{"; IDENT "variant"; var = variant; "}"; "="; p = program;
+ "in"; p2 = program ->
+ Let (f, without_effect loc (LetRec (f,bl,v,var,p)), p2)
+
+ | "@"; s = STRING; p = program ->
+ Debug (s,p)
+
+ | "("; p = program; args = LIST0 arg; ")" ->
+ match args with
+ [] ->
+ if p.pre<>[] or p.post<>None then
+ Pp.warning "Some annotations are lost";
+ p.desc
+ | _ ->
+ Apply(p,args)
+ ] ]
+ ;
+ arg:
+ [ [ "'"; t = type_v -> Type t
+ | p = program -> Term p
+ ] ]
+ ;
+ block:
+ [ [ s = block_statement; ";"; b = block -> s::b
+ | s = block_statement -> [s] ] ]
+ ;
+ block_statement:
+ [ [ IDENT "label"; s = IDENT -> Label s
+ | IDENT "assert"; c = assertion -> Assert c
+ | p = program -> Statement p ] ]
+ ;
+ relation:
+ [ [ "<" -> "Z_lt_ge_bool"
+ | "<=" -> "Z_le_gt_bool"
+ | ">" -> "Z_gt_le_bool"
+ | ">=" -> "Z_ge_lt_bool"
+ | "=" -> "Z_eq_bool"
+ | "<>" -> "Z_noteq_bool" ] ]
+ ;
+
+ (* Other entries (invariants, etc.) ***************************************)
+ invariant:
+ [ [ IDENT "invariant"; c = predicate -> c ] ]
+ ;
+ variant:
+ [ [ c = Constr.constr; "for"; r = Constr.constr -> (c, r)
+ | c = Constr.constr -> (c, ast_zwf_zero loc) ] ]
+ ;
+ END
+;;
+
+let wit_program, globwit_program, rawwit_program =
+ Genarg.create_arg "program"
+let wit_type_v, globwit_type_v, rawwit_type_v =
+ Genarg.create_arg "type_v"
+
+open Pp
+open Util
+open Himsg
+open Vernacinterp
+open Vernacexpr
+open Declare
+
+let is_assumed global ids =
+ if List.length ids = 1 then
+ msgnl (str (if global then "A global variable " else "") ++
+ pr_id (List.hd ids) ++ str " is assumed")
+ else
+ msgnl (str (if global then "Some global variables " else "") ++
+ prlist_with_sep (fun () -> (str ", ")) pr_id ids ++
+ str " are assumed")
+
+open Pcoq
+
+(* Variables *)
+
+let wit_variables, globwit_variables, rawwit_variables =
+ Genarg.create_arg "variables"
+
+let variables = Gram.Entry.create "Variables"
+
+GEXTEND Gram
+ variables: [ [ l = LIST1 Prim.ident SEP "," -> l ] ];
+END
+
+let pr_variables _prc _prtac l = spc() ++ prlist_with_sep pr_coma pr_id l
+
+let _ =
+ Pptactic.declare_extra_genarg_pprule true
+ (rawwit_variables, pr_variables)
+ (globwit_variables, pr_variables)
+ (wit_variables, pr_variables)
+
+(* then_tac *)
+
+open Genarg
+open Tacinterp
+
+let pr_then_tac _ prt = function
+ | None -> mt ()
+ | Some t -> pr_semicolon () ++ prt t
+
+ARGUMENT EXTEND then_tac
+ TYPED AS tactic_opt
+ PRINTED BY pr_then_tac
+ INTERPRETED BY interp_genarg
+ GLOBALIZED BY intern_genarg
+| [ ";" tactic(t) ] -> [ Some t ]
+| [ ] -> [ None ]
+END
+
+(* Correctness *)
+
+VERNAC COMMAND EXTEND Correctness
+ [ "Correctness" preident(str) program(pgm) then_tac(tac) ]
+ -> [ Ptactic.correctness str pgm (option_app Tacinterp.interp tac) ]
+END
+
+(* Show Programs *)
+
+let show_programs () =
+ fold_all
+ (fun (id,v) _ ->
+ msgnl (pr_id id ++ str " : " ++
+ hov 2 (match v with TypeV v -> pp_type_v v
+ | Set -> (str "Set")) ++
+ fnl ()))
+ Penv.empty ()
+
+VERNAC COMMAND EXTEND ShowPrograms
+ [ "Show" "Programs" ] -> [ show_programs () ]
+END
+
+(* Global Variable *)
+
+let global_variable ids v =
+ List.iter
+ (fun id -> if Penv.is_global id then
+ Util.errorlabstrm "PROGVARIABLE"
+ (str"Clash with previous constant " ++ pr_id id))
+ ids;
+ Pdb.check_type_v (all_refs ()) v;
+ let env = empty in
+ let ren = update empty_ren "" [] in
+ let v = Ptyping.cic_type_v env ren v in
+ if not (is_mutable v) then begin
+ let c =
+ Entries.ParameterEntry (trad_ml_type_v ren env v),
+ Decl_kinds.IsAssumption Decl_kinds.Definitional in
+ List.iter
+ (fun id -> ignore (Declare.declare_constant id c)) ids;
+ if_verbose (is_assumed false) ids
+ end;
+ if not (is_pure v) then begin
+ List.iter (fun id -> ignore (Penv.add_global id v None)) ids;
+ if_verbose (is_assumed true) ids
+ end
+
+VERNAC COMMAND EXTEND ProgVariable
+ [ "Global" "Variable" variables(ids) ":" type_v(t) ]
+ -> [ global_variable ids t]
+END
+
+let pr_id id = pr_id (Constrextern.v7_to_v8_id id)
+
+(* Type printer *)
+
+let pr_reads = function
+ | [] -> mt ()
+ | l -> spc () ++
+ hov 0 (str "reads" ++ spc () ++ prlist_with_sep pr_coma pr_id l)
+
+let pr_writes = function
+ | [] -> mt ()
+ | l -> spc () ++
+ hov 0 (str "writes" ++ spc () ++ prlist_with_sep pr_coma pr_id l)
+
+let pr_effects x =
+ let (ro,rw) = Peffect.get_repr x in pr_reads ro ++ pr_writes rw
+
+let pr_predicate delimited { a_name = n; a_value = c } =
+ (if delimited then Ppconstrnew.pr_lconstr else Ppconstrnew.pr_constr) c ++
+ (match n with Name id -> spc () ++ str "as " ++ pr_id id | Anonymous -> mt())
+
+let pr_assert b { p_name = x; p_value = v } =
+ pr_predicate b { a_name = x; a_value = v }
+
+let pr_pre_condition_list = function
+ | [] -> mt ()
+ | [pre] -> spc() ++ hov 0 (str "pre" ++ spc () ++ pr_assert false pre)
+ | _ -> assert false
+
+let pr_post_condition_opt = function
+ | None -> mt ()
+ | Some post ->
+ spc() ++ hov 0 (str "post" ++ spc () ++ pr_predicate false post)
+
+let rec pr_type_v_v8 = function
+ | Array (a,v) ->
+ str "array" ++ spc() ++ Ppconstrnew.pr_constr a ++ spc() ++ str "of " ++
+ pr_type_v_v8 v
+ | v -> pr_type_v3 v
+
+and pr_type_v3 = function
+ | Ref v -> pr_type_v3 v ++ spc () ++ str "ref"
+ | Arrow (bl,((id,v),e,prel,postl)) ->
+ str "fun" ++ spc() ++ hov 0 (prlist_with_sep cut pr_binder bl) ++
+ spc () ++ str "returns" ++ spc () ++ pr_id id ++ str ":" ++
+ pr_type_v_v8 v ++ pr_effects e ++
+ pr_pre_condition_list prel ++ pr_post_condition_opt postl ++
+ spc () ++ str "end"
+ | TypePure a -> Ppconstrnew.pr_constr a
+ | v -> str "(" ++ pr_type_v_v8 v ++ str ")"
+
+and pr_binder = function
+ | (id,BindType c) ->
+ str "(" ++ pr_id id ++ str ":" ++ pr_type_v_v8 c ++ str ")"
+ | (id,BindSet) ->
+ str "(" ++ pr_id id ++ str ":" ++ str "Set" ++ str ")"
+ | (id,Untyped) ->
+ str "<<<<< TODO: Untyped binder >>>>"
+
+let _ =
+ Pptactic.declare_extra_genarg_pprule true
+ (rawwit_type_v, fun _ _ -> pr_type_v_v8)
+ (globwit_type_v, fun _ -> raise Not_found)
+ (wit_type_v, fun _ -> raise Not_found)
+
+(* Program printer *)
+
+let pr_precondition pred = str "{" ++ pr_assert true pred ++ str "}" ++ spc ()
+
+let pr_postcondition pred = str "{" ++ pr_predicate true pred ++ str "}"
+
+let pr_invariant = function
+ | None -> mt ()
+ | Some c -> hov 2 (str "invariant" ++ spc () ++ pr_predicate false c)
+
+let pr_variant (c1,c2) =
+ Ppconstrnew.pr_constr c1 ++
+ (try Constrextern.check_same_type c2 (ast_zwf_zero dummy_loc); mt ()
+ with _ -> spc() ++ hov 0 (str "for" ++ spc () ++ Ppconstrnew.pr_constr c2))
+
+let rec pr_desc = function
+ | Variable id ->
+ (* Unsafe: should distinguish global names and bound vars *)
+ let vars = (* TODO *) Idset.empty in
+ let id = try
+ snd (repr_qualid
+ (snd (qualid_of_reference
+ (Constrextern.extern_reference
+ dummy_loc vars (Nametab.locate (make_short_qualid id))))))
+ with _ -> id in
+ pr_id id
+ | Acc id -> str "!" ++ pr_id id
+ | Aff (id,p) -> pr_id id ++ spc() ++ str ":=" ++ spc() ++ pr_prog p
+ | TabAcc (b,id,p) -> pr_id id ++ str "[" ++ pr_prog p ++ str "]"
+ | TabAff (b,id,p1,p2) ->
+ pr_id id ++ str "[" ++ pr_prog p1 ++ str "]" ++
+ str ":=" ++ pr_prog p2
+ | Seq bll ->
+ hv 0 (str "begin" ++ spc () ++ pr_block bll ++ spc () ++ str "end")
+ | While (p1,inv,var,bll) ->
+ hv 0 (
+ hov 0 (str "while" ++ spc () ++ pr_prog p1 ++ spc () ++ str "do") ++
+ brk (1,2) ++
+ hv 2 (
+ str "{ " ++
+ pr_invariant inv ++ spc() ++
+ hov 0 (str "variant" ++ spc () ++ pr_variant var)
+ ++ str " }") ++ cut () ++
+ hov 0 (pr_block bll) ++ cut () ++
+ str "done")
+ | If (p1,p2,p3) ->
+ hov 1 (str "if " ++ pr_prog p1) ++ spc () ++
+ hov 0 (str "then" ++ spc () ++ pr_prog p2) ++ spc () ++
+ hov 0 (str "else" ++ spc () ++ pr_prog p3)
+ | Lam (bl,p) ->
+ hov 0
+ (str "fun" ++ spc () ++ hov 0 (prlist_with_sep cut pr_binder bl) ++
+ spc () ++ str "=>") ++
+ pr_prog p
+ | Apply ({desc=Expression e; pre=[]; post=None} as p,args) when isConst e ->
+ begin match
+ string_of_id (snd (repr_path (Nametab.sp_of_global (ConstRef (destConst e))))),
+ args
+ with
+ | "Zmult", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"*" ++ pr_arg a2 ++ str ")"
+ | "Zplus", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"+" ++ pr_arg a2 ++ str ")"
+ | "Zminus", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"-" ++ pr_arg a2 ++ str ")"
+ | "Zopp", [a] ->
+ str "( -" ++ pr_arg a ++ str ")"
+ | "Z_lt_ge_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"<" ++ pr_arg a2 ++ str ")"
+ | "Z_le_gt_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"<=" ++ pr_arg a2 ++ str ")"
+ | "Z_gt_le_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str">" ++ pr_arg a2 ++ str ")"
+ | "Z_ge_lt_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str">=" ++ pr_arg a2 ++ str ")"
+ | "Z_eq_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"=" ++ pr_arg a2 ++ str ")"
+ | "Z_noteq_bool", [a1;a2] ->
+ str "(" ++ pr_arg a1 ++ str"<> " ++ pr_arg a2 ++ str ")"
+ | _ ->
+ str "(" ++ pr_prog p ++ spc () ++ prlist_with_sep spc pr_arg args ++
+ str ")"
+ end
+ | Apply (p,args) ->
+ str "(" ++ pr_prog p ++ spc () ++ prlist_with_sep spc pr_arg args ++
+ str ")"
+ | SApp ([Variable v], args) ->
+ begin match string_of_id v, args with
+ | "prog_bool_and", [a1;a2] ->
+ str"(" ++ pr_prog a1 ++ spc() ++ str"and " ++ pr_prog a2 ++str")"
+ | "prog_bool_or", [a1;a2] ->
+ str"(" ++ pr_prog a1 ++ spc() ++ str"or " ++ pr_prog a2 ++ str")"
+ | "prog_bool_not", [a] ->
+ str "(not " ++ pr_prog a ++ str ")"
+ | _ -> failwith "Correctness printer: TODO"
+ end
+ | SApp _ -> failwith "Correctness printer: TODO"
+ | LetRef (v,p1,p2) ->
+ hov 2 (
+ str "let " ++ pr_id v ++ str " =" ++ spc () ++ str "ref" ++ spc () ++
+ pr_prog p1 ++ str " in") ++
+ spc () ++ pr_prog p2
+ | Let (id, {desc=LetRec (f,bl,v,var,p); pre=[]; post=None },p2) when f=id ->
+ hov 2 (
+ str "let rec " ++ pr_id f ++ spc () ++
+ hov 0 (prlist_with_sep cut pr_binder bl) ++ spc () ++
+ str ":" ++ pr_type_v_v8 v ++ spc () ++
+ hov 2 (str "{ variant" ++ spc () ++ pr_variant var ++ str " }") ++
+ spc() ++ str "=" ++ spc () ++ pr_prog p ++
+ str " in") ++
+ spc () ++ pr_prog p2
+ | Let (v,p1,p2) ->
+ hov 2 (
+ str "let " ++ pr_id v ++ str " =" ++ spc () ++ pr_prog p1 ++ str" in")
+ ++ spc () ++ pr_prog p2
+ | LetRec (f,bl,v,var,p) ->
+ str "let rec " ++ pr_id f ++ spc () ++
+ hov 0 (prlist_with_sep cut pr_binder bl) ++ spc () ++
+ str ":" ++ pr_type_v_v8 v ++ spc () ++
+ hov 2 (str "{ variant" ++ spc () ++ pr_variant var ++ str " }") ++
+ spc () ++ str "=" ++ spc () ++ pr_prog p
+ | PPoint _ -> str "TODO: Ppoint" (* Internal use only *)
+ | Expression c ->
+ (* Numeral or "tt": use a printer which doesn't globalize *)
+ Ppconstr.pr_constr
+ (Constrextern.extern_constr_in_scope false "Z_scope" (Global.env()) c)
+ | Debug (s,p) -> str "@" ++ Pptacticnew.qsnew s ++ pr_prog p
+
+and pr_block_st = function
+ | Label s -> hov 0 (str "label" ++ spc() ++ str s)
+ | Assert pred ->
+ hov 0 (str "assert" ++ spc() ++ hov 0 (pr_postcondition pred))
+ | Statement p -> pr_prog p
+
+and pr_block bl = prlist_with_sep pr_semicolon pr_block_st bl
+
+and pr_arg = function
+ | Past.Term p -> pr_prog p
+ | Past.Type t -> str "'" ++ pr_type_v_v8 t
+ | Refarg _ -> str "TODO: Refarg" (* Internal use only *)
+
+and pr_prog0 b { desc = desc; pre = pre; post = post } =
+ hv 0 (
+ prlist pr_precondition pre ++
+ hov 0
+ (if b & post<>None then str"(" ++ pr_desc desc ++ str")"
+ else pr_desc desc)
+ ++ Ppconstrnew.pr_opt pr_postcondition post)
+
+and pr_prog x = pr_prog0 true x
+
+let _ =
+ Pptactic.declare_extra_genarg_pprule true
+ (rawwit_program, fun _ _ a -> spc () ++ pr_prog0 false a)
+ (globwit_program, fun _ -> raise Not_found)
+ (wit_program, fun _ -> raise Not_found)
+
diff --git a/contrib/correctness/psyntax.mli b/contrib/correctness/psyntax.mli
new file mode 100644
index 00000000..18912548
--- /dev/null
+++ b/contrib/correctness/psyntax.mli
@@ -0,0 +1,25 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: psyntax.mli,v 1.3.2.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Pcoq
+open Ptype
+open Past
+open Topconstr
+
+(* Grammar for the programs and the tactic Correctness *)
+
+module Programs :
+ sig
+ val program : program Gram.Entry.e
+ val type_v : constr_expr ml_type_v Gram.Entry.e
+ val type_c : constr_expr ml_type_c Gram.Entry.e
+ end
diff --git a/contrib/correctness/ptactic.ml b/contrib/correctness/ptactic.ml
new file mode 100644
index 00000000..4b22954e
--- /dev/null
+++ b/contrib/correctness/ptactic.ml
@@ -0,0 +1,258 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ptactic.ml,v 1.30.2.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Pp
+open Options
+open Names
+open Libnames
+open Term
+open Pretyping
+open Pfedit
+open Decl_kinds
+open Vernacentries
+
+open Pmisc
+open Putil
+open Past
+open Penv
+open Prename
+open Peffect
+open Pmonad
+
+(* [coqast_of_prog: program -> constr * constr]
+ * Traduction d'un programme impératif en un but (second constr)
+ * et un terme de preuve partiel pour ce but (premier constr)
+ *)
+
+let coqast_of_prog p =
+ (* 1. db : séparation dB/var/const *)
+ let p = Pdb.db_prog p in
+
+ (* 2. typage avec effets *)
+ deb_mess (str"Ptyping.states: Typing with effects..." ++ fnl ());
+ let env = Penv.empty in
+ let ren = initial_renaming env in
+ let p = Ptyping.states ren env p in
+ let ((_,v),_,_,_) as c = p.info.kappa in
+ Perror.check_for_not_mutable p.loc v;
+ deb_print pp_type_c c;
+
+ (* 3. propagation annotations *)
+ let p = Pwp.propagate ren p in
+
+ (* 4a. traduction type *)
+ let ty = Pmonad.trad_ml_type_c ren env c in
+ deb_print (Printer.prterm_env (Global.env())) ty;
+
+ (* 4b. traduction terme (terme intermédiaire de type cc_term) *)
+ deb_mess
+ (fnl () ++ str"Mlize.trad: Translation program -> cc_term..." ++ fnl ());
+ let cc = Pmlize.trans ren p in
+ let cc = Pred.red cc in
+ deb_print Putil.pp_cc_term cc;
+
+ (* 5. traduction en constr *)
+ deb_mess
+ (fnl () ++ str"Pcic.constr_of_prog: Translation cc_term -> rawconstr..." ++
+ fnl ());
+ let r = Pcic.rawconstr_of_prog cc in
+ deb_print Printer.pr_rawterm r;
+
+ (* 6. résolution implicites *)
+ deb_mess (fnl () ++ str"Resolution implicits (? => Meta(n))..." ++ fnl ());
+ let oc = understand_gen_tcc Evd.empty (Global.env()) [] None r in
+ deb_print (Printer.prterm_env (Global.env())) (snd oc);
+
+ p,oc,ty,v
+
+(* [automatic : tactic]
+ *
+ * Certains buts engendrés par "correctness" (ci-dessous)
+ * sont réellement triviaux. On peut les résoudre aisément, sans pour autant
+ * tomber dans la solution trop lourde qui consiste ą faire "; Auto."
+ *
+ * Cette tactique fait les choses suivantes :
+ * o elle élimine les hypothčses de nom loop<i>
+ * o sur G |- (well_founded nat lt) ==> Exact lt_wf.
+ * o sur G |- (well_founded Z (Zwf c)) ==> Exact (Zwf_well_founded c)
+ * o sur G |- e = e' ==> Reflexivity. (arg. de decr. des boucles)
+ * sinon Try Assumption.
+ * o sur G |- P /\ Q ==> Try (Split; Assumption). (sortie de boucle)
+ * o sinon, Try AssumptionBis (= Assumption + décomposition /\ dans hyp.)
+ * (pour entrée dans corps de boucle par ex.)
+ *)
+
+open Pattern
+open Tacmach
+open Tactics
+open Tacticals
+open Equality
+open Nametab
+
+let nat = IndRef (coq_constant ["Init";"Datatypes"] "nat", 0)
+let lt = ConstRef (coq_constant ["Init";"Peano"] "lt")
+let well_founded = ConstRef (coq_constant ["Init";"Wf"] "well_founded")
+let z = IndRef (coq_constant ["ZArith";"BinInt"] "Z", 0)
+let and_ = IndRef (coq_constant ["Init";"Logic"] "and", 0)
+let eq = IndRef (coq_constant ["Init";"Logic"] "eq", 0)
+
+let mkmeta n = Nameops.make_ident "X" (Some n)
+let mkPMeta n = PMeta (Some (mkmeta n))
+
+(* ["(well_founded nat lt)"] *)
+let wf_nat_pattern =
+ PApp (PRef well_founded, [| PRef nat; PRef lt |])
+(* ["((well_founded Z (Zwf ?1))"] *)
+let wf_z_pattern =
+ let zwf = ConstRef (coq_constant ["ZArith";"Zwf"] "Zwf") in
+ PApp (PRef well_founded, [| PRef z; PApp (PRef zwf, [| mkPMeta 1 |]) |])
+(* ["(and ?1 ?2)"] *)
+let and_pattern =
+ PApp (PRef and_, [| mkPMeta 1; mkPMeta 2 |])
+(* ["(eq ?1 ?2 ?3)"] *)
+let eq_pattern =
+ PApp (PRef eq, [| mkPMeta 1; mkPMeta 2; mkPMeta 3 |])
+
+(* loop_ids: remove loop<i> hypotheses from the context, and rewrite
+ * using Variant<i> hypotheses when needed. *)
+
+let (loop_ids : tactic) = fun gl ->
+ let rec arec hyps gl =
+ let env = pf_env gl in
+ let concl = pf_concl gl in
+ match hyps with
+ | [] -> tclIDTAC gl
+ | (id,a) :: al ->
+ let s = string_of_id id in
+ let n = String.length s in
+ if n >= 4 & (let su = String.sub s 0 4 in su="loop" or su="Bool")
+ then
+ tclTHEN (clear [id]) (arec al) gl
+ else if n >= 7 & String.sub s 0 7 = "Variant" then begin
+ match pf_matches gl eq_pattern (body_of_type a) with
+ | [_; _,varphi; _] when isVar varphi ->
+ let phi = destVar varphi in
+ if Termops.occur_var env phi concl then
+ tclTHEN (rewriteLR (mkVar id)) (arec al) gl
+ else
+ arec al gl
+ | _ -> assert false end
+ else
+ arec al gl
+ in
+ arec (pf_hyps_types gl) gl
+
+(* assumption_bis: like assumption, but also solves ... h:A/\B ... |- A
+ * (resp. B) *)
+
+let (assumption_bis : tactic) = fun gl ->
+ let concl = pf_concl gl in
+ let rec arec = function
+ | [] -> Util.error "No such assumption"
+ | (s,a) :: al ->
+ let a = body_of_type a in
+ if pf_conv_x_leq gl a concl then
+ refine (mkVar s) gl
+ else if pf_is_matching gl and_pattern a then
+ match pf_matches gl and_pattern a with
+ | [_,c1; _,c2] ->
+ if pf_conv_x_leq gl c1 concl then
+ exact_check (applistc (constant "proj1") [c1;c2;mkVar s]) gl
+ else if pf_conv_x_leq gl c2 concl then
+ exact_check (applistc (constant "proj2") [c1;c2;mkVar s]) gl
+ else
+ arec al
+ | _ -> assert false
+ else
+ arec al
+ in
+ arec (pf_hyps_types gl)
+
+(* automatic: see above *)
+
+let (automatic : tactic) =
+ tclTHEN
+ loop_ids
+ (fun gl ->
+ let c = pf_concl gl in
+ if pf_is_matching gl wf_nat_pattern c then
+ exact_check (constant "lt_wf") gl
+ else if pf_is_matching gl wf_z_pattern c then
+ let (_,z) = List.hd (pf_matches gl wf_z_pattern c) in
+ exact_check (Term.applist (constant "Zwf_well_founded",[z])) gl
+ else if pf_is_matching gl and_pattern c then
+ (tclORELSE assumption_bis
+ (tclTRY (tclTHEN simplest_split assumption))) gl
+ else if pf_is_matching gl eq_pattern c then
+ (tclORELSE reflexivity (tclTRY assumption_bis)) gl
+ else
+ tclTRY assumption_bis gl)
+
+(* [correctness s p] : string -> program -> tactic option -> unit
+ *
+ * Vernac: Correctness <string> <program> [; <tactic>].
+ *)
+
+let reduce_open_constr (em0,c) =
+ let existential_map_of_constr =
+ let rec collect em c = match kind_of_term c with
+ | Cast (c',t) ->
+ (match kind_of_term c' with
+ | Evar (ev,_) ->
+ if not (Evd.in_dom em ev) then
+ Evd.add em ev (Evd.map em0 ev)
+ else
+ em
+ | _ -> fold_constr collect em c)
+ | Evar _ ->
+ assert false (* all existentials should be casted *)
+ | _ ->
+ fold_constr collect em c
+ in
+ collect Evd.empty
+ in
+ let c = Pred.red_cci c in
+ let em = existential_map_of_constr c in
+ (em,c)
+
+let register id n =
+ let id' = match n with None -> id | Some id' -> id' in
+ Penv.register id id'
+
+ (* On dit ą la commande "Save" d'enregistrer les nouveaux programmes *)
+let correctness_hook _ ref =
+ let pf_id = Nametab.id_of_global ref in
+ register pf_id None
+
+let correctness s p opttac =
+ Library.check_required_library ["Coq";"correctness";"Correctness"];
+ Pmisc.reset_names();
+ let p,oc,cty,v = coqast_of_prog p in
+ let env = Global.env () in
+ let sign = Global.named_context () in
+ let sigma = Evd.empty in
+ let cty = Reduction.nf_betaiota cty in
+ let id = id_of_string s in
+ start_proof id (IsGlobal (Proof Lemma)) sign cty correctness_hook;
+ Penv.new_edited id (v,p);
+ if !debug then msg (Pfedit.pr_open_subgoals());
+ deb_mess (str"Pred.red_cci: Reduction..." ++ fnl ());
+ let oc = reduce_open_constr oc in
+ deb_mess (str"AFTER REDUCTION:" ++ fnl ());
+ deb_print (Printer.prterm_env (Global.env())) (snd oc);
+ let tac = (tclTHEN (Extratactics.refine_tac oc) automatic) in
+ let tac = match opttac with
+ | None -> tac
+ | Some t -> tclTHEN tac t
+ in
+ solve_nth 1 tac;
+ if_verbose msg (pr_open_subgoals ())
diff --git a/contrib/correctness/ptactic.mli b/contrib/correctness/ptactic.mli
new file mode 100644
index 00000000..875e0780
--- /dev/null
+++ b/contrib/correctness/ptactic.mli
@@ -0,0 +1,22 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ptactic.mli,v 1.2.16.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+(* The main tactic: takes a name N, a program P, creates a goal
+ * of name N with the functional specification of P, then apply the Refine
+ * tactic with the partial proof term obtained by the translation of
+ * P into a functional program.
+ *
+ * Then an ad-hoc automatic tactic is applied on each subgoal to solve the
+ * trivial proof obligations *)
+
+val correctness : string -> Past.program -> Tacmach.tactic option -> unit
+
diff --git a/contrib/correctness/ptype.mli b/contrib/correctness/ptype.mli
new file mode 100644
index 00000000..f2dc85e3
--- /dev/null
+++ b/contrib/correctness/ptype.mli
@@ -0,0 +1,73 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ptype.mli,v 1.2.16.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Term
+
+(* Types des valeurs (V) et des calculs (C).
+ *
+ * On a C = r:V,E,P,Q
+ *
+ * et V = (x1:V1)...(xn:Vn)C | V ref | V array | <type pur>
+ *
+ * INVARIANT: l'effet E contient toutes les variables apparaissant dans
+ * le programme ET les annotations P et Q
+ * Si E = { x1,...,xn | y1,...,ym }, les variables x sont les
+ * variables en lecture seule et y1 les variables modifiées
+ * les xi sont libres dans P et Q, et les yi,result liées dans Q
+ * i.e. P = p(x)
+ * et Q = [y1]...[yn][res]q(x,y,res)
+ *)
+
+(* pre and post conditions *)
+
+type 'a precondition = { p_assert : bool; p_name : Names.name; p_value : 'a }
+
+type 'a assertion = { a_name : Names.name; a_value : 'a }
+
+type 'a postcondition = 'a assertion
+
+type predicate = constr assertion
+
+(* binders *)
+
+type 'a binder_type =
+ BindType of 'a
+ | BindSet
+ | Untyped
+
+type 'a binder = Names.identifier * 'a binder_type
+
+(* variant *)
+
+type variant = constr * constr * constr (* phi, R, A *)
+
+(* types des valeurs *)
+
+type 'a ml_type_v =
+ Ref of 'a ml_type_v
+ | Array of 'a * 'a ml_type_v (* size x type *)
+ | Arrow of 'a ml_type_v binder list * 'a ml_type_c
+
+ | TypePure of 'a
+
+(* et type des calculs *)
+
+and 'a ml_type_c =
+ (Names.identifier * 'a ml_type_v)
+ * Peffect.t
+ * ('a precondition list) * ('a postcondition option)
+
+(* at beginning they contain Coq AST but they become constr after typing *)
+type type_v = constr ml_type_v
+type type_c = constr ml_type_c
+
+
diff --git a/contrib/correctness/ptyping.ml b/contrib/correctness/ptyping.ml
new file mode 100644
index 00000000..9047a925
--- /dev/null
+++ b/contrib/correctness/ptyping.ml
@@ -0,0 +1,600 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ptyping.ml,v 1.7.6.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Pp
+open Util
+open Names
+open Term
+open Termops
+open Environ
+open Constrintern
+open Himsg
+open Proof_trees
+open Topconstr
+
+open Pmisc
+open Putil
+open Prename
+open Ptype
+open Past
+open Penv
+open Peffect
+open Pcicenv
+
+(* Ce module implante le jugement Gamma |-a e : kappa de la thčse.
+ * Les annotations passent du type CoqAst.t au type Term.constr ici.
+ * Les post-conditions sont abstraites par rapport au résultat. *)
+
+let simplify_type_of env sigma t =
+ Reductionops.nf_betaiota (Typing.type_of env sigma t)
+
+let just_reads e =
+ difference (get_reads e) (get_writes e)
+
+let type_v_sup loc t1 t2 =
+ if t1 = t2 then
+ t1
+ else
+ Perror.if_branches loc
+
+let typed_var ren env (phi,r) =
+ let sign = Pcicenv.before_after_sign_of ren env in
+ let a = simplify_type_of (Global.env_of_context sign) Evd.empty phi in
+ (phi,r,a)
+
+(* Application de fonction *)
+
+let rec convert = function
+ | (TypePure c1, TypePure c2) ->
+ Reductionops.is_conv (Global.env ()) Evd.empty c1 c2
+ | (Ref v1, Ref v2) ->
+ convert (v1,v2)
+ | (Array (s1,v1), Array (s2,v2)) ->
+ (Reductionops.is_conv (Global.env ()) Evd.empty s1 s2) && (convert (v1,v2))
+ | (v1,v2) -> v1 = v2
+
+let effect_app ren env f args =
+ let n = List.length args in
+ let tf =
+ let ((_,v),_,_,_) = f.info.kappa in
+ match v with TypePure c -> v_of_constr c | _ -> v
+ in
+ let bl,c =
+ match tf with
+ Arrow (bl, c) ->
+ if List.length bl <> n then Perror.partial_app f.loc;
+ bl,c
+ | _ -> Perror.app_of_non_function f.loc
+ in
+ let check_type loc v t so =
+ let v' = type_v_rsubst so v in
+ if not (convert (v',t)) then Perror.expected_type loc (pp_type_v v')
+ in
+ let s,so,ok =
+ (* s est la substitution des références, so celle des autres arg.
+ * ok nous dit si les arguments sont sans effet i.e. des expressions *)
+ List.fold_left
+ (fun (s,so,ok) (b,a) ->
+ match b,a with
+ (id,BindType (Ref _ | Array _ as v)), Refarg id' ->
+ let ta = type_in_env env id' in
+ check_type f.loc v ta so;
+ (id,id')::s, so, ok
+ | _, Refarg _ -> Perror.should_be_a_variable f.loc
+ | (id,BindType v), Term t ->
+ let ((_,ta),_,_,_) = t.info.kappa in
+ check_type t.loc v ta so;
+ (match t.desc with
+ Expression c -> s, (id,c)::so, ok
+ | _ -> s,so,false)
+ | (id,BindSet), Type v ->
+ let c = Pmonad.trad_ml_type_v ren env v in
+ s, (id,c)::so, ok
+ | (id,BindSet), Term t -> Perror.expects_a_type id t.loc
+ | (id,BindType _), Type _ -> Perror.expects_a_term id
+ | (_,Untyped), _ -> invalid_arg "effects_app")
+ ([],[],true)
+ (List.combine bl args)
+ in
+ let (id,v),ef,pre,post = type_c_subst s c in
+ (bl,c), (s,so,ok), ((id,type_v_rsubst so v),ef,pre,post)
+
+(* Execution of a Coq AST. Returns value and type.
+ * Also returns its variables *)
+
+let state_coq_ast sign a =
+ let env = Global.env_of_context sign in
+ let j =
+ reraise_with_loc (constr_loc a) (judgment_of_rawconstr Evd.empty env) a in
+ let ids = global_vars env j.uj_val in
+ j.uj_val, j.uj_type, ids
+
+(* [is_pure p] tests wether the program p is an expression or not. *)
+
+let type_of_expression ren env c =
+ let sign = now_sign_of ren env in
+ simplify_type_of (Global.env_of_context sign) Evd.empty c
+
+let rec is_pure_type_v = function
+ TypePure _ -> true
+ | Arrow (bl,c) -> List.for_all is_pure_arg bl & is_pure_type_c c
+ | Ref _ | Array _ -> false
+and is_pure_arg = function
+ (_,BindType v) -> is_pure_type_v v
+ | (_,BindSet) -> true
+ | (_,Untyped) -> false
+and is_pure_type_c = function
+ (_,v),_,[],None -> is_pure_type_v v
+ | _ -> false
+
+let rec is_pure_desc ren env = function
+ Variable id ->
+ not (is_in_env env id) or (is_pure_type_v (type_in_env env id))
+ | Expression c ->
+ (c = isevar) or (is_pure_cci (type_of_expression ren env c))
+ | Acc _ -> true
+ | TabAcc (_,_,p) -> is_pure ren env p
+ | Apply (p,args) ->
+ is_pure ren env p & List.for_all (is_pure_arg ren env) args
+ | SApp _ | Aff _ | TabAff _ | Seq _ | While _ | If _
+ | Lam _ | LetRef _ | Let _ | LetRec _ -> false
+ | Debug (_,p) -> is_pure ren env p
+ | PPoint (_,d) -> is_pure_desc ren env d
+and is_pure ren env p =
+ p.pre = [] & p.post = None & is_pure_desc ren env p.desc
+and is_pure_arg ren env = function
+ Term p -> is_pure ren env p
+ | Type _ -> true
+ | Refarg _ -> false
+
+(* [state_var ren env (phi,r)] returns a tuple (e,(phi',r'))
+ * where e is the effect of the variant phi and phi',r' the corresponding
+ * constr of phi and r.
+ *)
+
+let state_var ren env (phi,r) =
+ let sign = Pcicenv.before_after_sign_of ren env in
+ let phi',_,ids = state_coq_ast sign phi in
+ let ef = List.fold_left
+ (fun e id ->
+ if is_mutable_in_env env id then Peffect.add_read id e else e)
+ Peffect.bottom ids in
+ let r',_,_ = state_coq_ast (Global.named_context ()) r in
+ ef,(phi',r')
+
+(* [state_pre ren env pl] returns a pair (e,c) where e is the effect of the
+ * pre-conditions list pl and cl the corresponding constrs not yet abstracted
+ * over the variables xi (i.e. c NOT [x1]...[xn]c !)
+ *)
+
+let state_pre ren env pl =
+ let state e p =
+ let sign = Pcicenv.before_sign_of ren env in
+ let cc,_,ids = state_coq_ast sign p.p_value in
+ let ef = List.fold_left
+ (fun e id ->
+ if is_mutable_in_env env id then
+ Peffect.add_read id e
+ else if is_at id then
+ let uid,_ = un_at id in
+ if is_mutable_in_env env uid then
+ Peffect.add_read uid e
+ else
+ e
+ else
+ e)
+ e ids
+ in
+ ef,{ p_assert = p.p_assert; p_name = p.p_name; p_value = cc }
+ in
+ List.fold_left
+ (fun (e,cl) p -> let ef,c = state e p in (ef,c::cl))
+ (Peffect.bottom,[]) pl
+
+let state_assert ren env a =
+ let p = pre_of_assert true a in
+ let e,l = state_pre ren env [p] in
+ e,assert_of_pre (List.hd l)
+
+let state_inv ren env = function
+ None -> Peffect.bottom, None
+ | Some i -> let e,p = state_assert ren env i in e,Some p
+
+(* [state_post ren env (id,v,ef) q] returns a pair (e,c)
+ * where e is the effect of the
+ * post-condition q and c the corresponding constr not yet abstracted
+ * over the variables xi, yi and result.
+ * Moreover the RW variables not appearing in ef have been replaced by
+ * RO variables, and (id,v) is the result
+ *)
+
+let state_post ren env (id,v,ef) = function
+ None -> Peffect.bottom, None
+ | Some q ->
+ let v' = Pmonad.trad_ml_type_v ren env v in
+ let sign = Pcicenv.before_after_result_sign_of (Some (id,v')) ren env in
+ let cc,_,ids = state_coq_ast sign q.a_value in
+ let ef,c =
+ List.fold_left
+ (fun (e,c) id ->
+ if is_mutable_in_env env id then
+ if is_write ef id then
+ Peffect.add_write id e, c
+ else
+ Peffect.add_read id e,
+ subst_in_constr [id,at_id id ""] c
+ else if is_at id then
+ let uid,_ = un_at id in
+ if is_mutable_in_env env uid then
+ Peffect.add_read uid e, c
+ else
+ e,c
+ else
+ e,c)
+ (Peffect.bottom,cc) ids
+ in
+ let c = abstract [id,v'] c in
+ ef, Some { a_name = q.a_name; a_value = c }
+
+(* transformation of AST into constr in types V and C *)
+
+let rec cic_type_v env ren = function
+ | Ref v -> Ref (cic_type_v env ren v)
+ | Array (com,v) ->
+ let sign = Pcicenv.now_sign_of ren env in
+ let c = interp_constr Evd.empty (Global.env_of_context sign) com in
+ Array (c, cic_type_v env ren v)
+ | Arrow (bl,c) ->
+ let bl',ren',env' =
+ List.fold_left
+ (fun (bl,ren,env) b ->
+ let b' = cic_binder env ren b in
+ let env' = traverse_binders env [b'] in
+ let ren' = initial_renaming env' in
+ b'::bl,ren',env')
+ ([],ren,env) bl
+ in
+ let c' = cic_type_c env' ren' c in
+ Arrow (List.rev bl',c')
+ | TypePure com ->
+ let sign = Pcicenv.cci_sign_of ren env in
+ let c = interp_constr Evd.empty (Global.env_of_context sign) com in
+ TypePure c
+
+and cic_type_c env ren ((id,v),e,p,q) =
+ let v' = cic_type_v env ren v in
+ let cv = Pmonad.trad_ml_type_v ren env v' in
+ let efp,p' = state_pre ren env p in
+ let efq,q' = state_post ren env (id,v',e) q in
+ let ef = Peffect.union e (Peffect.union efp efq) in
+ ((id,v'),ef,p',q')
+
+and cic_binder env ren = function
+ | (id,BindType v) ->
+ let v' = cic_type_v env ren v in
+ let env' = add (id,v') env in
+ let ren' = initial_renaming env' in
+ (id, BindType v')
+ | (id,BindSet) -> (id,BindSet)
+ | (id,Untyped) -> (id,Untyped)
+
+and cic_binders env ren = function
+ [] -> []
+ | b::bl ->
+ let b' = cic_binder env ren b in
+ let env' = traverse_binders env [b'] in
+ let ren' = initial_renaming env' in
+ b' :: (cic_binders env' ren' bl)
+
+
+(* The case of expressions.
+ *
+ * Expressions are programs without neither effects nor pre/post conditions.
+ * But access to variables are allowed.
+ *
+ * Here we transform an expression into the corresponding constr,
+ * the variables still appearing as VAR (they will be abstracted in
+ * Mlise.trad)
+ * We collect the pre-conditions (e<N for t[e]) as we traverse the term.
+ * We also return the effect, which does contain only *read* variables.
+ *)
+
+let states_expression ren env expr =
+ let rec effect pl = function
+ | Variable id ->
+ (if is_global id then constant (string_of_id id) else mkVar id),
+ pl, Peffect.bottom
+ | Expression c -> c, pl, Peffect.bottom
+ | Acc id -> mkVar id, pl, Peffect.add_read id Peffect.bottom
+ | TabAcc (_,id,p) ->
+ let c,pl,ef = effect pl p.desc in
+ let pre = Pmonad.make_pre_access ren env id c in
+ Pmonad.make_raw_access ren env (id,id) c,
+ (anonymous_pre true pre)::pl, Peffect.add_read id ef
+ | Apply (p,args) ->
+ let a,pl,e = effect pl p.desc in
+ let args,pl,e =
+ List.fold_right
+ (fun arg (l,pl,e) ->
+ match arg with
+ Term p ->
+ let carg,pl,earg = effect pl p.desc in
+ carg::l,pl,Peffect.union e earg
+ | Type v ->
+ let v' = cic_type_v env ren v in
+ (Pmonad.trad_ml_type_v ren env v')::l,pl,e
+ | Refarg _ -> assert false)
+ args ([],pl,e)
+ in
+ Term.applist (a,args),pl,e
+ | _ -> invalid_arg "Ptyping.states_expression"
+ in
+ let e0,pl0 = state_pre ren env expr.pre in
+ let c,pl,e = effect [] expr.desc in
+ let sign = Pcicenv.before_sign_of ren env in
+ (*i WAS
+ let c = (Trad.ise_resolve true empty_evd [] (gLOB sign) c)._VAL in
+ i*)
+ let ty = simplify_type_of (Global.env_of_context sign) Evd.empty c in
+ let v = TypePure ty in
+ let ef = Peffect.union e0 e in
+ Expression c, (v,ef), pl0@pl
+
+
+(* We infer here the type with effects.
+ * The type of types with effects (ml_type_c) is defined in the module ProgAst.
+ *
+ * A program of the shape {P} e {Q} has a type
+ *
+ * V, E, {None|Some P}, {None|Some Q}
+ *
+ * where - V is the type of e
+ * - E = (I,O) is the effect; the input I contains
+ * all the input variables appearing in P,e and Q;
+ * the output O contains variables possibly modified in e
+ * - P is NOT abstracted
+ * - Q = [y'1]...[y'k][result]Q where O = {y'j}
+ * i.e. Q is only abstracted over the output and the result
+ * the other variables now refer to value BEFORE
+ *)
+
+let verbose_fix = ref false
+
+let rec states_desc ren env loc = function
+
+ Expression c ->
+ let ty = type_of_expression ren env c in
+ let v = v_of_constr ty in
+ Expression c, (v,Peffect.bottom)
+
+ | Acc _ ->
+ failwith "Ptyping.states: term is supposed not to be pure"
+
+ | Variable id ->
+ let v = type_in_env env id in
+ let ef = Peffect.bottom in
+ Variable id, (v,ef)
+
+ | Aff (x, e1) ->
+ Perror.check_for_reference loc x (type_in_env env x);
+ let s_e1 = states ren env e1 in
+ let _,e,_,_ = s_e1.info.kappa in
+ let ef = add_write x e in
+ let v = constant_unit () in
+ Aff (x, s_e1), (v, ef)
+
+ | TabAcc (check, x, e) ->
+ let s_e = states ren env e in
+ let _,efe,_,_ = s_e.info.kappa in
+ let ef = Peffect.add_read x efe in
+ let _,ty = dearray_type (type_in_env env x) in
+ TabAcc (check, x, s_e), (ty, ef)
+
+ | TabAff (check, x, e1, e2) ->
+ let s_e1 = states ren env e1 in
+ let s_e2 = states ren env e2 in
+ let _,ef1,_,_ = s_e1.info.kappa in
+ let _,ef2,_,_ = s_e2.info.kappa in
+ let ef = Peffect.add_write x (Peffect.union ef1 ef2) in
+ let v = constant_unit () in
+ TabAff (check, x, s_e1, s_e2), (v,ef)
+
+ | Seq bl ->
+ let bl,v,ef,_ = states_block ren env bl in
+ Seq bl, (v,ef)
+
+ | While(b, invopt, var, bl) ->
+ let efphi,(cvar,r') = state_var ren env var in
+ let ren' = next ren [] in
+ let s_b = states ren' env b in
+ let s_bl,_,ef_bl,_ = states_block ren' env bl in
+ let cb = s_b.info.kappa in
+ let efinv,inv = state_inv ren env invopt in
+ let _,efb,_,_ = s_b.info.kappa in
+ let ef =
+ Peffect.union (Peffect.union ef_bl efb) (Peffect.union efinv efphi)
+ in
+ let v = constant_unit () in
+ let cvar =
+ let al = List.map (fun id -> (id,at_id id "")) (just_reads ef) in
+ subst_in_constr al cvar
+ in
+ While (s_b,inv,(cvar,r'),s_bl), (v,ef)
+
+ | Lam ([],_) ->
+ failwith "Ptyping.states: abs. should have almost one binder"
+
+ | Lam (bl, e) ->
+ let bl' = cic_binders env ren bl in
+ let env' = traverse_binders env bl' in
+ let ren' = initial_renaming env' in
+ let s_e = states ren' env' e in
+ let v = make_arrow bl' s_e.info.kappa in
+ let ef = Peffect.bottom in
+ Lam(bl',s_e), (v,ef)
+
+ (* Connectives AND and OR *)
+ | SApp ([Variable id], [e1;e2]) ->
+ let s_e1 = states ren env e1
+ and s_e2 = states ren env e2 in
+ let (_,ef1,_,_) = s_e1.info.kappa
+ and (_,ef2,_,_) = s_e2.info.kappa in
+ let ef = Peffect.union ef1 ef2 in
+ SApp ([Variable id], [s_e1; s_e2]),
+ (TypePure (constant "bool"), ef)
+
+ (* Connective NOT *)
+ | SApp ([Variable id], [e]) ->
+ let s_e = states ren env e in
+ let (_,ef,_,_) = s_e.info.kappa in
+ SApp ([Variable id], [s_e]),
+ (TypePure (constant "bool"), ef)
+
+ | SApp _ -> invalid_arg "Ptyping.states (SApp)"
+
+ (* ATTENTION:
+ Si un argument réel de type ref. correspond ą une ref. globale
+ modifiée par la fonction alors la traduction ne sera pas correcte.
+ Exemple:
+ f=[x:ref Int]( r := !r+1 ; x := !x+1) modifie r et son argument x
+ donc si on l'applique ą r justement, elle ne modifiera que r
+ mais le séquencement ne sera pas correct. *)
+
+ | Apply (f, args) ->
+ let s_f = states ren env f in
+ let _,eff,_,_ = s_f.info.kappa in
+ let s_args = List.map (states_arg ren env) args in
+ let ef_args =
+ List.map
+ (function Term t -> let (_,e,_,_) = t.info.kappa in e
+ | _ -> Peffect.bottom)
+ s_args
+ in
+ let _,_,((_,tapp),efapp,_,_) = effect_app ren env s_f s_args in
+ let ef =
+ Peffect.compose (List.fold_left Peffect.compose eff ef_args) efapp
+ in
+ Apply (s_f, s_args), (tapp, ef)
+
+ | LetRef (x, e1, e2) ->
+ let s_e1 = states ren env e1 in
+ let (_,v1),ef1,_,_ = s_e1.info.kappa in
+ let env' = add (x,Ref v1) env in
+ let ren' = next ren [x] in
+ let s_e2 = states ren' env' e2 in
+ let (_,v2),ef2,_,_ = s_e2.info.kappa in
+ Perror.check_for_let_ref loc v2;
+ let ef = Peffect.compose ef1 (Peffect.remove ef2 x) in
+ LetRef (x, s_e1, s_e2), (v2,ef)
+
+ | Let (x, e1, e2) ->
+ let s_e1 = states ren env e1 in
+ let (_,v1),ef1,_,_ = s_e1.info.kappa in
+ Perror.check_for_not_mutable e1.loc v1;
+ let env' = add (x,v1) env in
+ let s_e2 = states ren env' e2 in
+ let (_,v2),ef2,_,_ = s_e2.info.kappa in
+ let ef = Peffect.compose ef1 ef2 in
+ Let (x, s_e1, s_e2), (v2,ef)
+
+ | If (b, e1, e2) ->
+ let s_b = states ren env b in
+ let s_e1 = states ren env e1
+ and s_e2 = states ren env e2 in
+ let (_,tb),efb,_,_ = s_b.info.kappa in
+ let (_,t1),ef1,_,_ = s_e1.info.kappa in
+ let (_,t2),ef2,_,_ = s_e2.info.kappa in
+ let ef = Peffect.compose efb (disj ef1 ef2) in
+ let v = type_v_sup loc t1 t2 in
+ If (s_b, s_e1, s_e2), (v,ef)
+
+ | LetRec (f,bl,v,var,e) ->
+ let bl' = cic_binders env ren bl in
+ let env' = traverse_binders env bl' in
+ let ren' = initial_renaming env' in
+ let v' = cic_type_v env' ren' v in
+ let efvar,var' = state_var ren' env' var in
+ let phi0 = phi_name () in
+ let tvar = typed_var ren env' var' in
+ (* effect for a let/rec construct is computed as a fixpoint *)
+ let rec state_rec c =
+ let tf = make_arrow bl' c in
+ let env'' = add_recursion (f,(phi0,tvar)) (add (f,tf) env') in
+ let s_e = states ren' env'' e in
+ if s_e.info.kappa = c then
+ s_e
+ else begin
+ if !verbose_fix then begin msgnl (pp_type_c s_e.info.kappa) end ;
+ state_rec s_e.info.kappa
+ end
+ in
+ let s_e = state_rec ((result_id,v'),efvar,[],None) in
+ let tf = make_arrow bl' s_e.info.kappa in
+ LetRec (f,bl',v',var',s_e), (tf,Peffect.bottom)
+
+ | PPoint (s,d) ->
+ let ren' = push_date ren s in
+ states_desc ren' env loc d
+
+ | Debug _ -> failwith "Ptyping.states: Debug: TODO"
+
+
+and states_arg ren env = function
+ Term a -> let s_a = states ren env a in Term s_a
+ | Refarg id -> Refarg id
+ | Type v -> let v' = cic_type_v env ren v in Type v'
+
+
+and states ren env expr =
+ (* Here we deal with the pre- and post- conditions:
+ * we add their effects to the effects of the program *)
+ let (d,(v,e),p1) =
+ if is_pure_desc ren env expr.desc then
+ states_expression ren env expr
+ else
+ let (d,ve) = states_desc ren env expr.loc expr.desc in (d,ve,[])
+ in
+ let (ep,p) = state_pre ren env expr.pre in
+ let (eq,q) = state_post ren env (result_id,v,e) expr.post in
+ let e' = Peffect.union e (Peffect.union ep eq) in
+ let p' = p1 @ p in
+ let tinfo = { env = env; kappa = ((result_id,v),e',p',q) } in
+ { desc = d;
+ loc = expr.loc;
+ pre = p'; post = q; (* on les conserve aussi ici pour prog_wp *)
+ info = tinfo }
+
+
+and states_block ren env bl =
+ let rec ef_block ren tyres = function
+ [] ->
+ begin match tyres with
+ Some ty -> [],ty,Peffect.bottom,ren
+ | None -> failwith "a block should contain at least one statement"
+ end
+ | (Assert p)::block ->
+ let ep,c = state_assert ren env p in
+ let bl,t,ef,ren' = ef_block ren tyres block in
+ (Assert c)::bl,t,Peffect.union ep ef,ren'
+ | (Label s)::block ->
+ let ren' = push_date ren s in
+ let bl,t,ef,ren'' = ef_block ren' tyres block in
+ (Label s)::bl,t,ef,ren''
+ | (Statement e)::block ->
+ let s_e = states ren env e in
+ let (_,t),efe,_,_ = s_e.info.kappa in
+ let ren' = next ren (get_writes efe) in
+ let bl,t,ef,ren'' = ef_block ren' (Some t) block in
+ (Statement s_e)::bl,t,Peffect.compose efe ef,ren''
+ in
+ ef_block ren None bl
+
diff --git a/contrib/correctness/ptyping.mli b/contrib/correctness/ptyping.mli
new file mode 100644
index 00000000..0c0d5905
--- /dev/null
+++ b/contrib/correctness/ptyping.mli
@@ -0,0 +1,36 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: ptyping.mli,v 1.3.6.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Names
+open Term
+open Topconstr
+
+open Ptype
+open Past
+open Penv
+
+(* This module realizes type and effect inference *)
+
+val cic_type_v : local_env -> Prename.t -> constr_expr ml_type_v -> type_v
+
+val effect_app : Prename.t -> local_env
+ -> (typing_info,'b) Past.t
+ -> (typing_info,constr) arg list
+ -> (type_v binder list * type_c)
+ * ((identifier*identifier) list * (identifier*constr) list * bool)
+ * type_c
+
+val typed_var : Prename.t -> local_env -> constr * constr -> variant
+
+val type_of_expression : Prename.t -> local_env -> constr -> constr
+
+val states : Prename.t -> local_env -> program -> typed_program
diff --git a/contrib/correctness/putil.ml b/contrib/correctness/putil.ml
new file mode 100644
index 00000000..48f0781a
--- /dev/null
+++ b/contrib/correctness/putil.ml
@@ -0,0 +1,303 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: putil.ml,v 1.10.2.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Util
+open Names
+open Nameops
+open Term
+open Termops
+open Pattern
+open Matching
+open Hipattern
+open Environ
+
+open Pmisc
+open Ptype
+open Past
+open Penv
+open Prename
+
+let is_mutable = function Ref _ | Array _ -> true | _ -> false
+let is_pure = function TypePure _ -> true | _ -> false
+
+let named_app f x = { a_name = x.a_name; a_value = (f x.a_value) }
+
+let pre_app f x =
+ { p_assert = x.p_assert; p_name = x.p_name; p_value = f x.p_value }
+
+let post_app = named_app
+
+let anonymous x = { a_name = Anonymous; a_value = x }
+
+let anonymous_pre b x = { p_assert = b; p_name = Anonymous; p_value = x }
+
+let force_name f x =
+ option_app (fun q -> { a_name = Name (f q.a_name); a_value = q.a_value }) x
+
+let force_post_name x = force_name post_name x
+
+let force_bool_name x =
+ force_name (function Name id -> id | Anonymous -> bool_name()) x
+
+let out_post = function
+ Some { a_value = x } -> x
+ | None -> invalid_arg "out_post"
+
+let pre_of_assert b x =
+ { p_assert = b; p_name = x.a_name; p_value = x.a_value }
+
+let assert_of_pre x =
+ { a_name = x.p_name; a_value = x.p_value }
+
+(* Some generic functions on programs *)
+
+let is_mutable_in_env env id =
+ (is_in_env env id) & (is_mutable (type_in_env env id))
+
+let now_vars env c =
+ Util.map_succeed
+ (function id -> if is_mutable_in_env env id then id else failwith "caught")
+ (global_vars (Global.env()) c)
+
+let make_before_after c =
+ let ids = global_vars (Global.env()) c in
+ let al =
+ Util.map_succeed
+ (function id ->
+ if is_at id then
+ match un_at id with (uid,"") -> (id,uid) | _ -> failwith "caught"
+ else failwith "caught")
+ ids
+ in
+ subst_in_constr al c
+
+(* [apply_pre] and [apply_post] instantiate pre- and post- conditions
+ * according to a given renaming of variables (and a date that means
+ * `before' in the case of the post-condition).
+ *)
+
+let make_assoc_list ren env on_prime ids =
+ List.fold_left
+ (fun al id ->
+ if is_mutable_in_env env id then
+ (id,current_var ren id)::al
+ else if is_at id then
+ let uid,d = un_at id in
+ if is_mutable_in_env env uid then
+ (match d with
+ "" -> (id,on_prime ren uid)
+ | _ -> (id,var_at_date ren d uid))::al
+ else
+ al
+ else
+ al)
+ [] ids
+
+let apply_pre ren env c =
+ let ids = global_vars (Global.env()) c.p_value in
+ let al = make_assoc_list ren env current_var ids in
+ { p_assert = c.p_assert; p_name = c.p_name;
+ p_value = subst_in_constr al c.p_value }
+
+let apply_assert ren env c =
+ let ids = global_vars (Global.env()) c.a_value in
+ let al = make_assoc_list ren env current_var ids in
+ { a_name = c.a_name; a_value = subst_in_constr al c.a_value }
+
+let apply_post ren env before c =
+ let ids = global_vars (Global.env()) c.a_value in
+ let al =
+ make_assoc_list ren env (fun r uid -> var_at_date r before uid) ids in
+ { a_name = c.a_name; a_value = subst_in_constr al c.a_value }
+
+(* [traverse_binder ren env bl] updates renaming [ren] and environment [env]
+ * as we cross the binders [bl]
+ *)
+
+let rec traverse_binders env = function
+ [] -> env
+ | (id,BindType v)::rem ->
+ traverse_binders (add (id,v) env) rem
+ | (id,BindSet)::rem ->
+ traverse_binders (add_set id env) rem
+ | (_,Untyped)::_ ->
+ invalid_arg "traverse_binders"
+
+let initial_renaming env =
+ let ids = Penv.fold_all (fun (id,_) l -> id::l) env [] in
+ update empty_ren "0" ids
+
+
+(* Substitutions *)
+
+let rec type_c_subst s ((id,t),e,p,q) =
+ let s' = s @ List.map (fun (x,x') -> (at_id x "", at_id x' "")) s in
+ (id, type_v_subst s t), Peffect.subst s e,
+ List.map (pre_app (subst_in_constr s)) p,
+ option_app (post_app (subst_in_constr s')) q
+
+and type_v_subst s = function
+ Ref v -> Ref (type_v_subst s v)
+ | Array (n,v) -> Array (n,type_v_subst s v)
+ | Arrow (bl,c) -> Arrow(List.map (binder_subst s) bl, type_c_subst s c)
+ | (TypePure _) as v -> v
+
+and binder_subst s = function
+ (n, BindType v) -> (n, BindType (type_v_subst s v))
+ | b -> b
+
+(* substitution of constr by others *)
+
+let rec type_c_rsubst s ((id,t),e,p,q) =
+ (id, type_v_rsubst s t), e,
+ List.map (pre_app (real_subst_in_constr s)) p,
+ option_app (post_app (real_subst_in_constr s)) q
+
+and type_v_rsubst s = function
+ Ref v -> Ref (type_v_rsubst s v)
+ | Array (n,v) -> Array (real_subst_in_constr s n,type_v_rsubst s v)
+ | Arrow (bl,c) -> Arrow(List.map (binder_rsubst s) bl, type_c_rsubst s c)
+ | TypePure c -> TypePure (real_subst_in_constr s c)
+
+and binder_rsubst s = function
+ | (n, BindType v) -> (n, BindType (type_v_rsubst s v))
+ | b -> b
+
+(* make_arrow bl c = (x1:V1)...(xn:Vn)c *)
+
+let make_arrow bl c = match bl with
+ | [] -> invalid_arg "make_arrow: no binder"
+ | _ -> Arrow (bl,c)
+
+(* misc. functions *)
+
+let deref_type = function
+ | Ref v -> v
+ | _ -> invalid_arg "deref_type"
+
+let dearray_type = function
+ | Array (size,v) -> size,v
+ | _ -> invalid_arg "dearray_type"
+
+let constant_unit () = TypePure (constant "unit")
+
+let id_from_name = function Name id -> id | Anonymous -> (id_of_string "X")
+
+(* v_of_constr : traduit un type CCI en un type ML *)
+
+(* TODO: faire un test plus serieux sur le type des objets Coq *)
+let rec is_pure_cci c = match kind_of_term c with
+ | Cast (c,_) -> is_pure_cci c
+ | Prod(_,_,c') -> is_pure_cci c'
+ | Rel _ | Ind _ | Const _ -> true (* heu... *)
+ | App _ -> not (is_matching_sigma c)
+ | _ -> Util.error "CCI term not acceptable in programs"
+
+let rec v_of_constr c = match kind_of_term c with
+ | Cast (c,_) -> v_of_constr c
+ | Prod _ ->
+ let revbl,t2 = Term.decompose_prod c in
+ let bl =
+ List.map
+ (fun (name,t1) -> (id_from_name name, BindType (v_of_constr t1)))
+ (List.rev revbl)
+ in
+ let vars = List.rev (List.map (fun (id,_) -> mkVar id) bl) in
+ Arrow (bl, c_of_constr (substl vars t2))
+ | Ind _ | Const _ | App _ ->
+ TypePure c
+ | _ ->
+ failwith "v_of_constr: TODO"
+
+and c_of_constr c =
+ if is_matching_sigma c then
+ let (a,q) = match_sigma c in
+ (result_id, v_of_constr a), Peffect.bottom, [], Some (anonymous q)
+ else
+ (result_id, v_of_constr c), Peffect.bottom, [], None
+
+
+(* pretty printers (for debugging purposes) *)
+
+open Pp
+open Util
+
+let prterm x = Printer.prterm_env (Global.env()) x
+
+let pp_pre = function
+ [] -> (mt ())
+ | l ->
+ hov 0 (str"pre " ++
+ prlist_with_sep (fun () -> (spc ()))
+ (fun x -> prterm x.p_value) l)
+
+let pp_post = function
+ None -> (mt ())
+ | Some c -> hov 0 (str"post " ++ prterm c.a_value)
+
+let rec pp_type_v = function
+ Ref v -> hov 0 (pp_type_v v ++ spc () ++ str"ref")
+ | Array (cc,v) -> hov 0 (str"array " ++ prterm cc ++ str" of " ++ pp_type_v v)
+ | Arrow (b,c) ->
+ hov 0 (prlist_with_sep (fun () -> (mt ())) pp_binder b ++
+ pp_type_c c)
+ | TypePure c -> prterm c
+
+and pp_type_c ((id,v),e,p,q) =
+ hov 0 (str"returns " ++ pr_id id ++ str":" ++ pp_type_v v ++ spc () ++
+ Peffect.pp e ++ spc () ++ pp_pre p ++ spc () ++ pp_post q ++
+ spc () ++ str"end")
+
+and pp_binder = function
+ id,BindType v -> (str"(" ++ pr_id id ++ str":" ++ pp_type_v v ++ str")")
+ | id,BindSet -> (str"(" ++ pr_id id ++ str":Set)")
+ | id,Untyped -> (str"(" ++ pr_id id ++ str")")
+
+(* pretty-print of cc-terms (intermediate terms) *)
+
+let rec pp_cc_term = function
+ CC_var id -> pr_id id
+ | CC_letin (_,_,bl,c,c1) ->
+ hov 0 (hov 2 (str"let " ++
+ prlist_with_sep (fun () -> (str","))
+ (fun (id,_) -> pr_id id) bl ++
+ str" =" ++ spc () ++
+ pp_cc_term c ++
+ str " in") ++
+ fnl () ++
+ pp_cc_term c1)
+ | CC_lam (bl,c) ->
+ hov 2 (prlist (fun (id,_) -> (str"[" ++ pr_id id ++ str"]")) bl ++
+ cut () ++
+ pp_cc_term c)
+ | CC_app (f,args) ->
+ hov 2 (str"(" ++
+ pp_cc_term f ++ spc () ++
+ prlist_with_sep (fun () -> (spc ())) pp_cc_term args ++
+ str")")
+ | CC_tuple (_,_,cl) ->
+ hov 2 (str"(" ++
+ prlist_with_sep (fun () -> (str"," ++ cut ()))
+ pp_cc_term cl ++
+ str")")
+ | CC_case (_,b,[e1;e2]) ->
+ hov 0 (str"if " ++ pp_cc_term b ++ str" then" ++ fnl () ++
+ str" " ++ hov 0 (pp_cc_term e1) ++ fnl () ++
+ str"else" ++ fnl () ++
+ str" " ++ hov 0 (pp_cc_term e2))
+ | CC_case _ ->
+ hov 0 (str"<Case: not yet implemented>")
+ | CC_expr c ->
+ hov 0 (prterm c)
+ | CC_hole c ->
+ (str"(?::" ++ prterm c ++ str")")
+
diff --git a/contrib/correctness/putil.mli b/contrib/correctness/putil.mli
new file mode 100644
index 00000000..b44774ae
--- /dev/null
+++ b/contrib/correctness/putil.mli
@@ -0,0 +1,72 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: putil.mli,v 1.3.2.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Pp
+open Names
+open Term
+open Pmisc
+open Ptype
+open Past
+open Penv
+
+val is_mutable : 'a ml_type_v -> bool
+val is_pure : 'a ml_type_v -> bool
+
+val named_app : ('a -> 'b) -> 'a assertion -> 'b assertion
+val pre_app : ('a -> 'b) -> 'a precondition -> 'b precondition
+val post_app : ('a -> 'b) -> 'a postcondition -> 'b postcondition
+
+val anonymous : 'a -> 'a assertion
+val anonymous_pre : bool -> 'a -> 'a precondition
+val out_post : 'a postcondition option -> 'a
+val pre_of_assert : bool -> 'a assertion -> 'a precondition
+val assert_of_pre : 'a precondition -> 'a assertion
+
+val force_post_name : 'a postcondition option -> 'a postcondition option
+val force_bool_name : 'a postcondition option -> 'a postcondition option
+
+val make_before_after : constr -> constr
+
+val traverse_binders : local_env -> (type_v binder) list -> local_env
+val initial_renaming : local_env -> Prename.t
+
+val apply_pre : Prename.t -> local_env -> constr precondition ->
+ constr precondition
+val apply_post : Prename.t -> local_env -> string -> constr postcondition ->
+ constr postcondition
+val apply_assert : Prename.t -> local_env -> constr assertion ->
+ constr assertion
+
+val type_v_subst : (identifier * identifier) list -> type_v -> type_v
+val type_c_subst : (identifier * identifier) list -> type_c -> type_c
+
+val type_v_rsubst : (identifier * constr) list -> type_v -> type_v
+val type_c_rsubst : (identifier * constr) list -> type_c -> type_c
+
+val make_arrow : ('a ml_type_v binder) list -> 'a ml_type_c -> 'a ml_type_v
+
+val is_mutable_in_env : local_env -> identifier -> bool
+val now_vars : local_env -> constr -> identifier list
+
+val deref_type : 'a ml_type_v -> 'a ml_type_v
+val dearray_type : 'a ml_type_v -> 'a * 'a ml_type_v
+val constant_unit : unit -> constr ml_type_v
+val v_of_constr : constr -> constr ml_type_v
+val c_of_constr : constr -> constr ml_type_c
+val is_pure_cci : constr -> bool
+
+(* pretty printers *)
+
+val pp_type_v : type_v -> std_ppcmds
+val pp_type_c : type_c -> std_ppcmds
+val pp_cc_term : cc_term -> std_ppcmds
+
diff --git a/contrib/correctness/pwp.ml b/contrib/correctness/pwp.ml
new file mode 100644
index 00000000..58bef673
--- /dev/null
+++ b/contrib/correctness/pwp.ml
@@ -0,0 +1,347 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pwp.ml,v 1.8.2.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Util
+open Names
+open Libnames
+open Term
+open Termops
+open Environ
+open Nametab
+
+open Pmisc
+open Ptype
+open Past
+open Putil
+open Penv
+open Peffect
+open Ptyping
+open Prename
+
+(* In this module:
+ * - we try to insert more annotations to achieve a greater completeness;
+ * - we recursively propagate annotations inside programs;
+ * - we normalize boolean expressions.
+ *
+ * The propagation schemas are the following:
+ *
+ * 1. (f a1 ... an) -> (f a1 ... an) {Qf} if the ai are functional
+ *
+ * 2. (if e1 then e2 else e3) {Q} -> (if e1 then e2 {Q} else e3 {Q}) {Q}
+ *
+ * 3. (let x = e1 in e2) {Q} -> (let x = e1 in e2 {Q}) {Q}
+ *)
+
+(* force a post-condition *)
+let update_post env top ef c =
+ let i,o = Peffect.get_repr ef in
+ let al =
+ List.fold_left
+ (fun l id ->
+ if is_mutable_in_env env id then
+ if is_write ef id then l else (id,at_id id "")::l
+ else if is_at id then
+ let (uid,d) = un_at id in
+ if is_mutable_in_env env uid & d="" then
+ (id,at_id uid top)::l
+ else
+ l
+ else
+ l)
+ [] (global_vars (Global.env()) c)
+ in
+ subst_in_constr al c
+
+let force_post up env top q e =
+ let (res,ef,p,_) = e.info.kappa in
+ let q' =
+ if up then option_app (named_app (update_post env top ef)) q else q
+ in
+ let i = { env = e.info.env; kappa = (res,ef,p,q') } in
+ { desc = e.desc; pre = e.pre; post = q'; loc = e.loc; info = i }
+
+(* put a post-condition if none is present *)
+let post_if_none_up env top q = function
+ | { post = None } as p -> force_post true env top q p
+ | p -> p
+
+let post_if_none env q = function
+ | { post = None } as p -> force_post false env "" q p
+ | p -> p
+
+(* [annotation_candidate p] determines if p is a candidate for a
+ * post-condition *)
+
+let annotation_candidate = function
+ | { desc = If _ | Let _ | LetRef _ ; post = None } -> true
+ | _ -> false
+
+(* [extract_pre p] erase the pre-condition of p and returns it *)
+let extract_pre pr =
+ let (v,e,p,q) = pr.info.kappa in
+ { desc = pr.desc; pre = []; post = pr.post; loc = pr.loc;
+ info = { env = pr.info.env; kappa = (v,e,[],q) } },
+ p
+
+(* adds some pre-conditions *)
+let add_pre p1 pr =
+ let (v,e,p,q) = pr.info.kappa in
+ let p' = p1 @ p in
+ { desc = pr.desc; pre = p'; post = pr.post; loc = pr.loc;
+ info = { env = pr.info.env; kappa = (v,e,p',q) } }
+
+(* change the statement *)
+let change_desc p d =
+ { desc = d; pre = p.pre; post = p.post; loc = p.loc; info = p.info }
+
+let create_bool_post c =
+ Some { a_value = c; a_name = Name (bool_name()) }
+
+(* [normalize_boolean b] checks if the boolean expression b (of type bool) is
+ * annotated, and if it is not the case tries to add the annotation
+ * (if result then c=true else c=false) if b is an expression c.
+ *)
+
+let is_bool = function
+ | TypePure c ->
+ (match kind_of_term (strip_outer_cast c) with
+ | Ind op ->
+ string_of_id (id_of_global (IndRef op)) = "bool"
+ | _ -> false)
+ | _ -> false
+
+let normalize_boolean ren env b =
+ let ((res,v),ef,p,q) = b.info.kappa in
+ Perror.check_no_effect b.loc ef;
+ if is_bool v then
+ match q with
+ | Some _ ->
+ (* il y a une annotation : on se contente de lui forcer un nom *)
+ let q = force_bool_name q in
+ { desc = b.desc; pre = b.pre; post = q; loc = b.loc;
+ info = { env = b.info.env; kappa = ((res,v),ef,p,q) } }
+ | None -> begin
+ (* il n'y a pas d'annotation : on cherche ą en mettre une *)
+ match b.desc with
+ Expression c ->
+ let c' = Term.applist (constant "annot_bool",[c]) in
+ let ty = type_of_expression ren env c' in
+ let (_,q') = Hipattern.match_sigma ty in
+ let q' = Some { a_value = q'; a_name = Name (bool_name()) } in
+ { desc = Expression c';
+ pre = b.pre; post = q'; loc = b.loc;
+ info = { env = b.info.env; kappa = ((res, v),ef,p,q') } }
+ | _ -> b
+ end
+ else
+ Perror.should_be_boolean b.loc
+
+(* [decomp_boolean c] returns the specs R and S of a boolean expression *)
+
+let decomp_boolean = function
+ | Some { a_value = q } ->
+ Reductionops.whd_betaiota (Term.applist (q, [constant "true"])),
+ Reductionops.whd_betaiota (Term.applist (q, [constant "false"]))
+ | _ -> invalid_arg "Ptyping.decomp_boolean"
+
+(* top point of a program *)
+
+let top_point = function
+ | PPoint (s,_) as p -> s,p
+ | p -> let s = label_name() in s,PPoint(s,p)
+
+let top_point_block = function
+ | (Label s :: _) as b -> s,b
+ | b -> let s = label_name() in s,(Label s)::b
+
+let abstract_unit q = abstract [result_id,constant "unit"] q
+
+(* [add_decreasing env ren ren' phi r bl] adds the decreasing condition
+ * phi(ren') r phi(ren)
+ * to the last assertion of the block [bl], which is created if needed
+ *)
+
+let add_decreasing env inv (var,r) lab bl =
+ let ids = now_vars env var in
+ let al = List.map (fun id -> (id,at_id id lab)) ids in
+ let var_lab = subst_in_constr al var in
+ let dec = Term.applist (r, [var;var_lab]) in
+ let post = match inv with
+ None -> anonymous dec
+ | Some i -> { a_value = conj dec i.a_value; a_name = i.a_name }
+ in
+ bl @ [ Assert post ]
+
+(* [post_last_statement env top q bl] annotates the last statement of the
+ * sequence bl with q if necessary *)
+
+let post_last_statement env top q bl =
+ match List.rev bl with
+ | Statement e :: rem when annotation_candidate e ->
+ List.rev ((Statement (post_if_none_up env top q e)) :: rem)
+ | _ -> bl
+
+(* [propagate_desc] moves the annotations inside the program
+ * info is the typing information coming from the outside annotations *)
+let rec propagate_desc ren info d =
+ let env = info.env in
+ let (_,_,p,q) = info.kappa in
+ match d with
+ | If (e1,e2,e3) ->
+ (* propagation number 2 *)
+ let e1' = normalize_boolean ren env (propagate ren e1) in
+ if e2.post = None or e3.post = None then
+ let top = label_name() in
+ let ren' = push_date ren top in
+ PPoint (top, If (e1',
+ propagate ren' (post_if_none_up env top q e2),
+ propagate ren' (post_if_none_up env top q e3)))
+ else
+ If (e1', propagate ren e2, propagate ren e3)
+ | Aff (x,e) ->
+ Aff (x, propagate ren e)
+ | TabAcc (ch,x,e) ->
+ TabAcc (ch, x, propagate ren e)
+ | TabAff (ch,x,({desc=Expression c} as e1),e2) ->
+ let p = Pmonad.make_pre_access ren env x c in
+ let e1' = add_pre [(anonymous_pre true p)] e1 in
+ TabAff (false, x, propagate ren e1', propagate ren e2)
+ | TabAff (ch,x,e1,e2) ->
+ TabAff (ch, x, propagate ren e1, propagate ren e2)
+ | Apply (f,l) ->
+ Apply (propagate ren f, List.map (propagate_arg ren) l)
+ | SApp (f,l) ->
+ let l =
+ List.map (fun e -> normalize_boolean ren env (propagate ren e)) l
+ in
+ SApp (f, l)
+ | Lam (bl,e) ->
+ Lam (bl, propagate ren e)
+ | Seq bl ->
+ let top,bl = top_point_block bl in
+ let bl = post_last_statement env top q bl in
+ Seq (propagate_block ren env bl)
+ | While (b,inv,var,bl) ->
+ let b = normalize_boolean ren env (propagate ren b) in
+ let lab,bl = top_point_block bl in
+ let bl = add_decreasing env inv var lab bl in
+ While (b,inv,var,propagate_block ren env bl)
+ | LetRef (x,e1,e2) ->
+ let top = label_name() in
+ let ren' = push_date ren top in
+ PPoint (top, LetRef (x, propagate ren' e1,
+ propagate ren' (post_if_none_up env top q e2)))
+ | Let (x,e1,e2) ->
+ let top = label_name() in
+ let ren' = push_date ren top in
+ PPoint (top, Let (x, propagate ren' e1,
+ propagate ren' (post_if_none_up env top q e2)))
+ | LetRec (f,bl,v,var,e) ->
+ LetRec (f, bl, v, var, propagate ren e)
+ | PPoint (s,d) ->
+ PPoint (s, propagate_desc ren info d)
+ | Debug _ | Variable _
+ | Acc _ | Expression _ as d -> d
+
+
+(* [propagate] adds new annotations if possible *)
+and propagate ren p =
+ let env = p.info.env in
+ let p = match p.desc with
+ | Apply (f,l) ->
+ let _,(_,so,ok),(_,_,_,qapp) = effect_app ren env f l in
+ if ok then
+ let q = option_app (named_app (real_subst_in_constr so)) qapp in
+ post_if_none env q p
+ else
+ p
+ | _ -> p
+ in
+ let d = propagate_desc ren p.info p.desc in
+ let p = change_desc p d in
+ match d with
+ | Aff (x,e) ->
+ let e1,p1 = extract_pre e in
+ change_desc (add_pre p1 p) (Aff (x,e1))
+
+ | TabAff (check, x, ({ desc = Expression _ } as e1), e2) ->
+ let e1',p1 = extract_pre e1 in
+ let e2',p2 = extract_pre e2 in
+ change_desc (add_pre (p1@p2) p) (TabAff (check,x,e1',e2'))
+
+ | While (b,inv,_,_) ->
+ let _,s = decomp_boolean b.post in
+ let s = make_before_after s in
+ let q = match inv with
+ None -> Some (anonymous s)
+ | Some i -> Some { a_value = conj i.a_value s; a_name = i.a_name }
+ in
+ let q = option_app (named_app abstract_unit) q in
+ post_if_none env q p
+
+ | SApp ([Variable id], [e1;e2])
+ when id = connective_and or id = connective_or ->
+ let (_,_,_,q1) = e1.info.kappa
+ and (_,_,_,q2) = e2.info.kappa in
+ let (r1,s1) = decomp_boolean q1
+ and (r2,s2) = decomp_boolean q2 in
+ let q =
+ let conn = if id = connective_and then "spec_and" else "spec_or" in
+ let c = Term.applist (constant conn, [r1; s1; r2; s2]) in
+ let c = Reduction.whd_betadeltaiota (Global.env()) c in
+ create_bool_post c
+ in
+ let d =
+ SApp ([Variable id;
+ Expression (out_post q1);
+ Expression (out_post q2)],
+ [e1; e2] )
+ in
+ post_if_none env q (change_desc p d)
+
+ | SApp ([Variable id], [e1]) when id = connective_not ->
+ let (_,_,_,q1) = e1.info.kappa in
+ let (r1,s1) = decomp_boolean q1 in
+ let q =
+ let c = Term.applist (constant "spec_not", [r1; s1]) in
+ let c = Reduction.whd_betadeltaiota (Global.env ()) c in
+ create_bool_post c
+ in
+ let d = SApp ([Variable id; Expression (out_post q1)], [ e1 ]) in
+ post_if_none env q (change_desc p d)
+
+ | _ -> p
+
+and propagate_arg ren = function
+ | Type _ | Refarg _ as a -> a
+ | Term e -> Term (propagate ren e)
+
+
+and propagate_block ren env = function
+ | [] ->
+ []
+ | (Statement p) :: (Assert q) :: rem when annotation_candidate p ->
+ (* TODO: plutot p.post = None ? *)
+ let q' =
+ let ((id,v),_,_,_) = p.info.kappa in
+ let tv = Pmonad.trad_ml_type_v ren env v in
+ named_app (abstract [id,tv]) q
+ in
+ let p' = post_if_none env (Some q') p in
+ (Statement (propagate ren p')) :: (Assert q)
+ :: (propagate_block ren env rem)
+ | (Statement p) :: rem ->
+ (Statement (propagate ren p)) :: (propagate_block ren env rem)
+ | (Label s as x) :: rem ->
+ x :: propagate_block (push_date ren s) env rem
+ | x :: rem ->
+ x :: propagate_block ren env rem
diff --git a/contrib/correctness/pwp.mli b/contrib/correctness/pwp.mli
new file mode 100644
index 00000000..015031a0
--- /dev/null
+++ b/contrib/correctness/pwp.mli
@@ -0,0 +1,18 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(* Certification of Imperative Programs / Jean-Christophe Filliātre *)
+
+(* $Id: pwp.mli,v 1.2.16.1 2004/07/16 19:30:06 herbelin Exp $ *)
+
+open Term
+open Penv
+
+val update_post : local_env -> string -> Peffect.t -> constr -> constr
+
+val propagate : Prename.t -> typed_program -> typed_program