14569
|
1 |
(* Title: HOL/ex/Exceptions.thy
|
|
2 |
ID: $Id$
|
|
3 |
Author: Tobias Nipkow
|
|
4 |
Copyright 2004 TU Muenchen
|
|
5 |
*)
|
|
6 |
|
|
7 |
header {* Compiling exception handling *}
|
|
8 |
|
|
9 |
theory Exceptions = List_Prefix:
|
|
10 |
|
|
11 |
text{* This is a formalization of \cite{HuttonW04}. *}
|
|
12 |
|
|
13 |
subsection{*The source language*}
|
|
14 |
|
|
15 |
datatype expr = Val int | Add expr expr | Throw | Catch expr expr
|
|
16 |
|
|
17 |
consts eval :: "expr \<Rightarrow> int option"
|
|
18 |
primrec
|
|
19 |
"eval (Val i) = Some i"
|
|
20 |
"eval (Add x y) =
|
|
21 |
(case eval x of None \<Rightarrow> None
|
|
22 |
| Some i \<Rightarrow> (case eval y of None \<Rightarrow> None
|
|
23 |
| Some j \<Rightarrow> Some(i+j)))"
|
|
24 |
"eval Throw = None"
|
|
25 |
"eval (Catch x h) = (case eval x of None \<Rightarrow> eval h | Some i \<Rightarrow> Some i)"
|
|
26 |
|
|
27 |
subsection{*The target language*}
|
|
28 |
|
|
29 |
datatype instr =
|
|
30 |
Push int | ADD | THROW | Mark nat | Unmark | Label nat | Jump nat
|
|
31 |
|
|
32 |
datatype item = VAL int | HAN nat
|
|
33 |
|
|
34 |
types code = "instr list"
|
|
35 |
stack = "item list"
|
|
36 |
|
|
37 |
consts
|
|
38 |
exec2 :: "bool * code * stack \<Rightarrow> stack"
|
|
39 |
jump :: "nat * code \<Rightarrow> code"
|
|
40 |
|
|
41 |
recdef jump "measure(%(l,cs). size cs)"
|
|
42 |
"jump(l,[]) = []"
|
|
43 |
"jump(l, Label l' # cs) = (if l = l' then cs else jump(l,cs))"
|
|
44 |
"jump(l, c # cs) = jump(l,cs)"
|
|
45 |
|
|
46 |
lemma size_jump1: "size (jump (l, cs)) < Suc(size cs)"
|
|
47 |
apply(induct cs)
|
|
48 |
apply simp
|
|
49 |
apply(case_tac a)
|
|
50 |
apply auto
|
|
51 |
done
|
|
52 |
|
|
53 |
lemma size_jump2: "size (jump (l, cs)) < size cs \<or> jump(l,cs) = cs"
|
|
54 |
apply(induct cs)
|
|
55 |
apply simp
|
|
56 |
apply(case_tac a)
|
|
57 |
apply auto
|
|
58 |
done
|
|
59 |
|
|
60 |
syntax
|
|
61 |
exec :: "code \<Rightarrow> stack \<Rightarrow> stack"
|
|
62 |
unwind :: "code \<Rightarrow> stack \<Rightarrow> stack"
|
|
63 |
translations
|
|
64 |
"exec cs s" == "exec2(True,cs,s)"
|
|
65 |
"unwind cs s" == "exec2(False,cs,s)"
|
|
66 |
|
|
67 |
recdef exec2
|
|
68 |
"inv_image (measure(%cs. size cs) <*lex*> measure(%s. size s))
|
|
69 |
(%(b,cs,s). (cs,s))"
|
|
70 |
"exec [] s = s"
|
|
71 |
"exec (Push i#cs) s = exec cs (VAL i # s)"
|
|
72 |
"exec (ADD#cs) (VAL j # VAL i # s) = exec cs (VAL(i+j) # s)"
|
|
73 |
"exec (THROW#cs) s = unwind cs s"
|
|
74 |
"exec (Mark l#cs) s = exec cs (HAN l # s)"
|
|
75 |
"exec (Unmark#cs) (v # HAN l # s) = exec cs (v # s)"
|
|
76 |
"exec (Label l#cs) s = exec cs s"
|
|
77 |
"exec (Jump l#cs) s = exec (jump(l,cs)) s"
|
|
78 |
|
|
79 |
"unwind cs [] = []"
|
|
80 |
"unwind cs (VAL i # s) = unwind cs s"
|
|
81 |
"unwind cs (HAN l # s) = exec (jump(l,cs)) s"
|
|
82 |
|
|
83 |
(hints recdef_simp: size_jump1 size_jump2)
|
|
84 |
|
|
85 |
subsection{*The compiler*}
|
|
86 |
|
|
87 |
consts
|
|
88 |
compile :: "nat \<Rightarrow> expr \<Rightarrow> code * nat"
|
|
89 |
primrec
|
|
90 |
"compile l (Val i) = ([Push i], l)"
|
|
91 |
"compile l (Add x y) = (let (xs,m) = compile l x; (ys,n) = compile m y
|
|
92 |
in (xs @ ys @ [ADD], n))"
|
|
93 |
"compile l Throw = ([THROW],l)"
|
|
94 |
"compile l (Catch x h) =
|
|
95 |
(let (xs,m) = compile (l+2) x; (hs,n) = compile m h
|
|
96 |
in (Mark l # xs @ [Unmark, Jump (l+1), Label l] @ hs @ [Label(l+1)], n))"
|
|
97 |
|
|
98 |
syntax cmp :: "nat \<Rightarrow> expr \<Rightarrow> code"
|
|
99 |
translations "cmp l e" == "fst(compile l e)"
|
|
100 |
|
|
101 |
consts
|
|
102 |
isFresh :: "nat \<Rightarrow> stack \<Rightarrow> bool"
|
|
103 |
primrec
|
|
104 |
"isFresh l [] = True"
|
|
105 |
"isFresh l (it#s) = (case it of VAL i \<Rightarrow> isFresh l s
|
|
106 |
| HAN l' \<Rightarrow> l' < l \<and> isFresh l s)"
|
|
107 |
|
|
108 |
constdefs
|
|
109 |
conv :: "code \<Rightarrow> stack \<Rightarrow> int option \<Rightarrow> stack"
|
|
110 |
"conv cs s io == case io of None \<Rightarrow> unwind cs s
|
|
111 |
| Some i \<Rightarrow> exec cs (VAL i # s)"
|
|
112 |
|
|
113 |
subsection{* The proofs*}
|
|
114 |
|
|
115 |
declare
|
|
116 |
conv_def[simp] option.splits[split] Let_def[simp]
|
|
117 |
|
|
118 |
lemma 3:
|
|
119 |
"(\<And>l. c = Label l \<Longrightarrow> isFresh l s) \<Longrightarrow> unwind (c#cs) s = unwind cs s"
|
|
120 |
apply(induct s)
|
|
121 |
apply simp
|
|
122 |
apply(auto)
|
|
123 |
apply(case_tac a)
|
|
124 |
apply auto
|
|
125 |
apply(case_tac c)
|
|
126 |
apply auto
|
|
127 |
done
|
|
128 |
|
|
129 |
corollary [simp]:
|
|
130 |
"(!!l. c \<noteq> Label l) \<Longrightarrow> unwind (c#cs) s = unwind cs s"
|
|
131 |
by(blast intro: 3)
|
|
132 |
|
|
133 |
corollary [simp]:
|
|
134 |
"isFresh l s \<Longrightarrow> unwind (Label l#cs) s = unwind cs s"
|
|
135 |
by(blast intro: 3)
|
|
136 |
|
|
137 |
|
|
138 |
lemma 5: "\<lbrakk> isFresh l s; l \<le> m \<rbrakk> \<Longrightarrow> isFresh m s"
|
|
139 |
apply(induct s)
|
|
140 |
apply simp
|
|
141 |
apply(auto split:item.split)
|
|
142 |
done
|
|
143 |
|
|
144 |
corollary [simp]: "isFresh l s \<Longrightarrow> isFresh (Suc l) s"
|
|
145 |
by(auto intro:5)
|
|
146 |
|
|
147 |
|
|
148 |
lemma 6: "\<And>l. l \<le> snd(compile l e)"
|
|
149 |
proof(induct e)
|
|
150 |
case Val thus ?case by simp
|
|
151 |
next
|
|
152 |
case (Add x y)
|
|
153 |
have "l \<le> snd (compile l x)"
|
|
154 |
and "snd (compile l x) \<le> snd (compile (snd (compile l x)) y)" .
|
|
155 |
thus ?case by(simp_all add:split_def)
|
|
156 |
next
|
|
157 |
case Throw thus ?case by simp
|
|
158 |
next
|
|
159 |
case (Catch x h)
|
|
160 |
have "l+2 \<le> snd (compile (l+2) x)"
|
|
161 |
and "snd (compile (l+2) x) \<le> snd (compile (snd (compile (l+2) x)) h)" .
|
|
162 |
thus ?case by(simp_all add:split_def)
|
|
163 |
qed
|
|
164 |
|
|
165 |
corollary [simp]: "l < m \<Longrightarrow> l < snd(compile m e)"
|
|
166 |
using 6[where l = m and e = e] by auto
|
|
167 |
|
|
168 |
corollary [simp]: "isFresh l s \<Longrightarrow> isFresh (snd(compile l e)) s"
|
|
169 |
using 5 6 by blast
|
|
170 |
|
|
171 |
|
|
172 |
text{* Contrary to the order of the lemmas in the paper, lemma 4 needs the
|
|
173 |
above corollary of 5 and 6. *}
|
|
174 |
|
|
175 |
lemma 4 [simp]: "\<And>l cs. isFresh l s \<Longrightarrow> unwind (cmp l e @ cs) s = unwind cs s"
|
|
176 |
by (induct e) (auto simp add:split_def)
|
|
177 |
|
|
178 |
|
|
179 |
lemma 7[simp]: "\<And>m cs. l < m \<Longrightarrow> jump(l, cmp m e @ cs) = jump(l, cs)"
|
|
180 |
by (induct e) (simp_all add:split_def)
|
|
181 |
|
|
182 |
text{* The compiler correctness theorem: *}
|
|
183 |
|
|
184 |
theorem "\<And>l s cs. isFresh l s \<Longrightarrow> exec (cmp l e @ cs) s = conv cs s (eval e)"
|
|
185 |
by(induct e)(auto simp add:split_def)
|
|
186 |
|
|
187 |
end
|