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