Release coccinelle-0.2.4
[bpt/coccinelle.git] / engine / asttoctl2.ml
CommitLineData
9bc82bae
C
1(*
2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
7 *
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
11 *
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
c491d8ee
C
25(*
26 * Copyright 2010, INRIA, University of Copenhagen
27 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
28 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
29 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
30 * This file is part of Coccinelle.
31 *
32 * Coccinelle is free software: you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation, according to version 2 of the License.
35 *
36 * Coccinelle is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
40 *
41 * You should have received a copy of the GNU General Public License
42 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
43 *
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
46 *)
47
48
34e49164
C
49(* for MINUS and CONTEXT, pos is always None in this file *)
50(*search for require*)
51(* true = don't see all matched nodes, only modified ones *)
52let onlyModif = ref true(*false*)
53
978fd7e5 54type ex = Exists | Forall
34e49164
C
55let exists = ref Forall
56
57module Ast = Ast_cocci
58module V = Visitor_ast
59module CTL = Ast_ctl
60
61let warning s = Printf.fprintf stderr "warning: %s\n" s
62
63type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif
64type formula =
65 (cocci_predicate,Ast.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl
66
67let union = Common.union_set
68let intersect l1 l2 = List.filter (function x -> List.mem x l2) l1
69let subset l1 l2 = List.for_all (function x -> List.mem x l2) l1
70
71let foldl1 f xs = List.fold_left f (List.hd xs) (List.tl xs)
72let foldr1 f xs =
73 let xs = List.rev xs in List.fold_left f (List.hd xs) (List.tl xs)
74
75let used_after = ref ([] : Ast.meta_name list)
76let guard_to_strict guard = if guard then CTL.NONSTRICT else CTL.STRICT
77
78let saved = ref ([] : Ast.meta_name list)
79
80let string2var x = ("",x)
81
82(* --------------------------------------------------------------------- *)
83(* predicates matching various nodes in the graph *)
84
85let ctl_and s x y =
86 match (x,y) with
87 (CTL.False,_) | (_,CTL.False) -> CTL.False
88 | (CTL.True,a) | (a,CTL.True) -> a
89 | _ -> CTL.And(s,x,y)
90
91let ctl_or x y =
92 match (x,y) with
93 (CTL.True,_) | (_,CTL.True) -> CTL.True
94 | (CTL.False,a) | (a,CTL.False) -> a
95 | _ -> CTL.Or(x,y)
96
97let ctl_or_fl x y =
98 match (x,y) with
99 (CTL.True,_) | (_,CTL.True) -> CTL.True
100 | (CTL.False,a) | (a,CTL.False) -> a
101 | _ -> CTL.Or(y,x)
102
103let ctl_seqor x y =
104 match (x,y) with
105 (CTL.True,_) | (_,CTL.True) -> CTL.True
106 | (CTL.False,a) | (a,CTL.False) -> a
107 | _ -> CTL.SeqOr(x,y)
108
109let ctl_not = function
110 CTL.True -> CTL.False
111 | CTL.False -> CTL.True
112 | x -> CTL.Not(x)
113
114let ctl_ax s = function
115 CTL.True -> CTL.True
116 | CTL.False -> CTL.False
117 | x ->
118 match !exists with
119 Exists -> CTL.EX(CTL.FORWARD,x)
120 | Forall -> CTL.AX(CTL.FORWARD,s,x)
34e49164
C
121
122let ctl_ax_absolute s = function
123 CTL.True -> CTL.True
124 | CTL.False -> CTL.False
125 | x -> CTL.AX(CTL.FORWARD,s,x)
126
127let ctl_ex = function
128 CTL.True -> CTL.True
129 | CTL.False -> CTL.False
130 | x -> CTL.EX(CTL.FORWARD,x)
131
132(* This stays being AX even for sgrep_mode, because it is used to identify
133the structure of the term, not matching the pattern. *)
134let ctl_back_ax = function
135 CTL.True -> CTL.True
136 | CTL.False -> CTL.False
137 | x -> CTL.AX(CTL.BACKWARD,CTL.NONSTRICT,x)
138
139let ctl_back_ex = function
140 CTL.True -> CTL.True
141 | CTL.False -> CTL.False
142 | x -> CTL.EX(CTL.BACKWARD,x)
143
144let ctl_ef = function
145 CTL.True -> CTL.True
146 | CTL.False -> CTL.False
147 | x -> CTL.EF(CTL.FORWARD,x)
148
149let ctl_ag s = function
150 CTL.True -> CTL.True
151 | CTL.False -> CTL.False
152 | x -> CTL.AG(CTL.FORWARD,s,x)
153
154let ctl_au s x y =
155 match (x,!exists) with
156 (CTL.True,Exists) -> CTL.EF(CTL.FORWARD,y)
157 | (CTL.True,Forall) -> CTL.AF(CTL.FORWARD,s,y)
34e49164
C
158 | (_,Exists) -> CTL.EU(CTL.FORWARD,x,y)
159 | (_,Forall) -> CTL.AU(CTL.FORWARD,s,x,y)
34e49164
C
160
161let ctl_anti_au s x y = (* only for ..., where the quantifier is changed *)
162 CTL.XX
163 (match (x,!exists) with
164 (CTL.True,Exists) -> CTL.AF(CTL.FORWARD,s,y)
165 | (CTL.True,Forall) -> CTL.EF(CTL.FORWARD,y)
34e49164 166 | (_,Exists) -> CTL.AU(CTL.FORWARD,s,x,y)
978fd7e5 167 | (_,Forall) -> CTL.EU(CTL.FORWARD,x,y))
34e49164
C
168
169let ctl_uncheck = function
170 CTL.True -> CTL.True
171 | CTL.False -> CTL.False
172 | x -> CTL.Uncheck x
173
174let label_pred_maker = function
175 None -> CTL.True
176 | Some (label_var,used) ->
177 used := true;
178 CTL.Pred(Lib_engine.PrefixLabel(label_var),CTL.Control)
179
180let bclabel_pred_maker = function
181 None -> CTL.True
182 | Some (label_var,used) ->
183 used := true;
184 CTL.Pred(Lib_engine.BCLabel(label_var),CTL.Control)
185
fc1ad971
C
186(* label used to be used here, but it is not used; label is only needed after
187and within dots *)
188let predmaker guard pred label = CTL.Pred pred
34e49164
C
189
190let aftpred = predmaker false (Lib_engine.After, CTL.Control)
191let retpred = predmaker false (Lib_engine.Return, CTL.Control)
192let funpred = predmaker false (Lib_engine.FunHeader, CTL.Control)
193let toppred = predmaker false (Lib_engine.Top, CTL.Control)
194let exitpred = predmaker false (Lib_engine.ErrorExit, CTL.Control)
195let endpred = predmaker false (Lib_engine.Exit, CTL.Control)
196let gotopred = predmaker false (Lib_engine.Goto, CTL.Control)
197let inlooppred = predmaker false (Lib_engine.InLoop, CTL.Control)
198let truepred = predmaker false (Lib_engine.TrueBranch, CTL.Control)
199let falsepred = predmaker false (Lib_engine.FalseBranch, CTL.Control)
200let fallpred = predmaker false (Lib_engine.FallThrough, CTL.Control)
951c7801 201let loopfallpred = predmaker false (Lib_engine.LoopFallThrough, CTL.Control)
34e49164 202
951c7801
C
203(*let aftret label_var =
204 ctl_or (aftpred label_var)
205 (ctl_or (loopfallpred label_var) (exitpred label_var))*)
34e49164
C
206
207let letctr = ref 0
208let get_let_ctr _ =
209 let cur = !letctr in
210 letctr := cur + 1;
211 Printf.sprintf "r%d" cur
212
213(* --------------------------------------------------------------------- *)
214(* --------------------------------------------------------------------- *)
215(* Eliminate OptStm *)
216
217(* for optional thing with nothing after, should check that the optional thing
218never occurs. otherwise the matching stops before it occurs *)
219let elim_opt =
220 let mcode x = x in
221 let donothing r k e = k e in
222
223 let fvlist l =
224 List.fold_left Common.union_set [] (List.map Ast.get_fvs l) in
225
226 let mfvlist l =
227 List.fold_left Common.union_set [] (List.map Ast.get_mfvs l) in
228
229 let freshlist l =
230 List.fold_left Common.union_set [] (List.map Ast.get_fresh l) in
231
232 let inheritedlist l =
233 List.fold_left Common.union_set [] (List.map Ast.get_inherited l) in
234
235 let savedlist l =
236 List.fold_left Common.union_set [] (List.map Ast.get_saved l) in
237
238 let varlists l =
239 (fvlist l, mfvlist l, freshlist l, inheritedlist l, savedlist l) in
240
241 let rec dots_list unwrapped wrapped =
242 match (unwrapped,wrapped) with
243 ([],_) -> []
244
245 | (Ast.Dots(_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest,
246 d0::s::d1::rest)
5636bb2c
C
247 | (Ast.Nest(_,_,_,_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)
248 ::urest,
951c7801 249 d0::s::d1::rest) -> (* why no case for nest as u? *)
34e49164
C
250 let l = Ast.get_line stm in
251 let new_rest1 = stm :: (dots_list (u::urest) (d1::rest)) in
252 let new_rest2 = dots_list urest rest in
253 let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) =
254 varlists new_rest1 in
255 let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) =
256 varlists new_rest2 in
257 [d0;
258 {(Ast.make_term
259 (Ast.Disj
260 [{(Ast.make_term(Ast.DOTS(new_rest1))) with
261 Ast.node_line = l;
262 Ast.free_vars = fv_rest1;
263 Ast.minus_free_vars = mfv_rest1;
264 Ast.fresh_vars = fresh_rest1;
265 Ast.inherited = inherited_rest1;
266 Ast.saved_witness = s1};
267 {(Ast.make_term(Ast.DOTS(new_rest2))) with
268 Ast.node_line = l;
269 Ast.free_vars = fv_rest2;
270 Ast.minus_free_vars = mfv_rest2;
271 Ast.fresh_vars = fresh_rest2;
272 Ast.inherited = inherited_rest2;
273 Ast.saved_witness = s2}])) with
274 Ast.node_line = l;
275 Ast.free_vars = fv_rest1;
276 Ast.minus_free_vars = mfv_rest1;
277 Ast.fresh_vars = fresh_rest1;
278 Ast.inherited = inherited_rest1;
279 Ast.saved_witness = s1}]
280
281 | (Ast.OptStm(stm)::urest,_::rest) ->
282 let l = Ast.get_line stm in
283 let new_rest1 = dots_list urest rest in
284 let new_rest2 = stm::new_rest1 in
285 let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) =
286 varlists new_rest1 in
287 let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) =
288 varlists new_rest2 in
289 [{(Ast.make_term
290 (Ast.Disj
291 [{(Ast.make_term(Ast.DOTS(new_rest2))) with
292 Ast.node_line = l;
293 Ast.free_vars = fv_rest2;
294 Ast.minus_free_vars = mfv_rest2;
295 Ast.fresh_vars = fresh_rest2;
296 Ast.inherited = inherited_rest2;
297 Ast.saved_witness = s2};
298 {(Ast.make_term(Ast.DOTS(new_rest1))) with
299 Ast.node_line = l;
300 Ast.free_vars = fv_rest1;
301 Ast.minus_free_vars = mfv_rest1;
302 Ast.fresh_vars = fresh_rest1;
303 Ast.inherited = inherited_rest1;
304 Ast.saved_witness = s1}])) with
305 Ast.node_line = l;
306 Ast.free_vars = fv_rest2;
307 Ast.minus_free_vars = mfv_rest2;
308 Ast.fresh_vars = fresh_rest2;
309 Ast.inherited = inherited_rest2;
310 Ast.saved_witness = s2}]
311
312 | ([Ast.Dots(_,_,_,_);Ast.OptStm(stm)],[d1;_]) ->
313 let l = Ast.get_line stm in
314 let fv_stm = Ast.get_fvs stm in
315 let mfv_stm = Ast.get_mfvs stm in
316 let fresh_stm = Ast.get_fresh stm in
317 let inh_stm = Ast.get_inherited stm in
318 let saved_stm = Ast.get_saved stm in
319 let fv_d1 = Ast.get_fvs d1 in
320 let mfv_d1 = Ast.get_mfvs d1 in
321 let fresh_d1 = Ast.get_fresh d1 in
322 let inh_d1 = Ast.get_inherited d1 in
323 let saved_d1 = Ast.get_saved d1 in
324 let fv_both = Common.union_set fv_stm fv_d1 in
325 let mfv_both = Common.union_set mfv_stm mfv_d1 in
326 let fresh_both = Common.union_set fresh_stm fresh_d1 in
327 let inh_both = Common.union_set inh_stm inh_d1 in
328 let saved_both = Common.union_set saved_stm saved_d1 in
329 [d1;
330 {(Ast.make_term
331 (Ast.Disj
332 [{(Ast.make_term(Ast.DOTS([stm]))) with
333 Ast.node_line = l;
334 Ast.free_vars = fv_stm;
335 Ast.minus_free_vars = mfv_stm;
336 Ast.fresh_vars = fresh_stm;
337 Ast.inherited = inh_stm;
338 Ast.saved_witness = saved_stm};
339 {(Ast.make_term(Ast.DOTS([d1]))) with
340 Ast.node_line = l;
341 Ast.free_vars = fv_d1;
342 Ast.minus_free_vars = mfv_d1;
343 Ast.fresh_vars = fresh_d1;
344 Ast.inherited = inh_d1;
345 Ast.saved_witness = saved_d1}])) with
346 Ast.node_line = l;
347 Ast.free_vars = fv_both;
348 Ast.minus_free_vars = mfv_both;
349 Ast.fresh_vars = fresh_both;
350 Ast.inherited = inh_both;
351 Ast.saved_witness = saved_both}]
352
5636bb2c 353 | ([Ast.Nest(_,_,_,_,_,_,_);Ast.OptStm(stm)],[d1;_]) ->
34e49164
C
354 let l = Ast.get_line stm in
355 let rw = Ast.rewrap stm in
356 let rwd = Ast.rewrap stm in
357 let dots = Ast.Dots(Ast.make_mcode "...",[],[],[]) in
358 [d1;rw(Ast.Disj
359 [rwd(Ast.DOTS([stm]));
360 {(Ast.make_term(Ast.DOTS([rw dots])))
361 with Ast.node_line = l}])]
362
363 | (_::urest,stm::rest) -> stm :: (dots_list urest rest)
364 | _ -> failwith "not possible" in
365
366 let stmtdotsfn r k d =
367 let d = k d in
368 Ast.rewrap d
369 (match Ast.unwrap d with
370 Ast.DOTS(l) -> Ast.DOTS(dots_list (List.map Ast.unwrap l) l)
371 | Ast.CIRCLES(l) -> failwith "elimopt: not supported"
372 | Ast.STARS(l) -> failwith "elimopt: not supported") in
ae4735db 373
34e49164
C
374 V.rebuilder
375 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
c491d8ee 376 donothing donothing stmtdotsfn donothing donothing
34e49164
C
377 donothing donothing donothing donothing donothing donothing donothing
378 donothing donothing donothing donothing donothing
379
380(* --------------------------------------------------------------------- *)
381(* after management *)
382(* We need Guard for the following case:
383<...
384 a
385 <...
386 b
387 ...>
388...>
389foo();
390
391Here the inner <... b ...> should not go past foo. But foo is not the
392"after" of the body of the outer nest, because we don't want to search for
393it in the case where the body of the outer nest ends in something other
394than dots or a nest. *)
395
396(* what is the difference between tail and end??? *)
397
398type after = After of formula | Guard of formula | Tail | End | VeryEnd
399
400let a2n = function After x -> Guard x | a -> a
401
402let print_ctl x =
403 let pp_pred (x,_) = Pretty_print_engine.pp_predicate x in
404 let pp_meta (_,x) = Common.pp x in
405 Pretty_print_ctl.pp_ctl (pp_pred,pp_meta) false x;
406 Format.print_newline()
407
408let print_after = function
409 After ctl -> Printf.printf "After:\n"; print_ctl ctl
410 | Guard ctl -> Printf.printf "Guard:\n"; print_ctl ctl
411 | Tail -> Printf.printf "Tail\n"
412 | VeryEnd -> Printf.printf "Very End\n"
413 | End -> Printf.printf "End\n"
414
415(* --------------------------------------------------------------------- *)
416(* Top-level code *)
417
418let fresh_var _ = string2var "_v"
419let fresh_pos _ = string2var "_pos" (* must be a constant *)
420
421let fresh_metavar _ = "_S"
422
423(* fvinfo is going to end up being from the whole associated statement.
424 it would be better if it were just the free variables in d, but free_vars.ml
425 doesn't keep track of free variables on + code *)
426let make_meta_rule_elem d fvinfo =
427 let nm = fresh_metavar() in
428 Ast.make_meta_rule_elem nm d fvinfo
429
430let get_unquantified quantified vars =
431 List.filter (function x -> not (List.mem x quantified)) vars
432
433let make_seq guard l =
434 let s = guard_to_strict guard in
435 foldr1 (function rest -> function cur -> ctl_and s cur (ctl_ax s rest)) l
436
437let make_seq_after2 guard first rest =
438 let s = guard_to_strict guard in
439 match rest with
440 After rest -> ctl_and s first (ctl_ax s (ctl_ax s rest))
441 | _ -> first
442
443let make_seq_after guard first rest =
444 match rest with
445 After rest -> make_seq guard [first;rest]
446 | _ -> first
447
448let opt_and guard first rest =
449 let s = guard_to_strict guard in
450 match first with
451 None -> rest
452 | Some first -> ctl_and s first rest
453
454let and_after guard first rest =
455 let s = guard_to_strict guard in
456 match rest with After rest -> ctl_and s first rest | _ -> first
457
458let contains_modif =
459 let bind x y = x or y in
460 let option_default = false in
91eba41f 461 let mcode r (_,_,kind,metapos) =
34e49164 462 match kind with
708f4980 463 Ast.MINUS(_,_,_,_) -> true
951c7801 464 | Ast.PLUS _ -> failwith "not possible"
34e49164
C
465 | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in
466 let do_nothing r k e = k e in
467 let rule_elem r k re =
468 let res = k re in
469 match Ast.unwrap re with
470 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
471 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
472 | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
473 | _ -> res in
90aeb998
C
474 let init r k i =
475 let res = k i in
476 match Ast.unwrap i with
c491d8ee 477 Ast.StrInitList(allminus,_,_,_,_) -> allminus or res
90aeb998 478 | _ -> res in
34e49164
C
479 let recursor =
480 V.combiner bind option_default
481 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
c491d8ee 482 do_nothing do_nothing do_nothing do_nothing do_nothing
90aeb998 483 do_nothing do_nothing do_nothing do_nothing init do_nothing
34e49164
C
484 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
485 recursor.V.combiner_rule_elem
486
91eba41f
C
487let contains_pos =
488 let bind x y = x or y in
489 let option_default = false in
490 let mcode r (_,_,kind,metapos) =
491 match metapos with
492 Ast.MetaPos(_,_,_,_,_) -> true
493 | Ast.NoMetaPos -> false in
494 let do_nothing r k e = k e in
495 let rule_elem r k re =
496 let res = k re in
497 match Ast.unwrap re with
498 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
499 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
500 | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
501 | _ -> res in
502 let recursor =
503 V.combiner bind option_default
504 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
c491d8ee 505 do_nothing do_nothing do_nothing do_nothing do_nothing
91eba41f
C
506 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
507 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
508 recursor.V.combiner_rule_elem
509
34e49164
C
510(* code is not a DisjRuleElem *)
511let make_match label guard code =
512 let v = fresh_var() in
513 let matcher = Lib_engine.Match(code) in
514 if contains_modif code && not guard
515 then CTL.Exists(true,v,predmaker guard (matcher,CTL.Modif v) label)
516 else
517 let iso_info = !Flag.track_iso_usage && not (Ast.get_isos code = []) in
518 (match (iso_info,!onlyModif,guard,
519 intersect !used_after (Ast.get_fvs code)) with
520 (false,true,_,[]) | (_,_,true,_) ->
521 predmaker guard (matcher,CTL.Control) label
522 | _ -> CTL.Exists(true,v,predmaker guard (matcher,CTL.UnModif v) label))
523
524let make_raw_match label guard code =
413ffc02
C
525 match intersect !used_after (Ast.get_fvs code) with
526 [] -> predmaker guard (Lib_engine.Match(code),CTL.Control) label
527 | _ ->
528 let v = fresh_var() in
529 CTL.Exists(true,v,predmaker guard (Lib_engine.Match(code),CTL.UnModif v)
530 label)
ae4735db 531
34e49164
C
532let rec seq_fvs quantified = function
533 [] -> []
534 | fv1::fvs ->
535 let t1fvs = get_unquantified quantified fv1 in
536 let termfvs =
537 List.fold_left Common.union_set []
538 (List.map (get_unquantified quantified) fvs) in
539 let bothfvs = Common.inter_set t1fvs termfvs in
540 let t1onlyfvs = Common.minus_set t1fvs bothfvs in
541 let new_quantified = Common.union_set bothfvs quantified in
542 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs)
543
544let quantify guard =
545 List.fold_right
546 (function cur ->
547 function code -> CTL.Exists (not guard && List.mem cur !saved,cur,code))
548
549let non_saved_quantify =
550 List.fold_right
551 (function cur -> function code -> CTL.Exists (false,cur,code))
552
553let intersectll lst nested_list =
554 List.filter (function x -> List.exists (List.mem x) nested_list) lst
555
556(* --------------------------------------------------------------------- *)
557(* Count depth of braces. The translation of a closed brace appears deeply
558nested within the translation of the sequence term, so the name of the
559paren var has to take into account the names of the nested braces. On the
560other hand the close brace does not escape, so we don't have to take into
561account other paren variable names. *)
562
563(* called repetitively, which is inefficient, but less trouble than adding a
564new field to Seq and FunDecl *)
565let count_nested_braces s =
566 let bind x y = max x y in
567 let option_default = 0 in
568 let stmt_count r k s =
569 match Ast.unwrap s with
708f4980 570 Ast.Seq(_,_,_) | Ast.FunDecl(_,_,_,_) -> (k s) + 1
34e49164
C
571 | _ -> k s in
572 let donothing r k e = k e in
573 let mcode r x = 0 in
574 let recursor = V.combiner bind option_default
575 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
c491d8ee 576 donothing donothing donothing donothing donothing
34e49164
C
577 donothing donothing donothing donothing donothing donothing
578 donothing donothing stmt_count donothing donothing donothing in
579 let res = string_of_int (recursor.V.combiner_statement s) in
580 string2var ("p"^res)
581
582let labelctr = ref 0
583let get_label_ctr _ =
584 let cur = !labelctr in
585 labelctr := cur + 1;
586 string2var (Printf.sprintf "l%d" cur)
587
588(* --------------------------------------------------------------------- *)
589(* annotate dots with before and after neighbors *)
590
591let print_bef_aft = function
592 Ast.WParen (re,n) ->
593 Printf.printf "bef/aft\n";
594 Pretty_print_cocci.rule_elem "" re;
595 Format.print_newline()
596 | Ast.Other s ->
597 Printf.printf "bef/aft\n";
598 Pretty_print_cocci.statement "" s;
599 Format.print_newline()
600 | Ast.Other_dots d ->
601 Printf.printf "bef/aft\n";
602 Pretty_print_cocci.statement_dots d;
603 Format.print_newline()
604
605(* [] can only occur if we are in a disj, where it comes from a ? In that
606case, we want to use a, which accumulates all of the previous patterns in
607their entirety. *)
608let rec get_before_elem sl a =
609 match Ast.unwrap sl with
610 Ast.DOTS(x) ->
611 let rec loop sl a =
612 match sl with
613 [] -> ([],Common.Right a)
614 | [e] ->
615 let (e,ea) = get_before_e e a in
616 ([e],Common.Left ea)
617 | e::sl ->
618 let (e,ea) = get_before_e e a in
619 let (sl,sla) = loop sl ea in
620 (e::sl,sla) in
621 let (l,a) = loop x a in
622 (Ast.rewrap sl (Ast.DOTS(l)),a)
623 | Ast.CIRCLES(x) -> failwith "not supported"
624 | Ast.STARS(x) -> failwith "not supported"
625
626and get_before sl a =
627 match get_before_elem sl a with
628 (term,Common.Left x) -> (term,x)
629 | (term,Common.Right x) -> (term,x)
630
631and get_before_whencode wc =
632 List.map
633 (function
634 Ast.WhenNot w -> let (w,_) = get_before w [] in Ast.WhenNot w
635 | Ast.WhenAlways w -> let (w,_) = get_before_e w [] in Ast.WhenAlways w
1be43e12
C
636 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
637 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
638 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
34e49164
C
639 wc
640
641and get_before_e s a =
642 match Ast.unwrap s with
643 Ast.Dots(d,w,_,aft) ->
644 (Ast.rewrap s (Ast.Dots(d,get_before_whencode w,a,aft)),a)
5636bb2c 645 | Ast.Nest(starter,stmt_dots,ender,w,multi,_,aft) ->
34e49164
C
646 let w = get_before_whencode w in
647 let (sd,_) = get_before stmt_dots a in
978fd7e5
C
648 (*let a =
649 got rid of this, don't want to let nests overshoot
34e49164
C
650 List.filter
651 (function
652 Ast.Other a ->
653 let unifies =
654 Unify_ast.unify_statement_dots
655 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
656 (match unifies with
657 Unify_ast.MAYBE -> false
658 | _ -> true)
659 | Ast.Other_dots a ->
660 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
661 (match unifies with
662 Unify_ast.MAYBE -> false
663 | _ -> true)
664 | _ -> true)
978fd7e5 665 a in*)
5636bb2c
C
666 (Ast.rewrap s (Ast.Nest(starter,sd,ender,w,multi,a,aft)),
667 [Ast.Other_dots stmt_dots])
34e49164
C
668 | Ast.Disj(stmt_dots_list) ->
669 let (dsl,dsla) =
670 List.split (List.map (function e -> get_before e a) stmt_dots_list) in
671 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
672 | Ast.Atomic(ast) ->
673 (match Ast.unwrap ast with
674 Ast.MetaStmt(_,_,_,_) -> (s,[])
675 | _ -> (s,[Ast.Other s]))
708f4980 676 | Ast.Seq(lbrace,body,rbrace) ->
34e49164 677 let index = count_nested_braces s in
708f4980
C
678 let (bd,_) = get_before body [Ast.WParen(lbrace,index)] in
679 (Ast.rewrap s (Ast.Seq(lbrace,bd,rbrace)),[Ast.WParen(rbrace,index)])
34e49164
C
680 | Ast.Define(header,body) ->
681 let (body,_) = get_before body [] in
682 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
683 | Ast.IfThen(ifheader,branch,aft) ->
684 let (br,_) = get_before_e branch [] in
685 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)), [Ast.Other s])
686 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
687 let (br1,_) = get_before_e branch1 [] in
688 let (br2,_) = get_before_e branch2 [] in
689 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
690 | Ast.While(header,body,aft) ->
691 let (bd,_) = get_before_e body [] in
692 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
693 | Ast.For(header,body,aft) ->
694 let (bd,_) = get_before_e body [] in
695 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
696 | Ast.Do(header,body,tail) ->
697 let (bd,_) = get_before_e body [] in
698 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
699 | Ast.Iterator(header,body,aft) ->
700 let (bd,_) = get_before_e body [] in
701 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
fc1ad971
C
702 | Ast.Switch(header,lb,decls,cases,rb) ->
703 let index = count_nested_braces s in
704 let (de,dea) = get_before decls [Ast.WParen(lb,index)] in
34e49164
C
705 let cases =
706 List.map
707 (function case_line ->
708 match Ast.unwrap case_line with
709 Ast.CaseLine(header,body) ->
710 let (body,_) = get_before body [] in
711 Ast.rewrap case_line (Ast.CaseLine(header,body))
712 | Ast.OptCase(case_line) -> failwith "not supported")
713 cases in
fc1ad971
C
714 (Ast.rewrap s (Ast.Switch(header,lb,de,cases,rb)),
715 [Ast.WParen(rb,index)])
708f4980
C
716 | Ast.FunDecl(header,lbrace,body,rbrace) ->
717 let (bd,_) = get_before body [] in
718 (Ast.rewrap s (Ast.FunDecl(header,lbrace,bd,rbrace)),[])
91eba41f
C
719 | _ ->
720 Pretty_print_cocci.statement "" s; Format.print_newline();
721 failwith "get_before_e: not supported"
34e49164
C
722
723let rec get_after sl a =
724 match Ast.unwrap sl with
725 Ast.DOTS(x) ->
726 let rec loop sl =
727 match sl with
728 [] -> ([],a)
729 | e::sl ->
730 let (sl,sla) = loop sl in
731 let (e,ea) = get_after_e e sla in
732 (e::sl,ea) in
733 let (l,a) = loop x in
734 (Ast.rewrap sl (Ast.DOTS(l)),a)
735 | Ast.CIRCLES(x) -> failwith "not supported"
736 | Ast.STARS(x) -> failwith "not supported"
737
738and get_after_whencode a wc =
739 List.map
740 (function
741 Ast.WhenNot w -> let (w,_) = get_after w a (*?*) in Ast.WhenNot w
742 | Ast.WhenAlways w -> let (w,_) = get_after_e w a in Ast.WhenAlways w
1be43e12
C
743 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
744 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
745 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
34e49164
C
746 wc
747
748and get_after_e s a =
749 match Ast.unwrap s with
750 Ast.Dots(d,w,bef,_) ->
751 (Ast.rewrap s (Ast.Dots(d,get_after_whencode a w,bef,a)),a)
5636bb2c 752 | Ast.Nest(starter,stmt_dots,ender,w,multi,bef,_) ->
34e49164
C
753 let w = get_after_whencode a w in
754 let (sd,_) = get_after stmt_dots a in
978fd7e5
C
755 (*let a =
756 got rid of this. don't want to let nests overshoot
34e49164
C
757 List.filter
758 (function
759 Ast.Other a ->
760 let unifies =
761 Unify_ast.unify_statement_dots
762 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
763 (match unifies with
764 Unify_ast.MAYBE -> false
765 | _ -> true)
766 | Ast.Other_dots a ->
767 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
768 (match unifies with
769 Unify_ast.MAYBE -> false
770 | _ -> true)
771 | _ -> true)
978fd7e5 772 a in*)
5636bb2c
C
773 (Ast.rewrap s (Ast.Nest(starter,sd,ender,w,multi,bef,a)),
774 [Ast.Other_dots stmt_dots])
34e49164
C
775 | Ast.Disj(stmt_dots_list) ->
776 let (dsl,dsla) =
777 List.split (List.map (function e -> get_after e a) stmt_dots_list) in
778 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
779 | Ast.Atomic(ast) ->
780 (match Ast.unwrap ast with
781 Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots _,i) ->
782 (* check "after" information for metavar optimization *)
783 (* if the error is not desired, could just return [], then
784 the optimization (check for EF) won't take place *)
785 List.iter
786 (function
787 Ast.Other x ->
788 (match Ast.unwrap x with
5636bb2c 789 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_,_,_) ->
34e49164
C
790 failwith
791 "dots/nest not allowed before and after stmt metavar"
792 | _ -> ())
793 | Ast.Other_dots x ->
794 (match Ast.undots x with
795 x::_ ->
796 (match Ast.unwrap x with
5636bb2c 797 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_,_,_) ->
34e49164
C
798 failwith
799 ("dots/nest not allowed before and after stmt "^
800 "metavar")
801 | _ -> ())
802 | _ -> ())
803 | _ -> ())
804 a;
805 (Ast.rewrap s
806 (Ast.Atomic
807 (Ast.rewrap s
808 (Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots a,i)))),[])
809 | Ast.MetaStmt(_,_,_,_) -> (s,[])
810 | _ -> (s,[Ast.Other s]))
708f4980 811 | Ast.Seq(lbrace,body,rbrace) ->
34e49164 812 let index = count_nested_braces s in
708f4980
C
813 let (bd,_) = get_after body [Ast.WParen(rbrace,index)] in
814 (Ast.rewrap s (Ast.Seq(lbrace,bd,rbrace)),
34e49164
C
815 [Ast.WParen(lbrace,index)])
816 | Ast.Define(header,body) ->
817 let (body,_) = get_after body a in
818 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
819 | Ast.IfThen(ifheader,branch,aft) ->
820 let (br,_) = get_after_e branch a in
821 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)),[Ast.Other s])
822 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
823 let (br1,_) = get_after_e branch1 a in
824 let (br2,_) = get_after_e branch2 a in
825 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
826 | Ast.While(header,body,aft) ->
827 let (bd,_) = get_after_e body a in
828 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
829 | Ast.For(header,body,aft) ->
830 let (bd,_) = get_after_e body a in
831 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
832 | Ast.Do(header,body,tail) ->
833 let (bd,_) = get_after_e body a in
834 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
835 | Ast.Iterator(header,body,aft) ->
836 let (bd,_) = get_after_e body a in
837 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
fc1ad971
C
838 | Ast.Switch(header,lb,decls,cases,rb) ->
839 let index = count_nested_braces s in
34e49164
C
840 let cases =
841 List.map
842 (function case_line ->
843 match Ast.unwrap case_line with
844 Ast.CaseLine(header,body) ->
fc1ad971 845 let (body,_) = get_after body [Ast.WParen(rb,index)] in
34e49164
C
846 Ast.rewrap case_line (Ast.CaseLine(header,body))
847 | Ast.OptCase(case_line) -> failwith "not supported")
848 cases in
fc1ad971
C
849 let (de,_) = get_after decls [] in
850 (Ast.rewrap s (Ast.Switch(header,lb,de,cases,rb)),[Ast.WParen(lb,index)])
708f4980
C
851 | Ast.FunDecl(header,lbrace,body,rbrace) ->
852 let (bd,_) = get_after body [] in
853 (Ast.rewrap s (Ast.FunDecl(header,lbrace,bd,rbrace)),[])
34e49164
C
854 | _ -> failwith "get_after_e: not supported"
855
856let preprocess_dots sl =
857 let (sl,_) = get_before sl [] in
858 let (sl,_) = get_after sl [] in
859 sl
860
861let preprocess_dots_e sl =
862 let (sl,_) = get_before_e sl [] in
863 let (sl,_) = get_after_e sl [] in
864 sl
865
866(* --------------------------------------------------------------------- *)
867(* various return_related things *)
868
869let rec ends_in_return stmt_list =
870 match Ast.unwrap stmt_list with
871 Ast.DOTS(x) ->
872 (match List.rev x with
873 x::_ ->
874 (match Ast.unwrap x with
875 Ast.Atomic(x) ->
1be43e12
C
876 let rec loop x =
877 match Ast.unwrap x with
878 Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) -> true
879 | Ast.DisjRuleElem((_::_) as l) -> List.for_all loop l
880 | _ -> false in
881 loop x
34e49164
C
882 | Ast.Disj(disjs) -> List.for_all ends_in_return disjs
883 | _ -> false)
884 | _ -> false)
885 | Ast.CIRCLES(x) -> failwith "not supported"
886 | Ast.STARS(x) -> failwith "not supported"
887
888(* --------------------------------------------------------------------- *)
889(* expressions *)
890
891let exptymatch l make_match make_guard_match =
892 let pos = fresh_pos() in
893 let matches_guard_matches =
894 List.map
895 (function x ->
896 let pos = Ast.make_mcode pos in
897 (make_match (Ast.set_pos x (Some pos)),
898 make_guard_match (Ast.set_pos x (Some pos))))
899 l in
900 let (matches,guard_matches) = List.split matches_guard_matches in
901 let rec suffixes = function
902 [] -> []
903 | x::xs -> xs::(suffixes xs) in
978fd7e5
C
904 let prefixes =
905 (* normally, we check that an expression does not match something
906 earlier in the disjunction (calculated as prefixes). But for large
907 disjunctions, this can result in a very big CTL formula. So we
908 give the user the option to say he doesn't want this feature, if that is
909 the case. *)
910 if !Flag_matcher.no_safe_expressions
911 then List.map (function _ -> []) matches
912 else List.rev (suffixes (List.rev guard_matches)) in
34e49164
C
913 let info = (* not null *)
914 List.map2
915 (function matcher ->
916 function negates ->
917 CTL.Exists
918 (false,pos,
919 ctl_and CTL.NONSTRICT matcher
920 (ctl_not
921 (ctl_uncheck (List.fold_left ctl_or_fl CTL.False negates)))))
922 matches prefixes in
923 CTL.InnerAnd(List.fold_left ctl_or_fl CTL.False (List.rev info))
924
925(* code might be a DisjRuleElem, in which case we break it apart
926 code might contain an Exp or Ty
927 this one pushes the quantifier inwards *)
928let do_re_matches label guard res quantified minus_quantified =
929 let make_guard_match x =
930 let stmt_fvs = Ast.get_mfvs x in
931 let fvs = get_unquantified minus_quantified stmt_fvs in
932 non_saved_quantify fvs (make_match None true x) in
933 let make_match x =
934 let stmt_fvs = Ast.get_fvs x in
935 let fvs = get_unquantified quantified stmt_fvs in
936 quantify guard fvs (make_match None guard x) in
fc1ad971 937(* label used to be used here, but it is not use; label is only needed after
ae4735db 938and within dots
fc1ad971 939 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
34e49164
C
940 (match List.map Ast.unwrap res with
941 [] -> failwith "unexpected empty disj"
942 | Ast.Exp(e)::rest -> exptymatch res make_match make_guard_match
943 | Ast.Ty(t)::rest -> exptymatch res make_match make_guard_match
944 | all ->
945 if List.exists (function Ast.Exp(_) | Ast.Ty(_) -> true | _ -> false)
946 all
947 then failwith "unexpected exp or ty";
978fd7e5 948 List.fold_left ctl_seqor CTL.False (List.map make_match res))
34e49164
C
949
950(* code might be a DisjRuleElem, in which case we break it apart
951 code doesn't contain an Exp or Ty
952 this one is for use when it is not practical to push the quantifier inwards
953 *)
954let header_match label guard code : ('a, Ast.meta_name, 'b) CTL.generic_ctl =
955 match Ast.unwrap code with
956 Ast.DisjRuleElem(res) ->
957 let make_match = make_match None guard in
958 let orop = if guard then ctl_or else ctl_seqor in
fc1ad971
C
959(* label used to be used here, but it is not use; label is only needed after
960and within dots
961 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
34e49164
C
962 (List.fold_left orop CTL.False (List.map make_match res))
963 | _ -> make_match label guard code
964
965(* --------------------------------------------------------------------- *)
966(* control structures *)
967
968let end_control_structure fvs header body after_pred
969 after_checks no_after_checks (afvs,afresh,ainh,aft) after label guard =
970 (* aft indicates what is added after the whole if, which has to be added
971 to the endif node *)
972 let (aft_needed,after_branch) =
973 match aft with
974 Ast.CONTEXT(_,Ast.NOTHING) ->
975 (false,make_seq_after2 guard after_pred after)
976 | _ ->
977 let match_endif =
978 make_match label guard
979 (make_meta_rule_elem aft (afvs,afresh,ainh)) in
980 (true,
981 make_seq_after guard after_pred
982 (After(make_seq_after guard match_endif after))) in
983 let body = body after_branch in
984 let s = guard_to_strict guard in
985 (* the code *)
986 quantify guard fvs
987 (ctl_and s header
988 (opt_and guard
989 (match (after,aft_needed) with
990 (After _,_) (* pattern doesn't end here *)
991 | (_,true) (* + code added after *) -> after_checks
992 | _ -> no_after_checks)
993 (ctl_ax_absolute s body)))
994
995let ifthen ifheader branch ((afvs,_,_,_) as aft) after
996 quantified minus_quantified label llabel slabel recurse make_match guard =
997(* "if (test) thn" becomes:
998 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
999
1000 "if (test) thn; after" becomes:
1001 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
1002 & EX After
1003*)
ae4735db 1004 (* free variables *)
34e49164
C
1005 let (efvs,bfvs) =
1006 match seq_fvs quantified
1007 [Ast.get_fvs ifheader;Ast.get_fvs branch;afvs] with
1008 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1009 | _ -> failwith "not possible" in
1010 let new_quantified = Common.union_set bfvs quantified in
1011 let (mefvs,mbfvs) =
1012 match seq_fvs minus_quantified
1013 [Ast.get_mfvs ifheader;Ast.get_mfvs branch;[]] with
1014 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1015 | _ -> failwith "not possible" in
1016 let new_mquantified = Common.union_set mbfvs minus_quantified in
1017 (* if header *)
1018 let if_header = quantify guard efvs (make_match ifheader) in
1019 (* then branch and after *)
1020 let lv = get_label_ctr() in
1021 let used = ref false in
1022 let true_branch =
002099fc
C
1023 (* no point to put a label on truepred etc; it is local to this construct
1024 so it must have the same label *)
34e49164 1025 make_seq guard
002099fc 1026 [truepred None; recurse branch Tail new_quantified new_mquantified
34e49164 1027 (Some (lv,used)) llabel slabel guard] in
002099fc 1028 let after_pred = aftpred None in
34e49164 1029 let or_cases after_branch =
002099fc 1030 ctl_or true_branch (ctl_or (fallpred None) after_branch) in
34e49164
C
1031 let (if_header,wrapper) =
1032 if !used
1033 then
1034 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1035 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
1036 (function body -> quantify true [lv] body))
1037 else (if_header,function x -> x) in
1038 wrapper
1039 (end_control_structure bfvs if_header or_cases after_pred
1040 (Some(ctl_ex after_pred)) None aft after label guard)
1041
1042let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after
1043 quantified minus_quantified label llabel slabel recurse make_match guard =
1044(* "if (test) thn else els" becomes:
1045 if(test) & AX((TrueBranch & AX thn) v
1046 (FalseBranch & AX (else & AX els)) v After)
1047 & EX FalseBranch
1048
1049 "if (test) thn else els; after" becomes:
1050 if(test) & AX((TrueBranch & AX thn) v
1051 (FalseBranch & AX (else & AX els)) v
1052 (After & AXAX after))
1053 & EX FalseBranch
1054 & EX After
1055*)
1056 (* free variables *)
1057 let (e1fvs,b1fvs,s1fvs) =
1058 match seq_fvs quantified
1059 [Ast.get_fvs ifheader;Ast.get_fvs branch1;afvs] with
1060 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
1061 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
1062 | _ -> failwith "not possible" in
1063 let (e2fvs,b2fvs,s2fvs) =
1064 (* fvs on else? *)
978fd7e5
C
1065 (* just combine with the else branch. no point to have separate
1066 quantifier, since there is only one possible control-flow path *)
1067 let else_fvs = Common.union_set (Ast.get_fvs els) (Ast.get_fvs branch2) in
1068 match seq_fvs quantified [Ast.get_fvs ifheader;else_fvs;afvs] with
34e49164 1069 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
978fd7e5 1070 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
34e49164
C
1071 | _ -> failwith "not possible" in
1072 let bothfvs = union (union b1fvs b2fvs) (intersect s1fvs s2fvs) in
1073 let exponlyfvs = intersect e1fvs e2fvs in
1074 let new_quantified = union bothfvs quantified in
1075 (* minus free variables *)
1076 let (me1fvs,mb1fvs,ms1fvs) =
1077 match seq_fvs minus_quantified
1078 [Ast.get_mfvs ifheader;Ast.get_mfvs branch1;[]] with
1079 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
1080 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
1081 | _ -> failwith "not possible" in
1082 let (me2fvs,mb2fvs,ms2fvs) =
1083 (* fvs on else? *)
978fd7e5
C
1084 (* just combine with the else branch. no point to have separate
1085 quantifier, since there is only one possible control-flow path *)
1086 let else_mfvs =
1087 Common.union_set (Ast.get_mfvs els) (Ast.get_mfvs branch2) in
1088 match seq_fvs minus_quantified [Ast.get_mfvs ifheader;else_mfvs;[]] with
34e49164
C
1089 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
1090 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
1091 | _ -> failwith "not possible" in
1092 let mbothfvs = union (union mb1fvs mb2fvs) (intersect ms1fvs ms2fvs) in
1093 let new_mquantified = union mbothfvs minus_quantified in
1094 (* if header *)
1095 let if_header = quantify guard exponlyfvs (make_match ifheader) in
1096 (* then and else branches *)
1097 let lv = get_label_ctr() in
1098 let used = ref false in
1099 let true_branch =
1100 make_seq guard
002099fc 1101 [truepred None; recurse branch1 Tail new_quantified new_mquantified
34e49164
C
1102 (Some (lv,used)) llabel slabel guard] in
1103 let false_branch =
1104 make_seq guard
002099fc 1105 [falsepred None;
978fd7e5
C
1106 quantify guard
1107 (Common.minus_set (Ast.get_fvs els) new_quantified)
002099fc 1108 (header_match None guard els);
34e49164
C
1109 recurse branch2 Tail new_quantified new_mquantified
1110 (Some (lv,used)) llabel slabel guard] in
002099fc 1111 let after_pred = aftpred None in
34e49164
C
1112 let or_cases after_branch =
1113 ctl_or true_branch (ctl_or false_branch after_branch) in
1114 let s = guard_to_strict guard in
1115 let (if_header,wrapper) =
1116 if !used
1117 then
1118 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1119 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
1120 (function body -> quantify true [lv] body))
1121 else (if_header,function x -> x) in
1122 wrapper
1123 (end_control_structure bothfvs if_header or_cases after_pred
002099fc
C
1124 (Some(ctl_and s (ctl_ex (falsepred None)) (ctl_ex after_pred)))
1125 (Some(ctl_ex (falsepred None)))
34e49164
C
1126 aft after label guard)
1127
1128let forwhile header body ((afvs,_,_,_) as aft) after
1129 quantified minus_quantified label recurse make_match guard =
1130 let process _ =
1131 (* the translation in this case is similar to that of an if with no else *)
ae4735db 1132 (* free variables *)
34e49164
C
1133 let (efvs,bfvs) =
1134 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body;afvs] with
1135 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1136 | _ -> failwith "not possible" in
1137 let new_quantified = Common.union_set bfvs quantified in
ae4735db 1138 (* minus free variables *)
34e49164
C
1139 let (mefvs,mbfvs) =
1140 match seq_fvs minus_quantified
1141 [Ast.get_mfvs header;Ast.get_mfvs body;[]] with
1142 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1143 | _ -> failwith "not possible" in
1144 let new_mquantified = Common.union_set mbfvs minus_quantified in
1145 (* loop header *)
1146 let header = quantify guard efvs (make_match header) in
1147 let lv = get_label_ctr() in
1148 let used = ref false in
1149 let body =
1150 make_seq guard
002099fc 1151 [inlooppred None;
34e49164
C
1152 recurse body Tail new_quantified new_mquantified
1153 (Some (lv,used)) (Some (lv,used)) None guard] in
951c7801 1154 let after_pred = loopfallpred None in
34e49164
C
1155 let or_cases after_branch = ctl_or body after_branch in
1156 let (header,wrapper) =
1157 if !used
1158 then
1159 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1160 (ctl_and CTL.NONSTRICT(*???*) header label_pred,
1161 (function body -> quantify true [lv] body))
1162 else (header,function x -> x) in
1163 wrapper
1164 (end_control_structure bfvs header or_cases after_pred
1165 (Some(ctl_ex after_pred)) None aft after label guard) in
1166 match (Ast.unwrap body,aft) with
1167 (Ast.Atomic(re),(_,_,_,Ast.CONTEXT(_,Ast.NOTHING))) ->
1168 (match Ast.unwrap re with
1169 Ast.MetaStmt((_,_,Ast.CONTEXT(_,Ast.NOTHING),_),
b1b2de81
C
1170 Type_cocci.Unitary,_,false)
1171 when after = Tail or after = End or after = VeryEnd ->
34e49164
C
1172 let (efvs) =
1173 match seq_fvs quantified [Ast.get_fvs header] with
1174 [(efvs,_)] -> efvs
1175 | _ -> failwith "not possible" in
1176 quantify guard efvs (make_match header)
1177 | _ -> process())
1178 | _ -> process()
ae4735db 1179
34e49164
C
1180(* --------------------------------------------------------------------- *)
1181(* statement metavariables *)
1182
1183(* issue: an S metavariable that is not an if branch/loop body
1184 should not match an if branch/loop body, so check that the labels
1185 of the nodes before the first node matched by the S are different
1186 from the label of the first node matched by the S *)
1187let sequencibility body label_pred process_bef_aft = function
1188 Ast.Sequencible | Ast.SequencibleAfterDots [] ->
1189 body
1190 (function x ->
1191 (ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1192 | Ast.SequencibleAfterDots l ->
1193 (* S appears after some dots. l is the code that comes after the S.
1194 want to search for that first, because S can match anything, while
1195 the stuff after is probably more restricted *)
1196 let afts = List.map process_bef_aft l in
1197 let ors = foldl1 ctl_or afts in
1198 ctl_and CTL.NONSTRICT
1199 (ctl_ef (ctl_and CTL.NONSTRICT ors (ctl_back_ax label_pred)))
1200 (body
1201 (function x ->
1202 ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1203 | Ast.NotSequencible -> body (function x -> x)
1204
1205let svar_context_with_add_after stmt s label quantified d ast
1206 seqible after process_bef_aft guard fvinfo =
1207 let label_var = (*fresh_label_var*) string2var "_lab" in
1208 let label_pred =
1209 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
951c7801
C
1210 (*let prelabel_pred =
1211 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in*)
34e49164
C
1212 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
1213 let full_metamatch = matcher d in
1214 let first_metamatch =
1215 matcher
1216 (match d with
951c7801
C
1217 Ast.CONTEXT(pos,Ast.BEFOREAFTER(bef,_,c)) ->
1218 Ast.CONTEXT(pos,Ast.BEFORE(bef,c))
34e49164 1219 | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
951c7801
C
1220 | Ast.MINUS(_,_,_,_) | Ast.PLUS _ -> failwith "not possible") in
1221(*
34e49164
C
1222 let middle_metamatch =
1223 matcher
1224 (match d with
1225 Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
951c7801
C
1226 | Ast.MINUS(_,_,_,_) | Ast.PLUS _ -> failwith "not possible") in
1227*)
34e49164
C
1228 let last_metamatch =
1229 matcher
1230 (match d with
951c7801
C
1231 Ast.CONTEXT(pos,Ast.BEFOREAFTER(_,aft,c)) ->
1232 Ast.CONTEXT(pos,Ast.AFTER(aft,c))
34e49164 1233 | Ast.CONTEXT(_,_) -> d
951c7801 1234 | Ast.MINUS(_,_,_,_) | Ast.PLUS _ -> failwith "not possible") in
34e49164 1235
951c7801 1236(*
34e49164 1237 let rest_nodes =
951c7801
C
1238 ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in
1239*)
1240
1241 let to_end = ctl_or (aftpred None) (loopfallpred None) in
34e49164 1242 let left_or = (* the whole statement is one node *)
951c7801
C
1243 make_seq_after guard
1244 (ctl_and CTL.NONSTRICT (ctl_not (ctl_ex to_end)) full_metamatch) after in
1245 let right_or = (* the statement covers multiple nodes *)
ae4735db 1246 ctl_and CTL.NONSTRICT
951c7801
C
1247 (ctl_ex
1248 (make_seq guard
1249 [to_end; make_seq_after guard last_metamatch after]))
1250 first_metamatch in
1251
1252(*
1253 let left_or =
34e49164
C
1254 make_seq guard
1255 [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in
951c7801 1256 let right_or =
34e49164
C
1257 make_seq guard
1258 [first_metamatch;
1259 ctl_au CTL.NONSTRICT
1260 rest_nodes
1261 (make_seq guard
1262 [ctl_and CTL.NONSTRICT last_metamatch label_pred;
1263 and_after guard
1264 (ctl_not prelabel_pred) after])] in
951c7801
C
1265*)
1266
34e49164
C
1267 let body f =
1268 ctl_and CTL.NONSTRICT label_pred
1269 (f (ctl_and CTL.NONSTRICT
1270 (make_raw_match label false ast) (ctl_or left_or right_or))) in
1271 let stmt_fvs = Ast.get_fvs stmt in
1272 let fvs = get_unquantified quantified stmt_fvs in
1273 quantify guard (label_var::fvs)
1274 (sequencibility body label_pred process_bef_aft seqible)
1275
1276let svar_minus_or_no_add_after stmt s label quantified d ast
1277 seqible after process_bef_aft guard fvinfo =
1278 let label_var = (*fresh_label_var*) string2var "_lab" in
1279 let label_pred =
1280 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
1281 let prelabel_pred =
1282 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in
1283 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
fc1ad971 1284 let ender =
708f4980 1285 match (d,after) with
951c7801
C
1286 (Ast.PLUS _, _) -> failwith "not possible"
1287 | (Ast.CONTEXT(pos,Ast.NOTHING),(Tail|End|VeryEnd)) ->
708f4980 1288 (* just match the root. don't care about label; always ok *)
951c7801
C
1289 make_raw_match None false ast
1290 | (Ast.CONTEXT(pos,Ast.BEFORE(_,_)),(Tail|End|VeryEnd)) ->
1291 ctl_and CTL.NONSTRICT
1292 (make_raw_match None false ast) (* statement *)
1293 (matcher d) (* transformation *)
1294 | (Ast.CONTEXT(pos,(Ast.NOTHING|Ast.BEFORE(_,_))),(After a | Guard a)) ->
1295 (* This case and the MINUS one couldprobably be merged, if
1296 HackForStmt were to notice when its arguments are trivial *)
34e49164 1297 let first_metamatch = matcher d in
951c7801
C
1298 (* try to follow after link *)
1299 let to_end = ctl_or (aftpred None) (loopfallpred None) in
1300 let is_compound =
1301 ctl_ex(make_seq guard [to_end; CTL.True; a]) in
1302 let not_compound =
1303 make_seq_after guard (ctl_not (ctl_ex to_end)) after in
fc1ad971 1304 ctl_and CTL.NONSTRICT (make_raw_match label false ast)
951c7801
C
1305 (ctl_and CTL.NONSTRICT
1306 first_metamatch (ctl_or is_compound not_compound))
1307 | (Ast.CONTEXT(pos,(Ast.AFTER _|Ast.BEFOREAFTER _)),_) ->
1308 failwith "not possible"
1309 | (Ast.MINUS(pos,inst,adj,l),after) ->
1310 let (first_metamatch,last_metamatch,rest_metamatch) =
1311 match l with
1312 [] -> (matcher(Ast.CONTEXT(pos,Ast.NOTHING)),CTL.True,matcher d)
1313 | _ -> (matcher d,
1314 matcher(Ast.MINUS(pos,inst,adj,[])),
1315 ctl_and CTL.NONSTRICT
1316 (ctl_not (make_raw_match label false ast))
1317 (matcher(Ast.MINUS(pos,inst,adj,[])))) in
1318 (* try to follow after link *)
1319 let to_end = ctl_or (aftpred None) (loopfallpred None) in
1320 let is_compound =
1321 ctl_ex
1322 (make_seq guard
1323 [to_end; make_seq_after guard last_metamatch after]) in
1324 let not_compound =
1325 make_seq_after guard (ctl_not (ctl_ex to_end)) after in
1326 ctl_and CTL.NONSTRICT
1327 (ctl_and CTL.NONSTRICT (make_raw_match label false ast)
1328 (ctl_and CTL.NONSTRICT
1329 first_metamatch (ctl_or is_compound not_compound)))
1330 (* don't have to put anything before the beginning, so don't have to
1331 distinguish the first node. so don't have to bother about paths,
1332 just use the label. label ensures that found nodes match up with
1333 what they should because it is in the lhs of the andany. *)
1334 (CTL.HackForStmt(CTL.FORWARD,CTL.NONSTRICT,
1335 ctl_and CTL.NONSTRICT label_pred
1336 (make_raw_match label false ast),
1337 ctl_and CTL.NONSTRICT rest_metamatch prelabel_pred))
1338 in
fc1ad971
C
1339 let body f = ctl_and CTL.NONSTRICT label_pred (f ender) in
1340 let stmt_fvs = Ast.get_fvs stmt in
1341 let fvs = get_unquantified quantified stmt_fvs in
1342 quantify guard (label_var::fvs)
34e49164
C
1343 (sequencibility body label_pred process_bef_aft seqible)
1344
1345(* --------------------------------------------------------------------- *)
1346(* dots and nests *)
1347
978fd7e5 1348let dots_au is_strict toend label s wrapcode n x seq_after y quantifier =
34e49164
C
1349 let matchgoto = gotopred None in
1350 let matchbreak =
1351 make_match None false
1352 (wrapcode
1353 (Ast.Break(Ast.make_mcode "break",Ast.make_mcode ";"))) in
1354 let matchcontinue =
1355 make_match None false
1356 (wrapcode
1357 (Ast.Continue(Ast.make_mcode "continue",Ast.make_mcode ";"))) in
485bce71 1358 let stop_early =
1be43e12 1359 if quantifier = Exists
485bce71 1360 then Common.Left(CTL.False)
34e49164 1361 else if toend
485bce71 1362 then Common.Left(CTL.Or(aftpred label,exitpred label))
34e49164 1363 else if is_strict
485bce71 1364 then Common.Left(aftpred label)
34e49164 1365 else
485bce71 1366 Common.Right
978fd7e5
C
1367 (function vx -> function v ->
1368 (* vx is the contents of the nest, if any. we can only stop early
1369 if we find neither the ending code nor the nest contents in
1370 the if branch. not sure if this is a good idea. *)
485bce71
C
1371 let lv = get_label_ctr() in
1372 let labelpred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1373 let preflabelpred = label_pred_maker (Some (lv,ref true)) in
951c7801 1374 (*let is_paren =
fc1ad971
C
1375 (* Rather a special case. But if the code afterwards is just
1376 a } then there is no point checking after a goto that it does
1377 not appear. *)
1378 (* this optimization doesn't work. probably depends on whether
1379 the destination of the break/goto is local or more global than
1380 the dots *)
1381 match seq_after with
1382 CTL.And(_,e1,e2) ->
1383 let is_paren = function
1384 CTL.Pred(Lib_engine.Paren _,_) -> true
1385 | _ -> false in
1386 is_paren e1 or is_paren e2
951c7801 1387 | _ -> false in *)
485bce71
C
1388 ctl_or (aftpred label)
1389 (quantify false [lv]
1390 (ctl_and CTL.NONSTRICT
1391 (ctl_and CTL.NONSTRICT (truepred label) labelpred)
1392 (ctl_au CTL.NONSTRICT
978fd7e5
C
1393 (ctl_and CTL.NONSTRICT (ctl_not v)
1394 (ctl_and CTL.NONSTRICT vx preflabelpred))
485bce71 1395 (ctl_and CTL.NONSTRICT preflabelpred
faf9a90c
C
1396 (if !Flag_matcher.only_return_is_error_exit
1397 then
1398 (ctl_and CTL.NONSTRICT
1399 (retpred None) (ctl_not seq_after))
1400 else
1401 (ctl_or
1402 (ctl_and CTL.NONSTRICT
1403 (ctl_or (retpred None) matchcontinue)
1404 (ctl_not seq_after))
1405 (ctl_and CTL.NONSTRICT
1406 (ctl_or matchgoto matchbreak)
fc1ad971
C
1407 ((*if is_paren
1408 (* an optim that failed see defn is_paren
1409 and tests/makes_a_loop *)
1410 then CTL.True
1411 else*)
1412 (ctl_ag s
1413 (ctl_not seq_after))))))))))) in
34e49164 1414 let op = if quantifier = !exists then ctl_au else ctl_anti_au in
485bce71
C
1415 let v = get_let_ctr() in
1416 op s x
1417 (match stop_early with
978fd7e5 1418 Common.Left x1 -> ctl_or y x1
485bce71 1419 | Common.Right stop_early ->
978fd7e5
C
1420 CTL.Let(v,y,
1421 ctl_or (CTL.Ref v)
fc1ad971
C
1422 (ctl_and CTL.NONSTRICT (label_pred_maker label)
1423 (stop_early n (CTL.Ref v)))))
34e49164
C
1424
1425let rec dots_and_nests plus nest whencodes bef aft dotcode after label
1be43e12 1426 process_bef_aft statement_list statement guard quantified wrapcode =
34e49164
C
1427 let ctl_and_ns = ctl_and CTL.NONSTRICT in
1428 (* proces bef_aft *)
1429 let shortest l =
1430 List.fold_left ctl_or_fl CTL.False (List.map process_bef_aft l) in
1431 let bef_aft = (* to be negated *)
1432 try
1433 let _ =
1434 List.find
1435 (function Ast.WhenModifier(Ast.WhenAny) -> true | _ -> false)
1436 whencodes in
1437 CTL.False
1438 with Not_found -> shortest (Common.union_set bef aft) in
1439 let is_strict =
1440 List.exists
1441 (function Ast.WhenModifier(Ast.WhenStrict) -> true | _ -> false)
1442 whencodes in
1443 let check_quantifier quant other =
1444 if List.exists
1445 (function Ast.WhenModifier(x) -> x = quant | _ -> false)
1446 whencodes
1447 then
1448 if List.exists
1449 (function Ast.WhenModifier(x) -> x = other | _ -> false)
1450 whencodes
1451 then failwith "inconsistent annotation on dots"
1452 else true
1453 else false in
1454 let quantifier =
1455 if check_quantifier Ast.WhenExists Ast.WhenForall
1456 then Exists
1457 else
1be43e12 1458 if check_quantifier Ast.WhenForall Ast.WhenExists
34e49164
C
1459 then Forall
1460 else !exists in
1461 (* the following is used when we find a goto, etc and consider accepting
1462 without finding the rest of the pattern *)
1463 let aft = shortest aft in
1464 (* process whencode *)
1465 let labelled = label_pred_maker label in
1466 let whencodes arg =
1467 let (poswhen,negwhen) =
1468 List.fold_left
1469 (function (poswhen,negwhen) ->
1470 function
1471 Ast.WhenNot whencodes ->
1472 (poswhen,ctl_or (statement_list whencodes) negwhen)
1473 | Ast.WhenAlways stm ->
1474 (ctl_and CTL.NONSTRICT (statement stm) poswhen,negwhen)
1be43e12
C
1475 | Ast.WhenModifier(_) -> (poswhen,negwhen)
1476 | Ast.WhenNotTrue(e) ->
1477 (poswhen,
1478 ctl_or (whencond_true e label guard quantified) negwhen)
1479 | Ast.WhenNotFalse(e) ->
1480 (poswhen,
1481 ctl_or (whencond_false e label guard quantified) negwhen))
978fd7e5
C
1482 (CTL.True,CTL.False(*bef_aft*)) (List.rev whencodes) in
1483 (*bef_aft modifies arg so that inside of a nest can't cause the next
1484 to overshoot its boundaries, eg a() <...f()...> b() where f is
1485 a metavariable and the whole thing matches code in a loop;
1486 don't want f to match eg b(), allowing to go around the loop again*)
34e49164
C
1487 let poswhen = ctl_and_ns arg poswhen in
1488 let negwhen =
1489(* if !exists
1490 then*)
1491 (* add in After, because it's not part of the program *)
1492 ctl_or (aftpred label) negwhen
1493 (*else negwhen*) in
1494 ctl_and_ns poswhen (ctl_not negwhen) in
1495 (* process dot code, if any *)
1496 let dotcode =
1497 match (dotcode,guard) with
1498 (None,_) | (_,true) -> CTL.True
1499 | (Some dotcode,_) -> dotcode in
1500 (* process nest code, if any *)
1501 (* whencode goes in the negated part of the nest; if no nest, just goes
1502 on the "true" in between code *)
1503 let plus_var = if plus then get_label_ctr() else string2var "" in
1504 let plus_var2 = if plus then get_label_ctr() else string2var "" in
978fd7e5
C
1505 let (ornest,just_nest) =
1506 (* just_nest is used when considering whether to stop early, to continue
1507 to collect nest information in the if branch *)
34e49164 1508 match (nest,guard && not plus) with
978fd7e5 1509 (None,_) | (_,true) -> (whencodes CTL.True,CTL.True)
34e49164
C
1510 | (Some nest,false) ->
1511 let v = get_let_ctr() in
1512 let is_plus x =
1513 if plus
1514 then
1515 (* the idea is that BindGood is sort of a witness; a witness to
1516 having found the subterm in at least one place. If there is
1517 not a witness, then there is a risk that it will get thrown
1518 away, if it is merged with a node that has an empty
1519 environment. See tests/nestplus. But this all seems
1520 rather suspicious *)
1521 CTL.And(CTL.NONSTRICT,x,
1522 CTL.Exists(true,plus_var2,
1523 CTL.Pred(Lib_engine.BindGood(plus_var),
1524 CTL.Modif plus_var2)))
1525 else x in
ae4735db 1526 let body =
978fd7e5
C
1527 CTL.Let(v,nest,
1528 CTL.Or(is_plus (CTL.Ref v),
1529 whencodes (CTL.Not(ctl_uncheck (CTL.Ref v))))) in
1530 (body,body) in
34e49164
C
1531 let plus_modifier x =
1532 if plus
1533 then
1534 CTL.Exists
1535 (false,plus_var,
1536 (CTL.And
1537 (CTL.NONSTRICT,x,
1538 CTL.Not(CTL.Pred(Lib_engine.BindBad(plus_var),CTL.Control)))))
1539 else x in
1540
1541 let ender =
1542 match after with
fc1ad971
C
1543 (* label within dots is taken care of elsewhere. the next two lines
1544 put the label on the code following dots *)
1545 After f -> ctl_and (guard_to_strict guard) f labelled
1546 | Guard f ->
1547 (* actually, label should be None based on the only use of Guard... *)
1548 assert (label = None);
1549 ctl_and CTL.NONSTRICT (ctl_uncheck f) labelled
34e49164
C
1550 | VeryEnd ->
1551 let exit = endpred label in
1552 let errorexit = exitpred label in
1553 ctl_or exit errorexit
1554 (* not at all sure what the next two mean... *)
1555 | End -> CTL.True
1556 | Tail ->
1557 (match label with
1558 Some (lv,used) -> used := true;
1559 ctl_or (CTL.Pred(Lib_engine.Label lv,CTL.Control))
1560 (ctl_back_ex (ctl_or (retpred label) (gotopred label)))
1561 | None -> endpred label)
1562 (* was the following, but not clear why sgrep should allow
1563 incomplete patterns
1564 let exit = endpred label in
1565 let errorexit = exitpred label in
1566 if !exists
1567 then ctl_or exit errorexit (* end anywhere *)
1568 else exit (* end at the real end of the function *) *) in
1569 plus_modifier
1570 (dots_au is_strict ((after = Tail) or (after = VeryEnd))
978fd7e5 1571 label (guard_to_strict guard) wrapcode just_nest
5636bb2c
C
1572 (ctl_and_ns dotcode
1573 (ctl_and_ns (ctl_and_ns (ctl_not bef_aft) ornest) labelled))
1574 aft ender quantifier)
34e49164 1575
1be43e12
C
1576and get_whencond_exps e =
1577 match Ast.unwrap e with
1578 Ast.Exp e -> [e]
1579 | Ast.DisjRuleElem(res) ->
1580 List.fold_left Common.union_set [] (List.map get_whencond_exps res)
1581 | _ -> failwith "not possible"
1582
1583and make_whencond_headers e e1 label guard quantified =
1584 let fvs = Ast.get_fvs e in
1585 let header_pred h =
1586 quantify guard (get_unquantified quantified fvs)
1587 (make_match label guard h) in
1588 let if_header e1 =
1589 header_pred
1590 (Ast.rewrap e
1591 (Ast.IfHeader
1592 (Ast.make_mcode "if",
1593 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1594 let while_header e1 =
1595 header_pred
1596 (Ast.rewrap e
1597 (Ast.WhileHeader
1598 (Ast.make_mcode "while",
1599 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1600 let for_header e1 =
1601 header_pred
1602 (Ast.rewrap e
1603 (Ast.ForHeader
1604 (Ast.make_mcode "for",Ast.make_mcode "(",None,Ast.make_mcode ";",
1605 Some e1,Ast.make_mcode ";",None,Ast.make_mcode ")"))) in
1606 let if_headers =
1607 List.fold_left ctl_or CTL.False (List.map if_header e1) in
1608 let while_headers =
1609 List.fold_left ctl_or CTL.False (List.map while_header e1) in
1610 let for_headers =
1611 List.fold_left ctl_or CTL.False (List.map for_header e1) in
1612 (if_headers, while_headers, for_headers)
1613
1614and whencond_true e label guard quantified =
1615 let e1 = get_whencond_exps e in
1616 let (if_headers, while_headers, for_headers) =
1617 make_whencond_headers e e1 label guard quantified in
1618 ctl_or
1619 (ctl_and CTL.NONSTRICT (truepred label) (ctl_back_ex if_headers))
1620 (ctl_and CTL.NONSTRICT
1621 (inlooppred label) (ctl_back_ex (ctl_or while_headers for_headers)))
1622
1623and whencond_false e label guard quantified =
1624 let e1 = get_whencond_exps e in
1625 let (if_headers, while_headers, for_headers) =
1626 make_whencond_headers e e1 label guard quantified in
88e71198 1627 (* if with else *)
1be43e12 1628 ctl_or (ctl_and CTL.NONSTRICT (falsepred label) (ctl_back_ex if_headers))
88e71198
C
1629 (* if without else *)
1630 (ctl_or (ctl_and CTL.NONSTRICT (fallpred label) (ctl_back_ex if_headers))
1631 (* failure of loop test *)
1632 (ctl_and CTL.NONSTRICT (loopfallpred label)
1be43e12
C
1633 (ctl_or (ctl_back_ex while_headers) (ctl_back_ex for_headers))))
1634
34e49164
C
1635(* --------------------------------------------------------------------- *)
1636(* the main translation loop *)
ae4735db 1637
34e49164
C
1638let rec statement_list stmt_list after quantified minus_quantified
1639 label llabel slabel dots_before guard =
1640 let isdots x =
1641 (* include Disj to be on the safe side *)
1642 match Ast.unwrap x with
1643 Ast.Dots _ | Ast.Nest _ | Ast.Disj _ -> true | _ -> false in
1644 let compute_label l e db = if db or isdots e then l else None in
1645 match Ast.unwrap stmt_list with
1646 Ast.DOTS(x) ->
1647 let rec loop quantified minus_quantified dots_before label llabel slabel
1648 = function
1649 ([],_,_) -> (match after with After f -> f | _ -> CTL.True)
1650 | ([e],_,_) ->
1651 statement e after quantified minus_quantified
1652 (compute_label label e dots_before)
1653 llabel slabel guard
1654 | (e::sl,fv::fvs,mfv::mfvs) ->
1655 let shared = intersectll fv fvs in
1656 let unqshared = get_unquantified quantified shared in
1657 let new_quantified = Common.union_set unqshared quantified in
1658 let minus_shared = intersectll mfv mfvs in
1659 let munqshared =
1660 get_unquantified minus_quantified minus_shared in
1661 let new_mquantified =
1662 Common.union_set munqshared minus_quantified in
1663 quantify guard unqshared
1664 (statement e
1665 (After
1666 (let (label1,llabel1,slabel1) =
1667 match Ast.unwrap e with
1668 Ast.Atomic(re) ->
1669 (match Ast.unwrap re with
1670 Ast.Goto _ -> (None,None,None)
1671 | _ -> (label,llabel,slabel))
1672 | _ -> (label,llabel,slabel) in
1673 loop new_quantified new_mquantified (isdots e)
1674 label1 llabel1 slabel1
1675 (sl,fvs,mfvs)))
1676 new_quantified new_mquantified
1677 (compute_label label e dots_before) llabel slabel guard)
1678 | _ -> failwith "not possible" in
1679 loop quantified minus_quantified dots_before
1680 label llabel slabel
1681 (x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x)
1682 | Ast.CIRCLES(x) -> failwith "not supported"
1683 | Ast.STARS(x) -> failwith "not supported"
1684
1685(* llabel is the label of the enclosing loop and slabel is the label of the
1686 enclosing switch *)
1687and statement stmt after quantified minus_quantified
1688 label llabel slabel guard =
1689 let ctl_au = ctl_au CTL.NONSTRICT in
1690 let ctl_ax = ctl_ax CTL.NONSTRICT in
1691 let ctl_and = ctl_and CTL.NONSTRICT in
1692 let make_seq = make_seq guard in
1693 let make_seq_after = make_seq_after guard in
1694 let real_make_match = make_match in
1695 let make_match = header_match label guard in
1696
1697 let dots_done = ref false in (* hack for dots cases we can easily handle *)
1698
1699 let term =
1700 match Ast.unwrap stmt with
1701 Ast.Atomic(ast) ->
1702 (match Ast.unwrap ast with
1703 (* the following optimisation is not a good idea, because when S
1704 is alone, we would like it not to match a declaration.
1705 this makes more matching for things like when (...) S, but perhaps
1706 that matching is not so costly anyway *)
1707 (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*)
951c7801 1708 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.BEFOREAFTER(_,_,_)) as d),_),
34e49164 1709 keep,seqible,_)
951c7801 1710 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.AFTER(_,_)) as d),_),
34e49164
C
1711 keep,seqible,_)->
1712 svar_context_with_add_after stmt s label quantified d ast seqible
1713 after
1714 (process_bef_aft quantified minus_quantified
1715 label llabel slabel true)
1716 guard
1717 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1718
1719 | Ast.MetaStmt((s,_,d,_),keep,seqible,_) ->
1720 svar_minus_or_no_add_after stmt s label quantified d ast seqible
1721 after
1722 (process_bef_aft quantified minus_quantified
1723 label llabel slabel true)
1724 guard
1725 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1726
1727 | _ ->
1728 let term =
1729 match Ast.unwrap ast with
1730 Ast.DisjRuleElem(res) ->
1731 do_re_matches label guard res quantified minus_quantified
1732 | Ast.Exp(_) | Ast.Ty(_) ->
1733 let stmt_fvs = Ast.get_fvs stmt in
1734 let fvs = get_unquantified quantified stmt_fvs in
1735 CTL.InnerAnd(quantify guard fvs (make_match ast))
1736 | _ ->
1737 let stmt_fvs = Ast.get_fvs stmt in
1738 let fvs = get_unquantified quantified stmt_fvs in
1739 quantify guard fvs (make_match ast) in
1740 match Ast.unwrap ast with
1741 Ast.Break(brk,semi) ->
1742 (match (llabel,slabel) with
1743 (_,Some(lv,used)) -> (* use switch label if there is one *)
1744 ctl_and term (bclabel_pred_maker slabel)
1745 | _ -> ctl_and term (bclabel_pred_maker llabel))
1746 | Ast.Continue(brk,semi) -> ctl_and term (bclabel_pred_maker llabel)
1747 | Ast.Return((_,info,retmc,pos),(_,_,semmc,_)) ->
1748 (* discard pattern that comes after return *)
1749 let normal_res = make_seq_after term after in
1750 (* the following code tries to propagate the modifications on
1751 return; to a close brace, in the case where the final return
1752 is absent *)
1753 let new_mc =
1754 match (retmc,semmc) with
708f4980
C
1755 (Ast.MINUS(_,inst1,adj1,l1),Ast.MINUS(_,_,_,l2))
1756 when !Flag.sgrep_mode2 ->
34e49164 1757 (* in sgrep mode, we can propagate the - *)
708f4980 1758 Some (Ast.MINUS(Ast.NoPos,inst1,adj1,l1@l2))
951c7801
C
1759 | (Ast.MINUS(_,_,_,l1),Ast.MINUS(_,_,_,l2)) ->
1760 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2,Ast.ONE)))
1761 | (Ast.CONTEXT(_,Ast.BEFORE(l1,c1)),
1762 Ast.CONTEXT(_,Ast.AFTER(l2,c2))) ->
1763 (if not (c1 = c2) then failwith "bad + code");
1764 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2,c1)))
34e49164
C
1765 | (Ast.CONTEXT(_,Ast.BEFORE(_)),Ast.CONTEXT(_,Ast.NOTHING))
1766 | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.NOTHING)) ->
1767 Some retmc
708f4980 1768 | (Ast.CONTEXT(_,Ast.NOTHING),
951c7801
C
1769 Ast.CONTEXT(_,Ast.AFTER(l,c))) ->
1770 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l,c)))
34e49164
C
1771 | _ -> None in
1772 let ret = Ast.make_mcode "return" in
1773 let edots =
1774 Ast.rewrap ast (Ast.Edots(Ast.make_mcode "...",None)) in
1775 let semi = Ast.make_mcode ";" in
1776 let simple_return =
1777 make_match(Ast.rewrap ast (Ast.Return(ret,semi))) in
1778 let return_expr =
1779 make_match(Ast.rewrap ast (Ast.ReturnExpr(ret,edots,semi))) in
1780 (match new_mc with
1781 Some new_mc ->
1782 let exit = endpred None in
1783 let mod_rbrace =
1784 Ast.rewrap ast (Ast.SeqEnd (("}",info,new_mc,pos))) in
1785 let stripped_rbrace =
1786 Ast.rewrap ast (Ast.SeqEnd(Ast.make_mcode "}")) in
1787 ctl_or normal_res
1788 (ctl_and (make_match mod_rbrace)
1789 (ctl_and
1790 (ctl_back_ax
1791 (ctl_not
1792 (ctl_uncheck
1793 (ctl_or simple_return return_expr))))
1794 (ctl_au
1795 (make_match stripped_rbrace)
1796 (* error exit not possible; it is in the middle
1797 of code, so a return is needed *)
1798 exit)))
1799 | _ ->
1800 (* some change in the middle of the return, so have to
1801 find an actual return *)
1802 normal_res)
1803 | _ ->
1804 (* should try to deal with the dots_bef_aft problem elsewhere,
1805 but don't have the courage... *)
1806 let term =
1807 if guard
1808 then term
1809 else
1810 do_between_dots stmt term End
1811 quantified minus_quantified label llabel slabel guard in
1812 dots_done := true;
1813 make_seq_after term after)
708f4980
C
1814 | Ast.Seq(lbrace,body,rbrace) ->
1815 let (lbfvs,b1fvs,b2fvs,rbfvs) =
34e49164
C
1816 match
1817 seq_fvs quantified
708f4980 1818 [Ast.get_fvs lbrace;
34e49164
C
1819 Ast.get_fvs body;Ast.get_fvs rbrace]
1820 with
708f4980
C
1821 [(lbfvs,b1fvs);(_,b2fvs);(rbfvs,_)] ->
1822 (lbfvs,b1fvs,b2fvs,rbfvs)
34e49164 1823 | _ -> failwith "not possible" in
708f4980 1824 let (mlbfvs,mb1fvs,mb2fvs,mrbfvs) =
34e49164
C
1825 match
1826 seq_fvs minus_quantified
708f4980 1827 [Ast.get_mfvs lbrace;
34e49164
C
1828 Ast.get_mfvs body;Ast.get_mfvs rbrace]
1829 with
708f4980
C
1830 [(lbfvs,b1fvs);(_,b2fvs);(rbfvs,_)] ->
1831 (lbfvs,b1fvs,b2fvs,rbfvs)
34e49164
C
1832 | _ -> failwith "not possible" in
1833 let pv = count_nested_braces stmt in
1834 let lv = get_label_ctr() in
1835 let paren_pred = CTL.Pred(Lib_engine.Paren pv,CTL.Control) in
1836 let label_pred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1837 let start_brace =
1838 ctl_and
1839 (quantify guard lbfvs (make_match lbrace))
1840 (ctl_and paren_pred label_pred) in
1be43e12
C
1841 let empty_rbrace =
1842 match Ast.unwrap rbrace with
1843 Ast.SeqEnd((data,info,_,pos)) ->
1844 Ast.rewrap rbrace(Ast.SeqEnd(Ast.make_mcode data))
1845 | _ -> failwith "unexpected close brace" in
34e49164
C
1846 let end_brace =
1847 (* label is not needed; paren_pred is enough *)
1be43e12
C
1848 quantify guard rbfvs
1849 (ctl_au (make_match empty_rbrace)
1850 (ctl_and
1851 (real_make_match None guard rbrace)
1852 paren_pred)) in
34e49164
C
1853 let new_quantified2 =
1854 Common.union_set b1fvs (Common.union_set b2fvs quantified) in
34e49164
C
1855 let new_mquantified2 =
1856 Common.union_set mb1fvs (Common.union_set mb2fvs minus_quantified) in
34e49164
C
1857 let pattern_as_given =
1858 let new_quantified2 = Common.union_set [pv] new_quantified2 in
34e49164
C
1859 quantify true [pv;lv]
1860 (quantify guard b1fvs
1861 (make_seq
1862 [start_brace;
951c7801
C
1863 (ctl_or
1864 (if !exists = Exists then CTL.False else (aftpred label))
1865 (quantify guard b2fvs
1866 (statement_list body
1867 (After (make_seq_after end_brace after))
1868 new_quantified2 new_mquantified2
1869 (Some (lv,ref true))
1870 llabel slabel false guard)))])) in
34e49164
C
1871 if ends_in_return body
1872 then
1873 (* matching error handling code *)
1874 (* Cases:
1875 1. The pattern as given
1876 2. A goto, and then some close braces, and then the pattern as
1877 given, but without the braces (only possible if there are no
1878 decls, and open and close braces are unmodified)
1879 3. Part of the pattern as given, then a goto, and then the rest
1880 of the pattern. For this case, we just check that all paths have
1881 a goto within the current braces. checking for a goto at every
1882 point in the pattern seems expensive and not worthwhile. *)
1883 let pattern2 =
34e49164
C
1884 let body = preprocess_dots body in (* redo, to drop braces *)
1885 make_seq
1886 [gotopred label;
1887 ctl_au
1888 (make_match empty_rbrace)
1889 (ctl_ax (* skip the destination label *)
708f4980 1890 (quantify guard b2fvs
34e49164 1891 (statement_list body End
708f4980 1892 new_quantified2 new_mquantified2 None llabel slabel
34e49164
C
1893 true guard)))] in
1894 let pattern3 =
1895 let new_quantified2 = Common.union_set [pv] new_quantified2 in
34e49164
C
1896 quantify true [pv;lv]
1897 (quantify guard b1fvs
1898 (make_seq
1899 [start_brace;
1900 ctl_and
1901 (CTL.AU (* want AF even for sgrep *)
1902 (CTL.FORWARD,CTL.STRICT,
1903 CTL.Pred(Lib_engine.PrefixLabel(lv),CTL.Control),
1904 ctl_and (* brace must be eventually after goto *)
1905 (gotopred (Some (lv,ref true)))
1906 (* want AF even for sgrep *)
1907 (CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace))))
1908 (quantify guard b2fvs
708f4980 1909 (statement_list body Tail
34e49164 1910 new_quantified2 new_mquantified2
978fd7e5 1911 None(*no label because past the goto*)
34e49164 1912 llabel slabel false guard))])) in
708f4980 1913 ctl_or pattern_as_given (ctl_or pattern2 pattern3)
34e49164
C
1914 else pattern_as_given
1915 | Ast.IfThen(ifheader,branch,aft) ->
1916 ifthen ifheader branch aft after quantified minus_quantified
1917 label llabel slabel statement make_match guard
ae4735db 1918
34e49164
C
1919 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
1920 ifthenelse ifheader branch1 els branch2 aft after quantified
1921 minus_quantified label llabel slabel statement make_match guard
1922
1923 | Ast.While(header,body,aft) | Ast.For(header,body,aft)
1924 | Ast.Iterator(header,body,aft) ->
1925 forwhile header body aft after quantified minus_quantified
1926 label statement make_match guard
1927
1928 | Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *)
002099fc
C
1929 (*ctl_and seems pointless, disjuncts see label too
1930 (label_pred_maker label)*)
34e49164
C
1931 (List.fold_left ctl_seqor CTL.False
1932 (List.map
1933 (function sl ->
1934 statement_list sl after quantified minus_quantified label
1935 llabel slabel true guard)
1936 stmt_dots_list))
1937
5636bb2c 1938 | Ast.Nest(starter,stmt_dots,ender,whencode,multi,bef,aft) ->
34e49164 1939 (* label in recursive call is None because label check is already
c491d8ee
C
1940 wrapped around the corresponding code. not good enough, want to stay
1941 in a specific region, dots and nests will keep going *)
34e49164
C
1942
1943 let bfvs =
1944 match seq_fvs quantified [Ast.get_wcfvs whencode;Ast.get_fvs stmt_dots]
1945 with
1946 [(wcfvs,bothfvs);(bdfvs,_)] -> bothfvs
1947 | _ -> failwith "not possible" in
1948
1949 (* no minus version because when code doesn't contain any minus code *)
1950 let new_quantified = Common.union_set bfvs quantified in
1951
5636bb2c
C
1952 let dot_code =
1953 match Ast.get_mcodekind starter with (*ender must have the same mcode*)
1954 Ast.MINUS(_,_,_,_) as d ->
1955 (* no need for the fresh metavar, but ... is a bit weird as a
1956 variable name *)
1957 Some(make_match (make_meta_rule_elem d ([],[],[])))
1958 | _ -> None in
1959
34e49164
C
1960 quantify guard bfvs
1961 (let dots_pattern =
1962 statement_list stmt_dots (a2n after) new_quantified minus_quantified
c491d8ee 1963 label(*None*) llabel slabel true guard in
34e49164 1964 dots_and_nests multi
5636bb2c 1965 (Some dots_pattern) whencode bef aft dot_code after label
34e49164 1966 (process_bef_aft new_quantified minus_quantified
c491d8ee 1967 label(*None*) llabel slabel true)
34e49164 1968 (function x ->
c491d8ee 1969 statement_list x Tail new_quantified minus_quantified label(*None*)
34e49164
C
1970 llabel slabel true true)
1971 (function x ->
c491d8ee 1972 statement x Tail new_quantified minus_quantified label(*None*)
34e49164 1973 llabel slabel true)
1be43e12
C
1974 guard quantified
1975 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x)))
34e49164
C
1976
1977 | Ast.Dots((_,i,d,_),whencodes,bef,aft) ->
1978 let dot_code =
1979 match d with
708f4980 1980 Ast.MINUS(_,_,_,_) ->
0708f913 1981 (* no need for the fresh metavar, but ... is a bit weird as a
34e49164
C
1982 variable name *)
1983 Some(make_match (make_meta_rule_elem d ([],[],[])))
1984 | _ -> None in
1985 dots_and_nests false None whencodes bef aft dot_code after label
1986 (process_bef_aft quantified minus_quantified None llabel slabel true)
1987 (function x ->
1988 statement_list x Tail quantified minus_quantified
1989 None llabel slabel true true)
1990 (function x ->
1991 statement x Tail quantified minus_quantified None llabel slabel true)
1be43e12
C
1992 guard quantified
1993 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x))
34e49164 1994
fc1ad971 1995 | Ast.Switch(header,lb,decls,cases,rb) ->
34e49164
C
1996 let rec intersect_all = function
1997 [] -> []
1998 | [x] -> x
1999 | x::xs -> intersect x (intersect_all xs) in
fc1ad971
C
2000 let rec intersect_all2 = function (* pairwise *)
2001 [] -> []
2002 | x::xs ->
2003 let front =
2004 List.filter
2005 (function elem -> List.exists (List.mem elem) xs)
2006 x in
2007 Common.union_set front (intersect_all2 xs) in
34e49164
C
2008 let rec union_all l = List.fold_left union [] l in
2009 (* start normal variables *)
2010 let header_fvs = Ast.get_fvs header in
2011 let lb_fvs = Ast.get_fvs lb in
fc1ad971 2012 let decl_fvs = union_all (List.map Ast.get_fvs (Ast.undots decls)) in
34e49164
C
2013 let case_fvs = List.map Ast.get_fvs cases in
2014 let rb_fvs = Ast.get_fvs rb in
2015 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
2016 all_casefvs,all_b3fvs,all_rbfvs) =
2017 List.fold_left
2018 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
2019 all_casefvs,all_b3fvs,all_rbfvs) ->
2020 function case_fvs ->
2021 match seq_fvs quantified [header_fvs;lb_fvs;case_fvs;rb_fvs] with
2022 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
2023 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
2024 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
2025 rbfvs::all_rbfvs)
2026 | _ -> failwith "not possible")
fc1ad971 2027 ([],[],[],[],[],[],[]) (decl_fvs :: case_fvs) in
34e49164
C
2028 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
2029 all_casefvs,all_b3fvs,all_rbfvs) =
2030 (List.rev all_efvs,List.rev all_b1fvs,List.rev all_lbfvs,
2031 List.rev all_b2fvs,List.rev all_casefvs,List.rev all_b3fvs,
2032 List.rev all_rbfvs) in
2033 let exponlyfvs = intersect_all all_efvs in
2034 let lbonlyfvs = intersect_all all_lbfvs in
2035(* don't do anything with right brace. Hope there is no + code on it *)
2036(* let rbonlyfvs = intersect_all all_rbfvs in*)
2037 let b1fvs = union_all all_b1fvs in
2038 let new1_quantified = union b1fvs quantified in
fc1ad971
C
2039 let b2fvs =
2040 union (union_all all_b2fvs) (intersect_all2 all_casefvs) in
34e49164
C
2041 let new2_quantified = union b2fvs new1_quantified in
2042(* let b3fvs = union_all all_b3fvs in*)
2043 (* ------------------- start minus free variables *)
2044 let header_mfvs = Ast.get_mfvs header in
2045 let lb_mfvs = Ast.get_mfvs lb in
fc1ad971 2046 let decl_mfvs = union_all (List.map Ast.get_mfvs (Ast.undots decls)) in
34e49164
C
2047 let case_mfvs = List.map Ast.get_mfvs cases in
2048 let rb_mfvs = Ast.get_mfvs rb in
2049 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
2050 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
2051 List.fold_left
2052 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
2053 all_casefvs,all_b3fvs,all_rbfvs) ->
2054 function case_mfvs ->
2055 match
2056 seq_fvs quantified
2057 [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with
2058 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
2059 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
2060 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
2061 rbfvs::all_rbfvs)
2062 | _ -> failwith "not possible")
fc1ad971 2063 ([],[],[],[],[],[],[]) (decl_mfvs::case_mfvs) in
34e49164
C
2064 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
2065 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
2066 (List.rev all_mefvs,List.rev all_mb1fvs,List.rev all_mlbfvs,
2067 List.rev all_mb2fvs,List.rev all_mcasefvs,List.rev all_mb3fvs,
2068 List.rev all_mrbfvs) in
2069(* don't do anything with right brace. Hope there is no + code on it *)
2070(* let rbonlyfvs = intersect_all all_rbfvs in*)
2071 let mb1fvs = union_all all_mb1fvs in
2072 let new1_mquantified = union mb1fvs quantified in
fc1ad971
C
2073 let mb2fvs =
2074 union (union_all all_mb2fvs) (intersect_all2 all_mcasefvs) in
34e49164
C
2075 let new2_mquantified = union mb2fvs new1_mquantified in
2076(* let b3fvs = union_all all_b3fvs in*)
2077 (* ------------------- end collection of free variables *)
2078 let switch_header = quantify guard exponlyfvs (make_match header) in
2079 let lb = quantify guard lbonlyfvs (make_match lb) in
2080(* let rb = quantify guard rbonlyfvs (make_match rb) in*)
2081 let case_headers =
2082 List.map
2083 (function case_line ->
2084 match Ast.unwrap case_line with
2085 Ast.CaseLine(header,body) ->
2086 let e1fvs =
2087 match seq_fvs new2_quantified [Ast.get_fvs header] with
2088 [(e1fvs,_)] -> e1fvs
2089 | _ -> failwith "not possible" in
2090 quantify guard e1fvs (real_make_match label true header)
2091 | Ast.OptCase(case_line) -> failwith "not supported")
2092 cases in
34e49164
C
2093 let lv = get_label_ctr() in
2094 let used = ref false in
fc1ad971
C
2095 let (decls_exists_code,decls_all_code) =
2096 (*don't really understand this*)
2097 if (Ast.undots decls) = []
2098 then (CTL.True,CTL.False)
2099 else
2100 let res =
2101 statement_list decls Tail
2102 new2_quantified new2_mquantified (Some (lv,used)) llabel None
2103 false(*?*) guard in
2104 (res,res) in
2105 let no_header =
2106 ctl_not
2107 (List.fold_left ctl_or_fl CTL.False
951c7801
C
2108 (List.map ctl_uncheck
2109 (decls_all_code::case_headers))) in
34e49164
C
2110 let case_code =
2111 List.map
2112 (function case_line ->
2113 match Ast.unwrap case_line with
2114 Ast.CaseLine(header,body) ->
2115 let (e1fvs,b1fvs,s1fvs) =
2116 let fvs = [Ast.get_fvs header;Ast.get_fvs body] in
2117 match seq_fvs new2_quantified fvs with
2118 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
2119 | _ -> failwith "not possible" in
2120 let (me1fvs,mb1fvs,ms1fvs) =
2121 let fvs = [Ast.get_mfvs header;Ast.get_mfvs body] in
2122 match seq_fvs new2_mquantified fvs with
2123 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
2124 | _ -> failwith "not possible" in
2125 let case_header =
2126 quantify guard e1fvs (make_match header) in
2127 let new3_quantified = union b1fvs new2_quantified in
2128 let new3_mquantified = union mb1fvs new2_mquantified in
2129 let body =
2130 statement_list body Tail
fc1ad971
C
2131 new3_quantified new3_mquantified (Some (lv,used)) llabel
2132 (Some (lv,used)) false(*?*) guard in
34e49164
C
2133 quantify guard b1fvs (make_seq [case_header; body])
2134 | Ast.OptCase(case_line) -> failwith "not supported")
2135 cases in
2136 let default_required =
2137 if List.exists
2138 (function case ->
2139 match Ast.unwrap case with
2140 Ast.CaseLine(header,_) ->
2141 (match Ast.unwrap header with
2142 Ast.Default(_,_) -> true
2143 | _ -> false)
2144 | _ -> false)
2145 cases
2146 then function x -> x
2147 else function x -> ctl_or (fallpred label) x in
2148 let after_pred = aftpred label in
2149 let body after_branch =
2150 ctl_or
2151 (default_required
2152 (quantify guard b2fvs
2153 (make_seq
2154 [ctl_and lb
2155 (List.fold_left ctl_and CTL.True
fc1ad971
C
2156 (List.map ctl_ex
2157 (decls_exists_code :: case_headers)));
2158 List.fold_left ctl_or_fl no_header
2159 (decls_all_code :: case_code)])))
34e49164
C
2160 after_branch in
2161 let aft =
2162 (rb_fvs,Ast.get_fresh rb,Ast.get_inherited rb,
2163 match Ast.unwrap rb with
2164 Ast.SeqEnd(rb) -> Ast.get_mcodekind rb
2165 | _ -> failwith "not possible") in
2166 let (switch_header,wrapper) =
2167 if !used
2168 then
2169 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
2170 (ctl_and switch_header label_pred,
2171 (function body -> quantify true [lv] body))
2172 else (switch_header,function x -> x) in
2173 wrapper
2174 (end_control_structure b1fvs switch_header body
2175 after_pred (Some(ctl_ex after_pred)) None aft after label guard)
708f4980
C
2176 | Ast.FunDecl(header,lbrace,body,rbrace) ->
2177 let (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,rbfvs) =
34e49164
C
2178 match
2179 seq_fvs quantified
708f4980 2180 [Ast.get_fvs header;Ast.get_fvs lbrace;
34e49164
C
2181 Ast.get_fvs body;Ast.get_fvs rbrace]
2182 with
708f4980
C
2183 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(rbfvs,_)] ->
2184 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,rbfvs)
34e49164 2185 | _ -> failwith "not possible" in
708f4980 2186 let (mhfvs,mb1fvs,mlbfvs,mb2fvs,mb3fvs,mrbfvs) =
34e49164
C
2187 match
2188 seq_fvs quantified
708f4980 2189 [Ast.get_mfvs header;Ast.get_mfvs lbrace;
34e49164
C
2190 Ast.get_mfvs body;Ast.get_mfvs rbrace]
2191 with
708f4980
C
2192 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(rbfvs,_)] ->
2193 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,rbfvs)
34e49164
C
2194 | _ -> failwith "not possible" in
2195 let function_header = quantify guard hfvs (make_match header) in
2196 let start_brace = quantify guard lbfvs (make_match lbrace) in
2197 let stripped_rbrace =
2198 match Ast.unwrap rbrace with
2199 Ast.SeqEnd((data,info,_,_)) ->
2200 Ast.rewrap rbrace(Ast.SeqEnd (Ast.make_mcode data))
2201 | _ -> failwith "unexpected close brace" in
2202 let end_brace =
2203 let exit = CTL.Pred (Lib_engine.Exit,CTL.Control) in
2204 let errorexit = CTL.Pred (Lib_engine.ErrorExit,CTL.Control) in
2205 let fake_brace = CTL.Pred (Lib_engine.FakeBrace,CTL.Control) in
2206 ctl_and
2207 (quantify guard rbfvs (make_match rbrace))
2208 (ctl_and
2209 (* the following finds the beginning of the fake braces,
2210 if there are any, not completely sure how this works.
2211 sse the examples sw and return *)
2212 (ctl_back_ex (ctl_not fake_brace))
2213 (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in
2214 let new_quantified3 =
2215 Common.union_set b1fvs
2216 (Common.union_set b2fvs (Common.union_set b3fvs quantified)) in
34e49164
C
2217 let new_mquantified3 =
2218 Common.union_set mb1fvs
2219 (Common.union_set mb2fvs
2220 (Common.union_set mb3fvs minus_quantified)) in
5636bb2c 2221 let not_minus = function Ast.MINUS(_,_,_,_) -> false | _ -> true in
978fd7e5 2222 let optim1 =
708f4980 2223 match (Ast.undots body,
91eba41f 2224 contains_modif rbrace or contains_pos rbrace) with
708f4980 2225 ([body],false) ->
34e49164 2226 (match Ast.unwrap body with
5636bb2c
C
2227 Ast.Nest(starter,stmt_dots,ender,[],false,_,_)
2228 (* perhaps could optimize for minus case too... TODO *)
2229 when not_minus (Ast.get_mcodekind starter)
2230 ->
978fd7e5
C
2231 (* special case for function header + body - header is unambiguous
2232 and unique, so we can just look for the nested body anywhere
2233 else in the CFG *)
2234 Some
2235 (CTL.AndAny
2236 (CTL.FORWARD,guard_to_strict guard,start_brace,
2237 statement_list stmt_dots
2238 (* discards match on right brace, but don't need it *)
2239 (Guard (make_seq_after end_brace after))
2240 new_quantified3 new_mquantified3
2241 None llabel slabel true guard))
2242 | Ast.Dots((_,i,d,_),whencode,_,_) when
1be43e12
C
2243 (List.for_all
2244 (* flow sensitive, so not optimizable *)
2245 (function Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2246 false
2247 | _ -> true) whencode) ->
978fd7e5
C
2248 (* try to be more efficient for the case where the body is just
2249 ... Perhaps this is too much of a special case, but useful
2250 for dropping a parameter and checking that it is never used. *)
2251 (match d with
2252 Ast.MINUS(_,_,_,_) -> None
2253 | _ ->
18b1275a
C
2254 let pv =
2255 (* no nested braces, because only dots *)
2256 string2var ("p1") in
2257 let paren_pred =
2258 CTL.Pred(Lib_engine.Paren pv,CTL.Control) in
978fd7e5
C
2259 Some (
2260 make_seq
18b1275a 2261 [ctl_and start_brace paren_pred;
978fd7e5
C
2262 match whencode with
2263 [] -> CTL.True
2264 | _ ->
2265 let leftarg =
2266 ctl_and
2267 (ctl_not
2268 (List.fold_left
2269 (function prev ->
2270 function
2271 Ast.WhenAlways(s) -> prev
2272 | Ast.WhenNot(sl) ->
2273 let x =
2274 statement_list sl Tail
2275 new_quantified3
2276 new_mquantified3
2277 label llabel slabel
2278 true true in
2279 ctl_or prev x
2280 | Ast.WhenNotTrue(_)
2281 | Ast.WhenNotFalse(_) ->
2282 failwith "unexpected"
2283 | Ast.WhenModifier
2284 (Ast.WhenAny) -> CTL.False
2285 | Ast.WhenModifier(_) -> prev)
2286 CTL.False whencode))
2287 (List.fold_left
2288 (function prev ->
2289 function
2290 Ast.WhenAlways(s) ->
2291 let x =
2292 statement s Tail
2293 new_quantified3
2294 new_mquantified3
2295 label llabel slabel true in
2296 ctl_and prev x
2297 | Ast.WhenNot(sl) -> prev
2298 | Ast.WhenNotTrue(_)
2299 | Ast.WhenNotFalse(_) ->
2300 failwith "unexpected"
2301 | Ast.WhenModifier(Ast.WhenAny) ->
2302 CTL.True
2303 | Ast.WhenModifier(_) -> prev)
2304 CTL.True whencode) in
18b1275a
C
2305 ctl_au leftarg
2306 (ctl_and
2307 (make_match stripped_rbrace)
2308 paren_pred)]))
978fd7e5
C
2309 | _ -> None)
2310 | _ -> None in
2311 let optim2 =
2312 (* function body is all minus, no whencode *)
2313 match Ast.undots body with
2314 [body] ->
ae4735db 2315 (match Ast.unwrap body with
978fd7e5
C
2316 Ast.Dots
2317 ((_,i,(Ast.MINUS(_,_,_,[]) as d),_),[],_,_) ->
2318 (match (Ast.unwrap lbrace,Ast.unwrap rbrace) with
2319 (Ast.SeqStart((_,_,Ast.MINUS(_,_,_,[]),_)),
2320 Ast.SeqEnd((_,_,Ast.MINUS(_,_,_,[]),_)))
2321 when not (contains_pos rbrace) ->
2322 Some
2323 (* andany drops everything to the end, including close
2324 braces - not just function body, could check
2325 label to keep braces *)
2326 (ctl_and start_brace
2327 (ctl_ax
2328 (CTL.AndAny
2329 (CTL.FORWARD,guard_to_strict guard,CTL.True,
2330 make_match
2331 (make_meta_rule_elem d ([],[],[]))))))
2332 | _ -> None)
34e49164
C
2333 | _ -> None)
2334 | _ -> None in
2335 let body_code =
978fd7e5
C
2336 match (optim1,optim2) with
2337 (Some o1,_) -> o1
2338 | (_,Some o2) -> o2
2339 | _ ->
34e49164
C
2340 make_seq
2341 [start_brace;
2342 quantify guard b3fvs
708f4980
C
2343 (statement_list body
2344 (After (make_seq_after end_brace after))
34e49164
C
2345 new_quantified3 new_mquantified3 None llabel slabel
2346 false guard)] in
2347 quantify guard b1fvs
2348 (make_seq [function_header; quantify guard b2fvs body_code])
2349 | Ast.Define(header,body) ->
2350 let (hfvs,bfvs,bodyfvs) =
2351 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body]
2352 with
2353 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2354 | _ -> failwith "not possible" in
2355 let (mhfvs,mbfvs,mbodyfvs) =
2356 match seq_fvs minus_quantified [Ast.get_mfvs header;Ast.get_mfvs body]
2357 with
2358 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2359 | _ -> failwith "not possible" in
2360 let define_header = quantify guard hfvs (make_match header) in
2361 let body_code =
2362 statement_list body after
2363 (Common.union_set bfvs quantified)
2364 (Common.union_set mbfvs minus_quantified)
2365 None llabel slabel true guard in
2366 quantify guard bfvs (make_seq [define_header; body_code])
2367 | Ast.OptStm(stm) ->
2368 failwith "OptStm should have been compiled away\n"
2369 | Ast.UniqueStm(stm) -> failwith "arities not yet supported"
2370 | _ -> failwith "not supported" in
2371 if guard or !dots_done
2372 then term
2373 else
2374 do_between_dots stmt term after quantified minus_quantified
2375 label llabel slabel guard
2376
2377(* term is the translation of stmt *)
2378and do_between_dots stmt term after quantified minus_quantified
2379 label llabel slabel guard =
2380 match Ast.get_dots_bef_aft stmt with
2381 Ast.AddingBetweenDots (brace_term,n)
2382 | Ast.DroppingBetweenDots (brace_term,n) ->
2383 let match_brace =
2384 statement brace_term after quantified minus_quantified
2385 label llabel slabel guard in
2386 let v = Printf.sprintf "_r_%d" n in
2387 let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in
2388 let case2 = ctl_and CTL.NONSTRICT (ctl_not (CTL.Ref v)) term in
2389 CTL.Let
2390 (v,ctl_or
2391 (ctl_back_ex (ctl_or (truepred label) (inlooppred label)))
2392 (ctl_back_ex (ctl_back_ex (falsepred label))),
ae4735db 2393 ctl_or case1 case2)
34e49164
C
2394 | Ast.NoDots -> term
2395
2396(* un_process_bef_aft is because we don't want to do transformation in this
2397 code, and thus don't case about braces before or after it *)
2398and process_bef_aft quantified minus_quantified label llabel slabel guard =
2399 function
2400 Ast.WParen (re,n) ->
2401 let paren_pred = CTL.Pred (Lib_engine.Paren n,CTL.Control) in
2402 let s = guard_to_strict guard in
2403 quantify true (get_unquantified quantified [n])
2404 (ctl_and s (make_raw_match None guard re) paren_pred)
2405 | Ast.Other s ->
2406 statement s Tail quantified minus_quantified label llabel slabel guard
2407 | Ast.Other_dots d ->
2408 statement_list d Tail quantified minus_quantified
2409 label llabel slabel true guard
2410
2411(* --------------------------------------------------------------------- *)
2412(* cleanup: convert AX to EX for pdots.
2413Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2414This is what we wanted in the first place, but it wasn't possible to make
2415because the AX and its argument are not created in the same place.
2416Rather clunky... *)
2417(* also cleanup XX, which is a marker for the case where the programmer
2418specifies to change the quantifier on .... Assumed to only occur after one AX
2419or EX, or at top level. *)
2420
2421let rec cleanup c =
2422 let c = match c with CTL.XX(c) -> c | _ -> c in
2423 match c with
2424 CTL.False -> CTL.False
2425 | CTL.True -> CTL.True
2426 | CTL.Pred(p) -> CTL.Pred(p)
2427 | CTL.Not(phi) -> CTL.Not(cleanup phi)
2428 | CTL.Exists(keep,v,phi) -> CTL.Exists(keep,v,cleanup phi)
2429 | CTL.AndAny(dir,s,phi1,phi2) ->
2430 CTL.AndAny(dir,s,cleanup phi1,cleanup phi2)
2431 | CTL.HackForStmt(dir,s,phi1,phi2) ->
2432 CTL.HackForStmt(dir,s,cleanup phi1,cleanup phi2)
2433 | CTL.And(s,phi1,phi2) -> CTL.And(s,cleanup phi1,cleanup phi2)
2434 | CTL.Or(phi1,phi2) -> CTL.Or(cleanup phi1,cleanup phi2)
2435 | CTL.SeqOr(phi1,phi2) -> CTL.SeqOr(cleanup phi1,cleanup phi2)
2436 | CTL.Implies(phi1,phi2) -> CTL.Implies(cleanup phi1,cleanup phi2)
2437 | CTL.AF(dir,s,phi1) -> CTL.AF(dir,s,cleanup phi1)
2438 | CTL.AX(CTL.FORWARD,s,
2439 CTL.Let(v1,e1,
2440 CTL.And(CTL.NONSTRICT,CTL.AU(CTL.FORWARD,s2,e2,e3),
2441 CTL.EU(CTL.FORWARD,e4,e5)))) ->
2442 CTL.Let(v1,e1,
2443 CTL.And(CTL.NONSTRICT,
2444 CTL.AX(CTL.FORWARD,s,CTL.AU(CTL.FORWARD,s2,e2,e3)),
2445 CTL.EX(CTL.FORWARD,CTL.EU(CTL.FORWARD,e4,e5))))
1be43e12 2446 | CTL.AX(dir,s,CTL.XX(phi)) -> CTL.EX(dir,cleanup phi)
34e49164 2447 | CTL.EX(dir,CTL.XX((CTL.AU(_,s,_,_)) as phi)) ->
1be43e12 2448 CTL.AX(dir,s,cleanup phi)
34e49164
C
2449 | CTL.XX(phi) -> failwith "bad XX"
2450 | CTL.AX(dir,s,phi1) -> CTL.AX(dir,s,cleanup phi1)
2451 | CTL.AG(dir,s,phi1) -> CTL.AG(dir,s,cleanup phi1)
2452 | CTL.EF(dir,phi1) -> CTL.EF(dir,cleanup phi1)
2453 | CTL.EX(dir,phi1) -> CTL.EX(dir,cleanup phi1)
2454 | CTL.EG(dir,phi1) -> CTL.EG(dir,cleanup phi1)
2455 | CTL.AW(dir,s,phi1,phi2) -> CTL.AW(dir,s,cleanup phi1,cleanup phi2)
2456 | CTL.AU(dir,s,phi1,phi2) -> CTL.AU(dir,s,cleanup phi1,cleanup phi2)
2457 | CTL.EU(dir,phi1,phi2) -> CTL.EU(dir,cleanup phi1,cleanup phi2)
2458 | CTL.Let (x,phi1,phi2) -> CTL.Let (x,cleanup phi1,cleanup phi2)
2459 | CTL.LetR (dir,x,phi1,phi2) -> CTL.LetR (dir,x,cleanup phi1,cleanup phi2)
2460 | CTL.Ref(s) -> CTL.Ref(s)
2461 | CTL.Uncheck(phi1) -> CTL.Uncheck(cleanup phi1)
2462 | CTL.InnerAnd(phi1) -> CTL.InnerAnd(cleanup phi1)
2463
2464(* --------------------------------------------------------------------- *)
2465(* Function declaration *)
2466
978fd7e5
C
2467(* ua = used_after, fua = fresh_used_after, fuas = fresh_used_after_seeds *)
2468
2469let top_level name ((ua,pos),fua) (fuas,t) =
34e49164
C
2470 let ua = List.filter (function (nm,_) -> nm = name) ua in
2471 used_after := ua;
2472 saved := Ast.get_saved t;
978fd7e5 2473 let quantified = Common.minus_set (Common.union_set ua fuas) pos in
34e49164
C
2474 quantify false quantified
2475 (match Ast.unwrap t with
2476 Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo"
2477 | Ast.DECL(stmt) ->
2478 let unopt = elim_opt.V.rebuilder_statement stmt in
2479 let unopt = preprocess_dots_e unopt in
2480 cleanup(statement unopt VeryEnd quantified [] None None None false)
2481 | Ast.CODE(stmt_dots) ->
2482 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in
2483 let unopt = preprocess_dots unopt in
2484 let starts_with_dots =
2485 match Ast.undots stmt_dots with
2486 d::ds ->
2487 (match Ast.unwrap d with
2488 Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
2489 | Ast.Stars(_,_,_,_) -> true
2490 | _ -> false)
2491 | _ -> false in
2492 let starts_with_brace =
2493 match Ast.undots stmt_dots with
2494 d::ds ->
2495 (match Ast.unwrap d with
2496 Ast.Seq(_) -> true
2497 | _ -> false)
2498 | _ -> false in
2499 let res =
2500 statement_list unopt VeryEnd quantified [] None None None
2501 false false in
2502 cleanup
2503 (if starts_with_dots
2504 then
2505 (* EX because there is a loop on enter/top *)
2506 ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res)
2507 else if starts_with_brace
2508 then
2509 ctl_and CTL.NONSTRICT
2510 (ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res
2511 else res)
2512 | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords")
2513
2514(* --------------------------------------------------------------------- *)
2515(* Entry points *)
2516
978fd7e5
C
2517let asttoctlz (name,(_,_,exists_flag),l)
2518 (used_after,fresh_used_after,fresh_used_after_seeds) positions =
34e49164
C
2519 letctr := 0;
2520 labelctr := 0;
2521 (match exists_flag with
2522 Ast.Exists -> exists := Exists
2523 | Ast.Forall -> exists := Forall
34e49164
C
2524 | Ast.Undetermined ->
2525 exists := if !Flag.sgrep_mode2 then Exists else Forall);
2526
2527 let (l,used_after) =
2528 List.split
2529 (List.filter
2530 (function (t,_) ->
2531 match Ast.unwrap t with Ast.ERRORWORDS(exps) -> false | _ -> true)
2532 (List.combine l (List.combine used_after positions))) in
978fd7e5
C
2533 let res =
2534 List.map2 (top_level name)
2535 (List.combine used_after fresh_used_after)
2536 (List.combine fresh_used_after_seeds l) in
34e49164
C
2537 exists := Forall;
2538 res
2539
2540let asttoctl r used_after positions =
2541 match r with
b1b2de81 2542 Ast.ScriptRule _ | Ast.InitialScriptRule _ | Ast.FinalScriptRule _ -> []
faf9a90c
C
2543 | Ast.CocciRule (a,b,c,_,Ast_cocci.Normal) ->
2544 asttoctlz (a,b,c) used_after positions
2545 | Ast.CocciRule (a,b,c,_,Ast_cocci.Generated) -> [CTL.True]
34e49164
C
2546
2547let pp_cocci_predicate (pred,modif) =
2548 Pretty_print_engine.pp_predicate pred
2549
2550let cocci_predicate_to_string (pred,modif) =
2551 Pretty_print_engine.predicate_to_string pred