1structure holfootParser :> holfootParser =
2struct
3
4(*
5quietdec := true;
6loadPath :=
7            (concat [Globals.HOLDIR, "/examples/separationLogic/src"]) ::
8            (concat [Globals.HOLDIR, "/examples/separationLogic/src/holfoot"]) ::
9            !loadPath;
10
11map load ["finite_mapTheory", "holfootTheory",
12     "Parsetree", "AssembleHolfootParser"];
13
14use (Globals.HOLDIR ^ "/examples/separationLogic/src/holfoot/hfheader.sml")
15
16show_assums := true;
17*)
18
19open HolKernel Parse boolLib finite_mapTheory
20open Parsetree;
21open separationLogicSyntax
22open vars_as_resourceSyntax
23open holfootSyntax
24
25(*
26quietdec := false;
27*)
28
29
30exception holfoot_unsupported_feature_exn of string;
31
32val list_data_tag = ref "hd";
33val data_list_tag = ref "dta";
34val array_data_tag = ref "dta";
35val list_link_tag = ref "tl"
36val tree_data_tag = ref "dta"
37val tree_link_tags = ref ("l", "r")
38
39
40fun mk_el_list 0 v = []
41  | mk_el_list n v =
42       (listSyntax.mk_hd v)::(mk_el_list (n-1) (listSyntax.mk_tl v))
43
44fun mk_list [] = Absyn.mk_ident "NIL"
45  | mk_list (e::es) =
46      Absyn.mk_app (Absyn.mk_app (Absyn.mk_ident "CONS", e), mk_list es)
47
48fun absyn2term a = absyn_to_term (term_grammar ()) a
49
50fun string_to_label s = mk_var (s, markerSyntax.label_ty);
51
52val parse = AssembleHolfootParser.raw_read_file;
53
54
55(*
56val file = "/home/tuerk/Downloads/holfoot/EXAMPLES/business2.sf";
57val file = "/home/tt291/Downloads/holfoot/EXAMPLES/business2.sf";
58
59val prog = parse file;
60*)
61
62fun vstruct_idents s (Absyn.VAQ _) = s
63  | vstruct_idents s (Absyn.VIDENT (_, i)) = Redblackset.add (s, i)
64  | vstruct_idents s (Absyn.VPAIR (_, vs1, vs2)) =
65       vstruct_idents (vstruct_idents s vs1) vs2
66  | vstruct_idents s (Absyn.VTYPED (_, vs, _)) =
67       vstruct_idents s vs;
68
69
70fun map_ident (s,f,f2_opt,f3_opt) l = case l of
71    Absyn.AQ    (locn,t)   => (s, Absyn.AQ (locn,t))
72  | Absyn.IDENT (locn,i)   =>
73         let
74            val (s', a) = f s locn i
75         in
76            (s', a)
77         end
78  | Absyn.QIDENT(locn,t,i) => (s, Absyn.QIDENT(locn,t,i))
79  | Absyn.APP   (locn,a1,a2) =>
80         let
81            val (s',  a1') = map_ident (s,f,f2_opt,f3_opt)   a1
82            val (s'', a2') = map_ident (s',f,f2_opt,f3_opt) a2
83         in
84            (s'', Absyn.APP (locn,a1',a2'))
85         end
86  | Absyn.LAM   (locn,v,a) =>
87         let
88            val is = vstruct_idents (Redblackset.empty String.compare) v;
89            val s' = if isSome f2_opt then (valOf f2_opt) s locn is else s;
90            val (s'',  a') = map_ident (s',f,f2_opt, f3_opt) a
91            val s''' = if isSome f3_opt then (valOf f3_opt) s'' locn is else s'';
92         in
93            (s''', Absyn.LAM (locn,v,a'))
94         end
95  | Absyn.TYPED (locn,a,p) =>
96         let
97            val (s',  a') = map_ident (s,f,f2_opt,f3_opt) a
98         in
99            (s', Absyn.TYPED (locn,a',p))
100         end
101
102fun collect_ident l =
103let
104   val is = Redblackset.empty String.compare
105   fun col set l s = (Redblackset.add (set,s), Absyn.IDENT (l, s))
106   fun del set l is = Redblackset.difference (set,is)
107   val (set, _) = map_ident (is, col,NONE, SOME del) l
108in
109   set
110end;
111
112
113fun string_list2set sL =
114   Redblackset.addList(Redblackset.empty String.compare, sL);
115
116
117fun is_holfoot_ex_ident i =
118   ((String.size i > 1) andalso
119    (String.sub (i,0) = #"_") andalso
120      not (String.sub (i,1) = #" "));
121fun norm_holfoot_ex_ident i = String.substring(i, 1, (String.size i) - 1);
122
123local
124   fun subst_qv_ident qv l i =
125       if (is_holfoot_ex_ident i) then
126       let
127          val i' = norm_holfoot_ex_ident i;
128          val qv' = Redblackset.add (qv, i')
129       in
130          (qv', Absyn.IDENT (l, i'))
131       end else (qv, Absyn.IDENT (l, i))
132in
133
134fun remove_qv a =
135      map_ident (Redblackset.empty String.compare, subst_qv_ident, NONE, NONE) a
136
137end;
138
139
140fun HOL_Absyn h =
141  let
142     val h' = String.translate (fn #"#" => "" | c => String.str c) h
143     val ha = Absyn [QUOTE h'];
144  in
145     ha
146  end;
147
148fun absyn_extract_vars vL a =
149  let
150     val eL_v = genvar (Type `:num list`);
151     val eL_L = mk_el_list (length vL) eL_v;
152     val substL = zip vL eL_L;
153     fun a_subst set l i = (if Redblackset.member (set, i) then Feedback.fail() else
154        (set, Absyn.mk_AQ (assoc i substL))) handle HOL_ERR _ => (set, Absyn.IDENT (l, i))
155     fun my_union set l is = Redblackset.union (set, is);
156     val (_, a') = map_ident (Redblackset.empty String.compare, a_subst, SOME my_union, NONE) a
157     val qa = Absyn.mk_lam (Absyn.VAQ (locn.Loc_None, eL_v), a')
158
159     val vL' = map (fn v => mk_comb(holfoot_exp_var_term, string2holfoot_var v)) vL;
160     val vLt = listSyntax.mk_list (vL', holfoot_a_expression_ty);
161  in
162     (qa, vLt)
163  end;
164
165
166fun replace_old os_opt l = case l of
167    Absyn.AQ    (locn,t)   => (os_opt, l)
168  | Absyn.IDENT (locn,i)   => (os_opt, l)
169  | Absyn.QIDENT(locn,t,i) => (os_opt, l)
170  | Absyn.APP   (locn,Absyn.IDENT(_,"old"),Absyn.IDENT(_,v)) =>
171    let
172       val os = if isSome os_opt then valOf os_opt else
173                  Feedback.failwith ("No old value of "^v^" available here!");
174       val nv_opt = Redblackmap.peek (os, v);
175       val (nv, os') = if isSome (nv_opt) then (valOf nv_opt, os) else
176                       let
177                          val nv = mk_var ("old_"^v, numLib.num);
178                          val os' = Redblackmap.insert(os,v,nv);
179                       in
180                          (nv,os')
181                       end;
182    in
183       (SOME os', Absyn.IDENT (locn,(fst o dest_var) nv))
184    end
185  | Absyn.APP   (locn,a1,a2) =>
186         let
187            val (os_opt, a1') = replace_old os_opt a1
188            val (os_opt, a2') = replace_old os_opt a2
189         in
190            (os_opt, Absyn.APP (locn,a1',a2'))
191         end
192  | Absyn.LAM   (locn,v,a) =>
193         let
194            val (os_opt,  a') = replace_old os_opt a
195         in
196            (os_opt, Absyn.LAM (locn,v,a'))
197         end
198  | Absyn.TYPED (locn,a,p) =>
199         let
200            val (os_opt,  a') = replace_old os_opt a
201         in
202            (os_opt, Absyn.TYPED (locn,a',p))
203         end
204
205
206fun HOL_Absyn_old_vars vs (os_opt, cs_opt) h =
207let
208   val ha = HOL_Absyn h
209
210   val (os_opt, ha) = replace_old os_opt ha;
211
212   val (ha, cs_opt) = if (not (isSome cs_opt)) then (ha, NONE) else
213       let
214          val used_vars = Redblackset.intersection (collect_ident ha, fst vs);
215          fun const_name v = v^"_lc";
216          fun my_union set l is = Redblackset.union (set, is);
217          fun my_work set l i =
218            let
219               val i' =  if not (Redblackset.member (used_vars, i)) orelse
220                            Redblackset.member (set,i) then i else
221                    ("_"^(const_name i))
222             in
223                (set, Absyn.IDENT (l, i'))
224             end
225
226          val (_, ha') = map_ident (Redblackset.empty String.compare,
227               my_work, SOME my_union, NONE) ha;
228          val used_varsL = Redblackset.listItems used_vars
229          val cs_opt' = SOME (
230               List.foldl (fn (k,d) => Redblackmap.insert (d, k,
231                   mk_var(const_name k, numLib.num))) (valOf cs_opt) used_varsL)
232       in
233          (ha', cs_opt')
234       end;
235in
236   ((os_opt, cs_opt), ha)
237end;
238
239
240fun holfoot_expression2absyn vs os_opt (Aexp_ident x) =
241   if (String.sub (x, 0) = #"#") then
242      (os_opt, Absyn.mk_app (Absyn.mk_AQ holfoot_exp_const_term,
243          Absyn.mk_ident (String.substring(x, 1, (String.size x) - 1))))
244   else if (is_holfoot_ex_ident x) orelse (Redblackset.member (snd vs, x)) then
245      (os_opt, Absyn.mk_app (Absyn.mk_AQ holfoot_exp_const_term,
246          Absyn.mk_ident x))
247   else
248      let
249         val var_term = string2holfoot_var x;
250         val term = mk_comb(holfoot_exp_var_term, var_term)
251      in
252         (os_opt, Absyn.mk_AQ term)
253      end
254| holfoot_expression2absyn vs os_opt (Aexp_old_ident x) =
255   let
256       val os = if isSome os_opt then valOf os_opt else
257                  Feedback.failwith ("No old value of "^x^" available here!");
258       val nv_opt = Redblackmap.peek (os, x);
259       val (nv, os') = if isSome (nv_opt) then (valOf nv_opt, os) else
260                       let
261                          val nv = mk_var ("old_"^x, numLib.num);
262                          val os' = Redblackmap.insert(os,x,nv);
263                       in
264                          (nv,os')
265                       end;
266       val et = mk_comb (holfoot_exp_const_term, nv);
267   in
268       (SOME os', Absyn.mk_AQ et)
269   end
270| holfoot_expression2absyn vs os_opt (Aexp_num n) =
271     (os_opt, Absyn.mk_AQ (mk_comb (holfoot_exp_const_term, numLib.term_of_int n)))
272| holfoot_expression2absyn vs os_opt (Aexp_infix (opstring, e1, e2)) =
273   let
274      val opterm = if (opstring = "-") then holfoot_exp_sub_term else
275                   if (opstring = "+") then holfoot_exp_add_term else
276                   if (opstring = "*") then holfoot_exp_mult_term else
277                   if (opstring = "/") then holfoot_exp_div_term else
278                   if (opstring = "%") then holfoot_exp_mod_term else
279                   if (opstring = "^") then holfoot_exp_exp_term else
280                       Raise (holfoot_unsupported_feature_exn ("Pexp_infix "^opstring));
281      val (os_opt' , t1) = holfoot_expression2absyn vs os_opt  e1;
282      val (os_opt'', t2) = holfoot_expression2absyn vs os_opt' e2;
283   in
284      (os_opt'', Absyn.list_mk_app (Absyn.mk_AQ opterm, [t1, t2]))
285   end
286| holfoot_expression2absyn vs os_opt (Aexp_hol h) =
287      let
288        val ((os_opt,_), ha) = HOL_Absyn_old_vars vs (os_opt,NONE) h;
289        val used_vars = Redblackset.listItems (Redblackset.intersection (collect_ident ha, fst vs))
290      in
291        if (null used_vars) then
292           (os_opt, Absyn.mk_app (Absyn.mk_AQ holfoot_exp_const_term, ha))
293        else
294           let
295             val (qha, vLt) = absyn_extract_vars used_vars ha
296           in
297             (os_opt, Absyn.list_mk_app (Absyn.mk_AQ holfoot_exp_op_term, [qha, Absyn.mk_AQ vLt]))
298           end
299      end;
300
301
302
303fun holfoot_p_condition2absyn vs Pcond_false =
304   Absyn.mk_AQ holfoot_pred_false_term
305| holfoot_p_condition2absyn vs Pcond_true =
306   Absyn.mk_AQ holfoot_pred_true_term
307| holfoot_p_condition2absyn vs (Pcond_neg c1) =
308   let
309      val t1 = holfoot_p_condition2absyn vs c1
310   in
311      (Absyn.mk_app (Absyn.mk_AQ holfoot_pred_neg_term, t1))
312   end
313| holfoot_p_condition2absyn vs (Pcond_and (c1,c2)) =
314   let
315      val t1 = holfoot_p_condition2absyn vs c1
316      val t2 = holfoot_p_condition2absyn vs c2
317   in
318      (Absyn.list_mk_app (Absyn.mk_AQ holfoot_pred_and_term, [t1, t2]))
319   end
320| holfoot_p_condition2absyn vs (Pcond_or (c1,c2)) =
321   let
322      val t1 = holfoot_p_condition2absyn vs c1
323      val t2 = holfoot_p_condition2absyn vs c2
324   in
325      (Absyn.list_mk_app (Absyn.mk_AQ holfoot_pred_or_term, [t1, t2]))
326   end
327| holfoot_p_condition2absyn vs (Pcond_compare (opstring, e1, e2)) =
328   let
329      val opterm = if (opstring = "==") then holfoot_pred_eq_term else
330                   if (opstring = "!=") then holfoot_pred_neq_term else
331                   if (opstring = "<")  then holfoot_pred_lt_term else
332                   if (opstring = "<=") then holfoot_pred_le_term else
333                   if (opstring = ">")  then holfoot_pred_gt_term else
334                   if (opstring = ">=") then holfoot_pred_ge_term else
335                      Raise (holfoot_unsupported_feature_exn ("Pcond_compare "^opstring));
336      val (_, t1) = holfoot_expression2absyn vs NONE e1;
337      val (_, t2) = holfoot_expression2absyn vs NONE e2;
338   in
339      (Absyn.list_mk_app (Absyn.mk_AQ opterm, [t1, t2]))
340   end
341| holfoot_p_condition2absyn vs (Pcond_hol h) =
342      let
343        val ha = HOL_Absyn h;
344        val used_vars = Redblackset.listItems (Redblackset.intersection (collect_ident ha, fst vs))
345      in
346        let
347          val (qha, vLt) = absyn_extract_vars used_vars ha
348        in
349          Absyn.list_mk_app (Absyn.mk_AQ holfoot_pred_term, [qha, Absyn.mk_AQ vLt])
350        end
351      end;
352
353
354
355val tag_a_expression_fmap_emp_term = ``FEMPTY:(holfoot_tag |-> holfoot_a_expression)``;
356val tag_a_expression_fmap_update_term = ``FUPDATE:(holfoot_tag |-> holfoot_a_expression)->
357(holfoot_tag # holfoot_a_expression)->(holfoot_tag |-> holfoot_a_expression)``;
358
359
360fun tag_a_expression_list2absyn vs rvm [] = (rvm, Absyn.mk_AQ tag_a_expression_fmap_emp_term) |
361    tag_a_expression_list2absyn vs rvm ((tag,exp1)::l) =
362      let
363         val tag_term = string2holfoot_tag tag;
364         val (rvm', exp_absyn) = holfoot_expression2absyn vs rvm exp1;
365         val a = Absyn.mk_pair (Absyn.mk_AQ tag_term, exp_absyn)
366         val (rvm'', rest) = tag_a_expression_list2absyn vs rvm' l;
367      in
368         (rvm'', Absyn.list_mk_app (Absyn.mk_AQ tag_a_expression_fmap_update_term, [rest, a]))
369      end;
370
371
372val genpredMap = ref (Redblackmap.mkDict String.compare)
373fun add_genpred (name:string, argL:Parsetree.a_genpredargType list, mk:Absyn.absyn list -> Absyn.absyn) =
374let
375   val map = (!genpredMap);
376   val oldEntry = Redblackmap.find (map, name) handle Redblackmap.NotFound => [];
377   val newEntry = (length argL, argL, mk)::oldEntry;
378   val map = Redblackmap.insert (map, name, newEntry);
379   val _ = genpredMap := map;
380in
381   ()
382end;
383
384fun reset_genpreds () =
385let
386   val _ = genpredMap := (Redblackmap.mkDict String.compare);
387in
388   ()
389end;
390
391
392fun lookup_genpredL name len =
393let
394   val l = Redblackmap.find ((!genpredMap), name);
395   val l' = filter (fn (len', _, _) => (len = len')) l;
396in
397   List.map (fn (_, argL, mk) => (argL, mk)) l'
398end handle Redblackmap.NotFound => [];
399
400
401local
402   exception arg_exception;
403
404   fun arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_tag (Aspred_arg_exp (Aexp_ident arg)) =
405         (os_opt, cs_opt, SOME (Absyn.mk_AQ (string2holfoot_tag arg)))
406     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_exp (Aspred_arg_exp arg_exp) =
407         let
408            val (os_opt, exp) = holfoot_expression2absyn vs os_opt arg_exp
409         in
410            (os_opt, cs_opt, SOME exp)
411         end
412     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_hol (Aspred_arg_exp (Aexp_hol arg)) =
413         let
414            val ((os_opt, cs_opt), hol) = HOL_Absyn_old_vars vs (os_opt, cs_opt) arg;
415         in
416            (os_opt, cs_opt, SOME hol)
417         end
418     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_hol (Aspred_arg_exp (Aexp_ident arg)) =
419       arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_hol (Aspred_arg_exp (Aexp_hol arg))
420     | arg2absyn vs (os_opt, cs_opt) (Aspred_arg_ty_list Aspred_arg_ty_tag) (Aspred_arg_string_list argL) =
421         let
422            val tag_t = listSyntax.mk_list (
423                 (map string2holfoot_tag argL), Type `:holfoot_tag`);
424         in
425            (os_opt, cs_opt, SOME (Absyn.mk_AQ tag_t))
426         end
427     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_comma Aspred_arg_comma =
428         (os_opt, cs_opt, NONE)
429     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_colon Aspred_arg_colon =
430         (os_opt, cs_opt, NONE)
431     | arg2absyn vs (os_opt, cs_opt) Aspred_arg_ty_semi Aspred_arg_semi =
432         (os_opt, cs_opt, NONE)
433     | arg2absyn _ _ _ _ = raise arg_exception;
434
435
436   fun args2absyn vs (os_opt, cs_opt) [] [] = (os_opt, cs_opt, [])
437     | args2absyn vs (os_opt, cs_opt) (ty::tys) (arg::args) =
438       let
439          val (os_opt, cs_opt, r_opt)  = arg2absyn  vs (os_opt, cs_opt) ty arg;
440          val (os_opt, cs_opt, rs) = args2absyn vs (os_opt, cs_opt) tys args;
441
442          val rs' = case r_opt of SOME r => r::rs | NONE => rs;
443       in
444          (os_opt, cs_opt, rs')
445       end;
446
447in
448
449fun holfoot_a_genpred2absyn vs (os_opt, cs_opt) name args line =
450   let
451      val candidates = lookup_genpredL name (length args);
452      fun try_canditate (arg_tys, c) =
453      let
454          val (os_opt, cs_opt, absynArgs) = args2absyn vs (os_opt, cs_opt) arg_tys args
455      in
456         ((os_opt, cs_opt), c absynArgs)
457      end handle arg_exception => Feedback.fail ()
458   in
459      tryfind try_canditate candidates handle HOL_ERR _ =>
460         let
461         val _ = AssembleHolfootParser.print_parse_error (
462                  "Undefined predicate '"^name^"' found in line "^
463                  (Int.toString (line+1))^"!")
464         in
465         ((os_opt, cs_opt), Absyn.mk_typed(Absyn.mk_ident ("!!!ERROR "^name^"!!!"),
466                            Pretype.fromType holfoot_a_proposition_ty)) end
467   end;
468end
469
470
471
472
473fun holfoot_a_space_pred2absyn vs (os_opt, cs_opt) (Aspred_empty) =
474   ((os_opt, cs_opt), Absyn.mk_AQ holfoot_stack_true_term)
475| holfoot_a_space_pred2absyn vs (os_opt, cs_opt) (Aspred_genpred (name,args,(_,line))) =
476  holfoot_a_genpred2absyn vs (os_opt, cs_opt) name args line
477| holfoot_a_space_pred2absyn vs (os_opt, cs_opt) (Aspred_boolhol h) =
478      let
479        val ((os_opt, _), ha) = HOL_Absyn_old_vars vs (os_opt, NONE) h;
480        val used_vars = Redblackset.listItems (Redblackset.intersection (collect_ident ha, fst vs))
481      in
482        if (null used_vars) then
483           ((os_opt, cs_opt), Absyn.mk_app (Absyn.mk_AQ holfoot_bool_proposition_term, ha))
484        else
485           let
486              val (qha, vLt) = absyn_extract_vars used_vars ha
487           in
488              ((os_opt, cs_opt), Absyn.list_mk_app (Absyn.mk_AQ holfoot_ap_expression_term, [qha, Absyn.mk_AQ vLt]))
489           end
490      end
491| holfoot_a_space_pred2absyn vs (os_opt, cs_opt) (Aspred_hol s) =
492  HOL_Absyn_old_vars vs (os_opt, cs_opt) s
493| holfoot_a_space_pred2absyn vs (os_opt, cs_opt) (Aspred_pointsto (exp, pl)) =
494  let
495     val (os_opt, a1) = holfoot_expression2absyn vs os_opt exp;
496     val (os_opt, a2) = tag_a_expression_list2absyn vs os_opt pl;
497  in
498     ((os_opt, cs_opt), Absyn.list_mk_app(Absyn.mk_AQ holfoot_ap_points_to_term, [a1, a2]))
499  end;
500
501
502
503fun invariant2a_proposition NONE =
504    Aprop_spred Aspred_empty
505  | invariant2a_proposition (SOME p) = p
506
507
508val holfoot_map_absyn = Absyn ([QUOTE
509      "var_res_map DISJOINT_FMAP_UNION"])
510
511fun holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_infix (opString, exp1, exp2)) =
512  let
513    val op_term = if (opString = "<") then holfoot_ap_lt_term else
514                  if (opString = "<=") then holfoot_ap_le_term else
515                  if (opString = ">") then holfoot_ap_gt_term else
516                  if (opString = ">=") then holfoot_ap_ge_term else
517                  if (opString = "==") then holfoot_ap_equal_term else
518                  if (opString = "!=") then holfoot_ap_unequal_term else
519                     Raise (holfoot_unsupported_feature_exn ("Aexp_infix "^opString))
520    val (os_opt, t1) = holfoot_expression2absyn vs os_opt exp1;
521    val (os_opt, t2) = holfoot_expression2absyn vs os_opt exp2;
522  in
523    ((os_opt,cs_opt), Absyn.list_mk_app (Absyn.mk_AQ op_term, [t1, t2]))
524  end
525| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_false) =
526    ((os_opt,cs_opt), Absyn.mk_AQ holfoot_ap_false_term)
527| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_ifthenelse (Aprop_infix (opString,exp1,exp2),ap1,ap2)) =
528  let
529      val (ap1,ap2) = if opString = "==" then (ap1,ap2) else
530                      if opString = "!=" then (ap2,ap1) else
531                      Raise (holfoot_unsupported_feature_exn "Currently only equality checks are allowed as conditions in propositions")
532
533      val (os_opt, exp1)  = holfoot_expression2absyn vs os_opt exp1;
534      val (os_opt, exp2)  = holfoot_expression2absyn vs os_opt exp2;
535      val ((os_opt,cs_opt), prop1) = holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) ap1;
536      val ((os_opt,cs_opt), prop2) = holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) ap2;
537   in
538      ((os_opt,cs_opt), Absyn.list_mk_app (Absyn.mk_AQ holfoot_ap_eq_cond_term, [exp1, exp2, prop1, prop2]))
539   end
540| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_ifthenelse _) =
541     Raise (holfoot_unsupported_feature_exn "Currently only equality checks are allowed as conditions in propositions")
542| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_star (ap1, ap2)) =
543  let
544     val ((os_opt,cs_opt), prop1) = holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) ap1;
545     val ((os_opt,cs_opt), prop2) = holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) ap2;
546  in
547     ((os_opt,cs_opt), Absyn.list_mk_app (Absyn.mk_AQ holfoot_ap_star_term, [prop1, prop2]))
548  end
549| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_map (vL, ap, l)) =
550  let
551      val vs2 = (fst vs, Redblackset.addList (snd vs, vL))
552      val ((os_opt,cs_opt), ap_a) = holfoot_a_proposition2absyn_context vs2 (os_opt,cs_opt) ap;
553      val pair_vs = end_itlist (fn v1 => fn v2 => Absyn.VPAIR (locn.Loc_None, v1, v2))
554                    (map (fn v => Absyn.VIDENT (locn.Loc_None, v)) vL)
555      val ap_la = Absyn.mk_lam (pair_vs,ap_a)
556      val l_a = HOL_Absyn l;
557  in
558     ((os_opt,cs_opt), Absyn.list_mk_app (holfoot_map_absyn,[ap_la, l_a]))
559  end
560| holfoot_a_proposition2absyn_context vs (os_opt,cs_opt) (Aprop_spred sp) =
561     holfoot_a_space_pred2absyn vs (os_opt,cs_opt) sp;
562
563
564exception NothingToDo;
565fun add_var_equations m a =
566let
567   val L = Redblackmap.listItems m;
568   val _ = if null L then raise NothingToDo else ();
569   fun mk_old_eq (hv, v) =
570       list_mk_comb (holfoot_ap_equal_term, [
571           mk_comb(holfoot_exp_var_term, string2holfoot_var hv),
572           mk_comb(holfoot_exp_const_term, v)])
573   val eqL = List.map mk_old_eq L
574   val eq_star = end_itlist (fn t => fn ts =>
575         list_mk_comb (holfoot_ap_star_term, [t, ts])) eqL;
576
577   val a' =  Absyn.list_mk_app (Absyn.mk_AQ holfoot_ap_star_term,
578      [Absyn.mk_AQ eq_star, a])
579in
580   a'
581end handle NothingToDo => a;
582
583
584fun holfoot_a_proposition2absyn vs os_opt x =
585let
586   val ((os_opt,cs_opt), a1) = holfoot_a_proposition2absyn_context vs
587       (os_opt, SOME (Redblackmap.mkDict String.compare)) x;
588
589   val a2 = if isSome cs_opt then add_var_equations (valOf cs_opt) a1 else a1;
590
591   val (s, a3) = remove_qv a2
592   val cs_opt = SOME (Redblackmap.mkDict String.compare)
593   val s' = if not (isSome cs_opt) then s else
594                let
595                   val vL = List.map (fst o dest_var o snd) (Redblackmap.listItems (valOf cs_opt))
596                in
597                   Redblackset.addList (s, vL)
598                end
599   val ex_vars = Redblackset.listItems s';
600
601   val a4 = foldr (fn (v,a) =>
602       let
603          val a_lam = Absyn.mk_lam (Absyn.VIDENT (locn.Loc_None, v), a);
604          val a' = Absyn.mk_app (Absyn.mk_ident "asl_exists", a_lam);
605       in a' end) a3 ex_vars
606in
607   (os_opt, a4)
608end;
609
610
611fun mk_holfoot_prop_input_absyn wp rp ap =
612 let
613   val rp = Redblackset.difference (rp, wp);
614
615   val rL = map string2holfoot_var (Redblackset.listItems rp);
616   val wL = map string2holfoot_var (Redblackset.listItems wp);
617   val dL = append rL wL
618
619   val da = mk_list(map Absyn.mk_AQ dL);
620   val rp_term = pred_setSyntax.prim_mk_set (rL, Type `:holfoot_var`);
621   val wp_term = pred_setSyntax.prim_mk_set (wL, Type `:holfoot_var`);
622   val wp_rp_pair_term = pairLib.mk_pair (wp_term, rp_term);
623 in
624   if length dL < 2 then
625      Absyn.list_mk_app (Absyn.mk_AQ holfoot_prop_input_ap_term, [Absyn.mk_AQ wp_rp_pair_term, ap])
626   else
627      Absyn.list_mk_app (Absyn.mk_AQ holfoot_prop_input_ap_distinct_term, [Absyn.mk_AQ wp_rp_pair_term, da, ap])
628 end;
629
630fun mk_holfoot_prop_input wp rp t =
631  absyn2term (mk_holfoot_prop_input_absyn wp rp (Absyn.mk_AQ t));
632
633
634fun holfoot_fcall_get_read_write_var_sets funL (funname:string) args =
635let
636  val (pL, rpe, wpe) = assoc funname funL handle HOL_ERR _ => Feedback.failwith (
637          "Unknown function '"^funname^"'")
638  val wL = map fst (filter (fn (_, do_write) => do_write) (zip args pL));
639in
640  (rpe:string list, (wpe@wL):string list)
641end;
642
643
644fun holfoot_fcall2absyn_internal funL vs (name, (rp,vp)) =
645let
646   val name_term = stringLib.fromMLstring name;
647
648   val var_list = map string2holfoot_var rp;
649   val rp_term = listSyntax.mk_list (var_list, Type `:holfoot_var`);
650
651   val vp_a = mk_list (map (fn t => snd (holfoot_expression2absyn vs NONE t)) vp);
652
653   val arg_a = Absyn.mk_pair (Absyn.mk_AQ rp_term, vp_a);
654   val _ = ((assoc name funL);()) handle HOL_ERR _ =>
655           let
656              val _ = AssembleHolfootParser.print_parse_error (
657                  "Call of undeclared function '"^name^"' found!");
658           in
659              Feedback.fail()
660           end;
661
662   val (_,wL) = holfoot_fcall_get_read_write_var_sets funL name rp;
663   val funcalls = [(name, rp)];
664in
665   (name_term, arg_a, wL, funcalls)
666end;
667
668
669fun holfoot_fcall2absyn funL vs (name, (rp, vp)) =
670let
671   val (name_term, arg_a, wL, funcalls) =
672       holfoot_fcall2absyn_internal funL vs (name, (rp,vp));
673in
674   (Absyn.list_mk_app(Absyn.mk_AQ holfoot_prog_procedure_call_term, [
675    Absyn.mk_AQ name_term, arg_a]), wL, funcalls)
676end;
677
678
679fun holfoot_parallel_fcall2absyn funL vs (name1, (rp1, vp1), name2, (rp2,vp2)) =
680let
681   val (name1_term, arg1_a, wL1, funcalls1) =
682       holfoot_fcall2absyn_internal funL vs (name1, (rp1,vp1));
683
684   val (name2_term, arg2_a, wL2, funcalls2) =
685       holfoot_fcall2absyn_internal funL vs (name2, (rp2,vp2));
686in
687   (Absyn.list_mk_app(Absyn.mk_AQ holfoot_prog_parallel_procedure_call_term, [
688       Absyn.mk_AQ name1_term, arg1_a,Absyn.mk_AQ name2_term, arg2_a]),
689       wL1@wL2, funcalls1@funcalls2)
690end;
691
692
693
694val unit_var_term = mk_var("uv", Type `:unit`);
695
696fun mk_list_pabs l =
697  let
698    val pairTerm = if null l then unit_var_term else
699                   (pairLib.list_mk_pair l);
700  in
701     fn t => pairLib.mk_pabs (pairTerm,t)
702  end;
703
704fun mk_list_plam l =
705  let
706    val pair_vs = if null l then Absyn.VAQ (locn.Loc_None, unit_var_term) else
707          end_itlist (fn v1 => fn v2 => Absyn.VPAIR (locn.Loc_None, v1, v2))
708             (map (fn v => Absyn.VAQ (locn.Loc_None, v)) l)
709  in
710     fn a => Absyn.mk_lam (pair_vs,a)
711  end;
712
713
714fun decode_rwOpt rwOpt = if isSome rwOpt then
715       (let val (force, wL, rL) = valOf rwOpt in
716       (force, wL, rL) end) else
717       (false, [], []);
718
719fun find_used_holvars res_varL ts t =
720  case (dest_term t) of
721     VAR (_, ty) => ts
722   | CONST _ => ts
723   | LAMB (t1, t2) =>
724      let
725         val emp_s = Redblackset.empty String.compare;
726         val ts1 = find_used_holvars res_varL emp_s t1
727         val ts2 = find_used_holvars res_varL emp_s t2
728         val ts12 = Redblackset.difference (ts2, ts1);
729      in
730         Redblackset.union (ts, ts12)
731      end
732   | COMB (t1, t2) => if (is_holfoot_var t) then Redblackset.add (ts, holfoot_var2string t) else
733     if (is_holfoot_prog_with_resource t) then
734     let
735        val (res_nt, p, b) = dest_holfoot_prog_with_resource t;
736        val tp = find_used_holvars res_varL (Redblackset.empty String.compare) p;
737        val tpb = find_used_holvars res_varL tp b;
738
739        val res_n = stringLib.fromHOLstring res_nt;
740        val res_vars = assoc res_n res_varL;
741        val tpbr = Redblackset.difference (tpb, string_list2set res_vars);
742     in
743         Redblackset.union (ts, tpbr)
744     end else
745     let
746        val ts'  = find_used_holvars res_varL ts  t1;
747        val ts'' = find_used_holvars res_varL ts' t2;
748     in
749        ts''
750     end
751
752
753fun get_read_write_var_set res_varL rwOpt wL aL =
754let
755   val (force_user_wr, wL1, rL1) = decode_rwOpt rwOpt;
756
757   val (wL2, rL2) = if force_user_wr then (wL1, rL1) else
758       let
759          val t = absyn2term (Absyn.list_mk_pair aL);
760          val rs = find_used_holvars res_varL (Redblackset.empty String.compare) t;
761          val rL3 = Redblackset.listItems rs;
762       in
763          (wL1 @ wL, rL1@rL3)
764       end
765
766   val write_var_set = string_list2set wL2;
767   val read_var_set  = string_list2set rL2;
768
769   val read_var_set' = Redblackset.difference (read_var_set, write_var_set);
770in
771   (write_var_set, read_var_set')
772end;
773
774
775fun rewrite_old_var os pre_a post_a =
776let
777   val pre_a' = add_var_equations os pre_a;
778in
779   (pre_a', post_a)
780end
781
782
783fun global_vars_restrict global_vars =
784 filter (fn v =>
785    not (Redblackset.member (global_vars, fst (dest_var v))));
786
787
788fun free_vars_restrict global_vars t =
789let
790   val fv_list = free_vars t;
791in
792   global_vars_restrict global_vars fv_list
793end
794
795
796(*returns the abstract syntax of the statement as well as set of variables, that need write permissions.
797  The set of variables that are read is figured out independently later.
798  Function calls might add to both sets by either their call-by-reference parameters or by
799  accessing global variables. Therefore, function calls and their call-by-reference parameters
800  are recorded as well *)
801fun holfoot_p_statement2absyn funL resL gv vs (Pstm_assign (v, expr)) =
802  let
803     val var_term = string2holfoot_var v;
804     val (_, exp) = holfoot_expression2absyn vs NONE expr;
805     val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_assign_term, [Absyn.mk_AQ var_term, exp]);
806  in
807     (comb_a, [v], [])
808  end
809| holfoot_p_statement2absyn funL resL gv vs (Pstm_fldlookup (v, expr, tag)) =
810  let
811     val var_term = string2holfoot_var v;
812     val (_, exp_a) = holfoot_expression2absyn vs NONE expr;
813     val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_field_lookup_term,
814          [Absyn.mk_AQ var_term, exp_a, Absyn.mk_AQ (string2holfoot_tag tag)]);
815  in
816     (comb_a, [v], [])
817  end
818| holfoot_p_statement2absyn funL resL gv vs (Pstm_fldassign (expr1, tag, expr2)) =
819  let
820     val (_, exp1) = holfoot_expression2absyn vs NONE expr1;
821     val (_, exp2) = holfoot_expression2absyn vs NONE expr2;
822     val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_field_assign_term, [
823          exp1, Absyn.mk_AQ (string2holfoot_tag tag), exp2]);
824  in
825     (comb_a, [], [])
826  end
827| holfoot_p_statement2absyn funL resL gv vs (Pstm_new (v, expr, tl)) =
828  let
829     val var_term = string2holfoot_var v;
830     val (_, exp) = holfoot_expression2absyn vs NONE expr;
831     val tl_L = map string2holfoot_tag tl;
832     val tl_t = listSyntax.mk_list (tl_L, holfoot_tag_ty);
833     val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_new_term, [exp, Absyn.mk_AQ var_term, Absyn.mk_AQ tl_t]);
834  in
835     (comb_a, [v], [])
836  end
837| holfoot_p_statement2absyn funL resL gv vs (Pstm_dispose (expr1, expr2)) =
838  let
839     val (_, exp1) = holfoot_expression2absyn vs NONE expr1;
840     val (_, exp2) = holfoot_expression2absyn vs NONE expr2;
841     val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_dispose_term, [exp2,exp1]);
842  in
843     (comb_a, [], [])
844  end
845| holfoot_p_statement2absyn funL resL gv vs Pstm_diverge =
846     (Absyn.mk_AQ holfoot_prog_diverge_term, [], [])
847| holfoot_p_statement2absyn funL resL gv vs Pstm_fail =
848     (Absyn.mk_AQ holfoot_prog_fail_term, [], [])
849| holfoot_p_statement2absyn funL resL gv vs (Pstm_block stmL) =
850  let
851     val l0 = map (holfoot_p_statement2absyn funL resL gv vs) stmL;
852     val (aL, wL, fL) = foldr (fn ((a, wL', fL'), (aL, wL, fL)) =>
853          (a::aL, wL'@wL, fL'@fL)) ([],[],[]) l0;
854     val comb_a = Absyn.mk_app (Absyn.mk_AQ holfoot_prog_block_term, mk_list aL);
855   in
856     (comb_a, wL, fL)
857   end
858| holfoot_p_statement2absyn funL resL gv vs (Pstm_if (cond, stm1, stm2)) =
859   let
860      val c_a = holfoot_p_condition2absyn vs cond;
861      val (stm1, wL1, fL1) = holfoot_p_statement2absyn funL resL gv vs stm1;
862      val (stm2, wL2, fL2) = holfoot_p_statement2absyn funL resL gv vs stm2;
863
864      val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_cond_term,
865             [c_a, stm1, stm2]);
866   in
867      (comb_a, wL1@wL2, fL1@fL2)
868   end
869| holfoot_p_statement2absyn funL resL gv vs (Pstm_ndet (stm1, stm2)) =
870   let
871      val (stm1, wL1, fL1) = holfoot_p_statement2absyn funL resL gv vs stm1;
872      val (stm2, wL2, fL2) = holfoot_p_statement2absyn funL resL gv vs stm2;
873
874      val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_choice_term,
875             [stm1, stm2]);
876   in
877      (comb_a, wL1@wL2, fL1@fL2)
878   end
879| holfoot_p_statement2absyn funL resL gv vs (Pstm_while (unroll, rwOpt, i, cond, stm1)) =
880   let
881      val (use_inv, i_a) = if isSome i then
882              (true, snd (holfoot_a_proposition2absyn vs NONE (valOf i)))
883          else (false, Absyn.mk_AQ holfoot_stack_true_term)
884
885      val (stm1_a, wL, fL) = holfoot_p_statement2absyn funL resL gv vs stm1;
886      val c_a = holfoot_p_condition2absyn vs cond;
887      val while_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_while_term, [c_a,stm1_a]);
888
889      val (write_var_set, read_var_set) = get_read_write_var_set resL rwOpt wL [i_a, while_a]
890
891      val full_a = if not use_inv then while_a else
892         let
893            val prop_a = mk_holfoot_prop_input_absyn write_var_set read_var_set i_a;
894            val cond_free_var_list = free_vars_restrict gv (absyn2term prop_a);
895            val abs_prop_a = mk_list_plam cond_free_var_list prop_a
896         in
897            Absyn.list_mk_app (Absyn.IDENT (locn.Loc_None, "asl_comment_loop_invariant"), [
898               abs_prop_a, while_a])
899         end
900      val unroll_a = if unroll = 0 then full_a else
901            Absyn.list_mk_app (Absyn.IDENT (locn.Loc_None, "asl_comment_loop_unroll"), [
902                Absyn.mk_AQ (numLib.term_of_int unroll), full_a])
903
904   in
905      (unroll_a, wL, fL)
906   end
907| holfoot_p_statement2absyn funL resL gv vs (Pstm_block_spec (loop, unroll, rwOpt, pre, stm1, post)) =
908   let
909      val (_, pre_a)  = holfoot_a_proposition2absyn vs NONE pre;
910      val (SOME os, post_a) = holfoot_a_proposition2absyn vs (SOME (Redblackmap.mkDict String.compare)) post;
911      val (pre_a, post_a) = rewrite_old_var os pre_a post_a;
912      val (force_user_wr, write_var_set_user, read_var_set_user) = decode_rwOpt rwOpt;
913
914      val (stm1_a, wL, fL) = holfoot_p_statement2absyn funL resL gv vs stm1;
915
916      val (write_var_set, read_var_set) = get_read_write_var_set resL rwOpt wL [
917         pre_a, post_a, stm1_a]
918
919      val (pre_a2, post_a2) =
920         let
921            val pre_a3 =  mk_holfoot_prop_input_absyn write_var_set read_var_set pre_a
922            val post_a3 = mk_holfoot_prop_input_absyn write_var_set read_var_set post_a
923            val cond_free_var_list = global_vars_restrict gv (
924                HOLset.listItems (FVL [absyn2term pre_a3, absyn2term post_a3] empty_tmset));
925            val abs_pre_a = mk_list_plam cond_free_var_list pre_a3
926            val abs_post_a = mk_list_plam cond_free_var_list post_a3
927         in
928            (abs_pre_a, abs_post_a)
929         end
930      val stm1_a = if not loop then stm1_a else
931          let
932             fun isPstm_block (Pstm_block _) = true
933               | isPstm_block _ = false;
934             val stm1_a' = if isPstm_block stm1 then stm1_a else
935                 (Absyn.mk_app (Absyn.mk_AQ holfoot_prog_block_term, mk_list [stm1_a]));
936          in
937             stm1_a'
938          end;
939      val spec_a = Absyn.list_mk_app (
940          Absyn.IDENT (locn.Loc_None, if loop then "asl_comment_loop_spec" else
941                "asl_comment_block_spec"),
942          [Absyn.mk_pair (pre_a2, post_a2), stm1_a]);
943      val unroll_a = if unroll = 0 then spec_a else
944            Absyn.list_mk_app (Absyn.IDENT (locn.Loc_None, "asl_comment_loop_unroll"), [
945                Absyn.mk_AQ (numLib.term_of_int unroll), spec_a])
946   in
947      (unroll_a, wL, fL)
948   end
949| holfoot_p_statement2absyn funL resL gv vs (Pstm_withres (res, cond, stm1)) =
950   let
951      val c_a = holfoot_p_condition2absyn vs cond;
952      val (stm1_a,wL,fL) = holfoot_p_statement2absyn funL resL gv vs stm1;
953      val res_term = stringLib.fromMLstring res;
954      val res_varL = assoc res resL handle HOL_ERR _ =>
955           let
956              val _ = AssembleHolfootParser.print_parse_error (
957                  "Undeclared resource '"^res^"' used!");
958           in
959              Feedback.fail()
960           end;
961      val wL' = filter (fn v => not (mem v res_varL)) wL;
962      val comb_a = Absyn.list_mk_app (Absyn.mk_AQ holfoot_prog_with_resource_term, [
963              Absyn.mk_AQ res_term, c_a, stm1_a]);
964   in
965      (comb_a, wL', fL)
966   end
967| holfoot_p_statement2absyn funL resL gv vs (Pstm_assert p) =
968   let
969      val (_, p_a)  = holfoot_a_proposition2absyn vs NONE p;
970      val abs_p_a =
971         let
972            val cond_free_var_list = global_vars_restrict gv (
973                HOLset.listItems (FVL [absyn2term p_a] empty_tmset));
974            val abs_p_a = mk_list_plam cond_free_var_list p_a
975         in
976            abs_p_a
977         end
978      val comb_a =  Absyn.mk_app (
979          Absyn.IDENT (locn.Loc_None, "asl_comment_assert"), abs_p_a);
980   in
981      (comb_a, [], [])
982   end
983| holfoot_p_statement2absyn funL resL gv vs (Pstm_fcall(name,args)) =
984       holfoot_fcall2absyn funL vs (name, args)
985| holfoot_p_statement2absyn funL resL gv vs (Pstm_parallel_fcall(name1,args1,name2,args2)) =
986       holfoot_parallel_fcall2absyn funL vs (name1, args1, name2, args2);
987
988
989
990(*
991val dummy_fundecl =
992Pfundecl("proc", ([], ["x", "y"]),
993                       SOME(Aprop_spred(Aspred_pointsto(Aexp_ident "x", []))),
994                       [],
995                       [Pstm_fldassign(Pexp_ident "x", "tl", Pexp_ident "y")],
996                       SOME(Aprop_spred(Aspred_pointsto(Aexp_ident "x",
997                                                        [("tl",
998                                                          Aexp_ident "y")]))))
999
1000
1001fun destPfundecl (Pfundecl(funname, (ref_args, val_args), preCond, localV,
1002   fun_body, postCond)) =
1003   (funname, (ref_args, val_args), preCond, localV,
1004   fun_body, postCond);
1005
1006val (funname, (ref_args, val_args), preCondOpt, localV,
1007   fun_body, postCondOpt) = destPfundecl dummy_fundecl;
1008
1009val var = "y";
1010val term = fun_body_term;
1011*)
1012
1013
1014
1015
1016
1017
1018
1019(*
1020   fun dest_Presource (Presource(resname, varL, invariant)) =
1021        (resname, varL, invariant);
1022
1023
1024   val (resname, varL, invariant) = dest_Presource ((el 2 (program_item_decl)));
1025
1026*)
1027
1028
1029fun Presource2hol vs (Presource(resname, varL, invariant)) =
1030let
1031   val write_varL = map string2holfoot_var varL;
1032   val (_, i_a) = holfoot_a_proposition2absyn vs NONE invariant;
1033in
1034   (resname, (absyn2term i_a, write_varL))
1035end |
1036 Presource2hol _ _ = Raise (holfoot_unsupported_feature_exn ("-"));
1037
1038
1039
1040(*
1041   fun dest_Pfundecl (Pfundecl(funname, (ref_args, val_args), preCondOpt, localV,
1042   fun_body, postCondOpt)) = (funname, (ref_args, val_args), preCondOpt, localV,
1043   fun_body, postCondOpt);
1044
1045
1046   val (funname, (ref_args, val_args), preCondOpt, localV,
1047   fun_body, postCondOpt) = dest_Pfundecl ((el 2 (program_item_decl)));
1048
1049   val resL = resource_parseL
1050   val resL = []
1051   val funL = []
1052*)
1053
1054fun extend_set_if_necessary b (s1, s2) =
1055  let
1056     val s' = Redblackset.difference (s2, s1);
1057  in
1058     if Redblackset.isEmpty s' then (s1, b) else
1059          (Redblackset.union (s1, s'), true)
1060  end;
1061
1062
1063fun Pfundecl_preprocess resL global_vars (funL, vs,
1064   Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt, localV,
1065   fun_body, postCondOpt)) =
1066let
1067   val (fun_body_a, wL, funcalls) =
1068        holfoot_p_statement2absyn funL resL global_vars vs (Pstm_block fun_body)
1069
1070   val vs_na = (List.foldl (fn (v,vs) => Redblackset.delete (vs, v) handle NotFound => vs) (fst vs) val_args, snd vs);
1071   val (_, pre_a)  = holfoot_a_proposition2absyn vs_na NONE (invariant2a_proposition preCondOpt);
1072   val (SOME os, post_a) = holfoot_a_proposition2absyn vs_na (SOME (Redblackmap.mkDict String.compare))
1073        (invariant2a_proposition postCondOpt);
1074   val (pre_a, post_a) = rewrite_old_var os pre_a post_a;
1075
1076   val aL_t = absyn2term (Absyn.list_mk_pair [fun_body_a, pre_a, post_a]);
1077   val (ws, rs) = get_read_write_var_set resL rwOpt wL [Absyn.mk_AQ aL_t];
1078   val vs' = Redblackset.union (ws, rs);
1079   val local_vars = val_args@localV;
1080   val ws' = Redblackset.difference (ws, string_list2set local_vars)
1081   val rs' = Redblackset.difference (rs, string_list2set local_vars)
1082
1083   val (vs_vars2, changed) = extend_set_if_necessary false (fst vs, vs');
1084   val vs2 = (vs_vars2, snd vs);
1085   val (pL, rpe, wpe) = assoc funname funL handle HOL_ERR _ => Feedback.failwith (
1086          "Unknown function '"^funname^"'")
1087   val pL2 = map (fn s => Redblackset.member (ws', s)) ref_args;
1088   val changed = changed orelse not (pL2 = pL);
1089
1090   val (rps2, changed) = extend_set_if_necessary changed
1091         (string_list2set rpe, Redblackset.difference (rs', string_list2set ref_args))
1092   val (wps2, changed) = extend_set_if_necessary changed
1093         (string_list2set wpe, Redblackset.difference (ws', string_list2set ref_args))
1094   val rpe2 = Redblackset.listItems rps2;
1095   val wpe2 = Redblackset.listItems wps2;
1096in
1097   (changed, funname, pre_a, fun_body_a, post_a, ws', rs', vs2, pL2, rpe2, wpe2)
1098end;
1099
1100fun Pfundecl2hol_final (funname, assume_opt, ref_args, val_args, localV,
1101   global_vars, pre_t, fun_body_t, post_t, ws, rs) =
1102   let
1103   val fun_body_local_var_term = foldr holfoot_mk_local_var fun_body_t localV;
1104
1105   val used_vars = ref (free_vars_restrict global_vars fun_body_local_var_term);
1106   fun mk_new_var x = let
1107                    val v = variant (!used_vars) (mk_var x);
1108                    val _ = used_vars := v::(!used_vars);
1109                 in v end;
1110   val arg_ref_term = mk_new_var ("arg_refL", Type `:holfoot_var list`);
1111   val arg_val_term = mk_new_var ("arg_valL", Type `:num list`);
1112   val arg_valL = mk_el_list (length val_args) arg_val_term;
1113
1114   val fun_body_val_args_term = foldr holfoot_mk_call_by_value_arg fun_body_local_var_term (zip val_args arg_valL);
1115
1116   val arg_refL = mk_el_list (length ref_args) arg_ref_term;
1117   val arg_ref_varL = map string2holfoot_var ref_args;
1118   val arg_ref_subst = map (fn (vt, s) => (vt |-> s)) (zip arg_ref_varL arg_refL)
1119   val fun_body_final_term = subst arg_ref_subst fun_body_val_args_term;
1120   val fun_term = pairLib.mk_pabs (pairLib.mk_pair(arg_ref_term, arg_val_term), fun_body_final_term);
1121
1122   val arg_val_varL = map (fn s => mk_comb (holfoot_exp_var_term, string2holfoot_var s)) val_args;
1123   val arg_val_expL = map (fn c => mk_comb (holfoot_exp_const_term, c)) arg_valL;
1124   val arg_val_subst1 = map (fn (vt, s) => (vt |-> s)) (zip arg_val_varL arg_val_expL);
1125
1126   val arg_val_numL = map (fn s => mk_var (s, numLib.num)) val_args;
1127   val arg_val_subst2 = map (fn (vt, s) => (vt |-> s)) (zip arg_val_numL arg_valL);
1128   val arg_val_subst = append arg_val_subst1 arg_val_subst2;
1129
1130   val preCond2 = mk_holfoot_prop_input ws rs pre_t;
1131   val postCond2 = mk_holfoot_prop_input ws rs post_t;
1132
1133   val preCond3 = subst (append arg_val_subst arg_ref_subst) preCond2;
1134   val postCond3 = subst (append arg_val_subst arg_ref_subst) postCond2;
1135
1136
1137   val cond_free_var_list =
1138       let
1139          val set1 = HOLset.addList(empty_tmset, free_vars_restrict global_vars preCond3);
1140          val set2 = HOLset.addList(set1, free_vars_restrict global_vars postCond3);
1141          val set3 = HOLset.delete (set2, arg_ref_term) handle HOLset.NotFound => set2;
1142          val set4 = HOLset.delete (set3, arg_val_term) handle HOLset.NotFound => set3;
1143          val set5 = HOLset.delete (set4, fun_body_final_term) handle HOLset.NotFound => set4;
1144          val fv_list = HOLset.listItems set5;
1145       in
1146         fv_list
1147       end;
1148
1149   val ref_arg_names = listSyntax.mk_list (map string_to_label ref_args, markerSyntax.label_ty);
1150   val val_args_const = map (fn s => s ^ "_const") val_args;
1151   val val_arg_names = listSyntax.mk_list (map string_to_label val_args_const, markerSyntax.label_ty);
1152
1153   val wrapped_preCond = list_mk_icomb (asl_procedure_call_preserve_names_wrapper_term,
1154      [ref_arg_names, val_arg_names,
1155       pairLib.mk_pabs (pairLib.mk_pair(arg_ref_term, arg_val_term), preCond3),
1156       pairLib.mk_pair(arg_ref_term, arg_val_term)]);
1157
1158   val abstr_prog =
1159       list_mk_icomb (holfoot_prog_quant_best_local_action_term, [mk_list_pabs cond_free_var_list wrapped_preCond, mk_list_pabs cond_free_var_list postCond3])
1160   val abstr_prog_val_args_term = pairLib.mk_pabs (pairLib.mk_pair(arg_ref_term, arg_val_term), abstr_prog);
1161
1162   (*access to global variables*)
1163   val global_vars = Redblackset.listItems (Redblackset.difference (Redblackset.union (ws, rs),
1164      string_list2set (ref_args @ val_args @ localV)))
1165in
1166   (assume_opt, funname, fun_term, abstr_prog_val_args_term, global_vars)
1167end;
1168
1169
1170fun Pfundecl_list2hol global_vars res_varL fun_decl_list =
1171let
1172   fun initPfundecl (Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt, localV,
1173   fun_body, postCondOpt)) =
1174      (funname, ((map (K false) ref_args), []:string list, []:string list))
1175   val init_funL = map initPfundecl fun_decl_list;
1176   val emp_s = Redblackset.empty String.compare
1177   val init = map (fn p => (init_funL, (emp_s,emp_s), p)) fun_decl_list
1178
1179   fun internal l =
1180   let
1181      val l' = map (Pfundecl_preprocess res_varL global_vars) l;
1182      val changed = exists (#1) l';
1183   in
1184      if changed then
1185         let
1186           fun iter_funL (changed, funname, pre_a, fun_body_a, post_a, ws', rs', vs2, pL2, rpe2, wpe2) =
1187               (funname, (pL2, rpe2, wpe2))
1188           val funL' = map iter_funL l';
1189           fun iter_fin (p, (changed, funname, pre_a, fun_body_a, post_a, ws', rs', vs2, pL2, rpe2, wpe2)) =
1190               (funL', vs2, p)
1191           val l'' = map iter_fin (zip fun_decl_list l')
1192         in
1193           internal l''
1194         end
1195      else
1196        let
1197           fun fin (changed, funname, pre_a, fun_body_a, post_a, ws', rs', vs2, pL2, rpe2, wpe2) =
1198               (funname, pre_a, fun_body_a, post_a, ws', rs')
1199        in
1200           map fin l'
1201        end
1202   end;
1203
1204   fun extract (Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt, localV,
1205      fun_body, postCondOpt), (funname2, pre_a, fun_body_a, post_a, ws, rs)) =
1206      let
1207         val tp = absyn2term (Absyn.list_mk_pair [pre_a, fun_body_a, post_a]);
1208         val tL = pairSyntax.strip_pair tp;
1209         val pre_t = el 1 tL
1210         val fun_body_t = el 2 tL
1211         val post_t = el 3 tL
1212      in
1213      (funname, assume_opt, ref_args, val_args, localV, global_vars,
1214       pre_t, fun_body_t, post_t, ws, rs)
1215      end;
1216
1217   val finalL = map extract (zip fun_decl_list (internal init))
1218
1219in
1220   map Pfundecl2hol_final finalL
1221end;
1222
1223
1224
1225fun add_init_spec init_post_prop (Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt, localV,
1226   fun_body, postCondOpt)) =
1227   if (not (funname = "init")) then
1228      Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt, localV,
1229          fun_body, postCondOpt) (*unchanged*)
1230   else
1231      let
1232         val _ = if isSome preCondOpt orelse isSome postCondOpt orelse
1233                    isSome rwOpt orelse
1234                    not (ref_args = []) orelse not (val_args = []) then
1235                    raise holfoot_unsupported_feature_exn ("init function must not have parameters or pre- / postconditions") else ();
1236         val preCondOpt' = SOME (Aprop_spred Aspred_empty)
1237         val postCondOpt' = SOME init_post_prop
1238      in
1239         Pfundecl(assume_opt, funname, (ref_args, val_args), rwOpt, preCondOpt', localV,
1240             fun_body, postCondOpt')
1241      end;
1242
1243
1244(*
1245
1246val (funname, (ref_args, write_var_set, read_var_set, local_var_set,
1247        funcalls, done_funcalls),
1248        (fun_body_term, val_args, localV, preCond, postCond)) =
1249 hd fun_decl_parse_read_writeL3;
1250*)
1251
1252
1253
1254fun p_item___is_fun_decl (Pfundecl _) = true |
1255     p_item___is_fun_decl _ = false;
1256
1257
1258fun p_item___is_resource (Presource _) = true |
1259     p_item___is_resource _ = false;
1260
1261(*
1262val examplesDir = Globals.HOLDIR  ^ "/examples/separationLogic/src/holfoot/EXAMPLES/";
1263val file = examplesDir ^ "mem.sf" ;
1264
1265
1266val examplesDir = Globals.HOLDIR  ^ "/examples/separationLogic/src/holfoot/EXAMPLES/";
1267val file = examplesDir ^ "/automatic/entailments.ent" ;
1268
1269val prog2 = parse file
1270val t = parse_holfoot_file file
1271
1272
1273fun dest_Pprogram (Pprogram (ident_decl, program_item_decl)) =
1274   (ident_decl, program_item_decl);
1275
1276val (ident_decl, program_item_decl) = dest_Pprogram prog2;
1277
1278val Pentailments ((comment, p1, p2)::_) = prog2
1279*)
1280
1281fun find_duplicates [] = []
1282  | find_duplicates (x::xs) =
1283    let
1284       val (xL,xs') = partition (fn y => (x = y)) xs;
1285       val dL = find_duplicates xs';
1286    in
1287       if null xL then dL else ((hd xL)::dL)
1288    end;
1289
1290
1291fun Pprogram2hol procL_opt (Pprogram (ident_decl, global_decl, program_item_decl)) =
1292   let
1293      (*ignore ident_decl*)
1294
1295      (*parse resources*)
1296      val resource_list = filter p_item___is_resource program_item_decl;
1297      val resource_names = map (fn Presource (name,_,_) => name) resource_list;
1298      val resource_names_dL = find_duplicates resource_names;
1299      val _ = if null resource_names_dL then () else
1300              (AssembleHolfootParser.print_parse_error (String.concat (
1301                  "Multiple resource definition found for:\n"::
1302                   (map (fn n => (" - '"^n^"'\n")) resource_names_dL)));Feedback.fail ());
1303
1304      val emp_s = (Redblackset.empty String.compare);
1305      val resource_parseL = map (Presource2hol (emp_s, emp_s)) resource_list;
1306      val resource_parse_termL = map (fn (name, (prop, vars)) =>
1307          let
1308             val name_term = stringLib.fromMLstring name;
1309             val varL = listSyntax.mk_list (vars, Type `:holfoot_var`);
1310          in
1311             pairLib.mk_pair(name_term, pairLib.mk_pair(varL, prop))
1312          end) resource_parseL
1313      val resource_parseL_term = listSyntax.mk_list (resource_parse_termL,
1314                         Type `:string # holfoot_var list # holfoot_a_proposition`);
1315      val resource_term = mk_comb (HOLFOOT_LOCK_ENV_MAP_term, resource_parseL_term);
1316
1317
1318      (*parse procedure specs*)
1319      val fun_decl_list = filter p_item___is_fun_decl program_item_decl;
1320      val fun_names = map (fn Pfundecl (_,name,_,_,_,_,_,_) => name) fun_decl_list;
1321      val fun_names_dL = find_duplicates fun_names;
1322      val _ = if null fun_names_dL then () else
1323              (AssembleHolfootParser.print_parse_error (String.concat (
1324                  "Multiple procedure definition found for:\n"::
1325                   (map (fn n => (" - '"^n^"'\n")) fun_names_dL)));Feedback.fail ());
1326
1327      val res_varL = map (fn Presource (n, vL, _) => (n, vL)) resource_list;
1328      val res_propL = map (fn Presource (_, _, p) => p) resource_list;
1329      val init_post_prop = if null res_propL then Aprop_spred Aspred_empty else
1330             (end_itlist (curry Aprop_star) res_propL)
1331      val fun_decl_list_init = map (add_init_spec init_post_prop) fun_decl_list
1332      val global_vars = string_list2set global_decl;
1333      val fun_decl_parseL = Pfundecl_list2hol global_vars res_varL fun_decl_list_init
1334
1335      fun assume_proc_spec assume_opt proc =
1336         if (not assume_opt) then F else
1337         if (not (isSome procL_opt)) then T else
1338         if (mem proc (valOf procL_opt)) then T else F;
1339
1340      fun mk_pair_terms (assume_opt, s, fun_body, spec, _) =
1341         pairLib.list_mk_pair [assume_proc_spec assume_opt s, stringLib.fromMLstring s, fun_body, spec];
1342      val fun_decl_parse_pairL = map mk_pair_terms fun_decl_parseL;
1343
1344      val input = listSyntax.mk_list (fun_decl_parse_pairL, type_of (hd fun_decl_parse_pairL));
1345
1346
1347      (* check for problems with variables protected by locks being used *)
1348      fun check_vars (_, fname, _, _, gvs) (Presource (rname, rvs, _)) =
1349         let
1350            val il = Lib.intersect gvs rvs;
1351         in
1352            if null il orelse (fname = "init") then NONE else SOME (fname, rname, il)
1353         end;
1354      val error_list = map valOf (filter isSome (flatten (map (fn fd => map (check_vars fd) resource_list) fun_decl_parseL)));
1355      val _ = if null error_list then () else
1356              let
1357                  fun error_report (fname, rname, vl) =
1358                    String.concat ["The function '", fname, "' accesses the variables [",
1359                    String.concat (Lib.commafy vl), "] which are protected by resource '", rname, "'!\n"];
1360              in
1361                 (AssembleHolfootParser.print_parse_error (String.concat (
1362                     map error_report error_list));Feedback.fail ())
1363              end;
1364   in
1365      (list_mk_icomb (HOLFOOT_SPECIFICATION_term, [resource_term, input]))
1366   end;
1367
1368
1369fun mk_entailment (comment, p1, p2) =
1370let
1371   val empty_vs = (Redblackset.empty String.compare, Redblackset.empty String.compare);
1372   val (_, a1) = holfoot_a_proposition2absyn empty_vs NONE p1
1373   val (_, a2) = holfoot_a_proposition2absyn empty_vs NONE p2
1374   val (write_var_set, read_var_set) = get_read_write_var_set [] NONE [] [a1, a2]
1375   val varL = Redblackset.listItems (Redblackset.union (write_var_set, read_var_set))
1376   val var_tL = map string2holfoot_var varL
1377   val r_bag = bagSyntax.mk_bag (var_tL, holfoot_var_ty);
1378   val w_bag = bagSyntax.mk_bag ([], holfoot_var_ty);
1379   val bag_t = pairSyntax.mk_pair (w_bag, r_bag)
1380
1381   val sr_t = pairSyntax.mk_pair (F, optionSyntax.mk_some
1382        (listSyntax.mk_list ([string_to_label comment], markerSyntax.label_ty)))
1383
1384   val a12_t = absyn2term (Absyn.mk_pair (a1, a2));
1385   val b1 = bagSyntax.mk_bag (strip_asl_star (rand (rator a12_t)),
1386         holfoot_a_proposition_ty)
1387   val b2 = bagSyntax.mk_bag (strip_asl_star (rand a12_t), holfoot_a_proposition_ty);
1388
1389   val t0 = list_mk_comb (HOLFOOT_VAR_RES_FRAME_SPLIT_term, [sr_t, bag_t]);
1390   val t1 = mk_comb (t0, inst [alpha |-> holfoot_var_ty] bagSyntax.EMPTY_BAG_tm)
1391   val t2 = mk_comb (t1, inst [alpha |-> holfoot_a_proposition_ty] bagSyntax.EMPTY_BAG_tm)
1392   val t3 = list_mk_comb (t2, [b1,b2, HOLFOOT_VAR_RES_FRAME_SPLIT___EMP_PRED_term]);
1393in
1394   t3
1395end;
1396
1397
1398fun Pentailments2hol res_opt (Pentailments eL) =
1399   let
1400      val eL' = if isSome (res_opt) then
1401             filter (fn (c, p1, p2) => mem c (valOf res_opt)) eL else eL
1402      val tL = List.map mk_entailment eL'
1403   in
1404      (boolSyntax.list_mk_conj tL)
1405   end;
1406
1407fun Ptop2hol res_opt (Pentailments x) =
1408    Pentailments2hol res_opt (Pentailments x)
1409  | Ptop2hol res_opt (Pprogram x) =
1410    Pprogram2hol res_opt (Pprogram x);
1411
1412val parse_holfoot_file = (Ptop2hol NONE) o parse;
1413fun parse_holfoot_file_restrict procL = (Ptop2hol (SOME procL)) o parse;
1414
1415
1416
1417fun print_file_contents file =
1418   let
1419      val is = Portable.open_in file
1420      val _ = print ("\nContents of file \""^file^"\":\n\n");
1421      val _ = print "--------------------------------------------\n";
1422      val _ = while (not (Portable.end_of_stream is)) do
1423        (print (Portable.input_line is));
1424      val _ = Portable.close_in is;
1425      val _ = print "--------------------------------------------\n\n";
1426   in
1427      ()
1428   end
1429
1430end
1431