2 * Copyright 2005-2008, 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.
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.
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.
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/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
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*)
28 type ex = Exists | Forall | ReverseForall
29 let exists = ref Forall
31 module Ast = Ast_cocci
32 module V = Visitor_ast
35 let warning s = Printf.fprintf stderr "warning: %s\n" s
37 type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif
39 (cocci_predicate,Ast.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl
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
45 let foldl1 f xs = List.fold_left f (List.hd xs) (List.tl xs)
47 let xs = List.rev xs in List.fold_left f (List.hd xs) (List.tl xs)
49 let used_after = ref ([] : Ast.meta_name list)
50 let guard_to_strict guard = if guard then CTL.NONSTRICT else CTL.STRICT
52 let saved = ref ([] : Ast.meta_name list)
54 let string2var x = ("",x)
56 (* --------------------------------------------------------------------- *)
57 (* predicates matching various nodes in the graph *)
61 (CTL.False,_) | (_,CTL.False) -> CTL.False
62 | (CTL.True,a) | (a,CTL.True) -> a
67 (CTL.True,_) | (_,CTL.True) -> CTL.True
68 | (CTL.False,a) | (a,CTL.False) -> a
73 (CTL.True,_) | (_,CTL.True) -> CTL.True
74 | (CTL.False,a) | (a,CTL.False) -> a
79 (CTL.True,_) | (_,CTL.True) -> CTL.True
80 | (CTL.False,a) | (a,CTL.False) -> a
83 let ctl_not = function
85 | CTL.False -> CTL.True
88 let ctl_ax s = function
90 | CTL.False -> CTL.False
93 Exists -> CTL.EX(CTL.FORWARD,x)
94 | Forall -> CTL.AX(CTL.FORWARD,s,x)
95 | ReverseForall -> failwith "not supported"
97 let ctl_ax_absolute s = function
99 | CTL.False -> CTL.False
100 | x -> CTL.AX(CTL.FORWARD,s,x)
102 let ctl_ex = function
104 | CTL.False -> CTL.False
105 | x -> CTL.EX(CTL.FORWARD,x)
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
111 | CTL.False -> CTL.False
112 | x -> CTL.AX(CTL.BACKWARD,CTL.NONSTRICT,x)
114 let ctl_back_ex = function
116 | CTL.False -> CTL.False
117 | x -> CTL.EX(CTL.BACKWARD,x)
119 let ctl_ef = function
121 | CTL.False -> CTL.False
122 | x -> CTL.EF(CTL.FORWARD,x)
124 let ctl_ag s = function
126 | CTL.False -> CTL.False
127 | x -> CTL.AG(CTL.FORWARD,s,x)
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"
138 let ctl_anti_au s x y = (* only for ..., where the quantifier is changed *)
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")
148 let ctl_uncheck = function
150 | CTL.False -> CTL.False
153 let label_pred_maker = function
155 | Some (label_var,used) ->
157 CTL.Pred(Lib_engine.PrefixLabel(label_var),CTL.Control)
159 let bclabel_pred_maker = function
161 | Some (label_var,used) ->
163 CTL.Pred(Lib_engine.BCLabel(label_var),CTL.Control)
165 let predmaker guard pred label =
166 ctl_and (guard_to_strict guard) (CTL.Pred pred) (label_pred_maker label)
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)
180 let aftret label_var f = ctl_or (aftpred label_var) (exitpred label_var)
186 Printf.sprintf "r%d" cur
188 (* --------------------------------------------------------------------- *)
189 (* --------------------------------------------------------------------- *)
190 (* Eliminate OptStm *)
192 (* for optional thing with nothing after, should check that the optional thing
193 never occurs. otherwise the matching stops before it occurs *)
196 let donothing r k e = k e in
199 List.fold_left Common.union_set [] (List.map Ast.get_fvs l) in
202 List.fold_left Common.union_set [] (List.map Ast.get_mfvs l) in
205 List.fold_left Common.union_set [] (List.map Ast.get_fresh l) in
207 let inheritedlist l =
208 List.fold_left Common.union_set [] (List.map Ast.get_inherited l) in
211 List.fold_left Common.union_set [] (List.map Ast.get_saved l) in
214 (fvlist l, mfvlist l, freshlist l, inheritedlist l, savedlist l) in
216 let rec dots_list unwrapped wrapped =
217 match (unwrapped,wrapped) with
220 | (Ast.Dots(_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest,
222 | (Ast.Nest(_,_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest,
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
234 [{(Ast.make_term(Ast.DOTS(new_rest1))) with
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
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
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}]
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
265 [{(Ast.make_term(Ast.DOTS(new_rest2))) with
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
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
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}]
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
306 [{(Ast.make_term(Ast.DOTS([stm]))) with
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
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
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}]
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
333 [rwd(Ast.DOTS([stm]));
334 {(Ast.make_term(Ast.DOTS([rw dots])))
335 with Ast.node_line = l}])]
337 | (_::urest,stm::rest) -> stm :: (dots_list urest rest)
338 | _ -> failwith "not possible" in
340 let stmtdotsfn r k 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
349 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
351 donothing donothing stmtdotsfn donothing
352 donothing donothing donothing donothing donothing donothing donothing
353 donothing donothing donothing donothing donothing
355 (* --------------------------------------------------------------------- *)
356 (* after management *)
357 (* We need Guard for the following case:
366 Here the inner <... b ...> should not go past foo. But foo is not the
367 "after" of the body of the outer nest, because we don't want to search for
368 it in the case where the body of the outer nest ends in something other
369 than dots or a nest. *)
371 (* what is the difference between tail and end??? *)
373 type after = After of formula | Guard of formula | Tail | End | VeryEnd
375 let a2n = function After x -> Guard x | a -> a
378 let pp_pred (x,_) = Pretty_print_engine.pp_predicate x in
379 let pp_meta (_,x) = Common.pp x in
380 Pretty_print_ctl.pp_ctl (pp_pred,pp_meta) false x;
381 Format.print_newline()
383 let print_after = function
384 After ctl -> Printf.printf "After:\n"; print_ctl ctl
385 | Guard ctl -> Printf.printf "Guard:\n"; print_ctl ctl
386 | Tail -> Printf.printf "Tail\n"
387 | VeryEnd -> Printf.printf "Very End\n"
388 | End -> Printf.printf "End\n"
390 (* --------------------------------------------------------------------- *)
393 let fresh_var _ = string2var "_v"
394 let fresh_pos _ = string2var "_pos" (* must be a constant *)
396 let fresh_metavar _ = "_S"
398 (* fvinfo is going to end up being from the whole associated statement.
399 it would be better if it were just the free variables in d, but free_vars.ml
400 doesn't keep track of free variables on + code *)
401 let make_meta_rule_elem d fvinfo =
402 let nm = fresh_metavar() in
403 Ast.make_meta_rule_elem nm d fvinfo
405 let get_unquantified quantified vars =
406 List.filter (function x -> not (List.mem x quantified)) vars
408 let make_seq guard l =
409 let s = guard_to_strict guard in
410 foldr1 (function rest -> function cur -> ctl_and s cur (ctl_ax s rest)) l
412 let make_seq_after2 guard first rest =
413 let s = guard_to_strict guard in
415 After rest -> ctl_and s first (ctl_ax s (ctl_ax s rest))
418 let make_seq_after guard first rest =
420 After rest -> make_seq guard [first;rest]
423 let opt_and guard first rest =
424 let s = guard_to_strict guard in
427 | Some first -> ctl_and s first rest
429 let and_after guard first rest =
430 let s = guard_to_strict guard in
431 match rest with After rest -> ctl_and s first rest | _ -> first
434 let bind x y = x or y in
435 let option_default = false in
436 let mcode r (_,_,kind,_) =
438 Ast.MINUS(_,_) -> true
439 | Ast.PLUS -> failwith "not possible"
440 | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in
441 let do_nothing r k e = k e in
442 let rule_elem r k re =
444 match Ast.unwrap re with
445 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
446 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
447 | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
450 V.combiner bind option_default
451 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
453 do_nothing do_nothing do_nothing do_nothing
454 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
455 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
456 recursor.V.combiner_rule_elem
458 (* code is not a DisjRuleElem *)
459 let make_match label guard code =
460 let v = fresh_var() in
461 let matcher = Lib_engine.Match(code) in
462 if contains_modif code && not guard
463 then CTL.Exists(true,v,predmaker guard (matcher,CTL.Modif v) label)
465 let iso_info = !Flag.track_iso_usage && not (Ast.get_isos code = []) in
466 (match (iso_info,!onlyModif,guard,
467 intersect !used_after (Ast.get_fvs code)) with
468 (false,true,_,[]) | (_,_,true,_) ->
469 predmaker guard (matcher,CTL.Control) label
470 | _ -> CTL.Exists(true,v,predmaker guard (matcher,CTL.UnModif v) label))
472 let make_raw_match label guard code =
473 predmaker guard (Lib_engine.Match(code),CTL.Control) label
475 let rec seq_fvs quantified = function
478 let t1fvs = get_unquantified quantified fv1 in
480 List.fold_left Common.union_set []
481 (List.map (get_unquantified quantified) fvs) in
482 let bothfvs = Common.inter_set t1fvs termfvs in
483 let t1onlyfvs = Common.minus_set t1fvs bothfvs in
484 let new_quantified = Common.union_set bothfvs quantified in
485 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs)
490 function code -> CTL.Exists (not guard && List.mem cur !saved,cur,code))
492 let non_saved_quantify =
494 (function cur -> function code -> CTL.Exists (false,cur,code))
496 let intersectll lst nested_list =
497 List.filter (function x -> List.exists (List.mem x) nested_list) lst
499 (* --------------------------------------------------------------------- *)
500 (* Count depth of braces. The translation of a closed brace appears deeply
501 nested within the translation of the sequence term, so the name of the
502 paren var has to take into account the names of the nested braces. On the
503 other hand the close brace does not escape, so we don't have to take into
504 account other paren variable names. *)
506 (* called repetitively, which is inefficient, but less trouble than adding a
507 new field to Seq and FunDecl *)
508 let count_nested_braces s =
509 let bind x y = max x y in
510 let option_default = 0 in
511 let stmt_count r k s =
512 match Ast.unwrap s with
513 Ast.Seq(_,_,_,_) | Ast.FunDecl(_,_,_,_,_) -> (k s) + 1
515 let donothing r k e = k e in
517 let recursor = V.combiner bind option_default
518 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
520 donothing donothing donothing donothing
521 donothing donothing donothing donothing donothing donothing
522 donothing donothing stmt_count donothing donothing donothing in
523 let res = string_of_int (recursor.V.combiner_statement s) in
527 let get_label_ctr _ =
528 let cur = !labelctr in
530 string2var (Printf.sprintf "l%d" cur)
532 (* --------------------------------------------------------------------- *)
533 (* annotate dots with before and after neighbors *)
535 let print_bef_aft = function
537 Printf.printf "bef/aft\n";
538 Pretty_print_cocci.rule_elem "" re;
539 Format.print_newline()
541 Printf.printf "bef/aft\n";
542 Pretty_print_cocci.statement "" s;
543 Format.print_newline()
544 | Ast.Other_dots d ->
545 Printf.printf "bef/aft\n";
546 Pretty_print_cocci.statement_dots d;
547 Format.print_newline()
549 (* [] can only occur if we are in a disj, where it comes from a ? In that
550 case, we want to use a, which accumulates all of the previous patterns in
552 let rec get_before_elem sl a =
553 match Ast.unwrap sl with
557 [] -> ([],Common.Right a)
559 let (e,ea) = get_before_e e a in
562 let (e,ea) = get_before_e e a in
563 let (sl,sla) = loop sl ea in
565 let (l,a) = loop x a in
566 (Ast.rewrap sl (Ast.DOTS(l)),a)
567 | Ast.CIRCLES(x) -> failwith "not supported"
568 | Ast.STARS(x) -> failwith "not supported"
570 and get_before sl a =
571 match get_before_elem sl a with
572 (term,Common.Left x) -> (term,x)
573 | (term,Common.Right x) -> (term,x)
575 and get_before_whencode wc =
578 Ast.WhenNot w -> let (w,_) = get_before w [] in Ast.WhenNot w
579 | Ast.WhenAlways w -> let (w,_) = get_before_e w [] in Ast.WhenAlways w
580 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
581 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
582 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
585 and get_before_e s a =
586 match Ast.unwrap s with
587 Ast.Dots(d,w,_,aft) ->
588 (Ast.rewrap s (Ast.Dots(d,get_before_whencode w,a,aft)),a)
589 | Ast.Nest(stmt_dots,w,multi,_,aft) ->
590 let w = get_before_whencode w in
591 let (sd,_) = get_before stmt_dots a in
597 Unify_ast.unify_statement_dots
598 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
600 Unify_ast.MAYBE -> false
602 | Ast.Other_dots a ->
603 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
605 Unify_ast.MAYBE -> false
609 (Ast.rewrap s (Ast.Nest(sd,w,multi,a,aft)),[Ast.Other_dots stmt_dots])
610 | Ast.Disj(stmt_dots_list) ->
612 List.split (List.map (function e -> get_before e a) stmt_dots_list) in
613 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
615 (match Ast.unwrap ast with
616 Ast.MetaStmt(_,_,_,_) -> (s,[])
617 | _ -> (s,[Ast.Other s]))
618 | Ast.Seq(lbrace,decls,body,rbrace) ->
619 let index = count_nested_braces s in
620 let (de,dea) = get_before decls [Ast.WParen(lbrace,index)] in
621 let (bd,_) = get_before body dea in
622 (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)),
623 [Ast.WParen(rbrace,index)])
624 | Ast.Define(header,body) ->
625 let (body,_) = get_before body [] in
626 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
627 | Ast.IfThen(ifheader,branch,aft) ->
628 let (br,_) = get_before_e branch [] in
629 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)), [Ast.Other s])
630 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
631 let (br1,_) = get_before_e branch1 [] in
632 let (br2,_) = get_before_e branch2 [] in
633 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
634 | Ast.While(header,body,aft) ->
635 let (bd,_) = get_before_e body [] in
636 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
637 | Ast.For(header,body,aft) ->
638 let (bd,_) = get_before_e body [] in
639 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
640 | Ast.Do(header,body,tail) ->
641 let (bd,_) = get_before_e body [] in
642 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
643 | Ast.Iterator(header,body,aft) ->
644 let (bd,_) = get_before_e body [] in
645 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
646 | Ast.Switch(header,lb,cases,rb) ->
649 (function case_line ->
650 match Ast.unwrap case_line with
651 Ast.CaseLine(header,body) ->
652 let (body,_) = get_before body [] in
653 Ast.rewrap case_line (Ast.CaseLine(header,body))
654 | Ast.OptCase(case_line) -> failwith "not supported")
656 (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s])
657 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
658 let (de,dea) = get_before decls [] in
659 let (bd,_) = get_before body dea in
660 (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[])
661 | _ -> failwith "get_before_e: not supported"
663 let rec get_after sl a =
664 match Ast.unwrap sl with
670 let (sl,sla) = loop sl in
671 let (e,ea) = get_after_e e sla in
673 let (l,a) = loop x in
674 (Ast.rewrap sl (Ast.DOTS(l)),a)
675 | Ast.CIRCLES(x) -> failwith "not supported"
676 | Ast.STARS(x) -> failwith "not supported"
678 and get_after_whencode a wc =
681 Ast.WhenNot w -> let (w,_) = get_after w a (*?*) in Ast.WhenNot w
682 | Ast.WhenAlways w -> let (w,_) = get_after_e w a in Ast.WhenAlways w
683 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
684 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
685 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
688 and get_after_e s a =
689 match Ast.unwrap s with
690 Ast.Dots(d,w,bef,_) ->
691 (Ast.rewrap s (Ast.Dots(d,get_after_whencode a w,bef,a)),a)
692 | Ast.Nest(stmt_dots,w,multi,bef,_) ->
693 let w = get_after_whencode a w in
694 let (sd,_) = get_after stmt_dots a in
700 Unify_ast.unify_statement_dots
701 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
703 Unify_ast.MAYBE -> false
705 | Ast.Other_dots a ->
706 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
708 Unify_ast.MAYBE -> false
712 (Ast.rewrap s (Ast.Nest(sd,w,multi,bef,a)),[Ast.Other_dots stmt_dots])
713 | Ast.Disj(stmt_dots_list) ->
715 List.split (List.map (function e -> get_after e a) stmt_dots_list) in
716 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
718 (match Ast.unwrap ast with
719 Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots _,i) ->
720 (* check "after" information for metavar optimization *)
721 (* if the error is not desired, could just return [], then
722 the optimization (check for EF) won't take place *)
726 (match Ast.unwrap x with
727 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) ->
729 "dots/nest not allowed before and after stmt metavar"
731 | Ast.Other_dots x ->
732 (match Ast.undots x with
734 (match Ast.unwrap x with
735 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) ->
737 ("dots/nest not allowed before and after stmt "^
746 (Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots a,i)))),[])
747 | Ast.MetaStmt(_,_,_,_) -> (s,[])
748 | _ -> (s,[Ast.Other s]))
749 | Ast.Seq(lbrace,decls,body,rbrace) ->
750 let index = count_nested_braces s in
751 let (bd,bda) = get_after body [Ast.WParen(rbrace,index)] in
752 let (de,_) = get_after decls bda in
753 (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)),
754 [Ast.WParen(lbrace,index)])
755 | Ast.Define(header,body) ->
756 let (body,_) = get_after body a in
757 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
758 | Ast.IfThen(ifheader,branch,aft) ->
759 let (br,_) = get_after_e branch a in
760 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)),[Ast.Other s])
761 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
762 let (br1,_) = get_after_e branch1 a in
763 let (br2,_) = get_after_e branch2 a in
764 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
765 | Ast.While(header,body,aft) ->
766 let (bd,_) = get_after_e body a in
767 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
768 | Ast.For(header,body,aft) ->
769 let (bd,_) = get_after_e body a in
770 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
771 | Ast.Do(header,body,tail) ->
772 let (bd,_) = get_after_e body a in
773 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
774 | Ast.Iterator(header,body,aft) ->
775 let (bd,_) = get_after_e body a in
776 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
777 | Ast.Switch(header,lb,cases,rb) ->
780 (function case_line ->
781 match Ast.unwrap case_line with
782 Ast.CaseLine(header,body) ->
783 let (body,_) = get_after body [] in
784 Ast.rewrap case_line (Ast.CaseLine(header,body))
785 | Ast.OptCase(case_line) -> failwith "not supported")
787 (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s])
788 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
789 let (bd,bda) = get_after body [] in
790 let (de,_) = get_after decls bda in
791 (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[])
792 | _ -> failwith "get_after_e: not supported"
794 let preprocess_dots sl =
795 let (sl,_) = get_before sl [] in
796 let (sl,_) = get_after sl [] in
799 let preprocess_dots_e sl =
800 let (sl,_) = get_before_e sl [] in
801 let (sl,_) = get_after_e sl [] in
804 (* --------------------------------------------------------------------- *)
805 (* various return_related things *)
807 let rec ends_in_return stmt_list =
808 match Ast.unwrap stmt_list with
810 (match List.rev x with
812 (match Ast.unwrap x with
815 match Ast.unwrap x with
816 Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) -> true
817 | Ast.DisjRuleElem((_::_) as l) -> List.for_all loop l
820 | Ast.Disj(disjs) -> List.for_all ends_in_return disjs
823 | Ast.CIRCLES(x) -> failwith "not supported"
824 | Ast.STARS(x) -> failwith "not supported"
826 (* --------------------------------------------------------------------- *)
829 let exptymatch l make_match make_guard_match =
830 let pos = fresh_pos() in
831 let matches_guard_matches =
834 let pos = Ast.make_mcode pos in
835 (make_match (Ast.set_pos x (Some pos)),
836 make_guard_match (Ast.set_pos x (Some pos))))
838 let (matches,guard_matches) = List.split matches_guard_matches in
839 let rec suffixes = function
841 | x::xs -> xs::(suffixes xs) in
842 let prefixes = List.rev (suffixes (List.rev guard_matches)) in
843 let info = (* not null *)
849 ctl_and CTL.NONSTRICT matcher
851 (ctl_uncheck (List.fold_left ctl_or_fl CTL.False negates)))))
853 CTL.InnerAnd(List.fold_left ctl_or_fl CTL.False (List.rev info))
855 (* code might be a DisjRuleElem, in which case we break it apart
856 code might contain an Exp or Ty
857 this one pushes the quantifier inwards *)
858 let do_re_matches label guard res quantified minus_quantified =
859 let make_guard_match x =
860 let stmt_fvs = Ast.get_mfvs x in
861 let fvs = get_unquantified minus_quantified stmt_fvs in
862 non_saved_quantify fvs (make_match None true x) in
864 let stmt_fvs = Ast.get_fvs x in
865 let fvs = get_unquantified quantified stmt_fvs in
866 quantify guard fvs (make_match None guard x) in
867 ctl_and CTL.NONSTRICT (label_pred_maker label)
868 (match List.map Ast.unwrap res with
869 [] -> failwith "unexpected empty disj"
870 | Ast.Exp(e)::rest -> exptymatch res make_match make_guard_match
871 | Ast.Ty(t)::rest -> exptymatch res make_match make_guard_match
873 if List.exists (function Ast.Exp(_) | Ast.Ty(_) -> true | _ -> false)
875 then failwith "unexpected exp or ty";
876 List.fold_left ctl_seqor CTL.False
877 (List.rev (List.map make_match res)))
879 (* code might be a DisjRuleElem, in which case we break it apart
880 code doesn't contain an Exp or Ty
881 this one is for use when it is not practical to push the quantifier inwards
883 let header_match label guard code : ('a, Ast.meta_name, 'b) CTL.generic_ctl =
884 match Ast.unwrap code with
885 Ast.DisjRuleElem(res) ->
886 let make_match = make_match None guard in
887 let orop = if guard then ctl_or else ctl_seqor in
888 ctl_and CTL.NONSTRICT (label_pred_maker label)
889 (List.fold_left orop CTL.False (List.map make_match res))
890 | _ -> make_match label guard code
892 (* --------------------------------------------------------------------- *)
893 (* control structures *)
895 let end_control_structure fvs header body after_pred
896 after_checks no_after_checks (afvs,afresh,ainh,aft) after label guard =
897 (* aft indicates what is added after the whole if, which has to be added
899 let (aft_needed,after_branch) =
901 Ast.CONTEXT(_,Ast.NOTHING) ->
902 (false,make_seq_after2 guard after_pred after)
905 make_match label guard
906 (make_meta_rule_elem aft (afvs,afresh,ainh)) in
908 make_seq_after guard after_pred
909 (After(make_seq_after guard match_endif after))) in
910 let body = body after_branch in
911 let s = guard_to_strict guard in
916 (match (after,aft_needed) with
917 (After _,_) (* pattern doesn't end here *)
918 | (_,true) (* + code added after *) -> after_checks
919 | _ -> no_after_checks)
920 (ctl_ax_absolute s body)))
922 let ifthen ifheader branch ((afvs,_,_,_) as aft) after
923 quantified minus_quantified label llabel slabel recurse make_match guard =
924 (* "if (test) thn" becomes:
925 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
927 "if (test) thn; after" becomes:
928 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
933 match seq_fvs quantified
934 [Ast.get_fvs ifheader;Ast.get_fvs branch;afvs] with
935 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
936 | _ -> failwith "not possible" in
937 let new_quantified = Common.union_set bfvs quantified in
939 match seq_fvs minus_quantified
940 [Ast.get_mfvs ifheader;Ast.get_mfvs branch;[]] with
941 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
942 | _ -> failwith "not possible" in
943 let new_mquantified = Common.union_set mbfvs minus_quantified in
945 let if_header = quantify guard efvs (make_match ifheader) in
946 (* then branch and after *)
947 let lv = get_label_ctr() in
948 let used = ref false in
951 [truepred label; recurse branch Tail new_quantified new_mquantified
952 (Some (lv,used)) llabel slabel guard] in
953 let after_pred = aftpred label in
954 let or_cases after_branch =
955 ctl_or true_branch (ctl_or (fallpred label) after_branch) in
956 let (if_header,wrapper) =
959 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
960 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
961 (function body -> quantify true [lv] body))
962 else (if_header,function x -> x) in
964 (end_control_structure bfvs if_header or_cases after_pred
965 (Some(ctl_ex after_pred)) None aft after label guard)
967 let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after
968 quantified minus_quantified label llabel slabel recurse make_match guard =
969 (* "if (test) thn else els" becomes:
970 if(test) & AX((TrueBranch & AX thn) v
971 (FalseBranch & AX (else & AX els)) v After)
974 "if (test) thn else els; after" becomes:
975 if(test) & AX((TrueBranch & AX thn) v
976 (FalseBranch & AX (else & AX els)) v
977 (After & AXAX after))
982 let (e1fvs,b1fvs,s1fvs) =
983 match seq_fvs quantified
984 [Ast.get_fvs ifheader;Ast.get_fvs branch1;afvs] with
985 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
986 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
987 | _ -> failwith "not possible" in
988 let (e2fvs,b2fvs,s2fvs) =
990 match seq_fvs quantified
991 [Ast.get_fvs ifheader;Ast.get_fvs branch2;afvs] with
992 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
993 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
994 | _ -> failwith "not possible" in
995 let bothfvs = union (union b1fvs b2fvs) (intersect s1fvs s2fvs) in
996 let exponlyfvs = intersect e1fvs e2fvs in
997 let new_quantified = union bothfvs quantified in
998 (* minus free variables *)
999 let (me1fvs,mb1fvs,ms1fvs) =
1000 match seq_fvs minus_quantified
1001 [Ast.get_mfvs ifheader;Ast.get_mfvs branch1;[]] with
1002 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
1003 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
1004 | _ -> failwith "not possible" in
1005 let (me2fvs,mb2fvs,ms2fvs) =
1007 match seq_fvs minus_quantified
1008 [Ast.get_mfvs ifheader;Ast.get_mfvs branch2;[]] with
1009 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
1010 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
1011 | _ -> failwith "not possible" in
1012 let mbothfvs = union (union mb1fvs mb2fvs) (intersect ms1fvs ms2fvs) in
1013 let new_mquantified = union mbothfvs minus_quantified in
1015 let if_header = quantify guard exponlyfvs (make_match ifheader) in
1016 (* then and else branches *)
1017 let lv = get_label_ctr() in
1018 let used = ref false in
1021 [truepred label; recurse branch1 Tail new_quantified new_mquantified
1022 (Some (lv,used)) llabel slabel guard] in
1025 [falsepred label; make_match els;
1026 recurse branch2 Tail new_quantified new_mquantified
1027 (Some (lv,used)) llabel slabel guard] in
1028 let after_pred = aftpred label in
1029 let or_cases after_branch =
1030 ctl_or true_branch (ctl_or false_branch after_branch) in
1031 let s = guard_to_strict guard in
1032 let (if_header,wrapper) =
1035 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1036 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
1037 (function body -> quantify true [lv] body))
1038 else (if_header,function x -> x) in
1040 (end_control_structure bothfvs if_header or_cases after_pred
1041 (Some(ctl_and s (ctl_ex (falsepred label)) (ctl_ex after_pred)))
1042 (Some(ctl_ex (falsepred label)))
1043 aft after label guard)
1045 let forwhile header body ((afvs,_,_,_) as aft) after
1046 quantified minus_quantified label recurse make_match guard =
1048 (* the translation in this case is similar to that of an if with no else *)
1049 (* free variables *)
1051 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body;afvs] with
1052 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1053 | _ -> failwith "not possible" in
1054 let new_quantified = Common.union_set bfvs quantified in
1055 (* minus free variables *)
1057 match seq_fvs minus_quantified
1058 [Ast.get_mfvs header;Ast.get_mfvs body;[]] with
1059 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1060 | _ -> failwith "not possible" in
1061 let new_mquantified = Common.union_set mbfvs minus_quantified in
1063 let header = quantify guard efvs (make_match header) in
1064 let lv = get_label_ctr() in
1065 let used = ref false in
1069 recurse body Tail new_quantified new_mquantified
1070 (Some (lv,used)) (Some (lv,used)) None guard] in
1071 let after_pred = fallpred label in
1072 let or_cases after_branch = ctl_or body after_branch in
1073 let (header,wrapper) =
1076 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1077 (ctl_and CTL.NONSTRICT(*???*) header label_pred,
1078 (function body -> quantify true [lv] body))
1079 else (header,function x -> x) in
1081 (end_control_structure bfvs header or_cases after_pred
1082 (Some(ctl_ex after_pred)) None aft after label guard) in
1083 match (Ast.unwrap body,aft) with
1084 (Ast.Atomic(re),(_,_,_,Ast.CONTEXT(_,Ast.NOTHING))) ->
1085 (match Ast.unwrap re with
1086 Ast.MetaStmt((_,_,Ast.CONTEXT(_,Ast.NOTHING),_),
1087 Type_cocci.Unitary,_,false) ->
1089 match seq_fvs quantified [Ast.get_fvs header] with
1091 | _ -> failwith "not possible" in
1092 quantify guard efvs (make_match header)
1096 (* --------------------------------------------------------------------- *)
1097 (* statement metavariables *)
1099 (* issue: an S metavariable that is not an if branch/loop body
1100 should not match an if branch/loop body, so check that the labels
1101 of the nodes before the first node matched by the S are different
1102 from the label of the first node matched by the S *)
1103 let sequencibility body label_pred process_bef_aft = function
1104 Ast.Sequencible | Ast.SequencibleAfterDots [] ->
1107 (ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1108 | Ast.SequencibleAfterDots l ->
1109 (* S appears after some dots. l is the code that comes after the S.
1110 want to search for that first, because S can match anything, while
1111 the stuff after is probably more restricted *)
1112 let afts = List.map process_bef_aft l in
1113 let ors = foldl1 ctl_or afts in
1114 ctl_and CTL.NONSTRICT
1115 (ctl_ef (ctl_and CTL.NONSTRICT ors (ctl_back_ax label_pred)))
1118 ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1119 | Ast.NotSequencible -> body (function x -> x)
1121 let svar_context_with_add_after stmt s label quantified d ast
1122 seqible after process_bef_aft guard fvinfo =
1123 let label_var = (*fresh_label_var*) string2var "_lab" in
1125 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
1127 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in
1128 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
1129 let full_metamatch = matcher d in
1130 let first_metamatch =
1133 Ast.CONTEXT(pos,Ast.BEFOREAFTER(bef,_)) ->
1134 Ast.CONTEXT(pos,Ast.BEFORE(bef))
1135 | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1136 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1137 let middle_metamatch =
1140 Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1141 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1142 let last_metamatch =
1145 Ast.CONTEXT(pos,Ast.BEFOREAFTER(_,aft)) ->
1146 Ast.CONTEXT(pos,Ast.AFTER(aft))
1147 | Ast.CONTEXT(_,_) -> d
1148 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1151 ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in
1152 let left_or = (* the whole statement is one node *)
1154 [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in
1155 let right_or = (* the statement covers multiple nodes *)
1158 ctl_au CTL.NONSTRICT
1161 [ctl_and CTL.NONSTRICT last_metamatch label_pred;
1163 (ctl_not prelabel_pred) after])] in
1165 ctl_and CTL.NONSTRICT label_pred
1166 (f (ctl_and CTL.NONSTRICT
1167 (make_raw_match label false ast) (ctl_or left_or right_or))) in
1168 let stmt_fvs = Ast.get_fvs stmt in
1169 let fvs = get_unquantified quantified stmt_fvs in
1170 quantify guard (label_var::fvs)
1171 (sequencibility body label_pred process_bef_aft seqible)
1173 let svar_minus_or_no_add_after stmt s label quantified d ast
1174 seqible after process_bef_aft guard fvinfo =
1175 let label_var = (*fresh_label_var*) string2var "_lab" in
1177 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
1179 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in
1180 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
1182 (* don't have to put anything before the beginning, so don't have to
1183 distinguish the first node. so don't have to bother about paths,
1184 just use the label. label ensures that found nodes match up with
1185 what they should because it is in the lhs of the andany. *)
1187 Ast.MINUS(pos,[]) -> true
1188 | Ast.CONTEXT(pos,Ast.NOTHING) -> true
1191 match (pure_d,after) with
1192 (true,Tail) | (true,End) | (true,VeryEnd) ->
1193 (* the label sharing makes it safe to use AndAny *)
1194 CTL.HackForStmt(CTL.FORWARD,CTL.NONSTRICT,
1195 ctl_and CTL.NONSTRICT label_pred
1196 (make_raw_match label false ast),
1197 ctl_and CTL.NONSTRICT (matcher d) prelabel_pred)
1199 (* more safe but less efficient *)
1200 let first_metamatch = matcher d in
1201 let rest_metamatch =
1204 Ast.MINUS(pos,_) -> Ast.MINUS(pos,[])
1205 | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1206 | Ast.PLUS -> failwith "not possible") in
1207 let rest_nodes = ctl_and CTL.NONSTRICT rest_metamatch prelabel_pred in
1208 let last_node = and_after guard (ctl_not prelabel_pred) after in
1209 (ctl_and CTL.NONSTRICT (make_raw_match label false ast)
1212 ctl_au CTL.NONSTRICT rest_nodes last_node])) in
1213 let body f = ctl_and CTL.NONSTRICT label_pred (f ender) in
1214 let stmt_fvs = Ast.get_fvs stmt in
1215 let fvs = get_unquantified quantified stmt_fvs in
1216 quantify guard (label_var::fvs)
1217 (sequencibility body label_pred process_bef_aft seqible)
1219 (* --------------------------------------------------------------------- *)
1220 (* dots and nests *)
1222 let dots_au is_strict toend label s wrapcode x seq_after y quantifier =
1223 let matchgoto = gotopred None in
1225 make_match None false
1227 (Ast.Break(Ast.make_mcode "break",Ast.make_mcode ";"))) in
1229 make_match None false
1231 (Ast.Continue(Ast.make_mcode "continue",Ast.make_mcode ";"))) in
1233 if quantifier = Exists
1236 then CTL.Or(aftpred label,exitpred label)
1240 let lv = get_label_ctr() in
1241 let labelpred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1242 let preflabelpred = label_pred_maker (Some (lv,ref true)) in
1243 ctl_or (aftpred label)
1244 (quantify false [lv]
1245 (ctl_and CTL.NONSTRICT
1246 (ctl_and CTL.NONSTRICT (truepred label) labelpred)
1247 (ctl_au CTL.NONSTRICT
1248 (ctl_and CTL.NONSTRICT (ctl_not v) preflabelpred)
1249 (ctl_and CTL.NONSTRICT preflabelpred
1250 (ctl_or (retpred None)
1251 (if !Flag_matcher.only_return_is_error_exit
1254 (ctl_or matchcontinue
1255 (ctl_and CTL.NONSTRICT
1256 (ctl_or matchgoto matchbreak)
1257 (ctl_ag s (ctl_not seq_after)))))))))) in
1258 let v = get_let_ctr() in
1259 let op = if quantifier = !exists then ctl_au else ctl_anti_au in
1260 op s x (CTL.Let(v,y,ctl_or (CTL.Ref v) (stop_early (CTL.Ref v))))
1262 let rec dots_and_nests plus nest whencodes bef aft dotcode after label
1263 process_bef_aft statement_list statement guard quantified wrapcode =
1264 let ctl_and_ns = ctl_and CTL.NONSTRICT in
1265 (* proces bef_aft *)
1267 List.fold_left ctl_or_fl CTL.False (List.map process_bef_aft l) in
1268 let bef_aft = (* to be negated *)
1272 (function Ast.WhenModifier(Ast.WhenAny) -> true | _ -> false)
1275 with Not_found -> shortest (Common.union_set bef aft) in
1278 (function Ast.WhenModifier(Ast.WhenStrict) -> true | _ -> false)
1280 let check_quantifier quant other =
1282 (function Ast.WhenModifier(x) -> x = quant | _ -> false)
1286 (function Ast.WhenModifier(x) -> x = other | _ -> false)
1288 then failwith "inconsistent annotation on dots"
1292 if check_quantifier Ast.WhenExists Ast.WhenForall
1295 if check_quantifier Ast.WhenForall Ast.WhenExists
1298 (* the following is used when we find a goto, etc and consider accepting
1299 without finding the rest of the pattern *)
1300 let aft = shortest aft in
1301 (* process whencode *)
1302 let labelled = label_pred_maker label in
1304 let (poswhen,negwhen) =
1306 (function (poswhen,negwhen) ->
1308 Ast.WhenNot whencodes ->
1309 (poswhen,ctl_or (statement_list whencodes) negwhen)
1310 | Ast.WhenAlways stm ->
1311 (ctl_and CTL.NONSTRICT (statement stm) poswhen,negwhen)
1312 | Ast.WhenModifier(_) -> (poswhen,negwhen)
1313 | Ast.WhenNotTrue(e) ->
1315 ctl_or (whencond_true e label guard quantified) negwhen)
1316 | Ast.WhenNotFalse(e) ->
1318 ctl_or (whencond_false e label guard quantified) negwhen))
1319 (CTL.True,bef_aft) (List.rev whencodes) in
1320 let poswhen = ctl_and_ns arg poswhen in
1324 (* add in After, because it's not part of the program *)
1325 ctl_or (aftpred label) negwhen
1327 ctl_and_ns poswhen (ctl_not negwhen) in
1328 (* process dot code, if any *)
1330 match (dotcode,guard) with
1331 (None,_) | (_,true) -> CTL.True
1332 | (Some dotcode,_) -> dotcode in
1333 (* process nest code, if any *)
1334 (* whencode goes in the negated part of the nest; if no nest, just goes
1335 on the "true" in between code *)
1336 let plus_var = if plus then get_label_ctr() else string2var "" in
1337 let plus_var2 = if plus then get_label_ctr() else string2var "" in
1339 match (nest,guard && not plus) with
1340 (None,_) | (_,true) -> whencodes CTL.True
1341 | (Some nest,false) ->
1342 let v = get_let_ctr() in
1346 (* the idea is that BindGood is sort of a witness; a witness to
1347 having found the subterm in at least one place. If there is
1348 not a witness, then there is a risk that it will get thrown
1349 away, if it is merged with a node that has an empty
1350 environment. See tests/nestplus. But this all seems
1351 rather suspicious *)
1352 CTL.And(CTL.NONSTRICT,x,
1353 CTL.Exists(true,plus_var2,
1354 CTL.Pred(Lib_engine.BindGood(plus_var),
1355 CTL.Modif plus_var2)))
1358 CTL.Or(is_plus (CTL.Ref v),
1359 whencodes (CTL.Not(ctl_uncheck (CTL.Ref v))))) in
1360 let plus_modifier x =
1367 CTL.Not(CTL.Pred(Lib_engine.BindBad(plus_var),CTL.Control)))))
1373 | Guard f -> ctl_uncheck f
1375 let exit = endpred label in
1376 let errorexit = exitpred label in
1377 ctl_or exit errorexit
1378 (* not at all sure what the next two mean... *)
1382 Some (lv,used) -> used := true;
1383 ctl_or (CTL.Pred(Lib_engine.Label lv,CTL.Control))
1384 (ctl_back_ex (ctl_or (retpred label) (gotopred label)))
1385 | None -> endpred label)
1386 (* was the following, but not clear why sgrep should allow
1388 let exit = endpred label in
1389 let errorexit = exitpred label in
1391 then ctl_or exit errorexit (* end anywhere *)
1392 else exit (* end at the real end of the function *) *) in
1394 (dots_au is_strict ((after = Tail) or (after = VeryEnd))
1395 label (guard_to_strict guard) wrapcode
1396 (ctl_and_ns dotcode (ctl_and_ns ornest labelled))
1397 aft ender quantifier)
1399 and get_whencond_exps e =
1400 match Ast.unwrap e with
1402 | Ast.DisjRuleElem(res) ->
1403 List.fold_left Common.union_set [] (List.map get_whencond_exps res)
1404 | _ -> failwith "not possible"
1406 and make_whencond_headers e e1 label guard quantified =
1407 let fvs = Ast.get_fvs e in
1409 quantify guard (get_unquantified quantified fvs)
1410 (make_match label guard h) in
1415 (Ast.make_mcode "if",
1416 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1417 let while_header e1 =
1421 (Ast.make_mcode "while",
1422 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1427 (Ast.make_mcode "for",Ast.make_mcode "(",None,Ast.make_mcode ";",
1428 Some e1,Ast.make_mcode ";",None,Ast.make_mcode ")"))) in
1430 List.fold_left ctl_or CTL.False (List.map if_header e1) in
1432 List.fold_left ctl_or CTL.False (List.map while_header e1) in
1434 List.fold_left ctl_or CTL.False (List.map for_header e1) in
1435 (if_headers, while_headers, for_headers)
1437 and whencond_true e label guard quantified =
1438 let e1 = get_whencond_exps e in
1439 let (if_headers, while_headers, for_headers) =
1440 make_whencond_headers e e1 label guard quantified in
1442 (ctl_and CTL.NONSTRICT (truepred label) (ctl_back_ex if_headers))
1443 (ctl_and CTL.NONSTRICT
1444 (inlooppred label) (ctl_back_ex (ctl_or while_headers for_headers)))
1446 and whencond_false e label guard quantified =
1447 let e1 = get_whencond_exps e in
1448 let (if_headers, while_headers, for_headers) =
1449 make_whencond_headers e e1 label guard quantified in
1450 ctl_or (ctl_and CTL.NONSTRICT (falsepred label) (ctl_back_ex if_headers))
1451 (ctl_and CTL.NONSTRICT (fallpred label)
1452 (ctl_or (ctl_back_ex if_headers)
1453 (ctl_or (ctl_back_ex while_headers) (ctl_back_ex for_headers))))
1455 (* --------------------------------------------------------------------- *)
1456 (* the main translation loop *)
1458 let rec statement_list stmt_list after quantified minus_quantified
1459 label llabel slabel dots_before guard =
1461 (* include Disj to be on the safe side *)
1462 match Ast.unwrap x with
1463 Ast.Dots _ | Ast.Nest _ | Ast.Disj _ -> true | _ -> false in
1464 let compute_label l e db = if db or isdots e then l else None in
1465 match Ast.unwrap stmt_list with
1467 let rec loop quantified minus_quantified dots_before label llabel slabel
1469 ([],_,_) -> (match after with After f -> f | _ -> CTL.True)
1471 statement e after quantified minus_quantified
1472 (compute_label label e dots_before)
1474 | (e::sl,fv::fvs,mfv::mfvs) ->
1475 let shared = intersectll fv fvs in
1476 let unqshared = get_unquantified quantified shared in
1477 let new_quantified = Common.union_set unqshared quantified in
1478 let minus_shared = intersectll mfv mfvs in
1480 get_unquantified minus_quantified minus_shared in
1481 let new_mquantified =
1482 Common.union_set munqshared minus_quantified in
1483 quantify guard unqshared
1486 (let (label1,llabel1,slabel1) =
1487 match Ast.unwrap e with
1489 (match Ast.unwrap re with
1490 Ast.Goto _ -> (None,None,None)
1491 | _ -> (label,llabel,slabel))
1492 | _ -> (label,llabel,slabel) in
1493 loop new_quantified new_mquantified (isdots e)
1494 label1 llabel1 slabel1
1496 new_quantified new_mquantified
1497 (compute_label label e dots_before) llabel slabel guard)
1498 | _ -> failwith "not possible" in
1499 loop quantified minus_quantified dots_before
1501 (x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x)
1502 | Ast.CIRCLES(x) -> failwith "not supported"
1503 | Ast.STARS(x) -> failwith "not supported"
1505 (* llabel is the label of the enclosing loop and slabel is the label of the
1507 and statement stmt after quantified minus_quantified
1508 label llabel slabel guard =
1509 let ctl_au = ctl_au CTL.NONSTRICT in
1510 let ctl_ax = ctl_ax CTL.NONSTRICT in
1511 let ctl_and = ctl_and CTL.NONSTRICT in
1512 let make_seq = make_seq guard in
1513 let make_seq_after = make_seq_after guard in
1514 let real_make_match = make_match in
1515 let make_match = header_match label guard in
1517 let dots_done = ref false in (* hack for dots cases we can easily handle *)
1520 match Ast.unwrap stmt with
1522 (match Ast.unwrap ast with
1523 (* the following optimisation is not a good idea, because when S
1524 is alone, we would like it not to match a declaration.
1525 this makes more matching for things like when (...) S, but perhaps
1526 that matching is not so costly anyway *)
1527 (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*)
1528 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.BEFOREAFTER(_,_)) as d),_),
1530 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.AFTER(_)) as d),_),
1532 svar_context_with_add_after stmt s label quantified d ast seqible
1534 (process_bef_aft quantified minus_quantified
1535 label llabel slabel true)
1537 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1539 | Ast.MetaStmt((s,_,d,_),keep,seqible,_) ->
1540 svar_minus_or_no_add_after stmt s label quantified d ast seqible
1542 (process_bef_aft quantified minus_quantified
1543 label llabel slabel true)
1545 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1549 match Ast.unwrap ast with
1550 Ast.DisjRuleElem(res) ->
1551 do_re_matches label guard res quantified minus_quantified
1552 | Ast.Exp(_) | Ast.Ty(_) ->
1553 let stmt_fvs = Ast.get_fvs stmt in
1554 let fvs = get_unquantified quantified stmt_fvs in
1555 CTL.InnerAnd(quantify guard fvs (make_match ast))
1557 let stmt_fvs = Ast.get_fvs stmt in
1558 let fvs = get_unquantified quantified stmt_fvs in
1559 quantify guard fvs (make_match ast) in
1560 match Ast.unwrap ast with
1561 Ast.Break(brk,semi) ->
1562 (match (llabel,slabel) with
1563 (_,Some(lv,used)) -> (* use switch label if there is one *)
1564 ctl_and term (bclabel_pred_maker slabel)
1565 | _ -> ctl_and term (bclabel_pred_maker llabel))
1566 | Ast.Continue(brk,semi) -> ctl_and term (bclabel_pred_maker llabel)
1567 | Ast.Return((_,info,retmc,pos),(_,_,semmc,_)) ->
1568 (* discard pattern that comes after return *)
1569 let normal_res = make_seq_after term after in
1570 (* the following code tries to propagate the modifications on
1571 return; to a close brace, in the case where the final return
1574 match (retmc,semmc) with
1575 (Ast.MINUS(_,l1),Ast.MINUS(_,l2)) when !Flag.sgrep_mode2 ->
1576 (* in sgrep mode, we can propagate the - *)
1577 Some (Ast.MINUS(Ast.NoPos,l1@l2))
1578 | (Ast.MINUS(_,l1),Ast.MINUS(_,l2))
1579 | (Ast.CONTEXT(_,Ast.BEFORE(l1)),
1580 Ast.CONTEXT(_,Ast.AFTER(l2))) ->
1581 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2)))
1582 | (Ast.CONTEXT(_,Ast.BEFORE(_)),Ast.CONTEXT(_,Ast.NOTHING))
1583 | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.NOTHING)) ->
1585 | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.AFTER(l))) ->
1586 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l)))
1588 let ret = Ast.make_mcode "return" in
1590 Ast.rewrap ast (Ast.Edots(Ast.make_mcode "...",None)) in
1591 let semi = Ast.make_mcode ";" in
1593 make_match(Ast.rewrap ast (Ast.Return(ret,semi))) in
1595 make_match(Ast.rewrap ast (Ast.ReturnExpr(ret,edots,semi))) in
1598 let exit = endpred None in
1600 Ast.rewrap ast (Ast.SeqEnd (("}",info,new_mc,pos))) in
1601 let stripped_rbrace =
1602 Ast.rewrap ast (Ast.SeqEnd(Ast.make_mcode "}")) in
1604 (ctl_and (make_match mod_rbrace)
1609 (ctl_or simple_return return_expr))))
1611 (make_match stripped_rbrace)
1612 (* error exit not possible; it is in the middle
1613 of code, so a return is needed *)
1616 (* some change in the middle of the return, so have to
1617 find an actual return *)
1620 (* should try to deal with the dots_bef_aft problem elsewhere,
1621 but don't have the courage... *)
1626 do_between_dots stmt term End
1627 quantified minus_quantified label llabel slabel guard in
1629 make_seq_after term after)
1630 | Ast.Seq(lbrace,decls,body,rbrace) ->
1631 let (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs) =
1634 [Ast.get_fvs lbrace;Ast.get_fvs decls;
1635 Ast.get_fvs body;Ast.get_fvs rbrace]
1637 [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] ->
1638 (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs)
1639 | _ -> failwith "not possible" in
1640 let (mlbfvs,mb1fvs,mb2fvs,mb3fvs,mrbfvs) =
1642 seq_fvs minus_quantified
1643 [Ast.get_mfvs lbrace;Ast.get_mfvs decls;
1644 Ast.get_mfvs body;Ast.get_mfvs rbrace]
1646 [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] ->
1647 (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs)
1648 | _ -> failwith "not possible" in
1649 let pv = count_nested_braces stmt in
1650 let lv = get_label_ctr() in
1651 let paren_pred = CTL.Pred(Lib_engine.Paren pv,CTL.Control) in
1652 let label_pred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1655 (quantify guard lbfvs (make_match lbrace))
1656 (ctl_and paren_pred label_pred) in
1658 match Ast.unwrap rbrace with
1659 Ast.SeqEnd((data,info,_,pos)) ->
1660 Ast.rewrap rbrace(Ast.SeqEnd(Ast.make_mcode data))
1661 | _ -> failwith "unexpected close brace" in
1663 (* label is not needed; paren_pred is enough *)
1664 quantify guard rbfvs
1665 (ctl_au (make_match empty_rbrace)
1667 (real_make_match None guard rbrace)
1669 let new_quantified2 =
1670 Common.union_set b1fvs (Common.union_set b2fvs quantified) in
1671 let new_quantified3 = Common.union_set b3fvs new_quantified2 in
1672 let new_mquantified2 =
1673 Common.union_set mb1fvs (Common.union_set mb2fvs minus_quantified) in
1674 let new_mquantified3 = Common.union_set mb3fvs new_mquantified2 in
1675 let pattern_as_given =
1676 let new_quantified2 = Common.union_set [pv] new_quantified2 in
1677 let new_quantified3 = Common.union_set [pv] new_quantified3 in
1678 quantify true [pv;lv]
1679 (quantify guard b1fvs
1682 quantify guard b2fvs
1683 (statement_list decls
1685 (quantify guard b3fvs
1686 (statement_list body
1687 (After (make_seq_after end_brace after))
1688 new_quantified3 new_mquantified3
1689 (Some (lv,ref true)) (* label mostly useful *)
1690 llabel slabel true guard)))
1691 new_quantified2 new_mquantified2
1692 (Some (lv,ref true)) llabel slabel false guard)])) in
1693 if ends_in_return body
1695 (* matching error handling code *)
1697 1. The pattern as given
1698 2. A goto, and then some close braces, and then the pattern as
1699 given, but without the braces (only possible if there are no
1700 decls, and open and close braces are unmodified)
1701 3. Part of the pattern as given, then a goto, and then the rest
1702 of the pattern. For this case, we just check that all paths have
1703 a goto within the current braces. checking for a goto at every
1704 point in the pattern seems expensive and not worthwhile. *)
1706 let body = preprocess_dots body in (* redo, to drop braces *)
1710 (make_match empty_rbrace)
1711 (ctl_ax (* skip the destination label *)
1712 (quantify guard b3fvs
1713 (statement_list body End
1714 new_quantified3 new_mquantified3 None llabel slabel
1717 let new_quantified2 = Common.union_set [pv] new_quantified2 in
1718 let new_quantified3 = Common.union_set [pv] new_quantified3 in
1719 quantify true [pv;lv]
1720 (quantify guard b1fvs
1724 (CTL.AU (* want AF even for sgrep *)
1725 (CTL.FORWARD,CTL.STRICT,
1726 CTL.Pred(Lib_engine.PrefixLabel(lv),CTL.Control),
1727 ctl_and (* brace must be eventually after goto *)
1728 (gotopred (Some (lv,ref true)))
1729 (* want AF even for sgrep *)
1730 (CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace))))
1731 (quantify guard b2fvs
1732 (statement_list decls
1734 (quantify guard b3fvs
1735 (statement_list body Tail
1738 nopv_end_brace after)*)
1739 new_quantified3 new_mquantified3
1740 None llabel slabel true guard)))
1741 new_quantified2 new_mquantified2
1742 (Some (lv,ref true))
1743 llabel slabel false guard))])) in
1744 ctl_or pattern_as_given
1745 (match Ast.unwrap decls with
1746 Ast.DOTS([]) -> ctl_or pattern2 pattern3
1747 | Ast.DOTS(l) -> pattern3
1748 | _ -> failwith "circles and stars not supported")
1749 else pattern_as_given
1750 | Ast.IfThen(ifheader,branch,aft) ->
1751 ifthen ifheader branch aft after quantified minus_quantified
1752 label llabel slabel statement make_match guard
1754 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
1755 ifthenelse ifheader branch1 els branch2 aft after quantified
1756 minus_quantified label llabel slabel statement make_match guard
1758 | Ast.While(header,body,aft) | Ast.For(header,body,aft)
1759 | Ast.Iterator(header,body,aft) ->
1760 forwhile header body aft after quantified minus_quantified
1761 label statement make_match guard
1763 | Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *)
1765 (label_pred_maker label)
1766 (List.fold_left ctl_seqor CTL.False
1769 statement_list sl after quantified minus_quantified label
1770 llabel slabel true guard)
1773 | Ast.Nest(stmt_dots,whencode,multi,bef,aft) ->
1774 (* label in recursive call is None because label check is already
1775 wrapped around the corresponding code *)
1778 match seq_fvs quantified [Ast.get_wcfvs whencode;Ast.get_fvs stmt_dots]
1780 [(wcfvs,bothfvs);(bdfvs,_)] -> bothfvs
1781 | _ -> failwith "not possible" in
1783 (* no minus version because when code doesn't contain any minus code *)
1784 let new_quantified = Common.union_set bfvs quantified in
1788 statement_list stmt_dots (a2n after) new_quantified minus_quantified
1789 None llabel slabel true guard in
1790 dots_and_nests multi
1791 (Some dots_pattern) whencode bef aft None after label
1792 (process_bef_aft new_quantified minus_quantified
1793 None llabel slabel true)
1795 statement_list x Tail new_quantified minus_quantified None
1796 llabel slabel true true)
1798 statement x Tail new_quantified minus_quantified None
1801 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x)))
1803 | Ast.Dots((_,i,d,_),whencodes,bef,aft) ->
1807 (* no need for the fresh metavar, but ... is a bit wierd as a
1809 Some(make_match (make_meta_rule_elem d ([],[],[])))
1811 dots_and_nests false None whencodes bef aft dot_code after label
1812 (process_bef_aft quantified minus_quantified None llabel slabel true)
1814 statement_list x Tail quantified minus_quantified
1815 None llabel slabel true true)
1817 statement x Tail quantified minus_quantified None llabel slabel true)
1819 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x))
1821 | Ast.Switch(header,lb,cases,rb) ->
1822 let rec intersect_all = function
1825 | x::xs -> intersect x (intersect_all xs) in
1826 let rec union_all l = List.fold_left union [] l in
1827 (* start normal variables *)
1828 let header_fvs = Ast.get_fvs header in
1829 let lb_fvs = Ast.get_fvs lb in
1830 let case_fvs = List.map Ast.get_fvs cases in
1831 let rb_fvs = Ast.get_fvs rb in
1832 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1833 all_casefvs,all_b3fvs,all_rbfvs) =
1835 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1836 all_casefvs,all_b3fvs,all_rbfvs) ->
1837 function case_fvs ->
1838 match seq_fvs quantified [header_fvs;lb_fvs;case_fvs;rb_fvs] with
1839 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
1840 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
1841 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
1843 | _ -> failwith "not possible")
1844 ([],[],[],[],[],[],[]) case_fvs in
1845 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1846 all_casefvs,all_b3fvs,all_rbfvs) =
1847 (List.rev all_efvs,List.rev all_b1fvs,List.rev all_lbfvs,
1848 List.rev all_b2fvs,List.rev all_casefvs,List.rev all_b3fvs,
1849 List.rev all_rbfvs) in
1850 let exponlyfvs = intersect_all all_efvs in
1851 let lbonlyfvs = intersect_all all_lbfvs in
1852 (* don't do anything with right brace. Hope there is no + code on it *)
1853 (* let rbonlyfvs = intersect_all all_rbfvs in*)
1854 let b1fvs = union_all all_b1fvs in
1855 let new1_quantified = union b1fvs quantified in
1856 let b2fvs = union (union_all all_b1fvs) (intersect_all all_casefvs) in
1857 let new2_quantified = union b2fvs new1_quantified in
1858 (* let b3fvs = union_all all_b3fvs in*)
1859 (* ------------------- start minus free variables *)
1860 let header_mfvs = Ast.get_mfvs header in
1861 let lb_mfvs = Ast.get_mfvs lb in
1862 let case_mfvs = List.map Ast.get_mfvs cases in
1863 let rb_mfvs = Ast.get_mfvs rb in
1864 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
1865 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
1867 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1868 all_casefvs,all_b3fvs,all_rbfvs) ->
1869 function case_mfvs ->
1872 [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with
1873 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
1874 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
1875 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
1877 | _ -> failwith "not possible")
1878 ([],[],[],[],[],[],[]) case_mfvs in
1879 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
1880 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
1881 (List.rev all_mefvs,List.rev all_mb1fvs,List.rev all_mlbfvs,
1882 List.rev all_mb2fvs,List.rev all_mcasefvs,List.rev all_mb3fvs,
1883 List.rev all_mrbfvs) in
1884 (* don't do anything with right brace. Hope there is no + code on it *)
1885 (* let rbonlyfvs = intersect_all all_rbfvs in*)
1886 let mb1fvs = union_all all_mb1fvs in
1887 let new1_mquantified = union mb1fvs quantified in
1888 let mb2fvs = union (union_all all_mb1fvs) (intersect_all all_mcasefvs) in
1889 let new2_mquantified = union mb2fvs new1_mquantified in
1890 (* let b3fvs = union_all all_b3fvs in*)
1891 (* ------------------- end collection of free variables *)
1892 let switch_header = quantify guard exponlyfvs (make_match header) in
1893 let lb = quantify guard lbonlyfvs (make_match lb) in
1894 (* let rb = quantify guard rbonlyfvs (make_match rb) in*)
1897 (function case_line ->
1898 match Ast.unwrap case_line with
1899 Ast.CaseLine(header,body) ->
1901 match seq_fvs new2_quantified [Ast.get_fvs header] with
1902 [(e1fvs,_)] -> e1fvs
1903 | _ -> failwith "not possible" in
1904 quantify guard e1fvs (real_make_match label true header)
1905 | Ast.OptCase(case_line) -> failwith "not supported")
1908 ctl_not (List.fold_left ctl_or_fl CTL.False case_headers) in
1909 let lv = get_label_ctr() in
1910 let used = ref false in
1913 (function case_line ->
1914 match Ast.unwrap case_line with
1915 Ast.CaseLine(header,body) ->
1916 let (e1fvs,b1fvs,s1fvs) =
1917 let fvs = [Ast.get_fvs header;Ast.get_fvs body] in
1918 match seq_fvs new2_quantified fvs with
1919 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
1920 | _ -> failwith "not possible" in
1921 let (me1fvs,mb1fvs,ms1fvs) =
1922 let fvs = [Ast.get_mfvs header;Ast.get_mfvs body] in
1923 match seq_fvs new2_mquantified fvs with
1924 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
1925 | _ -> failwith "not possible" in
1927 quantify guard e1fvs (make_match header) in
1928 let new3_quantified = union b1fvs new2_quantified in
1929 let new3_mquantified = union mb1fvs new2_mquantified in
1931 statement_list body Tail
1932 new3_quantified new3_mquantified label llabel
1933 (Some (lv,used)) true(*?*) guard in
1934 quantify guard b1fvs (make_seq [case_header; body])
1935 | Ast.OptCase(case_line) -> failwith "not supported")
1937 let default_required =
1940 match Ast.unwrap case with
1941 Ast.CaseLine(header,_) ->
1942 (match Ast.unwrap header with
1943 Ast.Default(_,_) -> true
1947 then function x -> x
1948 else function x -> ctl_or (fallpred label) x in
1949 let after_pred = aftpred label in
1950 let body after_branch =
1953 (quantify guard b2fvs
1956 (List.fold_left ctl_and CTL.True
1957 (List.map ctl_ex case_headers));
1958 List.fold_left ctl_or_fl no_header case_code])))
1961 (rb_fvs,Ast.get_fresh rb,Ast.get_inherited rb,
1962 match Ast.unwrap rb with
1963 Ast.SeqEnd(rb) -> Ast.get_mcodekind rb
1964 | _ -> failwith "not possible") in
1965 let (switch_header,wrapper) =
1968 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1969 (ctl_and switch_header label_pred,
1970 (function body -> quantify true [lv] body))
1971 else (switch_header,function x -> x) in
1973 (end_control_structure b1fvs switch_header body
1974 after_pred (Some(ctl_ex after_pred)) None aft after label guard)
1975 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
1976 let (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs) =
1979 [Ast.get_fvs header;Ast.get_fvs lbrace;Ast.get_fvs decls;
1980 Ast.get_fvs body;Ast.get_fvs rbrace]
1982 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] ->
1983 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs)
1984 | _ -> failwith "not possible" in
1985 let (mhfvs,mb1fvs,mlbfvs,mb2fvs,mb3fvs,mb4fvs,mrbfvs) =
1988 [Ast.get_mfvs header;Ast.get_mfvs lbrace;Ast.get_mfvs decls;
1989 Ast.get_mfvs body;Ast.get_mfvs rbrace]
1991 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] ->
1992 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs)
1993 | _ -> failwith "not possible" in
1994 let function_header = quantify guard hfvs (make_match header) in
1995 let start_brace = quantify guard lbfvs (make_match lbrace) in
1996 let stripped_rbrace =
1997 match Ast.unwrap rbrace with
1998 Ast.SeqEnd((data,info,_,_)) ->
1999 Ast.rewrap rbrace(Ast.SeqEnd (Ast.make_mcode data))
2000 | _ -> failwith "unexpected close brace" in
2002 let exit = CTL.Pred (Lib_engine.Exit,CTL.Control) in
2003 let errorexit = CTL.Pred (Lib_engine.ErrorExit,CTL.Control) in
2004 let fake_brace = CTL.Pred (Lib_engine.FakeBrace,CTL.Control) in
2006 (quantify guard rbfvs (make_match rbrace))
2008 (* the following finds the beginning of the fake braces,
2009 if there are any, not completely sure how this works.
2010 sse the examples sw and return *)
2011 (ctl_back_ex (ctl_not fake_brace))
2012 (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in
2013 let new_quantified3 =
2014 Common.union_set b1fvs
2015 (Common.union_set b2fvs (Common.union_set b3fvs quantified)) in
2016 let new_quantified4 = Common.union_set b4fvs new_quantified3 in
2017 let new_mquantified3 =
2018 Common.union_set mb1fvs
2019 (Common.union_set mb2fvs
2020 (Common.union_set mb3fvs minus_quantified)) in
2021 let new_mquantified4 = Common.union_set mb4fvs new_mquantified3 in
2023 match (Ast.undots decls,Ast.undots body,contains_modif rbrace) with
2024 ([],[body],false) ->
2025 (match Ast.unwrap body with
2026 Ast.Nest(stmt_dots,[],multi,_,_) ->
2028 then None (* not sure how to optimize this case *)
2029 else Some (Common.Left stmt_dots)
2030 | Ast.Dots(_,whencode,_,_) when
2032 (* flow sensitive, so not optimizable *)
2033 (function Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2035 | _ -> true) whencode) ->
2036 Some (Common.Right whencode)
2041 Some (Common.Left stmt_dots) ->
2042 (* special case for function header + body - header is unambiguous
2043 and unique, so we can just look for the nested body anywhere
2046 (CTL.FORWARD,guard_to_strict guard,start_brace,
2047 statement_list stmt_dots
2048 (* discards match on right brace, but don't need it *)
2049 (Guard (make_seq_after end_brace after))
2050 new_quantified4 new_mquantified4
2051 None llabel slabel true guard)
2052 | Some (Common.Right whencode) ->
2053 (* try to be more efficient for the case where the body is just
2054 ... Perhaps this is too much of a special case, but useful
2055 for dropping a parameter and checking that it is never used. *)
2067 Ast.WhenAlways(s) -> prev
2068 | Ast.WhenNot(sl) ->
2070 statement_list sl Tail
2071 new_quantified4 new_mquantified4
2072 label llabel slabel true true in
2074 | Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2075 failwith "unexpected"
2076 | Ast.WhenModifier(Ast.WhenAny) -> CTL.False
2077 | Ast.WhenModifier(_) -> prev)
2078 CTL.False whencode))
2082 Ast.WhenAlways(s) ->
2085 new_quantified4 new_mquantified4
2086 label llabel slabel true in
2088 | Ast.WhenNot(sl) -> prev
2089 | Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2090 failwith "unexpected"
2091 | Ast.WhenModifier(Ast.WhenAny) -> CTL.True
2092 | Ast.WhenModifier(_) -> prev)
2093 CTL.True whencode) in
2094 ctl_au leftarg (make_match stripped_rbrace)]
2098 quantify guard b3fvs
2099 (statement_list decls
2101 (quantify guard b4fvs
2102 (statement_list body
2103 (After (make_seq_after end_brace after))
2104 new_quantified4 new_mquantified4
2105 None llabel slabel true guard)))
2106 new_quantified3 new_mquantified3 None llabel slabel
2108 quantify guard b1fvs
2109 (make_seq [function_header; quantify guard b2fvs body_code])
2110 | Ast.Define(header,body) ->
2111 let (hfvs,bfvs,bodyfvs) =
2112 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body]
2114 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2115 | _ -> failwith "not possible" in
2116 let (mhfvs,mbfvs,mbodyfvs) =
2117 match seq_fvs minus_quantified [Ast.get_mfvs header;Ast.get_mfvs body]
2119 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2120 | _ -> failwith "not possible" in
2121 let define_header = quantify guard hfvs (make_match header) in
2123 statement_list body after
2124 (Common.union_set bfvs quantified)
2125 (Common.union_set mbfvs minus_quantified)
2126 None llabel slabel true guard in
2127 quantify guard bfvs (make_seq [define_header; body_code])
2128 | Ast.OptStm(stm) ->
2129 failwith "OptStm should have been compiled away\n"
2130 | Ast.UniqueStm(stm) -> failwith "arities not yet supported"
2131 | _ -> failwith "not supported" in
2132 if guard or !dots_done
2135 do_between_dots stmt term after quantified minus_quantified
2136 label llabel slabel guard
2138 (* term is the translation of stmt *)
2139 and do_between_dots stmt term after quantified minus_quantified
2140 label llabel slabel guard =
2141 match Ast.get_dots_bef_aft stmt with
2142 Ast.AddingBetweenDots (brace_term,n)
2143 | Ast.DroppingBetweenDots (brace_term,n) ->
2145 statement brace_term after quantified minus_quantified
2146 label llabel slabel guard in
2147 let v = Printf.sprintf "_r_%d" n in
2148 let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in
2149 let case2 = ctl_and CTL.NONSTRICT (ctl_not (CTL.Ref v)) term in
2152 (ctl_back_ex (ctl_or (truepred label) (inlooppred label)))
2153 (ctl_back_ex (ctl_back_ex (falsepred label))),
2155 | Ast.NoDots -> term
2157 (* un_process_bef_aft is because we don't want to do transformation in this
2158 code, and thus don't case about braces before or after it *)
2159 and process_bef_aft quantified minus_quantified label llabel slabel guard =
2161 Ast.WParen (re,n) ->
2162 let paren_pred = CTL.Pred (Lib_engine.Paren n,CTL.Control) in
2163 let s = guard_to_strict guard in
2164 quantify true (get_unquantified quantified [n])
2165 (ctl_and s (make_raw_match None guard re) paren_pred)
2167 statement s Tail quantified minus_quantified label llabel slabel guard
2168 | Ast.Other_dots d ->
2169 statement_list d Tail quantified minus_quantified
2170 label llabel slabel true guard
2172 (* --------------------------------------------------------------------- *)
2173 (* cleanup: convert AX to EX for pdots.
2174 Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2175 This is what we wanted in the first place, but it wasn't possible to make
2176 because the AX and its argument are not created in the same place.
2178 (* also cleanup XX, which is a marker for the case where the programmer
2179 specifies to change the quantifier on .... Assumed to only occur after one AX
2180 or EX, or at top level. *)
2183 let c = match c with CTL.XX(c) -> c | _ -> c in
2185 CTL.False -> CTL.False
2186 | CTL.True -> CTL.True
2187 | CTL.Pred(p) -> CTL.Pred(p)
2188 | CTL.Not(phi) -> CTL.Not(cleanup phi)
2189 | CTL.Exists(keep,v,phi) -> CTL.Exists(keep,v,cleanup phi)
2190 | CTL.AndAny(dir,s,phi1,phi2) ->
2191 CTL.AndAny(dir,s,cleanup phi1,cleanup phi2)
2192 | CTL.HackForStmt(dir,s,phi1,phi2) ->
2193 CTL.HackForStmt(dir,s,cleanup phi1,cleanup phi2)
2194 | CTL.And(s,phi1,phi2) -> CTL.And(s,cleanup phi1,cleanup phi2)
2195 | CTL.Or(phi1,phi2) -> CTL.Or(cleanup phi1,cleanup phi2)
2196 | CTL.SeqOr(phi1,phi2) -> CTL.SeqOr(cleanup phi1,cleanup phi2)
2197 | CTL.Implies(phi1,phi2) -> CTL.Implies(cleanup phi1,cleanup phi2)
2198 | CTL.AF(dir,s,phi1) -> CTL.AF(dir,s,cleanup phi1)
2199 | CTL.AX(CTL.FORWARD,s,
2201 CTL.And(CTL.NONSTRICT,CTL.AU(CTL.FORWARD,s2,e2,e3),
2202 CTL.EU(CTL.FORWARD,e4,e5)))) ->
2204 CTL.And(CTL.NONSTRICT,
2205 CTL.AX(CTL.FORWARD,s,CTL.AU(CTL.FORWARD,s2,e2,e3)),
2206 CTL.EX(CTL.FORWARD,CTL.EU(CTL.FORWARD,e4,e5))))
2207 | CTL.AX(dir,s,CTL.XX(phi)) -> CTL.EX(dir,cleanup phi)
2208 | CTL.EX(dir,CTL.XX((CTL.AU(_,s,_,_)) as phi)) ->
2209 CTL.AX(dir,s,cleanup phi)
2210 | CTL.XX(phi) -> failwith "bad XX"
2211 | CTL.AX(dir,s,phi1) -> CTL.AX(dir,s,cleanup phi1)
2212 | CTL.AG(dir,s,phi1) -> CTL.AG(dir,s,cleanup phi1)
2213 | CTL.EF(dir,phi1) -> CTL.EF(dir,cleanup phi1)
2214 | CTL.EX(dir,phi1) -> CTL.EX(dir,cleanup phi1)
2215 | CTL.EG(dir,phi1) -> CTL.EG(dir,cleanup phi1)
2216 | CTL.AW(dir,s,phi1,phi2) -> CTL.AW(dir,s,cleanup phi1,cleanup phi2)
2217 | CTL.AU(dir,s,phi1,phi2) -> CTL.AU(dir,s,cleanup phi1,cleanup phi2)
2218 | CTL.EU(dir,phi1,phi2) -> CTL.EU(dir,cleanup phi1,cleanup phi2)
2219 | CTL.Let (x,phi1,phi2) -> CTL.Let (x,cleanup phi1,cleanup phi2)
2220 | CTL.LetR (dir,x,phi1,phi2) -> CTL.LetR (dir,x,cleanup phi1,cleanup phi2)
2221 | CTL.Ref(s) -> CTL.Ref(s)
2222 | CTL.Uncheck(phi1) -> CTL.Uncheck(cleanup phi1)
2223 | CTL.InnerAnd(phi1) -> CTL.InnerAnd(cleanup phi1)
2225 (* --------------------------------------------------------------------- *)
2226 (* Function declaration *)
2228 let top_level name (ua,pos) t =
2229 let ua = List.filter (function (nm,_) -> nm = name) ua in
2231 saved := Ast.get_saved t;
2232 let quantified = Common.minus_set ua pos in
2233 quantify false quantified
2234 (match Ast.unwrap t with
2235 Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo"
2237 let unopt = elim_opt.V.rebuilder_statement stmt in
2238 let unopt = preprocess_dots_e unopt in
2239 cleanup(statement unopt VeryEnd quantified [] None None None false)
2240 | Ast.CODE(stmt_dots) ->
2241 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in
2242 let unopt = preprocess_dots unopt in
2243 let starts_with_dots =
2244 match Ast.undots stmt_dots with
2246 (match Ast.unwrap d with
2247 Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
2248 | Ast.Stars(_,_,_,_) -> true
2251 let starts_with_brace =
2252 match Ast.undots stmt_dots with
2254 (match Ast.unwrap d with
2259 statement_list unopt VeryEnd quantified [] None None None
2262 (if starts_with_dots
2264 (* EX because there is a loop on enter/top *)
2265 ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res)
2266 else if starts_with_brace
2268 ctl_and CTL.NONSTRICT
2269 (ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res
2271 | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords")
2273 (* --------------------------------------------------------------------- *)
2276 let asttoctlz (name,(_,_,exists_flag),l) used_after positions =
2279 (match exists_flag with
2280 Ast.Exists -> exists := Exists
2281 | Ast.Forall -> exists := Forall
2282 | Ast.ReverseForall -> exists := ReverseForall
2283 | Ast.Undetermined ->
2284 exists := if !Flag.sgrep_mode2 then Exists else Forall);
2286 let (l,used_after) =
2290 match Ast.unwrap t with Ast.ERRORWORDS(exps) -> false | _ -> true)
2291 (List.combine l (List.combine used_after positions))) in
2292 let res = List.map2 (top_level name) used_after l in
2296 let asttoctl r used_after positions =
2298 Ast.ScriptRule _ -> []
2299 | Ast.CocciRule (a,b,c,_) -> asttoctlz (a,b,c) used_after positions
2301 let pp_cocci_predicate (pred,modif) =
2302 Pretty_print_engine.pp_predicate pred
2304 let cocci_predicate_to_string (pred,modif) =
2305 Pretty_print_engine.predicate_to_string pred