comparison src/StackMachine.v @ 20:c0cbf324ec7d

Finished typed example
author Adam Chlipala <adamc@hcoop.net>
date Wed, 03 Sep 2008 16:14:47 -0400
parents 5db67b182ef8
children 91e247c68ee8
comparison
equal deleted inserted replaced
19:5db67b182ef8 20:c0cbf324ec7d
21 As always, you can step through the source file %\texttt{%#<tt>#StackMachine.v#</tt>#%}% for this chapter interactively in Proof General. Alternatively, to get a feel for the whole lifecycle of creating a Coq development, you can enter the pieces of source code in this chapter in a new %\texttt{%#<tt>#.v#</tt>#%}% file in an Emacs buffer. If you do the latter, include a line [Require Import List Tactics] at the start of the file, to match some code hidden from the chapter source, and be sure to run the Coq binary %\texttt{%#<tt>#coqtop#</tt>#%}% with the command-line argument %\texttt{%#<tt>#-I SRC#</tt>#%}%, where %\texttt{%#<tt>#SRC#</tt>#%}% is the path to a directory containing the source for this book. In either case, if you have installed Proof General properly, it should start automatically when you visit a %\texttt{%#<tt>#.v#</tt>#%}% buffer in Emacs. 21 As always, you can step through the source file %\texttt{%#<tt>#StackMachine.v#</tt>#%}% for this chapter interactively in Proof General. Alternatively, to get a feel for the whole lifecycle of creating a Coq development, you can enter the pieces of source code in this chapter in a new %\texttt{%#<tt>#.v#</tt>#%}% file in an Emacs buffer. If you do the latter, include a line [Require Import List Tactics] at the start of the file, to match some code hidden from the chapter source, and be sure to run the Coq binary %\texttt{%#<tt>#coqtop#</tt>#%}% with the command-line argument %\texttt{%#<tt>#-I SRC#</tt>#%}%, where %\texttt{%#<tt>#SRC#</tt>#%}% is the path to a directory containing the source for this book. In either case, if you have installed Proof General properly, it should start automatically when you visit a %\texttt{%#<tt>#.v#</tt>#%}% buffer in Emacs.
22 22
23 With Proof General, the portion of a buffer that Coq has processed is highlighted in some way, like being given a blue background. You step through Coq source files by positioning the point at the position you want Coq to run to and pressing C-C C-RET. This can be used both for normal step-by-step coding, by placing the point inside some command past the end of the highlighted region; and for undoing, by placing the point inside the highlighted region. *) 23 With Proof General, the portion of a buffer that Coq has processed is highlighted in some way, like being given a blue background. You step through Coq source files by positioning the point at the position you want Coq to run to and pressing C-C C-RET. This can be used both for normal step-by-step coding, by placing the point inside some command past the end of the highlighted region; and for undoing, by placing the point inside the highlighted region. *)
24 24
25 25
26 (** * Arithmetic expressions over natural numbers *) 26 (** * Arithmetic Expressions Over Natural Numbers *)
27 27
28 (** We will begin with that staple of compiler textbooks, arithemtic expressions over a single type of numbers. *) 28 (** We will begin with that staple of compiler textbooks, arithemtic expressions over a single type of numbers. *)
29 29
30 (** ** Source language *) 30 (** ** Source Language *)
31 31
32 (** We begin with the syntax of the source language. *) 32 (** We begin with the syntax of the source language. *)
33 33
34 Inductive binop : Set := Plus | Times. 34 Inductive binop : Set := Plus | Times.
35 35
106 Eval simpl in expDenote (Binop Times (Binop Plus (Const 2) (Const 2)) (Const 7)). 106 Eval simpl in expDenote (Binop Times (Binop Plus (Const 2) (Const 2)) (Const 7)).
107 (** [[ 107 (** [[
108 = 28 : nat 108 = 28 : nat
109 ]] *) 109 ]] *)
110 110
111 (** ** Target language *) 111 (** ** Target Language *)
112 112
113 (** We will compile our source programs onto a simple stack machine, whose syntax is: *) 113 (** We will compile our source programs onto a simple stack machine, whose syntax is: *)
114 114
115 Inductive instr : Set := 115 Inductive instr : Set :=
116 | IConst : nat -> instr 116 | IConst : nat -> instr
188 (** [[ 188 (** [[
189 = Some (28 :: nil) : option stack 189 = Some (28 :: nil) : option stack
190 ]] *) 190 ]] *)
191 191
192 192
193 (** ** Translation correctness *) 193 (** ** Translation Correctness *)
194 194
195 (** We are ready to prove that our compiler is implemented correctly. We can use a new vernacular command [Theorem] to start a correctness proof, in terms of the semantics we defined earlier: *) 195 (** We are ready to prove that our compiler is implemented correctly. We can use a new vernacular command [Theorem] to start a correctness proof, in terms of the semantics we defined earlier: *)
196 196
197 Theorem compileCorrect : forall e, progDenote (compile e) nil = Some (expDenote e :: nil). 197 Theorem compileCorrect : forall e, progDenote (compile e) nil = Some (expDenote e :: nil).
198 (* begin hide *) 198 (* begin hide *)
511 511
512 reflexivity. 512 reflexivity.
513 Qed. 513 Qed.
514 514
515 515
516 (** * Typed expressions *) 516 (** * Typed Expressions *)
517 517
518 (** In this section, we will build on the initial example by adding additional expression forms that depend on static typing of terms for safety. *) 518 (** In this section, we will build on the initial example by adding additional expression forms that depend on static typing of terms for safety. *)
519 519
520 (** ** Source language *) 520 (** ** Source Language *)
521 521
522 (** We define a trivial language of types to classify our expressions: *) 522 (** We define a trivial language of types to classify our expressions: *)
523 523
524 Inductive type : Set := Nat | Bool. 524 Inductive type : Set := Nat | Bool.
525 525
629 (** [[ 629 (** [[
630 = true : typeDenote Bool 630 = true : typeDenote Bool
631 ]] *) 631 ]] *)
632 632
633 633
634 (** ** Target language *) 634 (** ** Target Language *)
635 635
636 (** Now we want to define a suitable stack machine target for compilation. In the example of the untyped language, stack machine programs could encounter stack underflows and "get stuck." This was unfortunate, since we had to deal with this complication even though we proved that our compiler never produced underflowing programs. We could have used dependent types to force all stack machine programs to be underflow-free. 636 (** Now we want to define a suitable stack machine target for compilation. In the example of the untyped language, stack machine programs could encounter stack underflows and "get stuck." This was unfortunate, since we had to deal with this complication even though we proved that our compiler never produced underflowing programs. We could have used dependent types to force all stack machine programs to be underflow-free.
637 637
638 For our new languages, besides underflow, we also have the problem of stack slots with naturals instead of bools or vice versa. This time, we will use indexed typed families to avoid the need to reason about potential failures. 638 For our new languages, besides underflow, we also have the problem of stack slots with naturals instead of bools or vice versa. This time, we will use indexed typed families to avoid the need to reason about potential failures.
639 639
783 (** [[ 783 (** [[
784 = (true, tt) : vstack (Bool :: nil) 784 = (true, tt) : vstack (Bool :: nil)
785 ]] *) 785 ]] *)
786 786
787 787
788 (** ** Translation correctness *) 788 (** ** Translation Correctness *)
789
790 (** We can state a correctness theorem similar to the last one. *)
791
792 Theorem tcompileCorrect : forall t (e : texp t), tprogDenote (tcompile e nil) tt = (texpDenote e, tt).
793 (* begin hide *)
794 Abort.
795 (* end hide *)
796
797 (** Again, we need to strengthen the theorem statement so that the induction will go through. This time, I will develop an alternative approach to this kind of proof, stating the key lemma as: *)
789 798
790 Lemma tcompileCorrect' : forall t (e : texp t) 799 Lemma tcompileCorrect' : forall t (e : texp t)
791 ts (s : vstack ts), 800 ts (s : vstack ts),
792 tprogDenote (tcompile e ts) s 801 tprogDenote (tcompile e ts) s
793 = (texpDenote e, s). 802 = (texpDenote e, s).
803
804 (** While lemma [compileCorrect'] quantified over a program that is the "continuation" for the expression we are considering, here we avoid drawing in any extra syntactic elements. In addition to the source expression and its type, we also quantify over an initial stack type and a stack compatible with it. Running the compilation of the program starting from that stack, we should arrive at a stack that differs only in having the program's denotation pushed onto it.
805
806 Let us try to prove this theorem in the same way that we settled on in the last section. *)
807
794 induction e; crush. 808 induction e; crush.
809
810 (** We are left with this unproved conclusion:
811
812 [[
813
814 tprogDenote
815 (tconcat (tcompile e2 ts)
816 (tconcat (tcompile e1 (arg2 :: ts))
817 (TCons (TIBinop ts t) (TNil (res :: ts))))) s =
818 (tbinopDenote t (texpDenote e1) (texpDenote e2), s)
819 ]]
820
821 We need an analogue to the [app_ass] theorem that we used to rewrite the goal in the last section. We can abort this proof and prove such a lemma about [tconcat].
822 *)
795 Abort. 823 Abort.
796 824
797 Lemma tconcatCorrect : forall ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'') 825 Lemma tconcatCorrect : forall ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'')
798 (s : vstack ts), 826 (s : vstack ts),
799 tprogDenote (tconcat p p') s 827 tprogDenote (tconcat p p') s
800 = tprogDenote p' (tprogDenote p s). 828 = tprogDenote p' (tprogDenote p s).
801 induction p; crush. 829 induction p; crush.
802 Qed. 830 Qed.
803 831
832 (** This one goes through completely automatically.
833
834 Some code behind the scenes registers [app_ass] for use by [crush]. We must register [tconcatCorrect] similarly to get the same effect: *)
835
804 Hint Rewrite tconcatCorrect : cpdt. 836 Hint Rewrite tconcatCorrect : cpdt.
837
838 (** We ask that the lemma be used for left-to-right rewriting, and we ask for the hint to be added to the hint database called [cpdt], which is the database used by [crush]. Now we are ready to return to [tcompileCorrect'], proving it automatically this time. *)
805 839
806 Lemma tcompileCorrect' : forall t (e : texp t) 840 Lemma tcompileCorrect' : forall t (e : texp t)
807 ts (s : vstack ts), 841 ts (s : vstack ts),
808 tprogDenote (tcompile e ts) s 842 tprogDenote (tcompile e ts) s
809 = (texpDenote e, s). 843 = (texpDenote e, s).
810 induction e; crush. 844 induction e; crush.
811 Qed. 845 Qed.
812 846
847 (** We can register this main lemma as another hint, allowing us to prove the final theorem trivially. *)
848
813 Hint Rewrite tcompileCorrect' : cpdt. 849 Hint Rewrite tcompileCorrect' : cpdt.
814 850
815 Theorem tcompileCorrect : forall t (e : texp t), tprogDenote (tcompile e nil) tt = (texpDenote e, tt). 851 Theorem tcompileCorrect : forall t (e : texp t), tprogDenote (tcompile e nil) tt = (texpDenote e, tt).
816 crush. 852 crush.
817 Qed. 853 Qed.