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