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