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