1structure exportLib :> exportLib =
2struct
3
4open HolKernel boolLib bossLib Parse;
5open helperLib graph_specsLib backgroundLib writerLib file_readerLib;
6open GraphLangTheory;
7
8
9(* exporter state *)
10
11val failed_ty_translations = ref ([]:hol_type list);
12val failed_tm_translations = ref ([]:term list);
13
14
15(* recording errors *)
16
17local
18  fun head_of t = fst (strip_comb t)
19  fun print_ty_fail ty = let
20    val _ = print "FAILED to translate type: "
21    val _ = print_type ty
22    val _ = print "\n"
23    in () end;
24  fun print_tm_fail tm = let
25    val _ = print "FAILED to translate term: "
26    val _ = print_term tm
27    val _ = (print "\n\nwith head: "; print_term (head_of tm))
28    val _ = (print "\nwith type: "; print_type (type_of tm); print "\n\n")
29    in () end;
30in
31  fun add_ty_fail ty = let
32    val _ = (failed_ty_translations := ty::(!failed_ty_translations))
33    in print_ty_fail ty end
34  fun add_tm_fail tm = let
35    val _ = (failed_tm_translations := tm::(!failed_tm_translations))
36    in print_tm_fail tm end
37end
38
39
40(* syntax functions *)
41
42fun dest_graph tm =
43  if can (match_term ``graph (xs:('a # 'b) list)``) tm then let
44    val (x,y) = dest_comb tm
45    fun f (x,y) = (numSyntax.int_of_term x, y)
46    in listSyntax.dest_list y |> fst |> map (f o pairSyntax.dest_pair) end
47    handle HOL_ERR _ => failwith "dest_graph"
48  else failwith "dest_graph"
49
50fun dest_str_graph tm =
51  if can (match_term ``graph (xs:('a # 'b) list)``) tm then let
52    val (x,y) = dest_comb tm
53    fun f (x,y) = (stringSyntax.fromHOLstring x, y)
54    in listSyntax.dest_list y |> fst |> map (f o pairSyntax.dest_pair) end
55    handle HOL_ERR _ => failwith "dest_graph"
56  else failwith "dest_graph"
57
58fun dest_string_list tm = let
59  val (xs,ty) = listSyntax.dest_list tm
60  val _ = (ty = ``:string``) orelse fail()
61  val ys = map stringSyntax.fromHOLstring xs
62  in ys end handle HOL_ERR _ => failwith "dest_string_list"
63
64local
65  val pat = ``GraphFunction inps outps gg ep``
66in
67  fun dest_GraphFunction tm = let
68    val _ = can (match_term pat) tm orelse fail()
69    val ep = tm |> rand |> numSyntax.int_of_term
70    val gs = tm |> rator |> rand |> dest_graph
71    val ys = tm |> rator |> rator |> rand |> dest_string_list
72    val xs = tm |> rator |> rator |> rator |> rand |> dest_string_list
73    in (xs,ys,gs,ep) end
74end
75
76local
77  val pat = ``Basic n xs``
78in
79  fun dest_Basic tm = let
80    val _ = can (match_term pat) tm orelse fail()
81    val next = tm |> rator |> rand
82    val (xs,ty) = tm |> rand |> listSyntax.dest_list
83    val _ = (ty = ``:string # (32 state -> 32 variable)``) orelse
84            (ty = ``:string # (64 state -> 64 variable)``) orelse fail()
85    val ys = xs |> map pairSyntax.dest_pair
86                |> map (fn (x,y) => (stringSyntax.fromHOLstring x,y))
87    in (next,ys) end
88end
89
90local
91  val pat = ``Cond n1 n2 p``
92in
93  fun dest_Cond tm = let
94    val _ = can (match_term pat) tm orelse fail()
95    val next1 = tm |> rator |> rator |> rand
96    val next2 = tm |> rator |> rand
97    val tm = tm |> rand
98    in (next1,next2,tm) end
99end
100
101local
102  val pat = ``Call next name args strs``
103in
104  fun dest_Call tm = let
105    val _ = can (match_term pat) tm orelse fail()
106    val next = tm |> rator  |> rator  |> rator |> rand
107    val (strs,ty) = tm |> rand |> listSyntax.dest_list
108    val _ = (ty = ``:string``) orelse fail()
109    val strs = strs |> map stringSyntax.fromHOLstring
110    val name = tm |> rator |> rator |> rand |> stringSyntax.fromHOLstring
111    val (args,ty) = tm |> rator |> rand |> listSyntax.dest_list
112    val _ = (ty = ``:32 state -> 32 variable``) orelse
113            (ty = ``:64 state -> 64 variable``) orelse
114            fail()
115    in (next,name,args,strs) end
116end
117
118local
119  val pat = ``NextNode n``
120in
121  fun dest_NextNode tm = let
122    val _ = can (match_term pat) tm orelse fail()
123    val next = tm |> rand |> numSyntax.int_of_term
124    in next end
125end
126
127local
128  val pat = ``var_acc str``
129in
130  fun dest_var_acc tm = let
131    val _ = can (match_term pat) tm orelse fail()
132    in tm |> rand |> stringSyntax.fromHOLstring end
133end
134
135local
136  val pat = ``SKIP_TAG str``
137in
138  fun dest_SKIP_TAG tm = let
139    val _ = can (match_term pat) tm orelse fail()
140    in tm |> rand |> stringSyntax.fromHOLstring end
141end
142
143local
144  fun any_var_acc pat = fn tm => let
145    val _ = can (match_term pat) tm orelse fail()
146    val x1 = tm |> rator |> rand |> stringSyntax.fromHOLstring
147    val x2 = tm |> rand
148    in (x1,x2) end
149in
150  val dest_var_word = any_var_acc ``var_word str s``
151  val dest_var_word8 = any_var_acc ``var_word8 str s``
152  val dest_var_nat = any_var_acc ``var_nat str s``
153  val dest_var_bool = any_var_acc ``var_bool str s``
154  val dest_var_mem = any_var_acc ``var_mem str s``
155  val dest_var_dom = any_var_acc ``var_dom str s``
156end;
157
158
159(* export to Graph's graph format *)
160
161val patterns =
162     [(``MemAcc8 m a``,"MemAcc"),
163      (``MemAcc32 m a``,"MemAcc"),
164      (``MemAcc64 m a``,"MemAcc"),
165      (``MemUpdate8 m a w``,"MemUpdate"),
166      (``MemUpdate32 m a w``,"MemUpdate"),
167      (``MemUpdate64 m a w``,"MemUpdate"),
168      (``x = (y:'a)``,"Equals"),
169      (``T``,"True"),
170      (``F``,"False"),
171      (``~(b:bool)``,"Not"),
172      (``word_1comp (x:'a word)``,"BWNot"),
173      (``word_add (x:'a word) y``,"Plus"),
174      (``word_sub (x:'a word) y``,"Minus"),
175      (``word_mul (x:'a word) y``,"Times"),
176      (``word_and (x:'a word) y``,"BWAnd"),
177      (``word_or (x:'a word) y``,"BWOr"),
178      (``word_xor (x:'a word) y``,"BWXOR"),
179      (``ShiftLeft (x:'a word) y``,"ShiftLeft"),
180      (``ShiftRight (x:'a word) y``,"ShiftRight"),
181      (``SignedShiftRight (x:'a word) y``,"SignedShiftRight"),
182      (``x ==> y:bool``,"Implies"),
183      (``x /\ y:bool``,"And"),
184      (``x \/ y:bool``,"Or"),
185      (``(x:'a word) < y``,"SignedLess"),
186      (``(x:'a word) <+ y``,"Less"),
187      (``(x:'a word) <= y``,"SignedLessEquals"),
188      (``(x:'a word) <=+ y``,"LessEquals"),
189      (``(x:'a word) IN y``,"MemDom"),
190      (``(w2w (x:'a word)):'b word``,"WordCast"),
191      (``(sw2sw (x:'a word)):'b word``,"WordCastSigned"),
192      (``(n:num) + m``,"Plus"),
193      (``if b then x else y : 'a``,"IfThenElse"),
194      (``word_reverse (x:'a word)``,"WordReverse"),
195      (``count_leading_zero_bits (w:'a word)``,"CountLeadingZeroes")];
196
197val last_fail_node_tm = ref T;
198
199fun export_graph name rhs = let
200  fun int_to_hex i =
201    "0x" ^ Arbnumcore.toHexString (Arbnum.fromInt i)
202  fun get_var_type "mem" = "Mem"
203    | get_var_type "dom" = "Dom"
204    | get_var_type "stack" = "Mem"
205    | get_var_type "dom_stack" = "Dom"
206    | get_var_type "n" = "Bool"
207    | get_var_type "z" = "Bool"
208    | get_var_type "c" = "Bool"
209    | get_var_type "v" = "Bool"
210    | get_var_type "clock" = "Word 64"
211    | get_var_type _ = "Word " ^ substring(type_to_string(tysize()),1,2)
212  fun arg s = "" ^ s ^ " " ^ get_var_type s
213  fun commas [] = ""
214    | commas [x] = x
215    | commas (x::xs) = x ^ " " ^ commas xs
216  fun export_list xs = int_to_string (length xs) ^ " " ^ commas xs
217  fun export_type ty = case total dest_type ty of
218    SOME ("cart", [_, idx]) => "Word "
219        ^ Arbnum.toString (fcpLib.index_to_num idx)
220  | _ => if ty = ``:word32->word8`` then "Mem" else
221         if ty = ``:word32->bool`` then "Dom" else
222         if ty = ``:word64->word8`` then "Mem" else
223         if ty = ``:word64->bool`` then "Dom" else
224         if ty = ``:bool`` then "Bool" else
225         if ty = ``:num`` then "Word 64" else failwith("type")
226  fun is_var_acc tm =
227    can dest_var_word tm orelse
228    can dest_var_word8 tm orelse
229    can dest_var_nat tm orelse
230    can dest_var_bool tm orelse
231    can dest_var_mem tm orelse
232    can dest_var_dom tm
233  fun match_pattern tm [] = fail()
234    | match_pattern tm ((pat,name)::xs) =
235        if not (can (match_term pat) tm) then match_pattern tm xs else let
236          val (s1,s2) = match_term pat tm
237          val cs = filter is_var (list_dest dest_comb pat)
238          in (name,map (subst s1 o inst s2) cs) end
239  fun term tm =
240    (* Num *)
241    (if numSyntax.is_numeral tm then
242      "Num " ^ int_to_string (tm |> numSyntax.int_of_term) ^ " Nat"
243    else if wordsSyntax.is_n2w tm then
244      let val i = tm |> rand |> numSyntax.dest_numeral
245      in "Num " ^ Arbnum.toString i ^ " " ^ export_type (type_of tm) end
246    (* Var *)
247    else if is_var_acc tm then
248      let val name = tm |> rator |> rand |> stringSyntax.fromHOLstring
249      in "Var " ^ name ^ " " ^ export_type (type_of tm) end
250    (* Op *)
251    else let
252      val (n,xs) = match_pattern tm patterns
253      val ty = export_type (type_of tm)
254      in "Op " ^ n ^ " " ^ ty ^ " " ^ export_list (map term xs) end
255    ) handle HOL_ERR err => (print (exn_to_string (HOL_ERR err));
256            add_tm_fail tm; fail())
257  val types = [``VarNat :num -> 'a variable``,
258               ``VarWord8 :word8 -> 'a variable``,
259               ``VarWord :'a word -> 'a variable``,
260               ``VarMem :('a word -> word8) -> 'a variable``,
261               ``VarDom :('a word -> bool) -> 'a variable``,
262               ``VarBool :bool -> 'a variable``]
263  fun bool_exp tm =
264    if can dest_var_acc tm then let
265      val n = dest_var_acc tm
266      in "Var " ^ n ^ " " ^ get_var_type n end
267    else let
268      val (s,e) = dest_abs tm
269      val _ = type_of s = ``:32 state`` orelse
270              type_of s = ``:64 state`` orelse failwith("bad exp")
271      val _ = type_of e = ``:bool`` orelse failwith("bad exp")
272      in term e end
273  fun exp tm =
274    if can dest_var_acc tm then let
275      val n = dest_var_acc tm
276      in "Var " ^ n ^ " " ^ get_var_type n end
277    else let
278      val (s,e) = dest_abs tm
279      val _ = type_of s = ``:32 state`` orelse
280              type_of s = ``:64 state`` orelse failwith("bad exp")
281      val (t,tm) = dest_comb e
282      val _ = term_mem t types
283      in term tm end
284  fun dest_abs_skip_tag test = let
285    val (v,x) = dest_abs test
286    val n = dest_SKIP_TAG x
287    in n end
288  fun assign_var (n,tm) =
289    "" ^ n ^ " " ^ get_var_type n ^ " " ^ exp tm
290  val ret_node = ``Ret``
291  val err_node = ``Err``
292  fun export_nextnode (tm:term) =
293    if aconv tm ret_node then "Ret" else
294    if aconv tm err_node then "Err" else let
295      val i = dest_NextNode tm
296      in int_to_hex i end
297  fun export_node (n,tm) = let
298    val (next,assign) = dest_Basic tm
299    in commas [int_to_hex n,"Basic",export_nextnode next,
300               export_list (map assign_var assign)] ^ "\n" end
301    handle HOL_ERR _ => let
302    val (next1,next2,test) = dest_Cond tm
303    in if can dest_abs_skip_tag test then
304         "# " ^ int_to_hex n ^ " node is " ^
305         dest_abs_skip_tag test ^ "\n" ^
306         commas [int_to_hex n,"Cond",
307                 export_nextnode next1,
308                 export_nextnode next2,
309                 "Op UnspecifiedPrecond Bool 0"] ^ "\n"
310       else
311         commas [int_to_hex n,"Cond",
312                 export_nextnode next1,
313                 export_nextnode next2,
314                 bool_exp test] ^ "\n" end
315    handle HOL_ERR _ => let
316    val (next,func_name,input,output) = dest_Call tm
317    in commas [int_to_hex n,"Call",
318               export_nextnode next,
319               func_name,
320               export_list (map exp input),
321               export_list (map arg output)] ^ "\n" end
322  val rhs = rhs |> QCONV (REWRITE_CONV [graph_format_preprocessing])
323                |> concl |> rand
324  val (input,output,nodes,entry) = dest_GraphFunction rhs
325  val decl = "Function " ^ name ^ " " ^
326                export_list (map arg input) ^ " " ^
327                export_list (map arg output) ^ "\n"
328  val _ = write_graph decl
329  fun my_map f [] = []
330    | my_map f (x::xs) =
331    ((let val y = f x in y end
332      handle Overflow => failwith "Overflow")
333     handle HOL_ERR e =>
334     let val _ = print "\n\nFailed to translate node: \n\n"
335         val _ = print_term (snd x)
336         val _ = print "\n\n"
337         val _ = (last_fail_node_tm := snd x)
338     in raise (HOL_ERR e) end) :: my_map f xs
339  val _ = my_map (write_graph o export_node) nodes
340  val last_line = "EntryPoint " ^ int_to_hex entry ^ "\n"
341  val _ = if List.null nodes then () else write_graph last_line
342  in () end
343
344(*
345val tm = !last_fail_node_tm
346*)
347
348
349(* export constant definition *)
350
351fun export_func lemma = let
352  val (lhs,rhs) = lemma |> concl |> dest_eq
353  val name = lhs |> dest_const |> fst |> clean_name
354  val _ = export_graph name rhs
355  in "define_" ^ name end
356
357
358(* print export report *)
359
360fun print_export_report () = let
361  val l = length (!failed_ty_translations) + length (!failed_tm_translations)
362  in if l = 0 then write_line "No export failures." else let
363       val _ = has_failures := true
364       val xs = map (fn ty => "Failed to translate type: " ^ type_to_string ty)
365                       (all_distinct (!failed_ty_translations)) @
366                map (fn tm => "Failed to translate term: " ^ term_to_string tm)
367                       (term_all_distinct (!failed_tm_translations))
368       in (map write_line xs; ()) end end
369
370
371(* conv used by func_decompiler *)
372
373val prepare_for_export_conv = let
374  fun unbeta_conv pat tm =
375    if is_comb tm andalso can (match_term pat) (rand tm) then let
376      val ty = rand tm |> type_of |> dest_type |> snd |> hd
377      in (RAND_CONV (REWR_CONV (GSYM ETA_AX))) tm end else NO_CONV tm
378  val foldback = (unbeta_conv ``var_bool str``) ORELSEC
379                 (unbeta_conv ``var_word str``) ORELSEC
380                 (unbeta_conv ``var_word8 str``) ORELSEC
381                 (unbeta_conv ``var_nat str``) ORELSEC
382                 (unbeta_conv ``var_mem str``) ORELSEC
383                 (unbeta_conv ``var_dom str``)
384  val c = PURE_REWRITE_CONV [decomp_simp1,all_names_def,
385            ret_and_all_names_def,
386            all_names_ignore_def, all_names_with_input_def] THENC
387          PURE_REWRITE_CONV [decomp_simp2] THENC
388          PURE_REWRITE_CONV [decomp_simp3] THENC
389          PURE_REWRITE_CONV [GSYM wordsTheory.WORD_NOT_LOWER,v2w_sing,
390                             wordsTheory.WORD_HIGHER_EQ,
391                             wordsTheory.WORD_HIGHER,
392                             wordsTheory.WORD_GREATER_EQ,
393                             wordsTheory.WORD_GREATER] THENC
394          DEPTH_CONV foldback
395  in QCONV c end;
396
397end
398