1292934Sdimstructure decompilerLib :> decompilerLib =
2292934Sdimstruct
3353358Sdim
4353358Sdimopen HolKernel boolLib bossLib Parse;
5353358Sdim
6292934Sdimopen listTheory wordsTheory pred_setTheory arithmeticTheory wordsLib pairTheory;
7292934Sdimopen set_sepTheory progTheory helperLib addressTheory;
8292934Sdim
9292934Sdimstructure Parse =
10292934Sdimstruct
11292934Sdim   open Parse
12292934Sdim   val (Type, Term) = parse_from_grammars addressTheory.address_grammars
13321369Sdimend
14314564Sdim
15292934Sdim(* -------------------------------------------------------------------------- *)
16292934Sdim(* Decompilation stages:                                                      *)
17292934Sdim(*   1. derive SPEC theorem for each machine instruction, abbreviate code     *)
18292934Sdim(*   2. extract control flow graph                                            *)
19292934Sdim(*   3. for each code segment:                                                *)
20292934Sdim(*        a. compose SPEC theorems for one-pass through the code              *)
21292934Sdim(*        b. merge one-pass theorems into one theorem                         *)
22292934Sdim(*        c. extract the function describing the code                         *)
23292934Sdim(*   4. store and return result of decompilation                              *)
24292934Sdim(* -------------------------------------------------------------------------- *)
25292934Sdim
26292934Sdim(* decompiler's memory *)
27314564Sdim
28292934Sdimval decompiler_memory = ref ([]:(string * (thm * int * int option)) list)
29314564Sdimval decompiler_finalise = ref (I:(thm * thm -> thm * thm))
30353358Sdimval code_abbreviations = ref ([]:thm list);
31314564Sdimval abbreviate_code = ref false;
32360784Sdimval user_defined_modifier = ref (fn (name:string) => fn (th:thm) => th);
33314564Sdimval decompile_as_single_function = ref false;
34327952Sdim
35292934Sdimval decompiler_set_pc = ref ((fn y => fn th => fail()) :int -> thm -> thm);
36292934Sdim
37292934Sdimfun add_decompiled (name,th,code_len,code_exit) =
38292934Sdim  (decompiler_memory := (name,(th,code_len,code_exit)) :: !decompiler_memory);
39292934Sdim
40292934Sdimfun get_decompiled name =
41292934Sdim  snd (hd (filter (fn (x,y) => x = name) (!decompiler_memory)))
42292934Sdim  handle _ => fail();
43292934Sdim
44292934Sdimfun add_code_abbrev thms = (code_abbreviations := thms @ !code_abbreviations);
45314564Sdimfun set_abbreviate_code b = (abbreviate_code := b);
46314564Sdimfun get_abbreviate_code () = !abbreviate_code;
47314564Sdim
48292934Sdimfun add_modifier name f = let
49292934Sdim  val current = !user_defined_modifier
50353358Sdim  in user_defined_modifier := (fn x => if x = name then f else current x) end;
51292934Sdimfun remove_all_modifiers () =
52360784Sdim  user_defined_modifier := (fn (name:string) => fn (th:thm) => th);
53360784Sdimfun modifier name th = (!user_defined_modifier) name th;
54360784Sdim
55314564Sdim
56314564Sdim(* general set-up *)
57360784Sdim
58360784Sdimval _ = map Parse.hide ["r0","r1","r2","r3","r4","r5","r6","r7","r8","r9",
59292934Sdim                        "r10","r11","r12","r13","r14","r15"];
60344779Sdimval _ = set_echo 5;
61353358Sdim
62344779Sdim
63292934Sdim(* -------------------------------------------------------------------------- *)
64292934Sdim(* Various helper functions                                                   *)
65292934Sdim(* -------------------------------------------------------------------------- *)
66292934Sdim
67353358Sdimfun take n [] = []
68353358Sdim  | take n (x::xs) = if n = 0 then [] else x :: take (n-1) xs
69292934Sdim
70292934Sdimfun drop n [] = []
71292934Sdim  | drop n (x::xs) = if n = 0 then x::xs else drop (n-1) xs
72292934Sdim
73292934Sdimfun take_until p [] = []
74353358Sdim  | take_until p (x::xs) = if p x then [] else x:: take_until p xs
75292934Sdim
76292934Sdimfun diff xs ys = filter (fn x => not (mem x ys)) xs
77292934Sdimfun subset xs ys = (diff xs ys = [])
78292934Sdimfun same_set xs ys = subset xs ys andalso subset ys xs
79292934Sdimfun disjoint xs ys = diff xs ys = xs
80321369Sdim
81292934Sdimfun negate tm = dest_neg tm handle HOL_ERR e => mk_neg tm
82292934Sdimfun the (SOME x) = x | the NONE = fail()
83353358Sdim
84292934Sdimfun is_new_var v =
85353358Sdim  (String.isPrefix "new@" o fst o dest_var) v handle HOL_ERR _ => false
86353358Sdimfun dest_new_var tm = if not (is_new_var tm) then fail() else let
87314564Sdim  val (s,ty) = dest_var tm
88353358Sdim  in mk_var(implode (drop 4 (explode s)), ty) end
89360784Sdim
90360784Sdimfun dest_tuple tm =
91353358Sdim  let val (x,y) = pairSyntax.dest_pair tm in x :: dest_tuple y end
92353358Sdim  handle HOL_ERR e => [tm];
93353358Sdim
94360784Sdimfun mk_tuple_abs (v,tm) =
95353358Sdim  if v = ``()`` then
96353358Sdim    (subst [mk_var("x",type_of tm) |-> tm]
97353358Sdim       (inst [``:'a``|->type_of tm] ``\():unit.x:'a``))
98353358Sdim else pairSyntax.list_mk_pabs([v],tm)
99353358Sdim
100353358Sdimfun dest_sep_cond tm =
101353358Sdim  if (fst o dest_const o fst o dest_comb) tm = "cond"
102353358Sdim  then snd (dest_comb tm) else fail();
103353358Sdim
104353358Sdimfun n_times 0 f x = x | n_times n f x = n_times (n-1) f (f x)
105314564Sdim
106360784Sdimfun replace_char c str =
107360784Sdim  String.translate (fn x => if x = c then str else implode [x]);
108360784Sdim
109314564Sdimfun REPLACE_CONV th tm = let
110292934Sdim  val th = SPEC_ALL th
111353358Sdim  val (i,j) = match_term ((fst o dest_eq o concl) th) tm
112292934Sdim  in INST i (INST_TYPE j th) end
113327952Sdim
114353358Sdim(* expands pairs
115353358Sdim     ``(x,y,z) = f`` --> (x = FST f) /\ (y = FST (SND f)) /\ (z = ...) *)
116353358Sdimfun expand_conv tm = let
117327952Sdim  val cc = RAND_CONV (REPLACE_CONV (GSYM pairTheory.PAIR))
118327952Sdim  val cc = cc THENC REPLACE_CONV pairTheory.PAIR_EQ
119292934Sdim  val th = cc tm
120360784Sdim  in CONV_RULE (RAND_CONV (RAND_CONV expand_conv)) th end
121360784Sdim  handle HOL_ERR e => REFL tm
122360784Sdim
123344779Sdimfun list_mk_pair xs = pairSyntax.list_mk_pair xs handle HOL_ERR e => ``()``
124353358Sdimfun list_dest_pair tm = let val (x,y) = pairSyntax.dest_pair tm
125353358Sdim in list_dest_pair x @ list_dest_pair y end handle HOL_ERR e => [tm]
126353358Sdim
127292934Sdimfun list_union [] xs = xs
128353358Sdim  | list_union (y::ys) xs =
129353358Sdim      if mem y xs then list_union ys xs else list_union ys (y::xs);
130353358Sdim
131353358Sdimfun append_lists [] = [] | append_lists (x::xs) = x @ append_lists xs
132292934Sdim
133292934Sdimval (no_tools:decompiler_tools) = let
134353358Sdim  val no_jump = fn x => fail()
135314564Sdim  val no_spec = fn x => fail()
136353358Sdim  in (no_spec, no_jump, TRUTH, T) end
137344779Sdim
138292934Sdimval curr_tools = ref no_tools;
139292934Sdim
140292934Sdimfun set_tools tools = (curr_tools := tools);
141292934Sdimfun get_tools () = !curr_tools
142
143fun get_pc () = let val (_,_,_,x) = get_tools () in x end;
144fun get_status () = let val (_,_,x,_) = get_tools () in x end;
145
146fun get_output_list def = let
147  val tm = (concl o last o CONJUNCTS o SPEC_ALL) def
148  val (fm,tm) = dest_eq tm
149  val t = (tm2ftree) tm
150  fun ftree2res (FUN_VAL tm) = [tm]
151    | ftree2res (FUN_IF (tm,x,y)) = ftree2res x @ ftree2res y
152    | ftree2res (FUN_LET (tm,tn,x)) = ftree2res x
153    | ftree2res (FUN_COND (tm,x)) = ftree2res x
154  val res = filter (fn x => not (x = fm)) (ftree2res t)
155  val result = dest_tuple (hd res)
156  fun deprime x = mk_var(replace_char #"'" "" (fst (dest_var x)), type_of x)
157                  handle HOL_ERR e => x
158  in pairSyntax.list_mk_pair(map deprime result) end;
159
160val GUARD_THM =
161  prove(``!m n x. GUARD n x = GUARD m x``, REWRITE_TAC [GUARD_def]);
162
163
164(* -------------------------------------------------------------------------- *)
165(* Implementation of STAGE 1                                                  *)
166(* -------------------------------------------------------------------------- *)
167
168(* formatting *)
169
170val stack_terms = ([]):term list;
171
172fun DISCH_ALL_AS_SINGLE_IMP th = let
173  val th = RW [AND_IMP_INTRO] (DISCH_ALL th)
174  in if is_imp (concl th) then th else DISCH ``T`` th end
175
176fun replace_abbrev_vars tm = let
177  fun f v = v |-> mk_var((Substring.string o hd o tl o
178                          Substring.tokens (fn x => x = #"@") o
179                          Substring.full o fst o dest_var) v, type_of v)
180            handle HOL_ERR e => v |-> v
181  in subst (map f (free_vars tm)) tm end
182
183fun name_for_abbrev p tm = let
184  val x = get_sep_domain tm
185  in first (fn t => rator t = x) p |> rand |> dest_var |> fst end
186  handle HOL_ERR _ =>
187  "v" ^ (int_to_string (Arbnum.toInt(numSyntax.dest_numeral(cdr (car tm)))))
188  handle HOL_ERR e =>
189  if (fst (dest_const (car tm)) = "tT") handle HOL_ERR e => false then "k" else
190  if is_const (cdr (car tm)) andalso is_const(car (car tm))
191     handle HOL_ERR e => false then
192    (to_lower o fst o dest_const o cdr o car) tm
193  else if can (match_term ``(f ((n2w n):'a word) (x:'c)):'d``) tm then
194    "r" ^ ((int_to_string o numSyntax.int_of_term o cdr o cdr o car) tm)
195  else
196    fst (dest_var (repeat cdr tm)) handle HOL_ERR e =>
197    fst (dest_var (find_term is_var tm)) handle HOL_ERR e =>
198    fst (dest_const (repeat car (get_sep_domain tm)));
199
200fun raw_abbreviate2 (var_name,y,tm) th = let
201  val y = mk_eq(mk_var(var_name,type_of y),y)
202  val cc = UNBETA_CONV tm
203           THENC (RAND_CONV) (fn t => GSYM (ASSUME y))
204           THENC BETA_CONV
205  val th = CONV_RULE (RAND_CONV cc) th
206  in th end;
207
208fun raw_abbreviate (var_name,y,tm) th = let
209  val y = mk_eq(mk_var(var_name,type_of y),y)
210  val cc = UNBETA_CONV tm
211           THENC (RAND_CONV o RAND_CONV) (fn t => GSYM (ASSUME y))
212           THENC BETA_CONV
213  val th = CONV_RULE (RAND_CONV cc) th
214  in th end;
215
216fun abbreviate (var_name,tm) th = raw_abbreviate (var_name,cdr tm,tm) th
217
218fun ABBREV_POSTS dont_abbrev_list prefix th = let
219  fun dont_abbrev tm = mem tm (dont_abbrev_list @ stack_terms)
220  fun next_abbrev p [] = fail()
221    | next_abbrev p (tm::xs) =
222    if (is_var (cdr tm) andalso
223       (name_for_abbrev p tm = fst (dest_var (cdr tm))))
224       handle HOL_ERR e => false then next_abbrev p xs else
225    if (prefix ^ (name_for_abbrev p tm) = fst (dest_var (cdr tm)))
226       handle HOL_ERR e => false then next_abbrev p xs else
227    if can dest_sep_hide tm then next_abbrev p xs else
228    if dont_abbrev (car tm) then next_abbrev p xs else
229      (prefix ^ name_for_abbrev p tm,tm)
230  val (th,b) = let
231    val (_,p,_,q) = dest_spec (concl th)
232    val p = list_dest dest_star p
233            |> filter (fn tm => (is_var o rand) tm handle HOL_ERR _ => false)
234    val xs = list_dest dest_star q
235    val th = abbreviate (next_abbrev p xs) th
236    in (th,true) end handle HOL_ERR e => (th,false) handle Empty => (th,false)
237  in if b then ABBREV_POSTS dont_abbrev_list prefix th else th end;
238
239fun ABBREV_PRECOND prefix th = let
240  val th = RW [SPEC_MOVE_COND] (SIMP_RULE (bool_ss++sep_cond_ss) [] th)
241  val tm = (fst o dest_imp o concl) th
242  val v = mk_var(prefix^"cond",``:bool``)
243  val thx = SYM (BETA_CONV (mk_comb(mk_abs(v,v),tm)))
244  val th = CONV_RULE ((RATOR_CONV o RAND_CONV) (fn tm => thx)) th
245  val th = SIMP_RULE (bool_ss++sep_cond_ss) [] (RW [precond_def] (UNDISCH th))
246  in th end handle HOL_ERR e => th handle Empty => th;
247
248fun ABBREV_STACK prefix th = let
249  val (_,p,_,q) = dest_spec (concl th)
250  val f = find_term (fn tm => mem (car tm) stack_terms
251          handle HOL_ERR _ => false)
252  val s_pre = f p
253  val s_post = f q
254  val xs = map (fn {redex=x1, residue=x2} => (x1,x2))
255               (fst (match_term s_pre s_post))
256  val th1 = CONV_RULE (UNBETA_CONV s_post) th
257  val ys = map (fn (x1,x2) =>
258                  mk_eq(mk_var(prefix ^ fst (dest_var x1), type_of x1),x2)) xs
259  val rw = map (GSYM o ASSUME) ys
260  val cs = map (fn th => fn tm =>
261                  if tm = fst (dest_eq (concl th)) then th else NO_CONV tm) rw
262  fun each [] = ALL_CONV | each (c::cs) = c ORELSEC each cs
263  val th1 = CONV_RULE (RAND_CONV (DEPTH_CONV (each cs)) THENC BETA_CONV) th1
264  in th1 end handle HOL_ERR _ => th
265
266fun ABBREV_ALL dont_abbrev_list prefix th = let
267  val th = ABBREV_POSTS dont_abbrev_list prefix th
268  val th = ABBREV_STACK prefix th
269  val th = ABBREV_PRECOND prefix th
270  in th end;
271
272fun ABBREV_CALL prefix th = let
273  val (_,_,_,q) = (dest_spec o concl) th
274  val (x,tm) = pairSyntax.dest_anylet q
275  val (x,y) = hd x
276  val ys = map (fn v => mk_var(prefix^(fst (dest_var v)),type_of v))
277               (dest_tuple x)
278  val thi = ASSUME (mk_eq(pairSyntax.list_mk_pair ys, y))
279  val thj = RW1 [LET_DEF] (GSYM thi)
280  val th = CONV_RULE (RAND_CONV (RAND_CONV (fn tm => thj))) (RW [LET_DEF] th)
281  val th = RW [FST,SND] (PairRules.PBETA_RULE (RW [LET_DEF] th))
282  in ABBREV_PRECOND prefix th end
283  handle HOL_ERR e => ABBREV_PRECOND prefix th
284  handle Empty => ABBREV_PRECOND prefix th;
285
286fun UNABBREV_ALL th = let
287  fun remove_abbrev th = let
288    val th = CONV_RULE ((RATOR_CONV o RAND_CONV) expand_conv) th
289    val th = RW [GSYM AND_IMP_INTRO] th
290    val (x,y) = (dest_eq o fst o dest_imp o concl) th
291    in MP (INST [x|->y] th) (REFL y) end
292    handle HOL_ERR e =>
293       UNDISCH (CONV_RULE ((RATOR_CONV o RAND_CONV) BETA_CONV) th)
294       handle HOL_ERR e => UNDISCH th
295  in repeat remove_abbrev (DISCH_ALL th) end;
296
297
298(* derive SPEC theorems *)
299
300fun pair_apply f ((th1,x1:int,x2:int option),NONE) = ((f th1,x1,x2),NONE)
301  | pair_apply f ((th1,x1,x2),SOME (th2,y1:int,y2:int option)) =
302      ((f th1,x1,x2),SOME (f th2,y1,y2))
303
304fun jump_apply f NONE = NONE | jump_apply f (SOME x) = SOME (f x);
305
306fun pair_jump_apply (f:int->int) ((th1,x1:int,x2:int option),NONE) =
307      ((th1,x1,jump_apply f x2),NONE)
308  | pair_jump_apply f ((th1:thm,x1,x2),SOME (th2:thm,y1:int,y2:int option)) =
309      ((th1,x1,jump_apply f x2),SOME (th2,y1,jump_apply f y2));
310
311fun introduce_guards thms = let
312  val pattern = (fst o dest_eq o concl o SPEC_ALL) cond_def
313(*
314  val (n,(th1,i1,j1),SOME (th2,i2,j2)) = el 8 res
315*)
316  fun intro (n,(th1,i1,j1),NONE) = (n,(th1,i1,j1),NONE)
317    | intro (n,(th1,i1,j1),SOME (th2,i2,j2)) = let
318    val t1 = cdr (find_term (can (match_term pattern)) (concl th1))
319    val t2 = cdr (find_term (can (match_term pattern)) (concl th2))
320    val h = RW [SPEC_MOVE_COND] o SIMP_RULE (bool_ss++sep_cond_ss) []
321    val (th1,th2) = (h th1,h th2)
322    val tm1 = (mk_neg o fst o dest_imp o concl) th1
323    val tm2 = (fst o dest_imp o concl) th2
324    val lemma =
325       auto_prove "introduce_guards" (mk_eq(tm2,tm1),SIMP_TAC std_ss [])
326    val th2 =
327       CONV_RULE ((RATOR_CONV o RAND_CONV) (ONCE_REWRITE_CONV [lemma])) th2
328    val rw = SPEC (numSyntax.term_of_int n) GUARD_def
329    val f1 =
330       CONV_RULE ((RATOR_CONV o RAND_CONV) (PURE_ONCE_REWRITE_CONV [GSYM rw]))
331    val f2 = CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV)
332                           (PURE_ONCE_REWRITE_CONV [GSYM rw]))
333    val (th1,th2) = if is_neg t1 then (f2 th1,f1 th2) else (f1 th1, f2 th2)
334    val h2 = RW [GSYM SPEC_MOVE_COND]
335    val (th1,th2) = (h2 th1,h2 th2)
336    in (n,(th1,i1,j1),SOME (th2,i2,j2)) end
337  val thms = map intro thms
338  in thms end
339
340fun derive_individual_specs tools (code:string list) = let
341  val (f,_,hide_th,pc) = tools
342  fun get_model_status_list th =
343    (map dest_sep_hide o list_dest dest_star o snd o dest_eq o concl) th
344    handle HOL_ERR e => []
345  val dont_abbrev_list = pc :: get_model_status_list hide_th
346  val delete_spaces = (implode o filter (fn x => not(x = #" ")) o explode)
347  fun list_find name [] = fail ()
348    | list_find name ((x,y)::xs) = if name = x then y else list_find name xs
349  fun get_specs (instruction,(n,ys)) =
350    if String.isPrefix "insert:" (delete_spaces instruction) then let
351      val name = delete_spaces instruction
352      val name = substring(name,7,length (explode name) - 7)
353      val (th,i,j) = list_find name (!decompiler_memory)
354      val th = RW [sidecond_def,hide_th,STAR_ASSOC] th
355      val th = ABBREV_CALL ("new@") th
356      val _ = echo 1 "  (insert command)\n"
357      in (n+1,(ys @ [(n,(th,i,j),NONE)])) end
358    else let
359      val _ = echo 1 ("  "^instruction^":")
360      val i = int_to_string n
361      val g = RW [precond_def] o ABBREV_ALL dont_abbrev_list ("new@")
362      val (x,y) = pair_apply g (f instruction)
363      val _ = echo 1 ".\n"
364      in (n+1,(ys @ [(n,x,y)])) end
365  val _ = echo 1 "\nDeriving theorems for individual instructions.\n"
366(*
367  val instruction = el 1 code
368  val ((th,_,_),_) = f instruction
369  val th = renamer th
370  val prefix = "foo@"
371*)
372  val res = snd (foldl get_specs (1,[]) code)
373  val res = introduce_guards res
374  fun calc_addresses i [] = []
375    | calc_addresses i ((n:int,(th1:thm,l1,j1),y)::xs)  = let
376    val (x,y) = pair_jump_apply (fn j => i+j) ((th1,l1,j1),y)
377    in (i,x,y) :: calc_addresses (i+l1) xs end
378  val res = calc_addresses 0 res
379  val _ = echo 1 "\n"
380  in res end;
381
382fun inst_pc_var tools thms = let
383  fun triple_apply f (y,(th1,x1:int,x2:int option),NONE) =
384        (y,(f y th1,x1,x2),NONE)
385    | triple_apply f (y,(th1,x1,x2),SOME (th2,y1:int,y2:int option)) =
386        (y,(f y th1,x1,x2),SOME (f y th2,y1,y2))
387  val i = [mk_var("pc",``:word32``) |-> mk_var("p",``:word32``),
388           mk_var("pc",``:word64``) |-> mk_var("p",``:word64``),
389           mk_var("eip",``:word32``) |-> mk_var("p",``:word32``),
390           mk_var("rip",``:word64``) |-> mk_var("p",``:word64``)]
391  val (_,_,_,pc) = tools
392  val ty = (hd o snd o dest_type o type_of) pc
393  fun f y th = (!decompiler_set_pc) y th handle HOL_ERR _ => let
394    val aa = (hd o tl o snd o dest_type) ty
395    val th = INST i th
396    val (_,p,_,_) = dest_spec (concl th)
397    val pattern = inst [``:'a``|->aa] ``(p:'a word) + n2w n``
398    val new_p =
399       subst [mk_var("n",``:num``)|-> numSyntax.mk_numeral (Arbnum.fromInt y)]
400         pattern
401    val th = INST [mk_var("p",type_of new_p)|->new_p] th
402    val (_,_,_,q) = dest_spec (concl th)
403    val tm = find_term (fn tm => car tm = pc handle HOL_ERR e => false) q
404    val cc =
405       SIMP_CONV std_ss [word_arith_lemma1,word_arith_lemma3,word_arith_lemma4]
406    val th = CONV_RULE ((RATOR_CONV o RAND_CONV) cc) th
407    val thi = QCONV cc tm
408    in PURE_REWRITE_RULE [thi,WORD_ADD_0] th end;
409  in map (triple_apply f) thms end
410
411fun UNABBREV_CODE_RULE th = let
412  val rw = (!code_abbreviations)
413  val c = REWRITE_CONV rw THENC
414          SIMP_CONV std_ss [word_arith_lemma1] THENC
415          REWRITE_CONV [INSERT_UNION_EQ,UNION_EMPTY]
416  val th = CONV_RULE ((RATOR_CONV o RAND_CONV) c) th
417  in th end;
418
419val ABBBREV_CODE_LEMMA = prove(
420  ``!a (x :('a, 'b, 'c) processor) p c q.
421      (a ==> SPEC x p c q) ==> !d. c SUBSET d ==> a ==> SPEC x p d q``,
422  REPEAT STRIP_TAC THEN RES_TAC THEN IMP_RES_TAC SPEC_SUBSET_CODE);
423
424fun abbreviate_code name thms = let
425  fun extract_code (_,(th,_,_),_) =
426     let val (_,_,c,_) = dest_spec (concl th) in c end
427  val cs = map extract_code thms
428  val ty = (hd o snd o dest_type o type_of o hd) cs
429  val tm = foldr pred_setSyntax.mk_union (pred_setSyntax.mk_empty ty) cs
430  val cth = QCONV (PURE_REWRITE_CONV [INSERT_UNION_EQ,UNION_EMPTY]) tm
431  val c = (cdr o concl) cth
432  val (_,(th,_,_),_) = hd thms
433  val (m,_,_,_) = dest_spec (concl th)
434  val model_name = (to_lower o implode o take_until (fn x => x = #"_") o
435                    explode o fst o dest_const) m
436  val x = list_mk_pair (free_vars c)
437  val def_name = name ^ "_" ^ model_name
438  val v = mk_var(def_name,type_of(mk_pabs(x,c)))
439  val code_def = new_definition(def_name ^ "_def",mk_eq(mk_comb(v,x),c))
440  val _ = add_code_abbrev [code_def]
441  fun triple_apply f (y,(th1,x1:int,x2:int option),NONE) =
442        (y,(f th1,x1,x2),NONE)
443    | triple_apply f (y,(th1,x1,x2),SOME (th2,y1:int,y2:int option)) =
444        (y,(f th1,x1,x2),SOME (f th2,y1,y2))
445  val code_thm = CONV_RULE (RAND_CONV (fn _ => GSYM cth)) (SPEC_ALL code_def)
446  fun foo th = let
447    val thi = MATCH_MP ABBBREV_CODE_LEMMA (DISCH_ALL_AS_SINGLE_IMP th)
448    val thi = SPEC ((fst o dest_eq o concl o SPEC_ALL) code_def) thi
449    val goal = (fst o dest_imp o concl) thi
450    val lemma = auto_prove "abbreviate_code" (goal,
451        REPEAT (REWRITE_TAC [code_thm,SUBSET_DEF,IN_UNION] THEN REPEAT STRIP_TAC
452                THEN ASM_REWRITE_TAC [] THEN (fn _ => fail()))
453        THEN REWRITE_TAC [EMPTY_SUBSET]
454        THEN REWRITE_TAC [SUBSET_DEF,IN_INSERT,IN_UNION,NOT_IN_EMPTY,code_def]
455        THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC std_ss [])
456    val thi =
457       UNDISCH_ALL (PURE_REWRITE_RULE [GSYM AND_IMP_INTRO] (MP thi lemma))
458    in thi end
459  val thms = map (triple_apply foo) thms
460  in thms end
461
462fun stage_1 name tools code =
463  let
464     val thms = derive_individual_specs tools code
465     val thms = inst_pc_var tools thms
466     val thms = abbreviate_code name thms
467  in
468     thms
469  end;
470
471
472(* -------------------------------------------------------------------------- *)
473(* Implementation of STAGE 2                                                  *)
474(* -------------------------------------------------------------------------- *)
475
476fun extract_graph thms = let
477  fun extract_jumps (i,(_,_,j),NONE) = [(i,j)]
478    | extract_jumps (i,(_,_,j),SOME (_,_,k)) = [(i,j),(i,k)]
479  val jumps = append_lists (map extract_jumps thms)
480  in jumps end;
481
482fun all_distinct [] = []
483  | all_distinct (x::xs) = x :: all_distinct (filter (fn z => not (x = z)) xs)
484
485fun drop_until P [] = []
486  | drop_until P (x::xs) = if P x then x::xs else drop_until P xs
487
488fun jumps2edges jumps = let
489  fun h (i,NONE) = []
490    | h (i,SOME j) = [(i,j)]
491  in append_lists (map h jumps) end;
492
493fun extract_loops jumps = let
494  (* find all possible paths *)
495  val edges = jumps2edges jumps
496  fun all_paths_from edges i prefix = let
497    fun f [] = []
498      | f ((k,j)::xs) = if i = k then j :: f xs else f xs
499    val next = all_distinct (f edges)
500    val prefix = prefix @ [i]
501    val xs = map (fn x => if mem x prefix then [prefix @ [x]] else
502                          all_paths_from edges x prefix) next
503    val xs = if xs = [] then [[prefix]] else xs
504    in append_lists xs end
505  val paths = all_paths_from edges 0 []
506  (* get looping points *)
507  fun is_loop xs = mem (last xs) (butlast xs)
508  val loops = all_distinct (map last (filter is_loop paths))
509  (* find loop bodies and tails *)
510  fun loop_body_tail i = let
511    val bodies = filter (fn xs => last xs = i) paths
512    val bodies = filter is_loop bodies
513    val bodies = map (drop_until (fn x => x = i) o butlast) bodies
514    val bodies = all_distinct (append_lists bodies)
515    val tails = filter (fn xs => mem i xs andalso not (last xs = i)) paths
516    val tails = map (drop_until (fn x => x = i)) tails
517    in (i,bodies,tails) end
518  val summaries = map loop_body_tail loops
519  (* clean loop tails *)
520  fun clean_tails (i,xs,tails) = let
521    val tails = map (drop_until (fn x => not (mem x xs))) tails
522    val tails = filter (fn xs => not (xs = [])) tails
523    in (i,xs,tails) end
524  val zs = map clean_tails summaries
525  (* merge combined loops *)
526  val zs = map (fn (x,y,z) => ([x],y,z)) zs
527  fun find_and_merge zs = let
528    val ls = append_lists (map (fn (x,y,z) => x) zs)
529    val qs = map (fn (x,y,z) => (x,y,map hd z)) zs
530    fun f ys = filter (fn x => mem x ls andalso (not (mem x ys)))
531    val qs = map (fn (x,y,z) => (x,all_distinct (f x y @ f x z))) qs
532    fun cross [] ys = []
533      | cross (x::xs) ys = map (fn y => (x,y)) ys @ cross xs ys
534    val edges = append_lists (map (fn (x,y) => cross x y) qs)
535    val paths = map (fn i => all_paths_from edges i []) ls
536    val goals = map (fn (x,y) => (y,x)) edges
537    fun sat_goal ((i,j),path) = (hd path = i) andalso (mem j (tl path))
538    val (i,j) = fst (hd (filter sat_goal (cross goals (append_lists paths))))
539    val (p1,q1,x1) = hd (filter (fn (x,y,z) => mem i x) zs)
540    val (p2,q2,x2) = hd (filter (fn (x,y,z) => mem j x) zs)
541    val (p,q,x) = (p1 @ p2, all_distinct (q1 @ q2), x1 @ x2)
542    val zs =
543       (p,q,x) :: filter (fn (x,y,z) => not (mem i x) andalso not (mem j x)) zs
544    val zs = map clean_tails zs
545    in zs end
546  val zs = repeat find_and_merge zs
547  (* attempt to find common exit point *)
548  fun mem_all x [] = true
549    | mem_all x (xs::xss) = mem x xs andalso mem_all x xss
550  fun find_exit_points (x,y,z) = let
551    val q = hd (filter (fn x => mem_all x (tl z)) (hd z))
552    in (x,[q]) end handle Empty => (x,all_distinct (map hd z))
553  val zs = map find_exit_points zs
554  (* finalise *)
555  val exit = (all_distinct o map last o filter (not o is_loop)) paths
556  val zero = ([0],exit)
557  val zs = if filter (fn (x,y) => mem 0 x andalso subset exit y) zs = []
558              then zs @ [zero]
559           else zs
560  fun list_before x y [] = true
561    | list_before x y (z::zs) = if z = y then false else
562                                if z = x then true else list_before x y zs
563  fun compare (xs,_) (ys,_) = let
564    val x = hd xs
565    val y = hd ys
566    val p = hd (filter (fn xs => mem x xs andalso mem y xs) paths)
567    in not (list_before x y p) end handle Empty => false
568  val loops = sort compare zs
569  (* sort internal  *)
570  val int_sort = sort (fn x => fn (y:int) => x <= y)
571  val loops = map (fn (xs,ys) => (int_sort xs, int_sort ys)) loops
572  (* deal with option to return result as a single function *)
573  val loops = if not (!decompile_as_single_function) then loops else let
574    val entry = all_distinct (append_lists (map fst loops))
575    val exit = diff (all_distinct (append_lists (map snd loops))) entry
576    in [(sort (fn x => fn y => (x <= y)) entry,exit)] end
577  (* TODO: final states should still be optimised... *)
578  in loops end;
579
580fun stage_12 name tools code =
581   let
582      val thms = stage_1 name tools code
583      val jumps = extract_graph thms
584      val loops = extract_loops jumps
585   in
586      (thms, loops)
587   end;
588
589
590(* -------------------------------------------------------------------------- *)
591(* Implementation of STAGE 3                                                  *)
592(* -------------------------------------------------------------------------- *)
593
594(* STAGE 3, part a ---------------------------------------------------------- *)
595
596local val varname_counter = ref 1 in
597  fun varname_reset () = (varname_counter := 1);
598  fun varname_next () = let
599    val v = !varname_counter
600    val _ = (varname_counter := v+1)
601    in v end
602end;
603
604(* functions for composing SPEC theorems *)
605
606fun replace_new_vars v th = let
607  fun mk_new_var prefix v = let
608    val (n,ty) = dest_var v
609    val _ = if String.isPrefix "new@" n then () else fail()
610    in mk_var (prefix ^ "@" ^ (implode o drop 4 o explode) n, ty) end
611  fun rename_new tm =
612    if is_comb tm
613       then (RATOR_CONV rename_new THENC RAND_CONV rename_new) tm
614    else if not (is_abs tm)
615       then ALL_CONV tm
616    else let
617      val (x,y) = dest_abs tm
618      val conv = ALPHA_CONV (mk_new_var v x) handle HOL_ERR e => ALL_CONV
619      in (conv THENC ABS_CONV rename_new) tm end
620  val th = GEN_ALL (DISCH_ALL th)
621  val th = CONV_RULE rename_new th
622  val th = UNDISCH_ALL (SPEC_ALL th)
623  in th end;
624
625fun SPEC_COMPOSE th1 th2 = let
626  (* replace "new@..." variables with fresh numbered variables *)
627  val th2a = replace_new_vars ("s" ^ int_to_string (varname_next ())) th2
628  in SPEC_COMPOSE_RULE [th1,th2a] end;
629
630fun number_GUARD (x,y,z) = let
631  val rw = SPEC (numSyntax.term_of_int (varname_next ())) GUARD_THM
632  fun f (th1,y1,y2) = (RW1[rw]th1,y1,y2)
633  fun apply_option g NONE = NONE
634    | apply_option g (SOME x) = SOME (g x)
635  in (x,f y,apply_option f z) end;
636
637(* multi-entry/exit preformatting *)
638
639fun format_for_multi_entry entry thms = let
640  val _ = if length entry = 1 then fail() else ()
641  val pc_tm = get_pc()
642  val pos = mk_var("pos",``:num``)
643  val mk_num = numSyntax.mk_numeral o Arbnum.fromInt
644  fun mk_pos i =
645     subst [mk_var("n",``:num``) |-> mk_num i] ``p + (n2w n):word32``
646  fun foo [] n = [] | foo (y::ys) n = n :: foo ys (n+1)
647  val xs = zip (map mk_num (foo entry 0)) (map mk_pos entry)
648  fun mk [] = fail()
649    | mk [(x,y)] = y
650    | mk ((x,y)::xs) = mk_cond(mk_eq(pos,x),y,mk xs)
651  val tm = mk xs
652  val case_list = map (fn (x,y) => mk_eq(pos,x)) xs
653  val format =
654    mk_imp(``GUARD 0 (pos = k:num)``,
655           mk_eq(mk_comb(pc_tm,mk_var("t1",``:word32``)),
656                 mk_comb(pc_tm,mk_var("t2",``:word32``))))
657  val format = subst [``t2:word32``|->tm] format
658  fun mk_sub (x,y) = subst [``k:num``|->x, ``t1:word32``|->y] format
659  fun mk_goals [] rest = fail()
660    | mk_goals [(x,y)] rest =
661       [mk_conj(mk_imp(rest,snd (dest_imp (mk_sub (x,y)))),mk_sub (x,y))]
662    | mk_goals ((x,y)::xs) rest = let
663       val xy = mk_sub (x,y)
664       val r = mk_neg((cdr o car) xy)
665       in mk_conj(mk_imp(rest,xy),xy) :: mk_goals xs (mk_conj(rest,r)) end
666  val goals = mk_goals xs T
667  fun two_conj th = let
668    val xs = CONJUNCTS th
669    in if length xs = 1 then (hd xs, hd xs) else (el 1 xs, el 2 xs) end
670  val ys =
671     map (fn goal => (two_conj o RW[AND_IMP_INTRO,GSYM CONJ_ASSOC,WORD_ADD_0])
672                       (prove(goal,SIMP_TAC std_ss [GUARD_def]))) goals
673  val posts = map snd ys
674  val pres = map fst ys
675  val posts =
676     map (RW [GUARD_def] o INST [pos|->mk_var("s10000@pos",type_of pos)]) posts
677  fun RW_CONV [] tm = NO_CONV tm
678    | RW_CONV (th::xs) tm =
679       if fst (dest_eq (concl th)) = tm then th else RW_CONV xs tm
680       handle HOL_ERR _ => NO_CONV tm
681  fun process th = let
682    val th = CONV_RULE (PRE_CONV (DEPTH_CONV (RW_CONV (map UNDISCH pres)))) th
683    val th = CONV_RULE (POST_CONV (DEPTH_CONV (RW_CONV (map UNDISCH posts)))) th
684    val th = UNDISCH (DISCH_ALL_AS_SINGLE_IMP th)
685    in th end
686  fun apply f (k,(th1,i1,j1),NONE) = (k,(f th1,i1,j1),NONE)
687    | apply f (k,(th1,i1,j1),SOME (th2,i2,j2)) =
688        (k,(f th1,i1,j1),SOME (f th2,i2,j2))
689  val thms = map (apply process) thms
690  in (case_list,thms) end handle HOL_ERR _ => ([],thms);
691
692(* functions for deriving one-pass theorems *)
693
694datatype mc_tree =
695    LEAF of thm * int
696  | SEQ of term list * mc_tree
697  | BRANCH of term * mc_tree * mc_tree;
698
699fun basic_find_composition th1 (th2,l2,j2) = let
700  val th1 = modifier "pre" th1
701  val th2 = modifier "pre" th2
702  val th = remove_primes (SPEC_COMPOSE th1 th2) handle HOL_ERR e =>
703           remove_primes (SPEC_COMPOSE th1 (UNABBREV_ALL th2))
704  val th = modifier "post" th
705  val th = RW [WORD_CMP_NORMALISE] th
706  val th = RW [GSYM WORD_NOT_LOWER, GSYM WORD_NOT_LESS] th
707  fun h x = (fst o dest_eq) x handle e => (fst o dest_abs o car) x
708  fun f [] ys = ys | f (x::xs) ys = f xs (h x :: ys handle e => ys)
709  val th2_hyps = f (hyp th2) []
710  fun g tm = mem (h tm) th2_hyps handle e => false
711  val lets = filter g (hyp th)
712  in ((th,l2,j2),lets) end
713
714fun find_cond_composition th1 NONE = fail()
715  | find_cond_composition th1 (SOME (th2,l2,j2)) = let
716  val th = RW [SPEC_MOVE_COND] th2
717  val th = if concl th = T then fail() else th
718  val th = if not (is_imp (concl th)) then th else
719             CONV_RULE
720                ((RATOR_CONV o RAND_CONV)
721                    (ONCE_REWRITE_CONV [GSYM CONTAINER_def])) th
722  val th = RW [GSYM SPEC_MOVE_COND] th
723  val ((th,l,j),lets) = basic_find_composition th1 (th,l2,j2)
724  val th = SIMP_RULE (bool_ss++sep_cond_ss) [SEP_CLAUSES] th
725  val th =
726     SIMP_RULE std_ss [SPEC_MOVE_COND,GSYM AND_IMP_INTRO,SEP_EXISTS_COND] th
727  fun imps tm xs =
728     let val (x,y) = dest_imp tm in imps y (x::xs) end handle e => xs
729  fun is_CONTAINER tm =
730     (fst o dest_const o car) tm = "CONTAINER" handle e => false
731  val xs = filter is_CONTAINER (imps (concl th) [])
732  val th = RW [GSYM SPEC_MOVE_COND,CONTAINER_def] th
733  in let val cond = snd (dest_comb (hd xs)) in
734     let val cond = dest_neg cond in (cond,(th,l,j)) end
735     handle e => (mk_neg cond,(th,l,j)) end
736     handle e => (``F:bool``,(th,l,j)) end;
737
738fun remove_guard tm =
739  (cdr o concl o REWRITE_CONV [GUARD_def]) tm handle UNCHANGED => tm;
740
741fun find_first i [] = fail()
742  | find_first i ((x,y,z)::xs) = if i = x then (x,y,z) else find_first i xs
743
744fun tree_composition (th,i:int,thms,entry,exit,conds,firstTime) =
745  if mem i entry andalso not firstTime then LEAF (th,i) else
746  if mem i exit then LEAF (th,i) else let
747    val (_,thi1,thi2) = number_GUARD (find_first i thms)
748    in let (* try composing second branch *)
749       val (cond,(th2,_,i2)) = find_cond_composition th thi2
750       val cond' = remove_guard cond
751       in if mem (negate cond') conds
752          then (* case: only second branch possible *)
753               tree_composition (th2,the i2,thms,entry,exit,conds,false)
754          else if mem cond' conds then fail()
755          else (* case: both branches possible *) let
756            val ((th1,_,i1),lets) = basic_find_composition th thi1
757            val t1 = tree_composition
758                       (th1,the i1,thms,entry,exit,cond'::conds,false)
759            val t2 = tree_composition
760                       (th2,the i2,thms,entry,exit,negate cond'::conds,false)
761            val t1 = if length lets = 0 then t1 else SEQ (lets,t1)
762            in BRANCH (cond,t1,t2) end end
763       handle e => (* case: only first branch possible *) let
764       val ((th,_,i),lets) = basic_find_composition th thi1
765       val result = tree_composition (th,the i,thms,entry,exit,conds,false)
766       in if length lets = 0 then result else SEQ (lets,result) end end
767
768fun map_spectree f (LEAF (thm,i)) = LEAF (f thm,i)
769  | map_spectree f (SEQ (x,t)) = SEQ(x, map_spectree f t)
770  | map_spectree f (BRANCH (j,t1,t2)) =
771      BRANCH (j, map_spectree f t1, map_spectree f t2)
772
773fun merge_entry_points [] ts = hd ts
774  | merge_entry_points [x] ts = hd ts
775  | merge_entry_points (x::xs) ts = let
776      val t1 = merge_entry_points xs (tl ts)
777      in BRANCH (mk_comb(``GUARD 0``,x), hd ts, t1) end
778
779fun generate_spectree thms (entry,exit) = let
780  val _ = varname_reset ()
781  val (_,(th,_,_),_) = hd thms
782  val hide_th = get_status()
783  fun apply_to_th f (i,(th,k,l),NONE) = (i,(f th,k,l),NONE)
784    | apply_to_th f (i,(th,k,l),SOME (th2,k2,l2)) =
785        (i,(f th,k,l),SOME (f th2,k2,l2))
786  val thms = map (apply_to_th (RW [hide_th])) thms
787  val (case_list,thms) = format_for_multi_entry entry thms
788  val (_,(th,_,_),_) = hd thms
789  val (m,_,_,_) = dest_spec (concl th)
790  val (default_th,is,conds,firstTime) =
791     (Q.SPECL [`emp`,`{}`] (ISPEC m SPEC_REFL),entry,[]:term list,true)
792  val i = hd is
793  val _ = echo 1 "Composing,"
794  val ts = map (fn i => let
795             val th = modifier ("shape " ^ int_to_string i) default_th
796             val t = tree_composition (th,i,thms,entry,exit,conds,firstTime)
797             in (i,t) end) is
798  val t = merge_entry_points case_list (map snd ts)
799  val t = if not (is_eq (concl (SPEC_ALL hide_th))) then t
800          else map_spectree (HIDE_STATUS_RULE true hide_th) t
801  val t = map_spectree (modifier "spec") t
802  in t end;
803
804(*
805val in_post = true
806fun spectree_leaves (LEAF (thm,i)) = [thm]
807  | spectree_leaves (SEQ (x,t)) = spectree_leaves t
808  | spectree_leaves (BRANCH (j,t1,t2)) = spectree_leaves t1 @ spectree_leaves t2
809val th = el 2 (spectree_leaves t)
810*)
811
812
813(* STAGE 3, part b ---------------------------------------------------------- *)
814
815(* merge spectree theorems *)
816
817fun strip_tag v = let
818  val vs = (drop_until (fn x => x = #"@") o explode o fst o dest_var) v
819  in if vs = [] then (fst o dest_var) v else implode (tl vs) end
820
821fun read_tag v = let
822  val xs = (explode o fst o dest_var) v
823  val vs = take_until (fn x => x = #"@") xs
824  in if length vs = length xs then "" else implode vs end
825
826fun ABBREV_NEW th = let
827  val pc = get_pc ()
828  val ty = (hd o snd o dest_type o type_of) pc
829  val tm =
830    find_term (can (match_term (mk_comb(pc,genvar(ty))))) (cdr (concl th))
831  val th = abbreviate ("new@p",tm) th
832  val ws = (filter (not o is_new_var) o free_vars o cdr o concl) th
833  fun one(v,th) = raw_abbreviate2 ("new@" ^ strip_tag v,v,v) th
834  val th = foldr one th ws
835  val th =
836    UNDISCH (RW [SPEC_MOVE_COND,AND_IMP_INTRO,GSYM CONJ_ASSOC] (DISCH_ALL th))
837  in th end
838
839fun remove_tags tm =
840  subst (map (fn v => v |-> mk_var(strip_tag v,type_of v)) (free_vars tm)) tm
841
842fun list_dest_sep_exists tm = let
843  val vs = list_dest dest_sep_exists tm
844  in (butlast vs, last vs) end;
845
846fun prepare_sep_disj_posts th1 th2 = let
847  val (_,_,_,q1) = dest_spec (concl th1)
848  val (_,_,_,q2) = dest_spec (concl th2)
849  in if can dest_sep_disj q1 orelse can dest_sep_disj q2 then let
850       val th1 = if can dest_sep_disj q2 then
851                   SPEC (snd (dest_sep_disj q2)) (MATCH_MP SPEC_ADD_DISJ th1)
852                 else th1
853       val th2 = if can dest_sep_disj q1 then
854                   SPEC (snd (dest_sep_disj q1)) (MATCH_MP SPEC_ADD_DISJ th2)
855                 else th2
856       val f =
857          RW [SEP_CLAUSES] o
858          CONV_RULE ((RAND_CONV o RAND_CONV)
859                     (SIMP_CONV std_ss [AC SEP_DISJ_ASSOC SEP_DISJ_COMM])) o
860          RW [SEP_DISJ_ASSOC]
861       val th1 = f th1
862       val th2 = f th2
863       in (th1,th2) end
864     else (th1,th2) end;
865
866val merge_mem = ref (T,TRUTH,TRUTH);
867(*
868val (guard,th1,th2) = (!merge_mem);
869*)
870
871fun MERGE guard th1 th2 = let
872  (* fill in preconditions *)
873  val th1 = remove_primes th1
874  val th2 = remove_primes th2
875  val p = get_pc ()
876  val (_,p1,_,q1) = dest_spec (concl th1)
877  val (_,p2,_,q2) = dest_spec (concl th2)
878  val (qs1,q1) = list_dest_sep_exists q1
879  val (qs2,q2) = list_dest_sep_exists q2
880  fun fst_sep_disj tm = fst (dest_sep_disj tm) handle HOL_ERR _ => tm
881  val xs1 = filter (fn x => not (p = get_sep_domain x))
882               (list_dest dest_star (fst_sep_disj q1))
883  val xs2 = filter (fn x => not (p = get_sep_domain x))
884               (list_dest dest_star (fst_sep_disj q2))
885  val xs1 = map remove_tags xs1
886  val xs2 = map remove_tags xs2
887  val zs1 = map get_sep_domain xs1
888  val zs2 = map get_sep_domain xs2
889  val ys1 = filter (fn x => not (mem (get_sep_domain x) zs1)) xs2
890  val ys2 = filter (fn x => not (mem (get_sep_domain x) zs2)) xs1
891  val th1 = SPEC (list_mk_star ys1 (type_of p1)) (MATCH_MP SPEC_FRAME th1)
892  val th2 = SPEC (list_mk_star ys2 (type_of p2)) (MATCH_MP SPEC_FRAME th2)
893  val th1 = SIMP_RULE std_ss [SEP_CLAUSES,STAR_ASSOC] th1
894  val th2 = SIMP_RULE std_ss [SEP_CLAUSES,STAR_ASSOC] th2
895  (* unhide relevant preconditions *)
896  val (_,p1,_,q1) = dest_spec (concl th1)
897  val (_,p2,_,q2) = dest_spec (concl th2)
898  val (ps1,p1) = list_dest_sep_exists p1
899  val (ps2,p2) = list_dest_sep_exists p2
900  val xs1 = filter (fn x => not (p = get_sep_domain x)) (list_dest dest_star p1)
901  val xs2 = filter (fn x => not (p = get_sep_domain x)) (list_dest dest_star p2)
902  val ys1 = map dest_sep_hide (filter (can dest_sep_hide) xs1)
903  val ys2 = map dest_sep_hide (filter (can dest_sep_hide) xs2)
904  val zs1 = (filter (not o can dest_sep_hide) xs1)
905  val zs2 = (filter (not o can dest_sep_hide) xs2)
906  val qs1 = filter (fn x => mem (car x) ys1 handle HOL_ERR _ => false) zs2
907  val qs2 = filter (fn x => mem (car x) ys2 handle HOL_ERR _ => false) zs1
908  val th1 = foldr (uncurry UNHIDE_PRE_RULE) th1 qs1
909  val th2 = foldr (uncurry UNHIDE_PRE_RULE) th2 qs2
910  (* hide relevant postconditions *)
911  val (_,p1,_,q1) = dest_spec (concl th1)
912  val (_,p2,_,q2) = dest_spec (concl th2)
913  val (qs1,q1) = list_dest_sep_exists q1
914  val (qs2,q2) = list_dest_sep_exists q2
915  val xs1 = filter (fn x => not (p = get_sep_domain x))
916               (list_dest dest_star (fst_sep_disj q1))
917  val xs2 = filter (fn x => not (p = get_sep_domain x))
918               (list_dest dest_star (fst_sep_disj q2))
919  val ys1 = map dest_sep_hide (filter (can dest_sep_hide) xs1)
920  val ys2 = map dest_sep_hide (filter (can dest_sep_hide) xs2)
921  fun safe_car tm = car tm handle HOL_ERR _ => tm
922  val zs1 = map safe_car (filter (not o can dest_sep_hide) xs1)
923  val zs2 = map safe_car (filter (not o can dest_sep_hide) xs2)
924  val qs1 = filter (fn x => mem x ys1) zs2
925  val qs2 = filter (fn x => mem x ys2) zs1
926  val th1 = foldr (uncurry HIDE_POST_RULE) th1 qs2
927  val th2 = foldr (uncurry HIDE_POST_RULE) th2 qs1
928  (* abbreviate posts *)
929  val f = CONV_RULE (PRE_CONV (SIMP_CONV (bool_ss++star_ss) []) THENC
930                     POST_CONV (SIMP_CONV (bool_ss++star_ss) []) THENC
931                     REWRITE_CONV [STAR_ASSOC])
932  val th1 = f (ABBREV_NEW th1)
933  val th2 = f (ABBREV_NEW th2)
934  (* do the merge *)
935  fun g x = PURE_REWRITE_RULE [AND_IMP_INTRO] o DISCH x o DISCH_ALL
936  val (th1,th2) = prepare_sep_disj_posts th1 th2
937  val th = MATCH_MP SPEC_COMBINE (g guard th1)
938  val th = MATCH_MP th (g (mk_neg guard) th2)
939  val th = UNDISCH (RW [UNION_IDEMPOT] th)
940  val th = remove_primes th
941  in th end handle HOL_ERR e => let
942    val _ = (merge_mem := (guard,th1,th2))
943    val th1 = DISCH_ALL th1
944    val th2 = DISCH_ALL th2
945    val _ = print ("\n\nval guard = ``"^ term_to_string guard ^"``;\n\n")
946    val _ = print ("\n\nval th1 = mk_thm([],``"^ term_to_string (concl th1) ^
947                   "``);\n\n")
948    val _ = print ("\n\nval th2 = mk_thm([],``"^ term_to_string (concl th2) ^
949                   "``);\n\n")
950    in raise HOL_ERR e end;
951
952fun merge_spectree_thm (LEAF (th,i)) = let
953      val th = SIMP_RULE (bool_ss++sep_cond_ss) [SEP_EXISTS_COND] th
954      val th = UNDISCH (RW [SPEC_MOVE_COND,AND_IMP_INTRO] (DISCH_ALL th))
955      in (th,LEAF (TRUTH,i)) end
956  | merge_spectree_thm (SEQ (tms,t)) = let
957      val (th,t) = merge_spectree_thm t
958      in (th,SEQ (tms,t)) end
959  | merge_spectree_thm (BRANCH (guard,t1,t2)) = let
960      val (th1,t1') = merge_spectree_thm t1
961      val (th2,t2') = merge_spectree_thm t2
962      val th = MERGE guard th1 th2
963      in (th,BRANCH (guard,t1',t2')) end
964
965fun merge_spectree name t = let
966  val _ = echo 1 " merging cases,"
967  val (th,_) = merge_spectree_thm t
968  val th = MERGE ``T`` th th
969  val th = UNDISCH_ALL (remove_primes (DISCH_ALL th))
970  in th end
971
972
973(* STAGE 3, part c ---------------------------------------------------------- *)
974
975(* clean the theorem *)
976
977fun tagged_var_to_num v = let
978  fun drop_until p [] = []
979    | drop_until p (x::xs) = if p x then x::xs else drop_until p xs
980  val xs = (take_until (fn x => x = #"@") o explode o fst o dest_var) v
981  val xs =
982     drop_until
983        (fn x => mem x [#"0",#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]) xs
984  val s = implode xs
985  val s = if s = "" then "100000" else s
986  in string_to_int s end
987
988val GUARD_T = prove(``!x. x = (x = GUARD 0 T)``,REWRITE_TAC [GUARD_def])
989val GUARD_F = prove(``!x. ~x = (x = GUARD 0 F)``,REWRITE_TAC [GUARD_def])
990
991fun init_clean th = let
992  fun side2guard_conv tm =
993    if not (can (match_term ``(\x.x:bool) y``) tm)
994    then NO_CONV tm else let
995      val v =
996        (numSyntax.term_of_int o tagged_var_to_num o fst o dest_abs o car) tm
997      in (BETA_CONV THENC ONCE_REWRITE_CONV [GSYM (SPEC v GUARD_def)]) tm end
998  val th = RW [PUSH_IF_LEMMA,GSYM CONJ_ASSOC] (DISCH_ALL th)
999  val th = CONV_RULE (DEPTH_CONV side2guard_conv) (DISCH_ALL th)
1000  val th = CONV_RULE ((RATOR_CONV o RAND_CONV)
1001                     (SIMP_CONV bool_ss [GSYM CONJ_ASSOC,NOT_IF])) th
1002  val th = remove_primes th
1003  fun bool_var_assign_conv tm =
1004    if is_conj tm then BINOP_CONV bool_var_assign_conv tm else
1005    if is_cond tm then BINOP_CONV bool_var_assign_conv tm else
1006    if is_var tm andalso type_of tm = ``:bool`` then SPEC tm GUARD_T else
1007    if is_neg tm andalso is_var (cdr tm ) then SPEC (cdr tm) GUARD_F
1008    else ALL_CONV tm
1009  val th = CONV_RULE ((RATOR_CONV o RAND_CONV) bool_var_assign_conv) th
1010  in th end;
1011
1012fun guard_to_num tm = (numSyntax.int_of_term o cdr o car) tm
1013fun assum_to_num tm =
1014  if is_var tm then tagged_var_to_num tm else
1015  if is_neg tm andalso is_var (cdr tm) then tagged_var_to_num (cdr tm) else
1016  if is_cond tm then 100000 else
1017  if can (match_term ``GUARD b x``) tm then guard_to_num tm else
1018  if can (match_term ``~(GUARD b x)``) tm then guard_to_num (cdr tm) else
1019    (hd o map tagged_var_to_num o free_vars o fst o dest_eq) tm
1020
1021fun push_if_inwards th = let
1022  fun drop_until p [] = []
1023    | drop_until p (x::xs) = if p x then x::xs else drop_until p xs
1024  fun strip_names v = let
1025    val vs = (drop_until (fn x => x = #"@") o explode o fst o dest_var) v
1026    in if vs = [] then (fst o dest_var) v else implode vs end
1027  fun sort_seq tms = let
1028    val xs = all_distinct (map assum_to_num tms)
1029    val xs = sort (fn x => fn y => x <= y) xs
1030    val xs = map (fn x => filter (fn tm => x = assum_to_num tm) tms) xs
1031    fun internal_sort ys = let
1032      val zs = filter (fn tm => can (match_term ``GUARD b x``) tm orelse
1033                                can (match_term ``~(GUARD b x)``) tm) ys
1034      val ys = diff ys zs
1035      fun comp tm1 tm2 = let
1036        val (defs,_) = dest_eq tm1
1037        val (_,refs) = dest_eq tm2
1038        in disjoint (map strip_names (free_vars defs))
1039                    (map strip_names (free_vars refs)) end
1040      fun f [] = []
1041        | f [x] = [x]
1042        | f (x::y::ys) = if comp x y then x :: f (y::ys) else y :: f (x::ys)
1043      in zs @ f ys end
1044    in append_lists (map internal_sort xs) end
1045  fun PUSH_IF_TERM tm = let
1046    val (b,t1,t2) = dest_cond tm
1047    val t1 = PUSH_IF_TERM t1
1048    val t2 = PUSH_IF_TERM t2
1049    val xs1 = list_dest dest_conj t1
1050    val xs2 = list_dest dest_conj t2
1051    val i = guard_to_num b
1052    val ys1 = filter (fn x => assum_to_num x < i) xs1
1053    val ys2 = filter (fn x => assum_to_num x < i) xs2
1054    val _ = if same_set ys1 ys2 then () else hd []
1055    val zs1 = sort_seq (diff xs1 ys1)
1056    val zs2 = sort_seq (diff xs2 ys2)
1057    val q = mk_cond(b,list_mk_conj zs1,list_mk_conj zs2)
1058    val goal = list_mk_conj(sort_seq ys1 @ [q])
1059    in goal end handle HOL_ERR _ =>
1060    list_mk_conj(sort_seq (list_dest dest_conj tm))
1061  val th = RW [NOT_IF] (DISCH_ALL th)
1062  val tm = (fst o dest_imp o concl) th
1063  val goal = mk_imp(PUSH_IF_TERM tm,tm)
1064  val simp = SIMP_CONV pure_ss [AC CONJ_ASSOC CONJ_COMM]
1065  val lemma = auto_prove "push_if_inwards" (goal,
1066    REWRITE_TAC [PUSH_IF_LEMMA]
1067    THEN CONV_TAC (RAND_CONV simp THENC (RATOR_CONV o RAND_CONV) simp)
1068    THEN REWRITE_TAC [])
1069  val th = DISCH_ALL (MP th (UNDISCH lemma))
1070  val th =
1071    CONV_RULE ((RATOR_CONV o RAND_CONV) (SIMP_CONV bool_ss [GUARD_EQ_ZERO])) th
1072  in th end;
1073
1074fun list_dest_exists tm ys = let
1075  val (v,y) = dest_exists tm
1076  in list_dest_exists y (v::ys) end handle e => (rev ys, tm)
1077
1078(* val tm = ``?x. (x = y + 5) /\ x < z /\ t < x`` *)
1079(* val tm = ``?z. (z = x + 5)`` *)
1080
1081fun INST_EXISTS_CONV tm = let
1082  val (v,rest) = dest_exists tm
1083  val (x,rest) = dest_conj rest
1084  val (x,y) = dest_eq x
1085  val th = ISPECL [mk_abs(v,rest),y] UNWIND_THM2
1086  val th = CONV_RULE (RAND_CONV BETA_CONV) th
1087  val th = CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV)
1088             (ALPHA_CONV v THENC ABS_CONV (RAND_CONV BETA_CONV))) th
1089  in if x = v then th else NO_CONV tm end handle HOL_ERR _ => let
1090  val (v,rest) = dest_exists tm
1091  val (x,y) = dest_eq rest
1092  val th = GEN_ALL (SIMP_CONV std_ss [] ``?x:'a. x = a``)
1093  val th = ISPEC y th
1094  val th = CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV)
1095             (ALPHA_CONV v)) th
1096  in if x = v then th else NO_CONV tm end
1097
1098(* val tm = ``!x. foo (FST x, SND (SND x)) = FST (SND x)`` *)
1099
1100val EXPAND_FORALL_CONV = let
1101  fun EXPAND_FORALL_ONCE_CONV tm =
1102    ((QUANT_CONV (UNBETA_CONV (fst (dest_forall tm))) THENC
1103      ONCE_REWRITE_CONV [FORALL_PROD] THENC
1104      (QUANT_CONV o QUANT_CONV) BETA_CONV)) tm
1105    handle HOL_ERR _ => ALL_CONV tm;
1106  in (REPEATC (DEPTH_CONV EXPAND_FORALL_ONCE_CONV)) end
1107
1108(* val tm = ``?z:num. y + x + 5 < 7`` *)
1109
1110fun PUSH_EXISTS_CONST_CONV tm = let
1111  val PUSH_EXISTS_CONST_LEMMA = auto_prove "PUSH_EXISTS_CONST_CONV"
1112   (``!p. (?x:'a. p) = p:bool``,
1113    REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC
1114    THEN EXISTS_TAC (genvar(``:'a``)) THEN ASM_SIMP_TAC std_ss []);
1115  val (v,n) = dest_exists tm
1116  val _ = if mem v (free_vars n) then hd [] else 1
1117  val th = SPEC n (INST_TYPE [``:'a``|->type_of v] PUSH_EXISTS_CONST_LEMMA)
1118  val th = CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV) (ALPHA_CONV v)) th
1119  in th end handle e => NO_CONV tm handle e => NO_CONV tm;
1120
1121(* val tm = ``?x. let (y,z,q) = foo t in y + x + z + 5 = 8 - q`` *)
1122
1123fun PUSH_EXISTS_LET_CONV tm = let
1124  val (v,n) = dest_exists tm
1125  val (x,rest) = pairSyntax.dest_anylet n
1126  val tm2 = pairSyntax.mk_anylet(x,mk_exists(v,rest))
1127  val goal = mk_eq(tm,tm2)
1128  val c = (RATOR_CONV o RATOR_CONV) (REWRITE_CONV [LET_DEF])
1129  val thi = auto_prove "PUSH_EXISTS_LET_CONV" (goal,
1130    SPEC_TAC (snd (hd x),genvar(type_of (snd (hd x))))
1131    THEN CONV_TAC EXPAND_FORALL_CONV THEN REPEAT STRIP_TAC
1132    THEN CONV_TAC ((RAND_CONV) c)
1133    THEN CONV_TAC ((RATOR_CONV o RAND_CONV o QUANT_CONV) c)
1134    THEN NTAC ((length o dest_tuple o fst o hd) x + 1)
1135      (CONV_TAC (ONCE_DEPTH_CONV BETA_CONV)
1136       THEN CONV_TAC (ONCE_DEPTH_CONV BETA_CONV)
1137       THEN REWRITE_TAC [UNCURRY_DEF]))
1138  in thi end handle e => NO_CONV tm
1139             handle e => NO_CONV tm;
1140
1141(* val tm = ``?x y z. if (q = 4) then (x + 1 = 6) else (y - 8 = z)`` *)
1142
1143fun PUSH_EXISTS_COND_CONV tm = let
1144  val (vs,n) = list_dest_exists tm []
1145  val _ = if vs = [] then hd [] else ()
1146  val (b,x1,x2) = dest_cond n
1147  val tm2 = mk_cond(b,list_mk_exists(vs,x1),list_mk_exists(vs,x2))
1148  val thi = auto_prove "PUSH_EXISTS_COND_CONV"
1149            (mk_eq(tm,tm2),Cases_on [ANTIQUOTE b] THEN ASM_REWRITE_TAC [])
1150  in thi end handle e => NO_CONV tm handle e => NO_CONV tm;
1151
1152(* val tm = ``?x y z. (q = 4) /\ (x + 1 = 6)`` *)
1153
1154fun PUSH_EXISTS_CONJ_CONV tm = let
1155  val (vs,n) = list_dest_exists tm []
1156  val xs = (list_dest dest_conj n)
1157  val _ = if disjoint (free_vars (hd xs)) vs then () else hd []
1158  val tm2 = mk_conj(hd xs,list_mk_exists(vs,list_mk_conj(tl xs)))
1159  fun PULL_EXISTS_CONV tm = let
1160    val (x,y) = dest_conj tm
1161    val (v,y) = dest_exists y
1162    val th = ISPEC (mk_abs(v,y)) (SPEC x (GSYM RIGHT_EXISTS_AND_THM))
1163    val th = CONV_RULE (RAND_CONV (
1164        RAND_CONV (ALPHA_CONV v) THENC
1165        QUANT_CONV (RAND_CONV BETA_CONV)) THENC
1166      (RATOR_CONV o RAND_CONV) (
1167        RAND_CONV (RAND_CONV (ALPHA_CONV v) THENC
1168                   QUANT_CONV BETA_CONV))) th
1169    in th end handle HOL_ERR _ => NO_CONV tm
1170  val thi = GSYM (REPEATC (ONCE_DEPTH_CONV PULL_EXISTS_CONV) tm2)
1171  in thi end handle e => NO_CONV tm handle e => NO_CONV tm;
1172
1173(* val tm = ``?x y z. 5 = 6 + tg`` *)
1174
1175fun PUSH_EXISTS_EMPTY_CONV tm = let
1176  fun DELETE_EXISTS_CONV tm = let
1177    val (v,rest) = dest_exists tm
1178    val _ = if mem v (free_vars rest) then hd [] else ()
1179    val w = genvar(``:bool``)
1180    val th = INST_TYPE [``:'a``|->type_of v] (SPEC w boolTheory.EXISTS_SIMP)
1181    val th = CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV) (ALPHA_CONV v)) th
1182    in INST [w |-> rest] th end handle e => NO_CONV tm
1183  val th = DEPTH_CONV DELETE_EXISTS_CONV tm
1184  in if (is_exists o cdr o concl) th then NO_CONV tm else th end
1185
1186fun DEPTH_EXISTS_CONV c tm =
1187  if is_exists tm then (c THENC DEPTH_EXISTS_CONV c) tm else
1188  if can (match_term ``GUARD n x``) tm then ALL_CONV tm else
1189  if is_comb tm then (RATOR_CONV (DEPTH_EXISTS_CONV c) THENC
1190                      RAND_CONV (DEPTH_EXISTS_CONV c)) tm else
1191  if is_abs tm then ABS_CONV (DEPTH_EXISTS_CONV c) tm else ALL_CONV tm;
1192
1193fun EXPAND_BASIC_LET_CONV tm = let
1194  val (xs,x) = pairSyntax.dest_anylet tm
1195  val (lhs,rhs) = hd xs
1196  val ys = dest_tuple lhs
1197  val zs = dest_tuple rhs
1198  val _ = if length zs = length ys then () else hd []
1199  fun every p [] = true
1200    | every p (x::xs) = if p x then every p xs else hd []
1201  val _ = every (fn x => every is_var (list_dest dest_conj x)) zs
1202  in (((RATOR_CONV o RATOR_CONV) (REWRITE_CONV [LET_DEF]))
1203      THENC DEPTH_CONV PairRules.PBETA_CONV) tm end
1204  handle e => NO_CONV tm;
1205
1206fun STRIP_FORALL_TAC (hs,tm) =
1207  if is_forall tm then STRIP_TAC (hs,tm) else NO_TAC (hs,tm)
1208
1209fun SPEC_AND_CASES_TAC x =
1210  SPEC_TAC (x,genvar(type_of x)) THEN Cases THEN REWRITE_TAC []
1211
1212fun GENSPEC_TAC [] = SIMP_TAC pure_ss [FORALL_PROD]
1213  | GENSPEC_TAC (x::xs) = SPEC_TAC (x,genvar(type_of x)) THEN GENSPEC_TAC xs;
1214
1215val EXPAND_BASIC_LET_TAC =
1216  CONV_TAC (DEPTH_CONV EXPAND_BASIC_LET_CONV)
1217  THEN REPEAT STRIP_FORALL_TAC
1218
1219fun AUTO_DECONSTRUCT_TAC finder (hs,goal) = let
1220  val tm = finder goal
1221  in if is_cond tm then let
1222       val (b,_,_) = dest_cond tm
1223       in SPEC_AND_CASES_TAC b (hs,goal) end
1224     else if is_let tm then let
1225       val (v,c) = (hd o fst o pairSyntax.dest_anylet) tm
1226       val c = if not (type_of c = ``:bool``) then c else
1227         (find_term (can (match_term ``GUARD x b``)) c handle e => c)
1228       val cs = dest_tuple c
1229       in (GENSPEC_TAC cs THEN EXPAND_BASIC_LET_TAC) (hs,goal) end
1230     else (REWRITE_TAC [] THEN NO_TAC) (hs,goal) end
1231
1232(* val v = ``v:num``
1233   val c = ``c:num``
1234   val tm =
1235      ``?x y v z. (x = 5) /\ (y = x + 6) /\ (v = c) /\ (z = v) /\ (n = v:num)``
1236*)
1237
1238fun FAST_EXISTS_INST_CONV v c tm = let
1239  val (x,y) = dest_exists tm
1240  in if not (x = v) then QUANT_CONV (FAST_EXISTS_INST_CONV v c) tm else let
1241  val imp = SPEC (mk_abs(v,y)) (ISPEC c EXISTS_EQ_LEMMA)
1242  val thi = MP (CONV_RULE ((RATOR_CONV o RAND_CONV) (SIMP_CONV bool_ss [])) imp) TRUTH
1243  val thi = CONV_RULE (RAND_CONV BETA_CONV THENC
1244                       (RATOR_CONV o RAND_CONV o RAND_CONV) (ALPHA_CONV v) THENC
1245                       (RATOR_CONV o RAND_CONV o QUANT_CONV) BETA_CONV) thi
1246  in thi end end;
1247
1248fun SUBST_EXISTS_CONV_AUX [] cs = ALL_CONV
1249  | SUBST_EXISTS_CONV_AUX vs [] = ALL_CONV
1250  | SUBST_EXISTS_CONV_AUX (v::vs) (c::cs) =
1251      FAST_EXISTS_INST_CONV v c THENC SUBST_EXISTS_CONV_AUX vs cs;
1252
1253fun SUBST_EXISTS_CONV vs cs =
1254  PURE_REWRITE_CONV [PAIR_EQ,GSYM CONJ_ASSOC]
1255  THENC SUBST_EXISTS_CONV_AUX vs cs
1256  THENC REWRITE_CONV [];
1257
1258(*
1259fun PRINT_GOAL_TAC s (hs,goal) = let
1260  val _ = print "\n\n"
1261  val _ = print s
1262  val _ = print ":\n\n"
1263  val _ = print_term goal
1264  val _ = print "\n\n"
1265  in ALL_TAC (hs,goal) end;
1266*)
1267
1268fun GUIDED_INST_EXISTS_TAC finder1 cc2 (hs,goal) = let
1269  val tm = finder1 goal
1270  val (xs,x) = pairSyntax.dest_anylet tm
1271  val (lhs,rhs) = hd xs
1272  val ys = dest_tuple lhs
1273  val zs = dest_tuple rhs
1274  val _ = if length zs = length ys then () else hd []
1275  val cond_var = mk_var("cond",``:bool``)
1276  in (if ys = [cond_var] then ALL_TAC (hs,goal)
1277      else CONV_TAC (cc2 (SUBST_EXISTS_CONV ys zs)) (hs,goal)) end
1278  handle e => let
1279    val _ = print "\n\nGUIDED_INST_EXISTS_TAC should not fail.\n\nGoal:\n\n"
1280    val _ = print_term goal
1281    val _ = print "\n\n"
1282    in raise e end;
1283
1284fun AUTO_DECONSTRUCT_EXISTS_TAC finder1 (cc1,cc2) (hs,goal) = let
1285  val tm = finder1 goal
1286  in if is_cond tm then let
1287       val (b,_,_) = dest_cond tm
1288       in SPEC_AND_CASES_TAC b (hs,goal) end
1289     else if is_let tm then let
1290       val cond_var = mk_var("cond",``:bool``)
1291       val (v,c) = (hd o fst o pairSyntax.dest_anylet) tm
1292       val c = if not (v = cond_var) then c
1293               else (find_term (can (match_term ``GUARD x b``)) c
1294                     handle e => ``GUARD 1000 F`` (* unlikely term *))
1295       val cs = dest_tuple c
1296       in (GENSPEC_TAC cs
1297           THEN REPEAT STRIP_TAC
1298           THEN REWRITE_TAC []
1299           THEN GUIDED_INST_EXISTS_TAC finder1 cc2
1300           THEN CONV_TAC (cc1 EXPAND_BASIC_LET_CONV)
1301           THEN REWRITE_TAC []) (hs,goal) end
1302     else (REWRITE_TAC [] THEN NO_TAC) (hs,goal) end;
1303
1304fun one_step_let_intro th = let
1305  val tm = fst (dest_imp (concl th))
1306  val g = last (list_dest boolSyntax.dest_exists tm)
1307  fun let_term tm = let
1308    val (g,x,y) = dest_cond tm
1309    in FUN_IF (g,let_term x,let_term y) end handle e => let
1310    val (x,y) = dest_conj tm
1311    in if can (match_term ``GUARD n y``) x
1312       then FUN_COND (x,let_term y)
1313       else let
1314         val (x1,x2) = dest_eq x
1315         val xs1 = dest_tuple x1
1316         in if is_new_var x1
1317               then FUN_VAL (mk_conj(tm,mk_var("cond",``:bool``)))
1318            else FUN_LET (x1,x2,let_term y)
1319         end end
1320  val let_tm =
1321     subst [mk_var("cond",``:bool``)|->``T:bool``] (ftree2tm (let_term g))
1322  val goal = mk_eq(tm,let_tm)
1323(*
1324set_goal([],goal)
1325*)
1326  val thi = RW [GSYM CONJ_ASSOC] (auto_prove "one_step_let_intro" (goal,
1327    REWRITE_TAC []
1328    THEN REPEAT (AUTO_DECONSTRUCT_EXISTS_TAC cdr
1329                   (RAND_CONV, RATOR_CONV o RAND_CONV))
1330    THEN SIMP_TAC pure_ss [AC CONJ_ASSOC CONJ_COMM] THEN REWRITE_TAC []
1331    THEN EQ_TAC THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC []))
1332  val th = RW1 [thi] th
1333  in th end;
1334
1335fun remove_constant_new_assigment avoid_vars th = let
1336  val vs = filter is_new_var (free_vars (concl th))
1337  fun is_real_assign tm = let
1338    val (x,y) = dest_eq tm
1339    in not (dest_new_var x = y) end handle HOL_ERR _ => false
1340  val ws = map (fst o dest_eq) (find_terms is_real_assign (concl th))
1341  val ws = diff vs ws
1342  val th1 = RW [] (INST (map (fn x => x |-> dest_new_var x) ws) th)
1343  val ts = (free_vars o fst o dest_imp o concl) th1
1344  fun mk_new_var v = let val (n,t) = dest_var v in mk_var("new@"^n,t) end
1345  val ws = diff (map dest_new_var ws) (ts @ avoid_vars)
1346  val th = RW [] (INST (map (fn x => mk_new_var x |-> x) ws) th)
1347  in th end;
1348
1349fun introduce_lets th = let
1350  val th = init_clean th
1351  val th = push_if_inwards th
1352  val (lhs,rhs) = (dest_imp o concl) th
1353  val vs = diff (free_vars lhs) (free_vars rhs)
1354  val vs = filter (fn v => not (read_tag v = "new")) vs
1355  val th = CONV_RULE ((RATOR_CONV o RAND_CONV)
1356                         (ONCE_REWRITE_CONV [GSYM CONTAINER_def])) th
1357  val th = SIMP_RULE bool_ss [LEFT_FORALL_IMP_THM] (GENL vs th)
1358  val th = RW1 [CONTAINER_def] th
1359  val th = one_step_let_intro th
1360  in th end;
1361
1362fun raw_tm2ftree tm = let
1363  val (x,y) = dest_conj tm
1364  val _ = if can (match_term ``GUARD b x``) x then () else fail()
1365  in FUN_COND (x,raw_tm2ftree y) end handle e => let
1366  val (b,x,y) = dest_cond tm
1367  in FUN_IF (b,raw_tm2ftree x,raw_tm2ftree y) end handle e => let
1368  val (x,y) = pairSyntax.dest_anylet tm
1369  val z = raw_tm2ftree y
1370  fun g((x,y),z) = FUN_LET (x,y,z)
1371  in foldr g z x end handle e => FUN_VAL tm;
1372
1373(* sorts in alphabetical order except for r1,r2,r3 which will come first *)
1374val var_sorter = let
1375  fun dest_reg_var s = let
1376    val xs = explode s
1377    in if hd xs = #"r" then string_to_int (implode (tl xs)) else fail() end
1378  val is_reg_var = can dest_reg_var
1379  fun name_of_var tm = let
1380    val s = fst (dest_var tm)
1381    in if s = "eax" then "r0" else
1382       if s = "ecx" then "r1" else
1383       if s = "edx" then "r2" else
1384       if s = "ebx" then "r3" else
1385       if s = "esp" then "r4" else
1386       if s = "ebp" then "r5" else
1387       if s = "esi" then "r6" else
1388       if s = "edi" then "r7" else s end
1389  fun cmp tm1 tm2 = let
1390    val s1 = name_of_var tm1
1391    val s2 = name_of_var tm2
1392    in if is_reg_var s1 = is_reg_var s2
1393       then (dest_reg_var s1 < dest_reg_var s2 handle e => s1 < s2)
1394       else is_reg_var s1 end
1395  in sort cmp end
1396
1397fun leaves (FUN_VAL tm)      f = FUN_VAL (f tm)
1398  | leaves (FUN_COND (c,t))  f = FUN_COND (c, leaves t f)
1399  | leaves (FUN_IF (a,b,c))  f = FUN_IF (a, leaves b f, leaves c f)
1400  | leaves (FUN_LET (v,y,t)) f = FUN_LET (v, y, leaves t f)
1401
1402fun erase_conds (FUN_VAL tm) = FUN_VAL tm
1403  | erase_conds (FUN_COND (c,t)) = erase_conds t
1404  | erase_conds (FUN_IF (a,b,c)) = FUN_IF (a,erase_conds b,erase_conds c)
1405  | erase_conds (FUN_LET (x,y,t)) = FUN_LET (x,y,erase_conds t)
1406
1407val REMOVE_TAGS_CONV = let
1408  val alpha_lemma = prove(``!b:bool. (b = T) ==> b``,Cases THEN REWRITE_TAC []);
1409  fun REMOVE_TAG_CONV tm = let
1410    val (v,x) = dest_abs tm
1411    val xs = free_vars x
1412    fun d [] = fail()
1413      | d (x::xs) = if x = #"@" then implode xs else d xs
1414    fun strip_tag v = mk_var((d o explode o fst o dest_var) v, type_of v)
1415    fun add_prime v = mk_var(fst (dest_var v) ^ "'", type_of v)
1416    fun is_ok v = not (mem v xs)
1417    fun UNTIL g f x = if g x then x else UNTIL g f (f x)
1418    val w = UNTIL is_ok add_prime (strip_tag v)
1419    val thi =
1420       SIMP_CONV std_ss [FUN_EQ_THM] (mk_eq(tm,mk_abs(w,subst [v|->w] x)))
1421    in MATCH_MP alpha_lemma thi end handle e => NO_CONV tm
1422  in (DEPTH_CONV REMOVE_TAG_CONV THENC REWRITE_CONV [GUARD_def]) end;
1423
1424fun simplify_and_define name x_in rhs = let (*  *)
1425  val ty = mk_type("fun",[type_of x_in, type_of rhs])
1426  val rw = REMOVE_TAGS_CONV rhs handle HOL_ERR _ => REFL rhs
1427  val tm = mk_eq(mk_comb(mk_var(name,ty),x_in),cdr (concl rw))
1428  val def = SPEC_ALL (new_definition(name ^ "_def", tm)) handle e =>
1429            (print ("\n\nERROR: Cannot define " ^ name ^ "_def as,\n\n");
1430             print_term tm; print "\n\n"; raise e)
1431  in CONV_RULE (RAND_CONV (fn tm => GSYM rw)) def end;
1432
1433fun pull_T (FUN_VAL tm) = FUN_VAL tm
1434  | pull_T (FUN_COND tm) = FUN_COND tm
1435  | pull_T (FUN_IF (tm,x,y)) = let
1436      val x' = pull_T x
1437      val y' = pull_T y
1438      in if ((x' = FUN_VAL ``T:bool``) andalso (y' = FUN_VAL ``T:bool``)) orelse
1439            (x' = y')
1440         then x' else FUN_IF (tm,x',y') end
1441  | pull_T (FUN_LET (tm,tn,x)) = let
1442      val x' = pull_T x
1443      val vs = free_vars (ftree2tm x')
1444      val ws = free_vars tm
1445      in if filter (fn v => mem v ws) vs = [] then x' else FUN_LET (tm,tn,x')
1446      end
1447
1448fun simplify_pre pre th = let
1449  val ft = pull_T (tm2ftree ((cdr o concl o SPEC_ALL) pre))
1450  val goal = mk_comb((car o concl o SPEC_ALL) pre, ftree2tm ft)
1451  in if not (ft = FUN_VAL ``T``) then (th,pre) else let
1452    val new_pre = (auto_prove "simplify_pre" (goal,
1453      REWRITE_TAC []
1454      THEN ONCE_REWRITE_TAC [pre]
1455      THEN REPEAT (AUTO_DECONSTRUCT_TAC I)))
1456    val th = RW [new_pre,SEP_CLAUSES] th
1457    in (th,new_pre) end end
1458
1459fun introduce_post_let th = let
1460  val (x,y) = (dest_comb o cdr o concl) th
1461  val (x,z) = pairSyntax.dest_pabs x
1462  val tm = pairSyntax.mk_anylet([(x,y)],z)
1463  val th1 = GSYM (SIMP_CONV std_ss [LET_DEF] tm)
1464  in CONV_RULE (RAND_CONV (ONCE_REWRITE_CONV [th1]))
1465       (SIMP_RULE std_ss [] th) end handle e => th;
1466
1467fun REMOVE_VARS_FROM_THM vs th = let
1468  fun REMOVE_FROM_LHS (v,th) = let
1469    val th = SIMP_RULE pure_ss [LEFT_FORALL_IMP_THM] (GEN v th)
1470    val c = DEPTH_EXISTS_CONV (PUSH_EXISTS_COND_CONV ORELSEC
1471                               PUSH_EXISTS_LET_CONV ORELSEC
1472                               PUSH_EXISTS_CONJ_CONV ORELSEC
1473                               INST_EXISTS_CONV ORELSEC
1474                               PUSH_EXISTS_CONST_CONV)
1475    val th = CONV_RULE ((RATOR_CONV o RAND_CONV) c) th
1476    in th end
1477  in foldr REMOVE_FROM_LHS th vs end
1478
1479fun HIDE_POST_VARS vs th = let
1480  val th = CONV_RULE ((RATOR_CONV o RAND_CONV)
1481                         (ONCE_REWRITE_CONV [GSYM CONTAINER_def])) th
1482  val th = foldr (uncurry SEP_EXISTS_POST_RULE) (UNDISCH_ALL th) vs
1483  val th = SEP_EXISTS_ELIM_RULE th
1484  val th = RW [CONTAINER_def] (DISCH_ALL th)
1485  val th = REMOVE_VARS_FROM_THM vs th
1486  in th end;
1487
1488fun HIDE_PRE_VARS vs th1 = let
1489  val th = CONV_RULE ((RATOR_CONV o RAND_CONV)
1490                         (ONCE_REWRITE_CONV [GSYM CONTAINER_def])) th1
1491  val th = foldr (uncurry SEP_EXISTS_PRE_RULE) (UNDISCH_ALL th) vs
1492  val th = SEP_EXISTS_ELIM_RULE th
1493  val th = RW [CONTAINER_def] (DISCH_ALL th)
1494  in th end;
1495
1496fun SORT_SEP_CONV tm = let
1497  fun remove_tags tm =
1498    subst (map (fn v => v |-> mk_var(strip_tag v,type_of v)) (free_vars tm)) tm
1499  val xs = list_dest dest_star tm
1500  fun compare tm1 tm2 = let
1501    val s1 = term_to_string (remove_tags (get_sep_domain tm1))
1502    val s2 = term_to_string (remove_tags (get_sep_domain tm2))
1503    in if size s2 < size s1 then 1 < 2 else
1504       if size s1 < size s2 then 2 < 1 else
1505       if not (s1 = s2) then s1 < s2 else
1506         term_to_string (remove_tags tm1) < term_to_string (remove_tags tm2) end
1507  val tm2 = list_mk_star (sort compare xs) (type_of tm)
1508  val thi =
1509     auto_prove "SORT_SEP_CONV" (mk_eq(tm,tm2),SIMP_TAC (bool_ss++star_ss) [])
1510  in thi end;
1511
1512fun LET_EXPAND_POS_CONV tm = let
1513  val x = (fst o dest_abs o fst o dest_let) tm
1514  in if not (x = mk_var("pos",``:num``)) then fail () else
1515     ((RATOR_CONV o RATOR_CONV) (ONCE_REWRITE_CONV [LET_DEF])
1516      THENC RATOR_CONV BETA_CONV THENC BETA_CONV THENC BETA_CONV) tm end
1517  handle HOL_ERR _ => NO_CONV tm;
1518
1519fun DEST_NEW_VAR_CONV tm =
1520  ALPHA_CONV (dest_new_var (fst (dest_abs tm))) tm
1521  handle HOL_ERR _ => NO_CONV tm;
1522
1523fun SEP_EXISTS_CONV c tm =
1524  if can dest_sep_exists tm
1525  then RAND_CONV (ABS_CONV (SEP_EXISTS_CONV c)) tm else ALL_CONV tm;
1526       (* is this right? shouldn't it be: c tm *)
1527
1528fun SEP_DISJ_CONV c tm =
1529  if can dest_sep_disj tm
1530  then ((RATOR_CONV o RAND_CONV) c) tm else c tm;
1531
1532val GEN_TUPLE_LEMMA = GSYM (CONV_RULE ((RATOR_CONV o RAND_CONV o RAND_CONV)
1533   (ALPHA_CONV (mk_var("_",``:'a # 'b``)))) FORALL_PROD)
1534fun GEN_TUPLE tm th =
1535  if not (pairSyntax.is_pair tm) then GEN tm th else let
1536    val (w,tm2) = pairSyntax.dest_pair tm
1537    val th = GEN_TUPLE tm2 th
1538    val v = fst (dest_forall (concl th))
1539    val th = CONV_RULE (UNBETA_CONV (pairSyntax.mk_pair(w,v))) (SPEC v th)
1540    val x = genvar(type_of tm)
1541    val th =
1542       GEN x (CONV_RULE BETA_CONV
1543              (SPEC x (PURE_REWRITE_RULE [GEN_TUPLE_LEMMA] (GEN w (GEN v th)))))
1544    in th end;
1545
1546fun extract_function name th entry exit function_in_out = let
1547  val _ = echo 1 " extracting function,"
1548  val output = (filter (not o is_new_var) o free_vars o cdr o concl) th
1549  fun drop_until p [] = []
1550    | drop_until p (x::xs) = if p x then x::xs else drop_until p xs
1551  fun strip_names v = let
1552    val vs = (tl o drop_until (fn x => x = #"@") o explode o fst o dest_var) v
1553    in if vs = [] then (fst o dest_var) v else implode vs end
1554    handle e => (fst o dest_var) v
1555  fun new_abbrev (v,th) = let
1556    val th = RW [GSYM SPEC_MOVE_COND] (DISCH_ALL th)
1557    val n = "new@" ^ strip_names v
1558    val th = raw_abbreviate2 (n,v,v) th
1559    val th = RW [SPEC_MOVE_COND,AND_IMP_INTRO] (DISCH_ALL th)
1560    val th = RW [PUSH_IF_LEMMA] th
1561    in th end
1562  val th = foldr new_abbrev th output
1563  val th = introduce_lets th
1564  val avoid_vars =
1565     case function_in_out of NONE => [] | SOME (p,q) => free_vars q
1566  val th = remove_constant_new_assigment avoid_vars th
1567  val pc = get_pc()
1568  val pc_type = (hd o snd o dest_type o type_of) pc
1569  val th = INST [mk_var("new@p",pc_type) |-> mk_var("set@p",pc_type)] th
1570  val t = tm2ftree ((cdr o car o concl o RW [WORD_ADD_0]) th)
1571  (* extract: step function and input, output tuples *)
1572  fun gen_pc n = if n = 0 then mk_var("p",pc_type) else
1573    (ASSUME (mk_eq(mk_var("_",pc_type),mk_var("p",pc_type))))
1574            |> (!decompiler_set_pc) n |> concl |> cdr
1575    handle HOL_ERR _ => subst [mk_var("n",``:num``) |-> numSyntax.term_of_int n]
1576      (inst [``:'a``|->(hd o tl o snd o dest_type) pc_type]
1577            ``(p:'a word) + n2w n``)
1578  val exit_tm = gen_pc (hd exit)
1579  val entry_tm = (snd o dest_eq o find_term (fn tm => let
1580                   val (x,y) = dest_eq tm
1581                   in fst (dest_var x) = "set@p" andalso not (y = exit_tm) end
1582                   handle HOL_ERR _ => false) o concl) th
1583                 handle HOL_ERR _ => gen_pc (hd entry)
1584  val final_node = mk_eq(mk_var("set@p",pc_type),exit_tm)
1585  fun is_terminal_node tm = can (find_term (fn x => x = final_node)) tm
1586  val output = (filter is_new_var o free_vars o cdr o cdr o concl) th
1587  fun strip_tag v =
1588     mk_var((implode o drop 4 o explode o fst o dest_var) v, type_of v)
1589  val output = var_sorter (map strip_tag output)
1590  fun rm_pc tm = let
1591    val xs = find_terms (fn x => fst (dest_eq x) = mk_var("set@p",pc_type)
1592                                 handle HOL_ERR _ => false) tm
1593    in subst (map (fn x => x |-> T) xs) tm end
1594  val iii = (list_mk_pair o var_sorter o filter (not o is_new_var) o
1595               free_vars o rm_pc o ftree2tm o leaves t)
1596            (fn x => if is_terminal_node x then x else ``T:bool``)
1597  val input = (var_sorter o filter (not o is_new_var) o filter (fn v => not (v = mk_var("cond",``:bool``))) o
1598               free_vars o rm_pc o ftree2tm o leaves t)
1599           (fn x => if is_terminal_node x then x else mk_eq(iii,iii))
1600  val input = if input = [] then [mk_var("()",``:unit``)] else input
1601  fun set_input_output NONE = (input,output)
1602    | set_input_output (SOME (ix,ox)) = (dest_tuple ix, dest_tuple ox)
1603  val (input,output) = set_input_output function_in_out
1604  val pos_subst = mk_var("pos",``:num``) |-> mk_var("s10000@pos",``:num``)
1605  val new_pos_subst =
1606     mk_var("s10000@pos",``:num``) |-> mk_var("new@pos",``:num``)
1607  fun new_into_subst tm = let
1608    val vs = list_dest dest_conj tm
1609    val vs = filter is_eq vs
1610    in subst
1611         (pos_subst ::
1612          map (fn x => let val (x,y) = dest_eq x in (strip_tag x) |-> y end) vs)
1613    end
1614  val x_in = list_mk_pair input
1615  val x_out = list_mk_pair output
1616  fun add_new_tag v = mk_var("new@" ^ fst (dest_var v), type_of v)
1617  val new_output = list_mk_pair (map add_new_tag output)
1618  val new_input = list_mk_pair (map add_new_tag input)
1619  val cond_var = mk_var("cond",``:bool``)
1620  fun mk_exit tm = pairSyntax.mk_pair(tm,cond_var)
1621  val step_fun =
1622      mk_pabs(x_in,ftree2tm (leaves t (fn x =>
1623                if is_terminal_node x
1624                then mk_exit(sumSyntax.mk_inr
1625                               (new_into_subst x x_out,type_of x_in))
1626                else mk_exit(sumSyntax.mk_inl
1627                               (new_into_subst x x_in,type_of x_out)))))
1628  val step_fun =
1629     (snd o dest_eq o concl o QCONV (REWRITE_CONV [GSYM CONJ_ASSOC]))
1630        (subst [cond_var |-> T] step_fun)
1631  (* define functions *)
1632  val func_name = name
1633  val tm_option = NONE
1634  val (main_thm,main_def,pre_thm,pre_def) =
1635         tailrecLib.tailrec_define_from_step func_name step_fun tm_option
1636  val finalise =
1637     CONV_RULE (REMOVE_TAGS_CONV THENC DEPTH_CONV (LET_EXPAND_POS_CONV))
1638  val main_thm = finalise main_thm
1639  val pre_thm = finalise pre_thm
1640  (* define temporary abbreviation *)
1641  val silly_string = Theory.temp_binding "(( step ))"
1642  val step_def =
1643     new_definition
1644        (silly_string,mk_eq(mk_var(silly_string,type_of step_fun),step_fun))
1645  val main_def = RW [GSYM step_def] main_def
1646  val pre_def = RW [GSYM step_def] pre_def
1647  val step_const = (fst o dest_eq o concl) step_def
1648(*
1649  (* try automatically proving pre = T, i.e. termination *)
1650  val pre_thm = let
1651    val tt = (fst o dest_eq o concl o SPEC_ALL o RW1 [FUN_EQ_THM]) pre_def
1652    val goal = mk_forall(cdr tt,mk_eq(tt,``T:bool``))
1653    val dummy_name = "no_name"
1654    val c = (repeat car o fst o dest_eq o concl o SPEC_ALL) main_thm
1655    val v = mk_var(dummy_name,type_of c)
1656    val fake_eq = subst [c|->v] ((concl o SPEC_ALL) main_thm)
1657    val defn = Hol_defn dummy_name [ANTIQUOTE fake_eq]
1658    val gs = TotalDefn.guessR defn
1659    fun case_tac x =
1660      TotalDefn.WF_REL_TAC [ANTIQUOTE x]
1661      THEN SRW_TAC [] [] THEN SIMP_TAC std_ss [GSYM word_sub_def]
1662      THEN REPEAT (POP_ASSUM MP_TAC)
1663      THEN SIMP_TAC std_ss (!termination_simps) THEN NO_TAC
1664    val AUX_TAC = FIRST (map case_tac gs)
1665    (* set_goal([],goal) *)
1666    val tac =
1667      PURE_REWRITE_TAC [pre_def,tailrecTheory.SHORT_TAILREC_PRE_def]
1668      THEN MATCH_MP_TAC tailrecTheory.TAILREC_PRE_IMP
1669      THEN Tactical.REVERSE STRIP_TAC
1670      THEN1 (SIMP_TAC std_ss [pairTheory.FORALL_PROD]
1671             THEN SRW_TAC [] [step_def,LET_DEF])
1672      THEN SIMP_TAC std_ss [step_def,LET_DEF,pairTheory.FORALL_PROD,GUARD_def]
1673      THEN AUX_TAC
1674    val pre_thm = (snd o tac) ([],goal) []
1675    val _ = echo 1 " (termination automatically proved),"
1676    in pre_thm end handle HOL_ERR _ => pre_thm
1677*)
1678  (* prove lemmas for final proof *)
1679  val _ = echo 1 " proving certificate,"
1680  val (th1,th2) = (th,th)
1681  val finder = cdr o el 2 o list_dest dest_conj o fst o dest_imp
1682  val tac2 = SIMP_TAC std_ss [step_def]
1683             THEN REPEAT (AUTO_DECONSTRUCT_TAC finder)
1684             THEN SIMP_TAC std_ss [sumTheory.OUTL,sumTheory.OUTR,
1685                                   sumTheory.ISR,sumTheory.ISL]
1686  val thi = ISPEC step_const SPEC_SHORT_TAILREC
1687  val thi = RW [GSYM main_def, GSYM pre_def] thi
1688  val lemma1 = let
1689    val th1 = INST [mk_var("set@p",pc_type) |-> exit_tm] th1
1690    val th1 = DISCH_ALL_AS_SINGLE_IMP (RW [] th1)
1691    val post = (free_vars o cdr o snd o dest_imp o concl) th1
1692    val top = (free_vars o fst o dest_imp o concl) th1
1693    val new_top = filter is_new_var top
1694    val vs = diff new_top (dest_tuple new_output @ output)
1695    val th1 = remove_primes (HIDE_POST_VARS vs th1)
1696    val pre = (free_vars o cdr o car o car o snd o dest_imp o concl) th1
1697    val ws = diff pre (mk_var("p",pc_type)::input)
1698    val tm = (fst o dest_imp o concl o DISCH_ALL) th1
1699    val ts = (list_dest dest_forall o snd o dest_conj o fst o dest_imp o
1700              concl o SPEC_ALL) thi
1701    val goal = (fst o dest_imp o last) ts
1702    val goal = subst [el 1 ts |-> x_in, el 2 ts |-> new_output] goal
1703    val goal = mk_imp(goal,tm)
1704    val lemma = UNDISCH (auto_prove "lemma1" (goal,tac2))
1705    val lemma1 = DISCH_ALL (MP th1 lemma)
1706    val (_,_,_,q) = dest_spec (concl (UNDISCH th1))
1707    val ws = diff ws (free_vars q)
1708    val lemma1 = HIDE_PRE_VARS ws lemma1
1709    in RW [GSYM step_def] lemma1 end
1710    handle e => (print "\n\nDecompiler failed to prove 'lemma 1'.\n\n"; raise e)
1711  val lemma2 = let
1712    val e_tm = subst [new_pos_subst] entry_tm
1713    val th2 = INST [mk_var("set@p",pc_type) |-> e_tm] th2
1714    val th2 = RW [WORD_ADD_0] th2
1715    val post = (free_vars o cdr o snd o dest_imp o concl) th1
1716    val top = (free_vars o fst o dest_imp o concl) th1
1717    val new_top = filter is_new_var top
1718    val vs = diff new_top (dest_tuple new_input)
1719    val th2 = remove_primes (HIDE_POST_VARS vs th2)
1720    val pre = (free_vars o cdr o car o car o snd o dest_imp o concl) th2
1721    val vs = diff pre (mk_var("p",pc_type)::input)
1722    val tm = (fst o dest_imp o concl o DISCH_ALL) th2
1723    val ts = (list_dest dest_forall o fst o dest_conj o fst o dest_imp o
1724              concl o SPEC_ALL) thi
1725    val goal = (fst o dest_imp o last) ts
1726    val goal = subst [el 1 ts |-> x_in, el 2 ts |-> new_input] goal
1727    val goal = mk_imp(goal,tm)
1728    val lemma = UNDISCH (auto_prove "lemma2" (goal,tac2))
1729    val lemma2 = DISCH_ALL (MP th2 lemma)
1730    val (_,_,_,q) = dest_spec (concl (UNDISCH th2))
1731    val ws = diff vs (free_vars q)
1732    val lemma2 = HIDE_PRE_VARS ws lemma2
1733    in RW [GSYM step_def] lemma2 end
1734    handle e => (print "\n\nDecompiler failed to prove 'lemma 2'.\n\n"; raise e)
1735  val sort_conv = PRE_CONV (SEP_EXISTS_CONV SORT_SEP_CONV) THENC
1736                  POST_CONV (SEP_EXISTS_CONV (SEP_DISJ_CONV SORT_SEP_CONV))
1737  val lemma1 = CONV_RULE (RAND_CONV sort_conv) lemma1
1738  val lemma2 = CONV_RULE (RAND_CONV sort_conv) lemma2
1739  (* simplification for cases of non-recursive functions *)
1740  val simp_lemma = let
1741    val (x,y) = dest_eq (concl (SPEC_ALL main_thm))
1742    val _ = if can (find_term (fn tm => car x = tm)) y then fail () else ()
1743    val goal = mk_eq((fst o dest_imp o concl o
1744      ISPEC (pairSyntax.mk_fst(mk_comb(step_fun,x_in)))) sumTheory.INL,F)
1745    val simp_lemma = auto_prove "simp_lemma" (goal,SIMP_TAC std_ss []
1746      THEN REPEAT (AUTO_DECONSTRUCT_TAC (cdr o cdr))
1747      THEN SIMP_TAC std_ss [])
1748    val simp_lemma = Q.SPEC `x` (GEN_TUPLE x_in simp_lemma)
1749    val simp_lemma = PURE_REWRITE_RULE [GSYM step_def] simp_lemma
1750    in GEN_ALL simp_lemma end handle HOL_ERR _ => TRUTH
1751  (* deal with SEP_DISJ in post -- move to pre *)
1752  val lemma1 = DISCH_ALL (MATCH_MP SPEC_PRE_DISJ_INTRO (UNDISCH lemma1))
1753               handle HOL_ERR _ => lemma1
1754  val lemma2 = DISCH_ALL (MATCH_MP SPEC_PRE_DISJ_INTRO (UNDISCH lemma2))
1755               handle HOL_ERR _ => lemma2
1756  (* certificate theorem *)
1757  fun remove_new_tags tm = let
1758    val vs = filter is_new_var (free_vars tm)
1759    in subst (map (fn v => v |-> strip_tag v) vs) tm end
1760  val (m,p,c,q) = (dest_spec o concl o UNDISCH_ALL) lemma1
1761  val thi = ISPEC (mk_pabs(x_in,p)) thi
1762  val thi = ISPEC (mk_pabs(x_out,remove_new_tags q)) thi
1763  val thi = ISPEC c thi
1764  val thi = ISPEC m thi
1765  val xi = GSYM (SIMP_CONV std_ss [] (mk_comb(mk_pabs(x_in,p),x_in)))
1766  val xin = GSYM (SIMP_CONV std_ss [] (mk_comb(mk_pabs(x_in,p),new_input)))
1767  val xon = GSYM (SIMP_CONV std_ss []
1768                    (mk_comb(mk_pabs(x_out,remove_new_tags q),new_output)))
1769  fun fix_star rw =
1770    SIMP_CONV (bool_ss++star_ss) []
1771    THENC ONCE_REWRITE_CONV
1772            [CONV_RULE (RATOR_CONV (SIMP_CONV (bool_ss++star_ss) [])) rw]
1773  val l1 = CONV_RULE (RAND_CONV (PRE_CONV (fix_star xi) THENC
1774                                 POST_CONV (fix_star xon))) lemma1
1775  val l2 = CONV_RULE (RAND_CONV (PRE_CONV (fix_star xi) THENC
1776                                 POST_CONV (fix_star xin))) lemma2
1777  val l1 = GEN_TUPLE x_in (GEN_TUPLE new_output l1)
1778  val l2 = GEN_TUPLE x_in (GEN_TUPLE new_input l2) handle HOL_ERR _ => l2
1779  val goal = (fst o dest_imp o concl) thi
1780  val th = auto_prove "decompiler certificate" (goal,
1781    STRIP_TAC
1782    THEN1 (ONCE_REWRITE_TAC [simp_lemma] THEN REWRITE_TAC [] THEN
1783           REPEAT STRIP_TAC THEN MATCH_MP_TAC l2 THEN FULL_SIMP_TAC std_ss [])
1784    THEN1 (REPEAT STRIP_TAC THEN MATCH_MP_TAC l1 THEN FULL_SIMP_TAC std_ss []))
1785  val th = MP thi th
1786  val th = SPEC x_in th
1787  val th = RW [GSYM SPEC_MOVE_COND] th
1788  val th = introduce_post_let th
1789  val th = INST [mk_var("()",``:unit``) |-> ``():unit``] th
1790  val th =
1791     th |> RW [SPEC_MOVE_COND] |> UNDISCH |> SIMP_RULE std_ss [SPEC_PRE_DISJ]
1792        |> CONJUNCTS |> hd |> DISCH_ALL |> RW [GSYM SPEC_MOVE_COND]
1793  val th = SPEC_ALL (SIMP_RULE bool_ss [SEP_CLAUSES,GSYM SPEC_PRE_EXISTS] th)
1794  val th = CONV_RULE (DEPTH_CONV DEST_NEW_VAR_CONV) th
1795  (* clean up and save function definitions *)
1796  val _ = delete_const (fst (dest_const step_const))
1797  val _ = echo 1 " done.\n"
1798  val _ = save_thm(name ^ "_def",main_thm)
1799  val _ = save_thm(name ^ "_pre_def",pre_thm)
1800  in (th,main_thm,pre_thm) end;
1801
1802
1803(* -------------------------------------------------------------------------- *)
1804(* Implementation of STAGE 4                                                  *)
1805(* -------------------------------------------------------------------------- *)
1806
1807fun prepare_for_reuse [] (th,i,j) k = []
1808  | prepare_for_reuse (n::ns) (th,i,j) k = let
1809  val prefix = "new@"
1810  val th = ABBREV_CALL prefix th
1811  val mk_num = numSyntax.mk_numeral o Arbnum.fromInt
1812  val th = SIMP_RULE std_ss [] (INST [mk_var("pos",``:num``) |-> mk_num k] th)
1813  in (n,(th,i,j),NONE) :: prepare_for_reuse ns (th,i,j) (k+1) end;
1814
1815fun decompile_part name thms (entry,exit)
1816      (function_in_out: (term * term) option) = let
1817  val t = generate_spectree thms (entry,exit)
1818  val th = merge_spectree name t
1819  val (th,def,pre) = extract_function name th entry exit function_in_out
1820  val (th,pre) = simplify_pre pre th
1821  val (th,def) = (!decompiler_finalise) (th,def)
1822  val def = modifier "func" def
1823  in (def,pre,th) end;
1824
1825val fio = (NONE: (term * term) option)
1826
1827fun decompile_io_with q (tools :decompiler_tools) name fio code =
1828let
1829  val _ = set_tools tools
1830  val (thms,loops) = stage_12 name tools (q code)
1831  fun decompile_all thms (defs,pres) [] prev =
1832         (LIST_CONJ defs,LIST_CONJ pres,prev)
1833    | decompile_all thms (defs,pres) ((entry,exit)::loops) prev = let
1834(*
1835  val (entry,exit)::loops = loops
1836*)
1837      val function_in_out = (NONE: (term * term) option)
1838      val suff = int_to_string (length loops)
1839      val (part_name,function_in_out) = if length loops = 0 then (name,fio)
1840                                        else (name ^ suff,function_in_out)
1841      val (def,pre,result) =
1842         decompile_part part_name thms (entry,exit) function_in_out
1843      val thms = prepare_for_reuse entry (result,0,SOME (hd exit)) 0 @ thms
1844      in decompile_all thms (def::defs,pre::pres) loops result end
1845  val (def,pre,result) = decompile_all thms ([],[]) loops TRUTH
1846  val exit = snd (last loops)
1847  val _ = add_decompiled (name,result,hd exit,SOME (hd exit))
1848  val result = if (get_abbreviate_code()) then result
1849               else UNABBREV_CODE_RULE result
1850  val func = RW [GSYM CONJ_ASSOC] (CONJ def pre)
1851  in (result,func) end;
1852
1853fun decompile_with q tools name code = decompile_io_with q tools name NONE code;
1854
1855val decompile_io =
1856   decompile_io_with (helperLib.quote_to_strings: term quotation -> string list)
1857
1858val decompile =
1859   decompile_with (helperLib.quote_to_strings: string quotation -> string list)
1860
1861val decompile_io_strings = decompile_io_with I
1862val decompile_strings = decompile_with I
1863
1864fun basic_decompile_with q (tools :decompiler_tools) name function_in_out code =
1865let
1866  val _ = set_tools tools
1867  val (thms,loops) = stage_12 name tools (q code)
1868  val (entry,exit) = (fn (x,y) => (hd x, hd y)) (last loops)
1869  val (entry,exit) = ([entry],[exit])
1870  val (def,pre,result) = decompile_part name thms (entry,exit) function_in_out
1871  val _ = add_decompiled (name,result,hd exit,SOME (hd exit))
1872  val result =
1873     if (get_abbreviate_code()) then result else UNABBREV_CODE_RULE result
1874  in (result,CONJ def pre) end;
1875
1876val basic_decompile =
1877   basic_decompile_with
1878      (helperLib.quote_to_strings: term quotation -> string list)
1879
1880val basic_decompile_strings = basic_decompile_with I
1881
1882end
1883