2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
25 (* for MINUS and CONTEXT, pos is always None in this file *)
26 (*search for require*)
27 (* true = don't see all matched nodes, only modified ones *)
28 let onlyModif = ref true(*false*)
30 type ex
= Exists
| Forall
31 let exists = ref Forall
33 module Ast
= Ast_cocci
34 module V
= Visitor_ast
37 let warning s
= Printf.fprintf stderr
"warning: %s\n" s
39 type cocci_predicate
= Lib_engine.predicate
* Ast.meta_name
Ast_ctl.modif
41 (cocci_predicate
,Ast.meta_name
, Wrapper_ctl.info
) Ast_ctl.generic_ctl
43 let union = Common.union_set
44 let intersect l1 l2
= List.filter
(function x
-> List.mem x l2
) l1
45 let subset l1 l2
= List.for_all
(function x
-> List.mem x l2
) l1
47 let foldl1 f xs
= List.fold_left f
(List.hd xs
) (List.tl xs
)
49 let xs = List.rev
xs in List.fold_left f
(List.hd
xs) (List.tl
xs)
51 let used_after = ref ([] : Ast.meta_name list
)
52 let guard_to_strict guard
= if guard
then CTL.NONSTRICT
else CTL.STRICT
54 let saved = ref ([] : Ast.meta_name list
)
56 let string2var x
= ("",x
)
58 (* --------------------------------------------------------------------- *)
59 (* predicates matching various nodes in the graph *)
63 (CTL.False
,_
) | (_
,CTL.False
) -> CTL.False
64 | (CTL.True
,a
) | (a
,CTL.True
) -> a
69 (CTL.True
,_
) | (_
,CTL.True
) -> CTL.True
70 | (CTL.False
,a
) | (a
,CTL.False
) -> a
75 (CTL.True
,_
) | (_
,CTL.True
) -> CTL.True
76 | (CTL.False
,a
) | (a
,CTL.False
) -> a
81 (* drop x or true case because x might have side effects *)
82 (CTL.True
,_
) (* | (_,CTL.True) *) -> CTL.True
83 | (CTL.False
,a
) | (a
,CTL.False
) -> a
86 let ctl_not = function
88 | CTL.False
-> CTL.True
91 let ctl_ax s
= function
93 | CTL.False
-> CTL.False
96 Exists
-> CTL.EX
(CTL.FORWARD
,x
)
97 | Forall
-> CTL.AX
(CTL.FORWARD
,s
,x
)
99 let ctl_ax_absolute s
= function
101 | CTL.False
-> CTL.False
102 | x
-> CTL.AX
(CTL.FORWARD
,s
,x
)
104 let ctl_ex = function
106 | CTL.False
-> CTL.False
107 | x
-> CTL.EX
(CTL.FORWARD
,x
)
109 (* This stays being AX even for sgrep_mode, because it is used to identify
110 the structure of the term, not matching the pattern. *)
111 let ctl_back_ax = function
113 | CTL.False
-> CTL.False
114 | x
-> CTL.AX
(CTL.BACKWARD
,CTL.NONSTRICT
,x
)
116 let ctl_back_ex = function
118 | CTL.False
-> CTL.False
119 | x
-> CTL.EX
(CTL.BACKWARD
,x
)
121 let ctl_ef = function
123 | CTL.False
-> CTL.False
124 | x
-> CTL.EF
(CTL.FORWARD
,x
)
126 let ctl_ag s
= function
128 | CTL.False
-> CTL.False
129 | x
-> CTL.AG
(CTL.FORWARD
,s
,x
)
132 match (x
,!exists) with
133 (CTL.True
,Exists
) -> CTL.EF
(CTL.FORWARD
,y
)
134 | (CTL.True
,Forall
) -> CTL.AF
(CTL.FORWARD
,s
,y
)
135 | (_
,Exists
) -> CTL.EU
(CTL.FORWARD
,x
,y
)
136 | (_
,Forall
) -> CTL.AU
(CTL.FORWARD
,s
,x
,y
)
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 | (_
,Exists
) -> CTL.AU
(CTL.FORWARD
,s
,x
,y
)
144 | (_
,Forall
) -> CTL.EU
(CTL.FORWARD
,x
,y
))
146 let ctl_uncheck = function
148 | CTL.False
-> CTL.False
151 let label_pred_maker = function
153 | Some
(label_var
,used
) ->
155 CTL.Pred
(Lib_engine.PrefixLabel
(label_var
),CTL.Control
)
157 let bclabel_pred_maker = function
159 | Some
(label_var
,used
) ->
161 CTL.Pred
(Lib_engine.BCLabel
(label_var
),CTL.Control
)
163 (* label used to be used here, but it is not used; label is only needed after
165 let predmaker guard pred label
= CTL.Pred pred
167 let aftpred = predmaker false (Lib_engine.After
, CTL.Control
)
168 let retpred = predmaker false (Lib_engine.Return
, CTL.Control
)
169 let funpred = predmaker false (Lib_engine.FunHeader
, CTL.Control
)
170 let toppred = predmaker false (Lib_engine.Top
, CTL.Control
)
171 let exitpred = predmaker false (Lib_engine.ErrorExit
, CTL.Control
)
172 let endpred = predmaker false (Lib_engine.Exit
, CTL.Control
)
173 let gotopred = predmaker false (Lib_engine.Goto
, CTL.Control
)
174 let inlooppred = predmaker false (Lib_engine.InLoop
, CTL.Control
)
175 let truepred = predmaker false (Lib_engine.TrueBranch
, CTL.Control
)
176 let falsepred = predmaker false (Lib_engine.FalseBranch
, CTL.Control
)
177 let fallpred = predmaker false (Lib_engine.FallThrough
, CTL.Control
)
178 let loopfallpred = predmaker false (Lib_engine.LoopFallThrough
, CTL.Control
)
180 (*let aftret label_var =
181 ctl_or (aftpred label_var)
182 (ctl_or (loopfallpred label_var) (exitpred label_var))*)
188 Printf.sprintf
"r%d" cur
190 (* --------------------------------------------------------------------- *)
191 (* --------------------------------------------------------------------- *)
192 (* Eliminate OptStm *)
194 (* for optional thing with nothing after, should check that the optional thing
195 never occurs. otherwise the matching stops before it occurs *)
198 let donothing r k e
= k e
in
201 List.fold_left
Common.union_set
[] (List.map
Ast.get_fvs l
) in
204 List.fold_left
Common.union_set
[] (List.map
Ast.get_mfvs l
) in
207 List.fold_left
Common.union_set
[] (List.map
Ast.get_fresh l
) in
209 let inheritedlist l
=
210 List.fold_left
Common.union_set
[] (List.map
Ast.get_inherited l
) in
213 List.fold_left
Common.union_set
[] (List.map
Ast.get_saved l
) in
216 (fvlist l
, mfvlist l
, freshlist l
, inheritedlist l
, savedlist l
) in
218 let rec dots_list unwrapped wrapped
=
219 match (unwrapped
,wrapped
) with
222 | (Ast.Dots
(_
,_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
,_
) as u
)::urest
,
224 | (Ast.Nest
(_
,_
,_
,_
,_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
,_
) as u
)
226 d0
::s
::d1
::rest
) -> (* why no case for nest as u? *)
227 let l = Ast.get_line stm
in
228 let new_rest1 = stm
:: (dots_list (u
::urest
) (d1
::rest
)) in
229 let new_rest2 = dots_list urest rest
in
230 let (fv_rest1
,mfv_rest1
,fresh_rest1
,inherited_rest1
,s1
) =
231 varlists new_rest1 in
232 let (fv_rest2
,mfv_rest2
,fresh_rest2
,inherited_rest2
,s2
) =
233 varlists new_rest2 in
237 [{(Ast.make_term
(Ast.DOTS
(new_rest1))) with
239 Ast.free_vars
= fv_rest1
;
240 Ast.minus_free_vars
= mfv_rest1
;
241 Ast.fresh_vars
= fresh_rest1
;
242 Ast.inherited
= inherited_rest1
;
243 Ast.saved_witness
= s1
};
244 {(Ast.make_term
(Ast.DOTS
(new_rest2))) with
246 Ast.free_vars
= fv_rest2
;
247 Ast.minus_free_vars
= mfv_rest2
;
248 Ast.fresh_vars
= fresh_rest2
;
249 Ast.inherited
= inherited_rest2
;
250 Ast.saved_witness
= s2
}])) with
252 Ast.free_vars
= fv_rest1
;
253 Ast.minus_free_vars
= mfv_rest1
;
254 Ast.fresh_vars
= fresh_rest1
;
255 Ast.inherited
= inherited_rest1
;
256 Ast.saved_witness
= s1
}]
258 | (Ast.OptStm
(stm
)::urest
,_
::rest
) ->
259 let l = Ast.get_line stm
in
260 let new_rest1 = dots_list urest rest
in
261 let new_rest2 = stm
::new_rest1 in
262 let (fv_rest1
,mfv_rest1
,fresh_rest1
,inherited_rest1
,s1
) =
263 varlists new_rest1 in
264 let (fv_rest2
,mfv_rest2
,fresh_rest2
,inherited_rest2
,s2
) =
265 varlists new_rest2 in
268 [{(Ast.make_term
(Ast.DOTS
(new_rest2))) with
270 Ast.free_vars
= fv_rest2
;
271 Ast.minus_free_vars
= mfv_rest2
;
272 Ast.fresh_vars
= fresh_rest2
;
273 Ast.inherited
= inherited_rest2
;
274 Ast.saved_witness
= s2
};
275 {(Ast.make_term
(Ast.DOTS
(new_rest1))) with
277 Ast.free_vars
= fv_rest1
;
278 Ast.minus_free_vars
= mfv_rest1
;
279 Ast.fresh_vars
= fresh_rest1
;
280 Ast.inherited
= inherited_rest1
;
281 Ast.saved_witness
= s1
}])) with
283 Ast.free_vars
= fv_rest2
;
284 Ast.minus_free_vars
= mfv_rest2
;
285 Ast.fresh_vars
= fresh_rest2
;
286 Ast.inherited
= inherited_rest2
;
287 Ast.saved_witness
= s2
}]
289 | ([Ast.Dots
(_
,_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
290 let l = Ast.get_line stm
in
291 let fv_stm = Ast.get_fvs stm
in
292 let mfv_stm = Ast.get_mfvs stm
in
293 let fresh_stm = Ast.get_fresh stm
in
294 let inh_stm = Ast.get_inherited stm
in
295 let saved_stm = Ast.get_saved stm
in
296 let fv_d1 = Ast.get_fvs d1
in
297 let mfv_d1 = Ast.get_mfvs d1
in
298 let fresh_d1 = Ast.get_fresh d1
in
299 let inh_d1 = Ast.get_inherited d1
in
300 let saved_d1 = Ast.get_saved d1
in
301 let fv_both = Common.union_set
fv_stm fv_d1 in
302 let mfv_both = Common.union_set
mfv_stm mfv_d1 in
303 let fresh_both = Common.union_set
fresh_stm fresh_d1 in
304 let inh_both = Common.union_set
inh_stm inh_d1 in
305 let saved_both = Common.union_set
saved_stm saved_d1 in
309 [{(Ast.make_term
(Ast.DOTS
([stm
]))) with
311 Ast.free_vars
= fv_stm;
312 Ast.minus_free_vars
= mfv_stm;
313 Ast.fresh_vars
= fresh_stm;
314 Ast.inherited
= inh_stm;
315 Ast.saved_witness
= saved_stm};
316 {(Ast.make_term
(Ast.DOTS
([d1
]))) with
318 Ast.free_vars
= fv_d1;
319 Ast.minus_free_vars
= mfv_d1;
320 Ast.fresh_vars
= fresh_d1;
321 Ast.inherited
= inh_d1;
322 Ast.saved_witness
= saved_d1}])) with
324 Ast.free_vars
= fv_both;
325 Ast.minus_free_vars
= mfv_both;
326 Ast.fresh_vars
= fresh_both;
327 Ast.inherited
= inh_both;
328 Ast.saved_witness
= saved_both}]
330 | ([Ast.Nest
(_
,_
,_
,_
,_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
331 let l = Ast.get_line stm
in
332 let rw = Ast.rewrap stm
in
333 let rwd = Ast.rewrap stm
in
334 let dots = Ast.Dots
(Ast.make_mcode
"...",[],[],[]) in
336 [rwd(Ast.DOTS
([stm
]));
337 {(Ast.make_term
(Ast.DOTS
([rw dots])))
338 with Ast.node_line
= l}])]
340 | (_
::urest
,stm
::rest
) -> stm
:: (dots_list urest rest
)
341 | _
-> failwith
"not possible" in
343 let stmtdotsfn r k d
=
346 (match Ast.unwrap
d with
347 Ast.DOTS
(l) -> Ast.DOTS
(dots_list (List.map
Ast.unwrap
l) l)
348 | Ast.CIRCLES
(l) -> failwith
"elimopt: not supported"
349 | Ast.STARS
(l) -> failwith
"elimopt: not supported") in
352 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
353 donothing donothing stmtdotsfn donothing donothing
354 donothing donothing donothing donothing donothing donothing donothing
355 donothing donothing donothing donothing donothing
357 (* --------------------------------------------------------------------- *)
358 (* after management *)
359 (* We need Guard for the following case:
368 Here the inner <... b ...> should not go past foo. But foo is not the
369 "after" of the body of the outer nest, because we don't want to search for
370 it in the case where the body of the outer nest ends in something other
371 than dots or a nest. *)
373 (* what is the difference between tail and end??? *)
375 type after
= After
of formula
| Guard
of formula
| Tail
| End
| VeryEnd
377 let a2n = function After x
-> Guard x
| a
-> a
380 let pp_pred (x
,_
) = Pretty_print_engine.pp_predicate x
in
381 let pp_meta (_
,x
) = Common.pp x
in
382 Pretty_print_ctl.pp_ctl
(pp_pred,pp_meta) false x
;
383 Format.print_newline
()
385 let print_after = function
386 After ctl
-> Printf.printf
"After:\n"; print_ctl ctl
387 | Guard ctl
-> Printf.printf
"Guard:\n"; print_ctl ctl
388 | Tail
-> Printf.printf
"Tail\n"
389 | VeryEnd
-> Printf.printf
"Very End\n"
390 | End
-> Printf.printf
"End\n"
392 (* --------------------------------------------------------------------- *)
395 let fresh_var _
= string2var "_v"
396 let fresh_pos _
= string2var "_pos" (* must be a constant *)
398 let fresh_metavar _
= "_S"
400 (* fvinfo is going to end up being from the whole associated statement.
401 it would be better if it were just the free variables in d, but free_vars.ml
402 doesn't keep track of free variables on + code *)
403 let make_meta_rule_elem d fvinfo
=
404 let nm = fresh_metavar() in
405 Ast.make_meta_rule_elem nm d fvinfo
407 let get_unquantified quantified vars
=
408 List.filter
(function x
-> not
(List.mem x quantified
)) vars
410 let make_seq guard
l =
411 let s = guard_to_strict guard
in
412 foldr1 (function rest
-> function cur -> ctl_and s cur (ctl_ax s rest
)) l
414 let make_seq_after2 guard first rest
=
415 let s = guard_to_strict guard
in
417 After rest
-> ctl_and s first
(ctl_ax s (ctl_ax s rest
))
420 let make_seq_after guard first rest
=
422 After rest
-> make_seq guard
[first
;rest
]
425 let opt_and guard first rest
=
426 let s = guard_to_strict guard
in
429 | Some first
-> ctl_and s first rest
431 let and_after guard first rest
=
432 let s = guard_to_strict guard
in
433 match rest
with After rest
-> ctl_and s first rest
| _
-> first
436 let bind x y
= x
or y
in
437 let option_default = false in
438 let mcode r
(_
,_
,kind
,metapos
) =
440 Ast.MINUS
(_
,_
,_
,_
) -> true
441 | Ast.PLUS _
-> failwith
"not possible"
442 | Ast.CONTEXT
(_
,info
) -> not
(info
= Ast.NOTHING
) in
443 let do_nothing r k e
= k e
in
444 let rule_elem r k re
=
446 match Ast.unwrap re
with
447 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
448 bind (mcode r
((),(),bef
,[])) res
449 | Ast.Decl
(bef
,_
,decl
) -> bind (mcode r
((),(),bef
,[])) res
453 match Ast.unwrap i
with
454 Ast.StrInitList
(allminus
,_
,_
,_
,_
) -> allminus
or res
457 V.combiner
bind option_default
458 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
459 do_nothing do_nothing do_nothing do_nothing do_nothing
460 do_nothing do_nothing do_nothing do_nothing init do_nothing
461 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
462 recursor.V.combiner_rule_elem
465 let bind x y
= x
or y
in
466 let option_default = false in
467 let mcode r
(_
,_
,kind
,metapos
) = not
(metapos
= []) in
468 let do_nothing r k e
= k e
in
469 let rule_elem r k re
=
471 match Ast.unwrap re
with
472 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
473 bind (mcode r
((),(),bef
,[])) res
474 | Ast.Decl
(bef
,_
,decl
) -> bind (mcode r
((),(),bef
,[])) res
477 V.combiner
bind option_default
478 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
479 do_nothing do_nothing do_nothing do_nothing do_nothing
480 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
481 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
482 recursor.V.combiner_rule_elem
484 (* code is not a DisjRuleElem *)
485 let make_match label guard code
=
486 let v = fresh_var() in
487 let matcher = Lib_engine.Match
(code
) in
488 if contains_modif code
&& not guard
489 then CTL.Exists
(true,v,predmaker guard
(matcher,CTL.Modif
v) label
)
491 let iso_info = !Flag.track_iso_usage
&& not
(Ast.get_isos code
= []) in
492 (match (iso_info,!onlyModif,guard
,
493 intersect !used_after (Ast.get_fvs code
)) with
494 (false,true,_
,[]) | (_
,_
,true,_
) ->
495 predmaker guard
(matcher,CTL.Control
) label
496 | _
-> CTL.Exists
(true,v,predmaker guard
(matcher,CTL.UnModif
v) label
))
498 let make_raw_match label guard code
=
499 match intersect !used_after (Ast.get_fvs code
) with
500 [] -> predmaker guard
(Lib_engine.Match
(code
),CTL.Control
) label
502 let v = fresh_var() in
503 CTL.Exists
(true,v,predmaker guard
(Lib_engine.Match
(code
),CTL.UnModif
v)
506 let rec seq_fvs quantified
= function
509 let t1fvs = get_unquantified quantified fv1
in
511 List.fold_left
Common.union_set
[]
512 (List.map
(get_unquantified quantified
) fvs
) in
513 let bothfvs = Common.inter_set
t1fvs termfvs in
514 let t1onlyfvs = Common.minus_set
t1fvs bothfvs in
515 let new_quantified = Common.union_set
bothfvs quantified
in
516 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs
)
521 function code
-> CTL.Exists
(not guard
&& List.mem
cur !saved,cur,code
))
523 let non_saved_quantify =
525 (function cur -> function code
-> CTL.Exists
(false,cur,code
))
527 let intersectll lst nested_list
=
528 List.filter
(function x
-> List.exists (List.mem x
) nested_list
) lst
530 (* --------------------------------------------------------------------- *)
531 (* Count depth of braces. The translation of a closed brace appears deeply
532 nested within the translation of the sequence term, so the name of the
533 paren var has to take into account the names of the nested braces. On the
534 other hand the close brace does not escape, so we don't have to take into
535 account other paren variable names. *)
537 (* called repetitively, which is inefficient, but less trouble than adding a
538 new field to Seq and FunDecl *)
539 let count_nested_braces s =
540 let bind x y
= max x y
in
541 let option_default = 0 in
542 let stmt_count r k
s =
543 match Ast.unwrap
s with
544 Ast.Seq
(_
,_
,_
) | Ast.FunDecl
(_
,_
,_
,_
) -> (k
s) + 1
546 let donothing r k e
= k e
in
548 let recursor = V.combiner
bind option_default
549 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
550 donothing donothing donothing donothing donothing
551 donothing donothing donothing donothing donothing donothing
552 donothing donothing stmt_count donothing donothing donothing in
553 let res = string_of_int
(recursor.V.combiner_statement
s) in
557 let get_label_ctr _
=
558 let cur = !labelctr in
560 string2var (Printf.sprintf
"l%d" cur)
562 (* --------------------------------------------------------------------- *)
563 (* annotate dots with before and after neighbors *)
565 let print_bef_aft = function
567 Printf.printf
"bef/aft\n";
568 Pretty_print_cocci.rule_elem "" re
;
569 Format.print_newline
()
571 Printf.printf
"bef/aft\n";
572 Pretty_print_cocci.statement
"" s;
573 Format.print_newline
()
574 | Ast.Other_dots
d ->
575 Printf.printf
"bef/aft\n";
576 Pretty_print_cocci.statement_dots
d;
577 Format.print_newline
()
579 (* [] can only occur if we are in a disj, where it comes from a ? In that
580 case, we want to use a, which accumulates all of the previous patterns in
582 let rec get_before_elem sl a
=
583 match Ast.unwrap sl
with
587 [] -> ([],Common.Right a
)
589 let (e
,ea
) = get_before_e e a
in
592 let (e
,ea
) = get_before_e e a
in
593 let (sl
,sla
) = loop sl ea
in
595 let (l,a
) = loop x a
in
596 (Ast.rewrap sl
(Ast.DOTS
(l)),a
)
597 | Ast.CIRCLES
(x
) -> failwith
"not supported"
598 | Ast.STARS
(x
) -> failwith
"not supported"
600 and get_before sl a
=
601 match get_before_elem sl a
with
602 (term
,Common.Left x
) -> (term
,x
)
603 | (term
,Common.Right x
) -> (term
,x
)
605 and get_before_whencode wc
=
608 Ast.WhenNot w
-> let (w
,_
) = get_before w
[] in Ast.WhenNot w
609 | Ast.WhenAlways w
-> let (w
,_
) = get_before_e w
[] in Ast.WhenAlways w
610 | Ast.WhenModifier
(x
) -> Ast.WhenModifier
(x
)
611 | Ast.WhenNotTrue w
-> Ast.WhenNotTrue w
612 | Ast.WhenNotFalse w
-> Ast.WhenNotFalse w
)
615 and get_before_e
s a
=
616 match Ast.unwrap
s with
617 Ast.Dots
(d,w
,_
,aft
) ->
618 (Ast.rewrap
s (Ast.Dots
(d,get_before_whencode w
,a
,aft
)),a
)
619 | Ast.Nest
(starter
,stmt_dots
,ender
,w
,multi
,_
,aft
) ->
620 let w = get_before_whencode
w in
621 let (sd
,_
) = get_before stmt_dots a
in
623 got rid of this, don't want to let nests overshoot
628 Unify_ast.unify_statement_dots
629 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
631 Unify_ast.MAYBE -> false
633 | Ast.Other_dots a ->
634 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
636 Unify_ast.MAYBE -> false
640 (Ast.rewrap
s (Ast.Nest
(starter
,sd
,ender
,w,multi
,a,aft
)),
641 [Ast.Other_dots stmt_dots
])
642 | Ast.Disj
(stmt_dots_list
) ->
644 List.split
(List.map
(function e
-> get_before e
a) stmt_dots_list
) in
645 (Ast.rewrap
s (Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
647 (match Ast.unwrap ast
with
648 Ast.MetaStmt
(_
,_
,_
,_
) -> (s,[])
649 | _
-> (s,[Ast.Other
s]))
650 | Ast.Seq
(lbrace
,body
,rbrace
) ->
651 let index = count_nested_braces s in
652 let (bd
,_
) = get_before body
[Ast.WParen
(lbrace
,index)] in
653 (Ast.rewrap
s (Ast.Seq
(lbrace
,bd
,rbrace
)),[Ast.WParen
(rbrace
,index)])
654 | Ast.Define
(header
,body
) ->
655 let (body
,_
) = get_before body
[] in
656 (Ast.rewrap
s (Ast.Define
(header
,body
)), [Ast.Other
s])
657 | Ast.IfThen
(ifheader
,branch
,aft
) ->
658 let (br
,_
) = get_before_e branch
[] in
659 (Ast.rewrap
s (Ast.IfThen
(ifheader
,br
,aft
)), [Ast.Other
s])
660 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
661 let (br1
,_
) = get_before_e branch1
[] in
662 let (br2
,_
) = get_before_e branch2
[] in
663 (Ast.rewrap
s (Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other
s])
664 | Ast.While
(header
,body
,aft
) ->
665 let (bd
,_
) = get_before_e body
[] in
666 (Ast.rewrap
s (Ast.While
(header
,bd
,aft
)),[Ast.Other
s])
667 | Ast.For
(header
,body
,aft
) ->
668 let (bd
,_
) = get_before_e body
[] in
669 (Ast.rewrap
s (Ast.For
(header
,bd
,aft
)),[Ast.Other
s])
670 | Ast.Do
(header
,body
,tail
) ->
671 let (bd
,_
) = get_before_e body
[] in
672 (Ast.rewrap
s (Ast.Do
(header
,bd
,tail
)),[Ast.Other
s])
673 | Ast.Iterator
(header
,body
,aft
) ->
674 let (bd
,_
) = get_before_e body
[] in
675 (Ast.rewrap
s (Ast.Iterator
(header
,bd
,aft
)),[Ast.Other
s])
676 | Ast.Switch
(header
,lb
,decls
,cases
,rb
) ->
677 let index = count_nested_braces s in
678 let (de
,dea
) = get_before decls
[Ast.WParen
(lb
,index)] in
681 (function case_line
->
682 match Ast.unwrap case_line
with
683 Ast.CaseLine
(header
,body
) ->
684 let (body
,_
) = get_before body
[] in
685 Ast.rewrap case_line
(Ast.CaseLine
(header
,body
))
686 | Ast.OptCase
(case_line
) -> failwith
"not supported")
688 (Ast.rewrap
s (Ast.Switch
(header
,lb
,de
,cases,rb
)),
689 [Ast.WParen
(rb
,index)])
690 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
691 let (bd
,_
) = get_before body
[] in
692 (Ast.rewrap
s (Ast.FunDecl
(header
,lbrace
,bd
,rbrace
)),[])
694 Pretty_print_cocci.statement
"" s; Format.print_newline
();
695 failwith
"get_before_e: not supported"
697 let rec get_after sl
a =
698 match Ast.unwrap sl
with
704 let (sl
,sla
) = loop sl
in
705 let (e
,ea
) = get_after_e e sla
in
707 let (l,a) = loop x
in
708 (Ast.rewrap sl
(Ast.DOTS
(l)),a)
709 | Ast.CIRCLES
(x
) -> failwith
"not supported"
710 | Ast.STARS
(x
) -> failwith
"not supported"
712 and get_after_whencode
a wc
=
715 Ast.WhenNot
w -> let (w,_
) = get_after w a (*?*) in Ast.WhenNot
w
716 | Ast.WhenAlways
w -> let (w,_
) = get_after_e
w a in Ast.WhenAlways
w
717 | Ast.WhenModifier
(x
) -> Ast.WhenModifier
(x
)
718 | Ast.WhenNotTrue
w -> Ast.WhenNotTrue
w
719 | Ast.WhenNotFalse
w -> Ast.WhenNotFalse
w)
722 and get_after_e
s a =
723 match Ast.unwrap
s with
724 Ast.Dots
(d,w,bef
,_
) ->
725 (Ast.rewrap
s (Ast.Dots
(d,get_after_whencode
a w,bef
,a)),a)
726 | Ast.Nest
(starter
,stmt_dots
,ender
,w,multi
,bef
,_
) ->
727 let w = get_after_whencode
a w in
728 let (sd
,_
) = get_after stmt_dots
a in
730 got rid of this. don't want to let nests overshoot
735 Unify_ast.unify_statement_dots
736 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
738 Unify_ast.MAYBE -> false
740 | Ast.Other_dots a ->
741 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
743 Unify_ast.MAYBE -> false
747 (Ast.rewrap
s (Ast.Nest
(starter
,sd
,ender
,w,multi
,bef
,a)),
748 [Ast.Other_dots stmt_dots
])
749 | Ast.Disj
(stmt_dots_list
) ->
751 List.split
(List.map
(function e
-> get_after e
a) stmt_dots_list
) in
752 (Ast.rewrap
s (Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
754 (match Ast.unwrap ast
with
755 Ast.MetaStmt
(nm,keep
,Ast.SequencibleAfterDots _
,i
) ->
756 (* check "after" information for metavar optimization *)
757 (* if the error is not desired, could just return [], then
758 the optimization (check for EF) won't take place *)
762 (match Ast.unwrap x
with
763 Ast.Dots
(_
,_
,_
,_
) | Ast.Nest
(_
,_
,_
,_
,_
,_
,_
) ->
765 "dots/nest not allowed before and after stmt metavar"
767 | Ast.Other_dots x
->
768 (match Ast.undots x
with
770 (match Ast.unwrap x
with
771 Ast.Dots
(_
,_
,_
,_
) | Ast.Nest
(_
,_
,_
,_
,_
,_
,_
) ->
773 ("dots/nest not allowed before and after stmt "^
782 (Ast.MetaStmt
(nm,keep
,Ast.SequencibleAfterDots
a,i
)))),[])
783 | Ast.MetaStmt
(_
,_
,_
,_
) -> (s,[])
784 | _
-> (s,[Ast.Other
s]))
785 | Ast.Seq
(lbrace
,body
,rbrace
) ->
786 let index = count_nested_braces s in
787 let (bd
,_
) = get_after body
[Ast.WParen
(rbrace
,index)] in
788 (Ast.rewrap
s (Ast.Seq
(lbrace
,bd
,rbrace
)),
789 [Ast.WParen
(lbrace
,index)])
790 | Ast.Define
(header
,body
) ->
791 let (body
,_
) = get_after body
a in
792 (Ast.rewrap
s (Ast.Define
(header
,body
)), [Ast.Other
s])
793 | Ast.IfThen
(ifheader
,branch
,aft
) ->
794 let (br
,_
) = get_after_e branch
a in
795 (Ast.rewrap
s (Ast.IfThen
(ifheader
,br
,aft
)),[Ast.Other
s])
796 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
797 let (br1
,_
) = get_after_e branch1
a in
798 let (br2
,_
) = get_after_e branch2
a in
799 (Ast.rewrap
s (Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other
s])
800 | Ast.While
(header
,body
,aft
) ->
801 let (bd
,_
) = get_after_e body
a in
802 (Ast.rewrap
s (Ast.While
(header
,bd
,aft
)),[Ast.Other
s])
803 | Ast.For
(header
,body
,aft
) ->
804 let (bd
,_
) = get_after_e body
a in
805 (Ast.rewrap
s (Ast.For
(header
,bd
,aft
)),[Ast.Other
s])
806 | Ast.Do
(header
,body
,tail
) ->
807 let (bd
,_
) = get_after_e body
a in
808 (Ast.rewrap
s (Ast.Do
(header
,bd
,tail
)),[Ast.Other
s])
809 | Ast.Iterator
(header
,body
,aft
) ->
810 let (bd
,_
) = get_after_e body
a in
811 (Ast.rewrap
s (Ast.Iterator
(header
,bd
,aft
)),[Ast.Other
s])
812 | Ast.Switch
(header
,lb
,decls
,cases,rb
) ->
813 let index = count_nested_braces s in
816 (function case_line
->
817 match Ast.unwrap case_line
with
818 Ast.CaseLine
(header
,body
) ->
819 let (body
,_
) = get_after body
[Ast.WParen
(rb
,index)] in
820 Ast.rewrap case_line
(Ast.CaseLine
(header
,body
))
821 | Ast.OptCase
(case_line
) -> failwith
"not supported")
823 let (de
,_
) = get_after decls
[] in
824 (Ast.rewrap
s (Ast.Switch
(header
,lb
,de
,cases,rb
)),[Ast.WParen
(lb
,index)])
825 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
826 let (bd
,_
) = get_after body
[] in
827 (Ast.rewrap
s (Ast.FunDecl
(header
,lbrace
,bd
,rbrace
)),[])
828 | _
-> failwith
"get_after_e: not supported"
830 let preprocess_dots sl
=
831 let (sl
,_
) = get_before sl
[] in
832 let (sl
,_
) = get_after sl
[] in
835 let preprocess_dots_e sl
=
836 let (sl
,_
) = get_before_e sl
[] in
837 let (sl
,_
) = get_after_e sl
[] in
840 (* --------------------------------------------------------------------- *)
841 (* various return_related things *)
843 let rec ends_in_return stmt_list
=
844 match Ast.unwrap stmt_list
with
846 (match List.rev x
with
848 (match Ast.unwrap x
with
851 match Ast.unwrap x
with
852 Ast.Return
(_
,_
) | Ast.ReturnExpr
(_
,_
,_
) -> true
853 | Ast.DisjRuleElem
((_
::_
) as l) -> List.for_all
loop l
856 | Ast.Disj
(disjs
) -> List.for_all
ends_in_return disjs
859 | Ast.CIRCLES
(x
) -> failwith
"not supported"
860 | Ast.STARS
(x
) -> failwith
"not supported"
862 (* --------------------------------------------------------------------- *)
865 let exptymatch l make_match make_guard_match
=
866 let pos = fresh_pos() in
867 let matches_guard_matches =
870 let pos = Ast.make_mcode
pos in
871 (make_match (Ast.set_pos x
(Some
pos)),
872 make_guard_match
(Ast.set_pos x
(Some
pos))))
874 let (matches
,guard_matches
) = List.split
matches_guard_matches in
875 let rec suffixes = function
877 | x
::xs -> xs::(suffixes xs) in
879 (* normally, we check that an expression does not match something
880 earlier in the disjunction (calculated as prefixes). But for large
881 disjunctions, this can result in a very big CTL formula. So we
882 give the user the option to say he doesn't want this feature, if that is
884 if !Flag_matcher.no_safe_expressions
885 then List.map
(function _
-> []) matches
886 else List.rev
(suffixes (List.rev guard_matches
)) in
887 let info = (* not null *)
893 ctl_and CTL.NONSTRICT
matcher
895 (ctl_uncheck (List.fold_left
ctl_or_fl CTL.False negates
)))))
897 CTL.InnerAnd
(List.fold_left
ctl_or_fl CTL.False
(List.rev
info))
899 (* code might be a DisjRuleElem, in which case we break it apart
900 code might contain an Exp or Ty
901 this one pushes the quantifier inwards *)
902 let do_re_matches label guard
res quantified minus_quantified
=
903 let make_guard_match x
=
904 let stmt_fvs = Ast.get_mfvs x
in
905 let fvs = get_unquantified minus_quantified
stmt_fvs in
906 non_saved_quantify fvs (make_match None
true x
) in
908 let stmt_fvs = Ast.get_fvs x
in
909 let fvs = get_unquantified quantified
stmt_fvs in
910 quantify guard
fvs (make_match None guard x
) in
911 (* label used to be used here, but it is not use; label is only needed after
913 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
914 (match List.map
Ast.unwrap
res with
915 [] -> failwith
"unexpected empty disj"
916 | Ast.Exp
(e
)::rest
-> exptymatch res make_match make_guard_match
917 | Ast.Ty
(t
)::rest
-> exptymatch res make_match make_guard_match
919 if List.exists (function Ast.Exp
(_
) | Ast.Ty
(_
) -> true | _
-> false)
921 then failwith
"unexpected exp or ty";
922 List.fold_left
ctl_seqor CTL.False
(List.map
make_match res))
924 (* code might be a DisjRuleElem, in which case we break it apart
925 code doesn't contain an Exp or Ty
926 this one is for use when it is not practical to push the quantifier inwards
928 let header_match label guard code
: ('
a, Ast.meta_name
, 'b
) CTL.generic_ctl
=
929 match Ast.unwrap code
with
930 Ast.DisjRuleElem
(res) ->
931 let make_match = make_match None guard
in
932 let orop = if guard
then ctl_or else ctl_seqor in
933 (* label used to be used here, but it is not use; label is only needed after
935 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
936 (List.fold_left
orop CTL.False
(List.map
make_match res))
937 | _
-> make_match label guard code
939 (* --------------------------------------------------------------------- *)
940 (* control structures *)
942 let end_control_structure fvs header body after_pred
943 after_checks no_after_checks
(afvs
,afresh
,ainh
,aft
) after label guard
=
944 (* aft indicates what is added after the whole if, which has to be added
946 let (aft_needed
,after_branch
) =
948 Ast.CONTEXT
(_
,Ast.NOTHING
) ->
949 (false,make_seq_after2 guard after_pred after
)
952 make_match label guard
953 (make_meta_rule_elem aft
(afvs
,afresh
,ainh
)) in
955 make_seq_after guard after_pred
956 (After
(make_seq_after guard
match_endif after
))) in
957 let body = body after_branch
in
958 let s = guard_to_strict guard
in
963 (match (after
,aft_needed
) with
964 (After _
,_
) (* pattern doesn't end here *)
965 | (_
,true) (* + code added after *) -> after_checks
966 | _
-> no_after_checks
)
967 (ctl_ax_absolute s body)))
969 let ifthen ifheader branch
((afvs
,_
,_
,_
) as aft
) after
970 quantified minus_quantified label llabel slabel recurse
make_match guard
=
971 (* "if (test) thn" becomes:
972 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
974 "if (test) thn; after" becomes:
975 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
980 match seq_fvs quantified
981 [Ast.get_fvs ifheader
;Ast.get_fvs branch
;afvs
] with
982 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
983 | _
-> failwith
"not possible" in
984 let new_quantified = Common.union_set bfvs quantified
in
986 match seq_fvs minus_quantified
987 [Ast.get_mfvs ifheader
;Ast.get_mfvs branch
;[]] with
988 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
989 | _
-> failwith
"not possible" in
990 let new_mquantified = Common.union_set mbfvs minus_quantified
in
992 let if_header = quantify guard efvs
(make_match ifheader
) in
993 (* then branch and after *)
994 let lv = get_label_ctr() in
995 let used = ref false in
997 (* no point to put a label on truepred etc; it is local to this construct
998 so it must have the same label *)
1000 [truepred None
; recurse branch Tail
new_quantified new_mquantified
1001 (Some
(lv,used)) llabel slabel guard
] in
1002 let after_pred = aftpred None
in
1003 let or_cases after_branch
=
1004 ctl_or true_branch (ctl_or (fallpred None
) after_branch
) in
1005 let (if_header,wrapper
) =
1008 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1009 (ctl_and CTL.NONSTRICT
(*???*) if_header label_pred,
1010 (function body -> quantify true [lv] body))
1011 else (if_header,function x
-> x
) in
1013 (end_control_structure bfvs
if_header or_cases after_pred
1014 (Some
(ctl_ex after_pred)) None aft after label guard
)
1016 let ifthenelse ifheader branch1 els branch2
((afvs
,_
,_
,_
) as aft
) after
1017 quantified minus_quantified label llabel slabel recurse
make_match guard
=
1018 (* "if (test) thn else els" becomes:
1019 if(test) & AX((TrueBranch & AX thn) v
1020 (FalseBranch & AX (else & AX els)) v After)
1023 "if (test) thn else els; after" becomes:
1024 if(test) & AX((TrueBranch & AX thn) v
1025 (FalseBranch & AX (else & AX els)) v
1026 (After & AXAX after))
1030 (* free variables *)
1031 let (e1fvs
,b1fvs
,s1fvs
) =
1032 match seq_fvs quantified
1033 [Ast.get_fvs ifheader
;Ast.get_fvs branch1
;afvs
] with
1034 [(e1fvs
,b1fvs
);(s1fvs
,b1afvs
);_
] ->
1035 (e1fvs
,Common.union_set b1fvs b1afvs
,s1fvs
)
1036 | _
-> failwith
"not possible" in
1037 let (e2fvs
,b2fvs
,s2fvs
) =
1039 (* just combine with the else branch. no point to have separate
1040 quantifier, since there is only one possible control-flow path *)
1041 let else_fvs = Common.union_set
(Ast.get_fvs els
) (Ast.get_fvs branch2
) in
1042 match seq_fvs quantified
[Ast.get_fvs ifheader
;else_fvs;afvs
] with
1043 [(e2fvs
,b2fvs
);(s2fvs
,b2afvs
);_
] ->
1044 (e2fvs
,Common.union_set b2fvs b2afvs
,s2fvs
)
1045 | _
-> failwith
"not possible" in
1046 let bothfvs = union (union b1fvs b2fvs
) (intersect s1fvs s2fvs
) in
1047 let exponlyfvs = intersect e1fvs e2fvs
in
1048 let new_quantified = union bothfvs quantified
in
1049 (* minus free variables *)
1050 let (me1fvs
,mb1fvs
,ms1fvs
) =
1051 match seq_fvs minus_quantified
1052 [Ast.get_mfvs ifheader
;Ast.get_mfvs branch1
;[]] with
1053 [(e1fvs
,b1fvs
);(s1fvs
,b1afvs
);_
] ->
1054 (e1fvs
,Common.union_set b1fvs b1afvs
,s1fvs
)
1055 | _
-> failwith
"not possible" in
1056 let (me2fvs
,mb2fvs
,ms2fvs
) =
1058 (* just combine with the else branch. no point to have separate
1059 quantifier, since there is only one possible control-flow path *)
1061 Common.union_set
(Ast.get_mfvs els
) (Ast.get_mfvs branch2
) in
1062 match seq_fvs minus_quantified
[Ast.get_mfvs ifheader
;else_mfvs;[]] with
1063 [(e2fvs
,b2fvs
);(s2fvs
,b2afvs
);_
] ->
1064 (e2fvs
,Common.union_set b2fvs b2afvs
,s2fvs
)
1065 | _
-> failwith
"not possible" in
1066 let mbothfvs = union (union mb1fvs mb2fvs
) (intersect ms1fvs ms2fvs
) in
1067 let new_mquantified = union mbothfvs minus_quantified
in
1069 let if_header = quantify guard
exponlyfvs (make_match ifheader
) in
1070 (* then and else branches *)
1071 let lv = get_label_ctr() in
1072 let used = ref false in
1075 [truepred None
; recurse branch1 Tail
new_quantified new_mquantified
1076 (Some
(lv,used)) llabel slabel guard
] in
1081 (Common.minus_set
(Ast.get_fvs els
) new_quantified)
1082 (header_match None guard els
);
1083 recurse branch2 Tail
new_quantified new_mquantified
1084 (Some
(lv,used)) llabel slabel guard
] in
1085 let after_pred = aftpred None
in
1086 let or_cases after_branch
=
1087 ctl_or true_branch (ctl_or false_branch after_branch
) in
1088 let s = guard_to_strict guard
in
1089 let (if_header,wrapper
) =
1092 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1093 (ctl_and CTL.NONSTRICT
(*???*) if_header label_pred,
1094 (function body -> quantify true [lv] body))
1095 else (if_header,function x
-> x
) in
1097 (end_control_structure bothfvs if_header or_cases after_pred
1098 (Some
(ctl_and s (ctl_ex (falsepred None
)) (ctl_ex after_pred)))
1099 (Some
(ctl_ex (falsepred None
)))
1100 aft after label guard
)
1102 let forwhile header
body ((afvs
,_
,_
,_
) as aft
) after
1103 quantified minus_quantified label recurse
make_match guard
=
1105 (* the translation in this case is similar to that of an if with no else *)
1106 (* free variables *)
1108 match seq_fvs quantified
[Ast.get_fvs header
;Ast.get_fvs
body;afvs
] with
1109 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
1110 | _
-> failwith
"not possible" in
1111 let new_quantified = Common.union_set bfvs quantified
in
1112 (* minus free variables *)
1114 match seq_fvs minus_quantified
1115 [Ast.get_mfvs header
;Ast.get_mfvs
body;[]] with
1116 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
1117 | _
-> failwith
"not possible" in
1118 let new_mquantified = Common.union_set mbfvs minus_quantified
in
1120 let header = quantify guard efvs
(make_match header) in
1121 let lv = get_label_ctr() in
1122 let used = ref false in
1126 recurse
body Tail
new_quantified new_mquantified
1127 (Some
(lv,used)) (Some
(lv,used)) None guard
] in
1128 let after_pred = loopfallpred None
in
1129 let or_cases after_branch
= ctl_or body after_branch
in
1130 let (header,wrapper
) =
1133 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1134 (ctl_and CTL.NONSTRICT
(*???*) header label_pred,
1135 (function body -> quantify true [lv] body))
1136 else (header,function x
-> x
) in
1138 (end_control_structure bfvs
header or_cases after_pred
1139 (Some
(ctl_ex after_pred)) None aft after label guard
) in
1140 match (Ast.unwrap
body,aft
) with
1141 (Ast.Atomic
(re
),(_
,_
,_
,Ast.CONTEXT
(_
,Ast.NOTHING
))) ->
1142 (match Ast.unwrap re
with
1143 Ast.MetaStmt
((_
,_
,Ast.CONTEXT
(_
,Ast.NOTHING
),_
),
1144 Type_cocci.Unitary
,_
,false)
1145 when after
= Tail
or after
= End
or after
= VeryEnd
->
1147 match seq_fvs quantified
[Ast.get_fvs
header] with
1149 | _
-> failwith
"not possible" in
1150 quantify guard efvs
(make_match header)
1154 (* --------------------------------------------------------------------- *)
1155 (* statement metavariables *)
1157 (* issue: an S metavariable that is not an if branch/loop body
1158 should not match an if branch/loop body, so check that the labels
1159 of the nodes before the first node matched by the S are different
1160 from the label of the first node matched by the S *)
1161 let sequencibility body label_pred process_bef_aft
= function
1162 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
1165 (ctl_and CTL.NONSTRICT
(ctl_not (ctl_back_ax label_pred)) x
))
1166 | Ast.SequencibleAfterDots
l ->
1167 (* S appears after some dots. l is the code that comes after the S.
1168 want to search for that first, because S can match anything, while
1169 the stuff after is probably more restricted *)
1170 let afts = List.map process_bef_aft
l in
1171 let ors = foldl1 ctl_or afts in
1172 ctl_and CTL.NONSTRICT
1173 (ctl_ef (ctl_and CTL.NONSTRICT
ors (ctl_back_ax label_pred)))
1176 ctl_and CTL.NONSTRICT
(ctl_not (ctl_back_ax label_pred)) x
))
1177 | Ast.NotSequencible
-> body (function x
-> x
)
1179 let svar_context_with_add_after stmt
s label quantified
d ast
1180 seqible after process_bef_aft guard fvinfo
=
1181 let label_var = (*fresh_label_var*) string2var "_lab" in
1183 CTL.Pred
(Lib_engine.Label
(label_var),CTL.Control
) in
1184 (*let prelabel_pred =
1185 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in*)
1186 let matcher d = make_match None guard
(make_meta_rule_elem d fvinfo
) in
1187 let full_metamatch = matcher d in
1188 let first_metamatch =
1191 Ast.CONTEXT
(pos,Ast.BEFOREAFTER
(bef
,_
,c
)) ->
1192 Ast.CONTEXT
(pos,Ast.BEFORE
(bef
,c
))
1193 | Ast.CONTEXT
(pos,_
) -> Ast.CONTEXT
(pos,Ast.NOTHING
)
1194 | Ast.MINUS
(_
,_
,_
,_
) | Ast.PLUS _
-> failwith
"not possible") in
1196 let middle_metamatch =
1199 Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1200 | Ast.MINUS(_,_,_,_) | Ast.PLUS _ -> failwith "not possible") in
1202 let last_metamatch =
1205 Ast.CONTEXT
(pos,Ast.BEFOREAFTER
(_
,aft
,c
)) ->
1206 Ast.CONTEXT
(pos,Ast.AFTER
(aft
,c
))
1207 | Ast.CONTEXT
(_
,_
) -> d
1208 | Ast.MINUS
(_
,_
,_
,_
) | Ast.PLUS _
-> failwith
"not possible") in
1212 ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in
1215 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1216 let left_or = (* the whole statement is one node *)
1217 make_seq_after guard
1218 (ctl_and CTL.NONSTRICT
(ctl_not (ctl_ex to_end)) full_metamatch) after
in
1219 let right_or = (* the statement covers multiple nodes *)
1220 ctl_and CTL.NONSTRICT
1223 [to_end; make_seq_after guard
last_metamatch after
]))
1229 [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in
1233 ctl_au CTL.NONSTRICT
1236 [ctl_and CTL.NONSTRICT last_metamatch label_pred;
1238 (ctl_not prelabel_pred) after])] in
1242 ctl_and CTL.NONSTRICT
label_pred
1243 (f
(ctl_and CTL.NONSTRICT
1244 (make_raw_match label
false ast
) (ctl_or left_or right_or))) in
1245 let stmt_fvs = Ast.get_fvs stmt
in
1246 let fvs = get_unquantified quantified
stmt_fvs in
1247 quantify guard
(label_var::fvs)
1248 (sequencibility body label_pred process_bef_aft seqible
)
1250 let svar_minus_or_no_add_after stmt
s label quantified
d ast
1251 seqible after process_bef_aft guard fvinfo
=
1252 let label_var = (*fresh_label_var*) string2var "_lab" in
1254 CTL.Pred
(Lib_engine.Label
(label_var),CTL.Control
) in
1256 CTL.Pred
(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
1257 let matcher d = make_match None guard
(make_meta_rule_elem d fvinfo
) in
1259 match (d,after
) with
1260 (Ast.PLUS _
, _
) -> failwith
"not possible"
1261 | (Ast.CONTEXT
(pos,Ast.NOTHING
),(Tail
|End
|VeryEnd
)) ->
1262 (* just match the root. don't care about label; always ok *)
1263 make_raw_match None
false ast
1264 | (Ast.CONTEXT
(pos,Ast.BEFORE
(_
,_
)),(Tail
|End
|VeryEnd
)) ->
1265 ctl_and CTL.NONSTRICT
1266 (make_raw_match None
false ast
) (* statement *)
1267 (matcher d) (* transformation *)
1268 | (Ast.CONTEXT
(pos,(Ast.NOTHING
|Ast.BEFORE
(_
,_
))),(After
a | Guard
a)) ->
1269 (* This case and the MINUS one couldprobably be merged, if
1270 HackForStmt were to notice when its arguments are trivial *)
1271 let first_metamatch = matcher d in
1272 (* try to follow after link *)
1273 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1275 ctl_ex(make_seq guard
[to_end; CTL.True
; a]) in
1277 make_seq_after guard
(ctl_not (ctl_ex to_end)) after
in
1278 ctl_and CTL.NONSTRICT
(make_raw_match label
false ast
)
1279 (ctl_and CTL.NONSTRICT
1280 first_metamatch (ctl_or is_compound not_compound))
1281 | (Ast.CONTEXT
(pos,(Ast.AFTER _
|Ast.BEFOREAFTER _
)),_
) ->
1282 failwith
"not possible"
1283 | (Ast.MINUS
(pos,inst
,adj
,l),after
) ->
1284 let (first_metamatch,last_metamatch,rest_metamatch
) =
1286 [] -> (matcher(Ast.CONTEXT
(pos,Ast.NOTHING
)),CTL.True
,matcher d)
1288 matcher(Ast.MINUS
(pos,inst
,adj
,[])),
1289 ctl_and CTL.NONSTRICT
1290 (ctl_not (make_raw_match label
false ast
))
1291 (matcher(Ast.MINUS
(pos,inst
,adj
,[])))) in
1292 (* try to follow after link *)
1293 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1297 [to_end; make_seq_after guard
last_metamatch after
]) in
1299 make_seq_after guard
(ctl_not (ctl_ex to_end)) after
in
1300 ctl_and CTL.NONSTRICT
1301 (ctl_and CTL.NONSTRICT
(make_raw_match label
false ast
)
1302 (ctl_and CTL.NONSTRICT
1303 first_metamatch (ctl_or is_compound not_compound)))
1304 (* don't have to put anything before the beginning, so don't have to
1305 distinguish the first node. so don't have to bother about paths,
1306 just use the label. label ensures that found nodes match up with
1307 what they should because it is in the lhs of the andany. *)
1308 (CTL.HackForStmt
(CTL.FORWARD
,CTL.NONSTRICT
,
1309 ctl_and CTL.NONSTRICT
label_pred
1310 (make_raw_match label
false ast
),
1311 ctl_and CTL.NONSTRICT rest_metamatch
prelabel_pred))
1313 let body f
= ctl_and CTL.NONSTRICT
label_pred (f
ender) in
1314 let stmt_fvs = Ast.get_fvs stmt
in
1315 let fvs = get_unquantified quantified
stmt_fvs in
1316 quantify guard
(label_var::fvs)
1317 (sequencibility body label_pred process_bef_aft seqible
)
1319 (* --------------------------------------------------------------------- *)
1320 (* dots and nests *)
1322 let dots_au is_strict toend label
s wrapcode n x seq_after y quantifier
=
1323 let matchgoto = gotopred None
in
1325 make_match None
false
1327 (Ast.Break
(Ast.make_mcode
"break",Ast.make_mcode
";"))) in
1329 make_match None
false
1331 (Ast.Continue
(Ast.make_mcode
"continue",Ast.make_mcode
";"))) in
1333 if quantifier
= Exists
1334 then Common.Left
(CTL.False
)
1336 then Common.Left
(CTL.Or
(aftpred label
,exitpred label
))
1338 then Common.Left
(aftpred label
)
1341 (function vx
-> function v ->
1342 (* vx is the contents of the nest, if any. we can only stop early
1343 if we find neither the ending code nor the nest contents in
1344 the if branch. not sure if this is a good idea. *)
1345 let lv = get_label_ctr() in
1346 let labelpred = CTL.Pred
(Lib_engine.Label
lv,CTL.Control
) in
1347 let preflabelpred = label_pred_maker (Some
(lv,ref true)) in
1349 (* Rather a special case. But if the code afterwards is just
1350 a } then there is no point checking after a goto that it does
1352 (* this optimization doesn't work. probably depends on whether
1353 the destination of the break/goto is local or more global than
1355 match seq_after
with
1357 let is_paren = function
1358 CTL.Pred
(Lib_engine.Paren _
,_
) -> true
1360 is_paren e1
or is_paren e2
1362 ctl_or (aftpred label
)
1363 (quantify false [lv]
1364 (ctl_and CTL.NONSTRICT
1365 (ctl_and CTL.NONSTRICT
(truepred label
) labelpred)
1366 (ctl_au CTL.NONSTRICT
1367 (ctl_and CTL.NONSTRICT
(ctl_not v)
1368 (ctl_and CTL.NONSTRICT vx
preflabelpred))
1369 (ctl_and CTL.NONSTRICT
preflabelpred
1370 (if !Flag_matcher.only_return_is_error_exit
1372 (ctl_and CTL.NONSTRICT
1373 (retpred None
) (ctl_not seq_after
))
1376 (ctl_and CTL.NONSTRICT
1377 (ctl_or (retpred None
) matchcontinue)
1378 (ctl_not seq_after
))
1379 (ctl_and CTL.NONSTRICT
1380 (ctl_or matchgoto matchbreak)
1382 (* an optim that failed see defn is_paren
1383 and tests/makes_a_loop *)
1387 (ctl_not seq_after
))))))))))) in
1388 let op = if quantifier
= !exists then ctl_au else ctl_anti_au in
1389 let v = get_let_ctr() in
1391 (match stop_early with
1392 Common.Left x1
-> ctl_or y x1
1393 | Common.Right
stop_early ->
1396 (ctl_and CTL.NONSTRICT
(label_pred_maker label
)
1397 (stop_early n
(CTL.Ref
v)))))
1399 let rec dots_and_nests plus nest whencodes bef aft dotcode after label
1400 process_bef_aft statement_list statement guard quantified wrapcode
=
1401 let ctl_and_ns = ctl_and CTL.NONSTRICT
in
1402 (* proces bef_aft *)
1404 List.fold_left
ctl_or_fl CTL.False
(List.map process_bef_aft
l) in
1405 let bef_aft = (* to be negated *)
1409 (function Ast.WhenModifier
(Ast.WhenAny
) -> true | _ -> false)
1412 with Not_found
-> shortest (Common.union_set bef aft
) in
1415 (function Ast.WhenModifier
(Ast.WhenStrict
) -> true | _ -> false)
1417 let check_quantifier quant other
=
1419 (function Ast.WhenModifier
(x
) -> x
= quant
| _ -> false)
1423 (function Ast.WhenModifier
(x
) -> x
= other
| _ -> false)
1425 then failwith
"inconsistent annotation on dots"
1429 if check_quantifier Ast.WhenExists
Ast.WhenForall
1432 if check_quantifier Ast.WhenForall
Ast.WhenExists
1435 (* the following is used when we find a goto, etc and consider accepting
1436 without finding the rest of the pattern *)
1437 let aft = shortest aft in
1438 (* process whencode *)
1439 let labelled = label_pred_maker label
in
1441 let (poswhen
,negwhen
) =
1443 (function (poswhen
,negwhen
) ->
1445 Ast.WhenNot
whencodes ->
1446 (poswhen
,ctl_or (statement_list
whencodes) negwhen
)
1447 | Ast.WhenAlways stm
->
1448 (ctl_and CTL.NONSTRICT
(statement stm
) poswhen
,negwhen
)
1449 | Ast.WhenModifier
(_) -> (poswhen
,negwhen
)
1450 | Ast.WhenNotTrue
(e
) ->
1452 ctl_or (whencond_true e label guard quantified
) negwhen
)
1453 | Ast.WhenNotFalse
(e
) ->
1455 ctl_or (whencond_false e label guard quantified
) negwhen
))
1456 (CTL.True
,CTL.False
(*bef_aft*)) (List.rev
whencodes) in
1457 (*bef_aft modifies arg so that inside of a nest can't cause the next
1458 to overshoot its boundaries, eg a() <...f()...> b() where f is
1459 a metavariable and the whole thing matches code in a loop;
1460 don't want f to match eg b(), allowing to go around the loop again*)
1461 let poswhen = ctl_and_ns arg
poswhen in
1465 (* add in After, because it's not part of the program *)
1466 ctl_or (aftpred label
) negwhen
1468 ctl_and_ns poswhen (ctl_not negwhen) in
1469 (* process dot code, if any *)
1471 match (dotcode,guard
) with
1472 (None
,_) | (_,true) -> CTL.True
1473 | (Some
dotcode,_) -> dotcode in
1474 (* process nest code, if any *)
1475 (* whencode goes in the negated part of the nest; if no nest, just goes
1476 on the "true" in between code *)
1477 let plus_var = if plus
then get_label_ctr() else string2var "" in
1478 let plus_var2 = if plus
then get_label_ctr() else string2var "" in
1479 let (ornest
,just_nest
) =
1480 (* just_nest is used when considering whether to stop early, to continue
1481 to collect nest information in the if branch *)
1482 match (nest
,guard
&& not plus
) with
1483 (None
,_) | (_,true) -> (whencodes CTL.True
,CTL.True
)
1484 | (Some nest
,false) ->
1485 let v = get_let_ctr() in
1489 (* the idea is that BindGood is sort of a witness; a witness to
1490 having found the subterm in at least one place. If there is
1491 not a witness, then there is a risk that it will get thrown
1492 away, if it is merged with a node that has an empty
1493 environment. See tests/nestplus. But this all seems
1494 rather suspicious *)
1495 CTL.And
(CTL.NONSTRICT
,x
,
1496 CTL.Exists
(true,plus_var2,
1497 CTL.Pred
(Lib_engine.BindGood
(plus_var),
1498 CTL.Modif
plus_var2)))
1502 CTL.Or
(is_plus (CTL.Ref
v),
1503 whencodes (CTL.Not
(ctl_uncheck (CTL.Ref
v))))) in
1505 let plus_modifier x
=
1512 CTL.Not
(CTL.Pred
(Lib_engine.BindBad
(plus_var),CTL.Control
)))))
1517 (* label within dots is taken care of elsewhere. the next two lines
1518 put the label on the code following dots *)
1519 After f
-> ctl_and (guard_to_strict guard
) f
labelled
1521 (* actually, label should be None based on the only use of Guard... *)
1522 assert (label
= None
);
1523 ctl_and CTL.NONSTRICT
(ctl_uncheck f
) labelled
1525 let exit = endpred label
in
1526 let errorexit = exitpred label
in
1527 ctl_or exit errorexit
1528 (* not at all sure what the next two mean... *)
1532 Some
(lv,used) -> used := true;
1533 ctl_or (CTL.Pred
(Lib_engine.Label
lv,CTL.Control
))
1534 (ctl_back_ex (ctl_or (retpred label
) (gotopred label
)))
1535 | None
-> endpred label
)
1536 (* was the following, but not clear why sgrep should allow
1538 let exit = endpred label in
1539 let errorexit = exitpred label in
1541 then ctl_or exit errorexit (* end anywhere *)
1542 else exit (* end at the real end of the function *) *)
in
1544 (dots_au is_strict ((after
= Tail
) or (after
= VeryEnd
))
1545 label
(guard_to_strict guard
) wrapcode just_nest
1547 (ctl_and_ns (ctl_and_ns (ctl_not bef_aft) ornest
) labelled))
1548 aft ender quantifier)
1550 and get_whencond_exps e
=
1551 match Ast.unwrap e
with
1553 | Ast.DisjRuleElem
(res) ->
1554 List.fold_left
Common.union_set
[] (List.map get_whencond_exps
res)
1555 | _ -> failwith
"not possible"
1557 and make_whencond_headers e e1 label guard quantified
=
1558 let fvs = Ast.get_fvs e
in
1560 quantify guard
(get_unquantified quantified
fvs)
1561 (make_match label guard h
) in
1566 (Ast.make_mcode
"if",
1567 Ast.make_mcode
"(",e1
,Ast.make_mcode
")"))) in
1568 let while_header e1
=
1572 (Ast.make_mcode
"while",
1573 Ast.make_mcode
"(",e1
,Ast.make_mcode
")"))) in
1578 (Ast.make_mcode
"for",Ast.make_mcode
"(",None
,Ast.make_mcode
";",
1579 Some e1
,Ast.make_mcode
";",None
,Ast.make_mcode
")"))) in
1581 List.fold_left
ctl_or CTL.False
(List.map
if_header e1
) in
1583 List.fold_left
ctl_or CTL.False
(List.map
while_header e1
) in
1585 List.fold_left
ctl_or CTL.False
(List.map
for_header e1
) in
1586 (if_headers, while_headers, for_headers)
1588 and whencond_true e label guard quantified
=
1589 let e1 = get_whencond_exps e
in
1590 let (if_headers, while_headers, for_headers) =
1591 make_whencond_headers e
e1 label guard quantified
in
1593 (ctl_and CTL.NONSTRICT
(truepred label
) (ctl_back_ex if_headers))
1594 (ctl_and CTL.NONSTRICT
1595 (inlooppred label
) (ctl_back_ex (ctl_or while_headers for_headers)))
1597 and whencond_false e label guard quantified
=
1598 let e1 = get_whencond_exps e
in
1599 let (if_headers, while_headers, for_headers) =
1600 make_whencond_headers e
e1 label guard quantified
in
1602 ctl_or (ctl_and CTL.NONSTRICT
(falsepred label
) (ctl_back_ex if_headers))
1603 (* if without else *)
1604 (ctl_or (ctl_and CTL.NONSTRICT
(fallpred label
) (ctl_back_ex if_headers))
1605 (* failure of loop test *)
1606 (ctl_and CTL.NONSTRICT
(loopfallpred label
)
1607 (ctl_or (ctl_back_ex while_headers) (ctl_back_ex for_headers))))
1609 (* --------------------------------------------------------------------- *)
1610 (* the main translation loop *)
1612 let rec statement_list stmt_list after quantified minus_quantified
1613 label llabel slabel dots_before guard
=
1615 (* include Disj to be on the safe side *)
1616 match Ast.unwrap x
with
1617 Ast.Dots
_ | Ast.Nest
_ | Ast.Disj
_ -> true | _ -> false in
1618 let compute_label l e db
= if db
or isdots e
then l else None
in
1619 match Ast.unwrap stmt_list
with
1621 let rec loop quantified minus_quantified dots_before label llabel slabel
1623 ([],_,_) -> (match after
with After f
-> f
| _ -> CTL.True
)
1625 statement e after quantified minus_quantified
1626 (compute_label label e dots_before
)
1628 | (e
::sl
,fv
::fvs,mfv
::mfvs
) ->
1629 let shared = intersectll fv
fvs in
1630 let unqshared = get_unquantified quantified
shared in
1631 let new_quantified = Common.union_set
unqshared quantified
in
1632 let minus_shared = intersectll mfv mfvs
in
1634 get_unquantified minus_quantified
minus_shared in
1635 let new_mquantified =
1636 Common.union_set
munqshared minus_quantified
in
1637 quantify guard
unqshared
1640 (let (label1
,llabel1
,slabel1
) =
1641 match Ast.unwrap e
with
1643 (match Ast.unwrap re
with
1644 Ast.Goto
_ -> (None
,None
,None
)
1645 | _ -> (label
,llabel
,slabel
))
1646 | _ -> (label
,llabel
,slabel
) in
1647 loop new_quantified new_mquantified (isdots e
)
1648 label1 llabel1 slabel1
1650 new_quantified new_mquantified
1651 (compute_label label e dots_before
) llabel slabel guard
)
1652 | _ -> failwith
"not possible" in
1653 loop quantified minus_quantified dots_before
1655 (x
,List.map
Ast.get_fvs x
,List.map
Ast.get_mfvs x
)
1656 | Ast.CIRCLES
(x
) -> failwith
"not supported"
1657 | Ast.STARS
(x
) -> failwith
"not supported"
1659 (* llabel is the label of the enclosing loop and slabel is the label of the
1661 and statement stmt after quantified minus_quantified
1662 label llabel slabel guard
=
1663 let ctl_au = ctl_au CTL.NONSTRICT
in
1664 let ctl_ax = ctl_ax CTL.NONSTRICT
in
1665 let ctl_and = ctl_and CTL.NONSTRICT
in
1666 let make_seq = make_seq guard
in
1667 let make_seq_after = make_seq_after guard
in
1668 let real_make_match = make_match in
1669 let make_match = header_match label guard
in
1671 let dots_done = ref false in (* hack for dots cases we can easily handle *)
1674 match Ast.unwrap stmt
with
1676 (match Ast.unwrap ast
with
1677 (* the following optimisation is not a good idea, because when S
1678 is alone, we would like it not to match a declaration.
1679 this makes more matching for things like when (...) S, but perhaps
1680 that matching is not so costly anyway *)
1681 (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*)
1682 | Ast.MetaStmt
((s,_,(Ast.CONTEXT
(_,Ast.BEFOREAFTER
(_,_,_)) as d),_),
1684 | Ast.MetaStmt
((s,_,(Ast.CONTEXT
(_,Ast.AFTER
(_,_)) as d),_),
1686 svar_context_with_add_after stmt
s label quantified
d ast seqible
1688 (process_bef_aft quantified minus_quantified
1689 label llabel slabel
true)
1691 (Ast.get_fvs stmt
, Ast.get_fresh stmt
, Ast.get_inherited stmt
)
1693 | Ast.MetaStmt
((s,_,d,_),keep
,seqible
,_) ->
1694 svar_minus_or_no_add_after stmt
s label quantified
d ast seqible
1696 (process_bef_aft quantified minus_quantified
1697 label llabel slabel
true)
1699 (Ast.get_fvs stmt
, Ast.get_fresh stmt
, Ast.get_inherited stmt
)
1703 match Ast.unwrap ast
with
1704 Ast.DisjRuleElem
(res) ->
1705 do_re_matches label guard
res quantified minus_quantified
1706 | Ast.Exp
(_) | Ast.Ty
(_) ->
1707 let stmt_fvs = Ast.get_fvs stmt
in
1708 let fvs = get_unquantified quantified
stmt_fvs in
1709 CTL.InnerAnd
(quantify guard
fvs (make_match ast
))
1711 let stmt_fvs = Ast.get_fvs stmt
in
1712 let fvs = get_unquantified quantified
stmt_fvs in
1713 quantify guard
fvs (make_match ast
) in
1714 match Ast.unwrap ast
with
1715 Ast.Break
(brk
,semi
) ->
1716 (match (llabel
,slabel
) with
1717 (_,Some
(lv,used)) -> (* use switch label if there is one *)
1718 ctl_and term (bclabel_pred_maker slabel
)
1719 | _ -> ctl_and term (bclabel_pred_maker llabel
))
1720 | Ast.Continue
(brk
,semi
) -> ctl_and term (bclabel_pred_maker llabel
)
1721 | Ast.Return
((_,info,retmc
,pos),(_,_,semmc
,_)) ->
1722 (* discard pattern that comes after return *)
1723 let normal_res = make_seq_after term after
in
1724 (* the following code tries to propagate the modifications on
1725 return; to a close brace, in the case where the final return
1728 match (retmc
,semmc
) with
1729 (Ast.MINUS
(_,inst1
,adj1
,l1
),Ast.MINUS
(_,_,_,l2
))
1730 when !Flag.sgrep_mode2
->
1731 (* in sgrep mode, we can propagate the - *)
1732 Some
(Ast.MINUS
(Ast.NoPos
,inst1
,adj1
,l1
@l2
))
1733 | (Ast.MINUS
(_,_,_,l1
),Ast.MINUS
(_,_,_,l2
)) ->
1734 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l1
@l2
,Ast.ONE
)))
1735 | (Ast.CONTEXT
(_,Ast.BEFORE
(l1
,c1
)),
1736 Ast.CONTEXT
(_,Ast.AFTER
(l2
,c2
))) ->
1737 (if not
(c1
= c2
) then failwith
"bad + code");
1738 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l1
@l2
,c1
)))
1739 | (Ast.CONTEXT
(_,Ast.BEFORE
(_)),Ast.CONTEXT
(_,Ast.NOTHING
))
1740 | (Ast.CONTEXT
(_,Ast.NOTHING
),Ast.CONTEXT
(_,Ast.NOTHING
)) ->
1742 | (Ast.CONTEXT
(_,Ast.NOTHING
),
1743 Ast.CONTEXT
(_,Ast.AFTER
(l,c
))) ->
1744 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l,c
)))
1746 let ret = Ast.make_mcode
"return" in
1748 Ast.rewrap ast
(Ast.Edots
(Ast.make_mcode
"...",None
)) in
1749 let semi = Ast.make_mcode
";" in
1751 make_match(Ast.rewrap ast
(Ast.Return
(ret,semi))) in
1753 make_match(Ast.rewrap ast
(Ast.ReturnExpr
(ret,edots,semi))) in
1756 let exit = endpred None
in
1758 Ast.rewrap ast
(Ast.SeqEnd
(("}",info,new_mc,pos))) in
1759 let stripped_rbrace =
1760 Ast.rewrap ast
(Ast.SeqEnd
(Ast.make_mcode
"}")) in
1762 (ctl_and (make_match mod_rbrace)
1767 (ctl_or simple_return return_expr))))
1769 (make_match stripped_rbrace)
1770 (* error exit not possible; it is in the middle
1771 of code, so a return is needed *)
1774 (* some change in the middle of the return, so have to
1775 find an actual return *)
1778 (* should try to deal with the dots_bef_aft problem elsewhere,
1779 but don't have the courage... *)
1784 do_between_dots stmt
term End
1785 quantified minus_quantified label llabel slabel guard
in
1787 make_seq_after term after
)
1788 | Ast.Seq
(lbrace
,body,rbrace
) ->
1789 let (lbfvs
,b1fvs
,b2fvs
,rbfvs
) =
1792 [Ast.get_fvs lbrace
;Ast.get_fvs
body;Ast.get_fvs rbrace
]
1794 [(lbfvs
,b1fvs
);(_,b2fvs
);(rbfvs
,_)] -> (lbfvs
,b1fvs
,b2fvs
,rbfvs
)
1795 | _ -> failwith
"not possible" in
1796 let (mlbfvs
,mb1fvs
,mb2fvs
,mrbfvs
) =
1798 seq_fvs minus_quantified
1799 [Ast.get_mfvs lbrace
;Ast.get_mfvs
body;Ast.get_mfvs rbrace
]
1801 [(lbfvs
,b1fvs
);(_,b2fvs
);(rbfvs
,_)] ->
1802 (lbfvs
,b1fvs
,b2fvs
,rbfvs
)
1803 | _ -> failwith
"not possible" in
1804 let pv = count_nested_braces stmt
in
1805 let lv = get_label_ctr() in
1806 let paren_pred = CTL.Pred
(Lib_engine.Paren
pv,CTL.Control
) in
1807 let label_pred = CTL.Pred
(Lib_engine.Label
lv,CTL.Control
) in
1810 (quantify guard lbfvs
(make_match lbrace
))
1811 (ctl_and paren_pred label_pred) in
1813 match Ast.unwrap rbrace
with
1814 Ast.SeqEnd
((data
,info,_,pos)) ->
1815 Ast.rewrap rbrace
(Ast.SeqEnd
(Ast.make_mcode data
))
1816 | _ -> failwith
"unexpected close brace" in
1818 (* label is not needed; paren_pred is enough *)
1819 quantify guard rbfvs
1820 (ctl_au (make_match empty_rbrace)
1821 (ctl_and (real_make_match None guard rbrace
) paren_pred)) in
1822 let new_quantified2 =
1823 Common.union_set b1fvs
(Common.union_set b2fvs quantified
) in
1824 let new_mquantified2 =
1825 Common.union_set mb1fvs
(Common.union_set mb2fvs minus_quantified
) in
1826 let pattern_as_given =
1827 let new_quantified2 = Common.union_set
[pv] new_quantified2 in
1828 quantify true [pv;lv]
1829 (quantify guard b1fvs
1833 (if !exists = Exists
then CTL.False
else (aftpred label
))
1834 (quantify guard b2fvs
1835 (statement_list body
1836 (After
(make_seq_after end_brace after
))
1837 new_quantified2 new_mquantified2
1838 (Some
(lv,ref true))
1839 llabel slabel
false guard
)))])) in
1841 match Ast.undots
body with
1843 (match Ast.unwrap
body with
1845 ((_,i
,Ast.CONTEXT
(_,Ast.NOTHING
),_),[],_,_) ->
1846 (match Ast.unwrap rbrace
with
1847 Ast.SeqEnd
((_,_,Ast.CONTEXT
(_,Ast.NOTHING
),_))
1848 when not
(contains_pos rbrace
) -> true
1852 if empty_body && after
= Tail
1853 (* for just a match of an if branch of the form { ... }, just
1854 match the first brace *)
1855 then quantify guard lbfvs
(make_match lbrace
)
1856 else if ends_in_return body
1858 (* matching error handling code *)
1860 1. The pattern as given
1861 2. A goto, and then some close braces, and then the pattern as
1862 given, but without the braces (only possible if there are no
1863 decls, and open and close braces are unmodified)
1864 3. Part of the pattern as given, then a goto, and then the rest
1865 of the pattern. For this case, we just check that all paths have
1866 a goto within the current braces. checking for a goto at every
1867 point in the pattern seems expensive and not worthwhile. *)
1869 let body = preprocess_dots body in (* redo, to drop braces *)
1873 (make_match empty_rbrace)
1874 (ctl_ax (* skip the destination label *)
1875 (quantify guard b2fvs
1876 (statement_list body End
1877 new_quantified2 new_mquantified2 None llabel slabel
1880 let new_quantified2 = Common.union_set
[pv] new_quantified2 in
1881 quantify true [pv;lv]
1882 (quantify guard b1fvs
1886 (CTL.AU
(* want AF even for sgrep *)
1887 (CTL.FORWARD
,CTL.STRICT
,
1888 CTL.Pred
(Lib_engine.PrefixLabel
(lv),CTL.Control
),
1889 ctl_and (* brace must be eventually after goto *)
1890 (gotopred (Some
(lv,ref true)))
1891 (* want AF even for sgrep *)
1892 (CTL.AF
(CTL.FORWARD
,CTL.STRICT
,end_brace))))
1893 (quantify guard b2fvs
1894 (statement_list body Tail
1895 new_quantified2 new_mquantified2
1896 None
(*no label because past the goto*)
1897 llabel slabel
false guard
))])) in
1898 ctl_or pattern_as_given (ctl_or pattern2 pattern3)
1899 else pattern_as_given
1900 | Ast.IfThen
(ifheader
,branch
,aft) ->
1901 ifthen ifheader branch
aft after quantified minus_quantified
1902 label llabel slabel statement
make_match guard
1904 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft) ->
1905 ifthenelse ifheader branch1 els branch2
aft after quantified
1906 minus_quantified label llabel slabel statement
make_match guard
1908 | Ast.While
(header,body,aft) | Ast.For
(header,body,aft)
1909 | Ast.Iterator
(header,body,aft) ->
1910 forwhile header body aft after quantified minus_quantified
1911 label statement
make_match guard
1913 | Ast.Disj
(stmt_dots_list
) -> (* list shouldn't be empty *)
1914 (*ctl_and seems pointless, disjuncts see label too
1915 (label_pred_maker label)*)
1916 (List.fold_left
ctl_seqor CTL.False
1919 statement_list sl after quantified minus_quantified label
1920 llabel slabel
true guard
)
1923 | Ast.Nest
(starter
,stmt_dots
,ender,whencode
,multi
,bef
,aft) ->
1924 (* label in recursive call is None because label check is already
1925 wrapped around the corresponding code. not good enough, want to stay
1926 in a specific region, dots and nests will keep going *)
1929 match seq_fvs quantified
[Ast.get_wcfvs whencode
;Ast.get_fvs stmt_dots
]
1931 [(wcfvs
,bothfvs);(bdfvs
,_)] -> bothfvs
1932 | _ -> failwith
"not possible" in
1934 (* no minus version because when code doesn't contain any minus code *)
1935 let new_quantified = Common.union_set
bfvs quantified
in
1938 match Ast.get_mcodekind starter
with (*ender must have the same mcode*)
1939 Ast.MINUS
(_,_,_,_) as d ->
1940 (* no need for the fresh metavar, but ... is a bit weird as a
1942 Some
(make_match (make_meta_rule_elem d ([],[],[])))
1947 statement_list stmt_dots
(a2n after
) new_quantified minus_quantified
1948 label
(*None*) llabel slabel
true guard
in
1949 dots_and_nests multi
1950 (Some
dots_pattern) whencode bef
aft dot_code after label
1951 (process_bef_aft
new_quantified minus_quantified
1952 label
(*None*) llabel slabel
true)
1954 statement_list x Tail
new_quantified minus_quantified label
(*None*)
1955 llabel slabel
true true)
1957 statement x Tail
new_quantified minus_quantified label
(*None*)
1960 (function x
-> Ast.set_fvs
[] (Ast.rewrap stmt x
)))
1962 | Ast.Dots
((_,i
,d,_),whencodes,bef
,aft) ->
1965 Ast.MINUS
(_,_,_,_) ->
1966 (* no need for the fresh metavar, but ... is a bit weird as a
1968 Some
(make_match (make_meta_rule_elem d ([],[],[])))
1970 dots_and_nests false None
whencodes bef
aft dot_code after label
1971 (process_bef_aft quantified minus_quantified None llabel slabel
true)
1973 statement_list x Tail quantified minus_quantified
1974 None llabel slabel
true true)
1976 statement x Tail quantified minus_quantified None llabel slabel
true)
1978 (function x
-> Ast.set_fvs
[] (Ast.rewrap stmt x
))
1980 | Ast.Switch
(header,lb
,decls
,cases,rb
) ->
1981 let rec intersect_all = function
1984 | x
::xs -> intersect x
(intersect_all xs) in
1985 let rec intersect_all2 = function (* pairwise *)
1990 (function elem
-> List.exists (List.mem elem
) xs)
1992 Common.union_set
front (intersect_all2 xs) in
1993 let rec union_all l = List.fold_left
union [] l in
1994 (* start normal variables *)
1995 let header_fvs = Ast.get_fvs
header in
1996 let lb_fvs = Ast.get_fvs lb
in
1997 let decl_fvs = union_all (List.map
Ast.get_fvs
(Ast.undots decls
)) in
1998 let case_fvs = List.map
Ast.get_fvs
cases in
1999 let rb_fvs = Ast.get_fvs rb
in
2000 let (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
2001 all_casefvs
,all_b3fvs
,all_rbfvs
) =
2003 (function (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
2004 all_casefvs
,all_b3fvs
,all_rbfvs
) ->
2005 function case_fvs ->
2006 match seq_fvs quantified
[header_fvs;lb_fvs;case_fvs;rb_fvs] with
2007 [(efvs
,b1fvs
);(lbfvs
,b2fvs
);(casefvs
,b3fvs
);(rbfvs
,_)] ->
2008 (efvs
::all_efvs
,b1fvs
::all_b1fvs
,lbfvs
::all_lbfvs
,
2009 b2fvs
::all_b2fvs
,casefvs
::all_casefvs
,b3fvs
::all_b3fvs
,
2011 | _ -> failwith
"not possible")
2012 ([],[],[],[],[],[],[]) (decl_fvs :: case_fvs) in
2013 let (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
2014 all_casefvs
,all_b3fvs
,all_rbfvs
) =
2015 (List.rev all_efvs
,List.rev all_b1fvs
,List.rev all_lbfvs
,
2016 List.rev all_b2fvs
,List.rev all_casefvs
,List.rev all_b3fvs
,
2017 List.rev all_rbfvs
) in
2018 let exponlyfvs = intersect_all all_efvs
in
2019 let lbonlyfvs = intersect_all all_lbfvs
in
2020 (* don't do anything with right brace. Hope there is no + code on it *)
2021 (* let rbonlyfvs = intersect_all all_rbfvs in*)
2022 let b1fvs = union_all all_b1fvs
in
2023 let new1_quantified = union b1fvs quantified
in
2025 union (union_all all_b2fvs
) (intersect_all2 all_casefvs
) in
2026 let new2_quantified = union b2fvs new1_quantified in
2027 (* let b3fvs = union_all all_b3fvs in*)
2028 (* ------------------- start minus free variables *)
2029 let header_mfvs = Ast.get_mfvs
header in
2030 let lb_mfvs = Ast.get_mfvs lb
in
2031 let decl_mfvs = union_all (List.map
Ast.get_mfvs
(Ast.undots decls
)) in
2032 let case_mfvs = List.map
Ast.get_mfvs
cases in
2033 let rb_mfvs = Ast.get_mfvs rb
in
2034 let (all_mefvs
,all_mb1fvs
,all_mlbfvs
,all_mb2fvs
,
2035 all_mcasefvs
,all_mb3fvs
,all_mrbfvs
) =
2037 (function (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
2038 all_casefvs
,all_b3fvs
,all_rbfvs
) ->
2039 function case_mfvs ->
2042 [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with
2043 [(efvs
,b1fvs);(lbfvs
,b2fvs);(casefvs
,b3fvs);(rbfvs
,_)] ->
2044 (efvs
::all_efvs
,b1fvs::all_b1fvs
,lbfvs
::all_lbfvs
,
2045 b2fvs::all_b2fvs
,casefvs
::all_casefvs
,b3fvs::all_b3fvs
,
2047 | _ -> failwith
"not possible")
2048 ([],[],[],[],[],[],[]) (decl_mfvs::case_mfvs) in
2049 let (all_mefvs
,all_mb1fvs
,all_mlbfvs
,all_mb2fvs
,
2050 all_mcasefvs
,all_mb3fvs
,all_mrbfvs
) =
2051 (List.rev all_mefvs
,List.rev all_mb1fvs
,List.rev all_mlbfvs
,
2052 List.rev all_mb2fvs
,List.rev all_mcasefvs
,List.rev all_mb3fvs
,
2053 List.rev all_mrbfvs
) in
2054 (* don't do anything with right brace. Hope there is no + code on it *)
2055 (* let rbonlyfvs = intersect_all all_rbfvs in*)
2056 let mb1fvs = union_all all_mb1fvs
in
2057 let new1_mquantified = union mb1fvs quantified
in
2059 union (union_all all_mb2fvs
) (intersect_all2 all_mcasefvs
) in
2060 let new2_mquantified = union mb2fvs new1_mquantified in
2061 (* let b3fvs = union_all all_b3fvs in*)
2062 (* ------------------- end collection of free variables *)
2063 let switch_header = quantify guard
exponlyfvs (make_match header) in
2064 let lb = quantify guard
lbonlyfvs (make_match lb) in
2065 (* let rb = quantify guard rbonlyfvs (make_match rb) in*)
2068 (function case_line
->
2069 match Ast.unwrap case_line
with
2070 Ast.CaseLine
(header,body) ->
2072 match seq_fvs new2_quantified [Ast.get_fvs
header] with
2073 [(e1fvs,_)] -> e1fvs
2074 | _ -> failwith
"not possible" in
2075 quantify guard
e1fvs (real_make_match label
true header)
2076 | Ast.OptCase
(case_line
) -> failwith
"not supported")
2078 let lv = get_label_ctr() in
2079 let used = ref false in
2080 let (decls_exists_code
,decls_all_code
) =
2081 (*don't really understand this*)
2082 if (Ast.undots decls
) = []
2083 then (CTL.True
,CTL.False
)
2086 statement_list decls Tail
2087 new2_quantified new2_mquantified (Some
(lv,used)) llabel None
2092 (List.fold_left
ctl_or_fl CTL.False
2093 (List.map
ctl_uncheck
2094 (decls_all_code
::case_headers))) in
2097 (function case_line
->
2098 match Ast.unwrap case_line
with
2099 Ast.CaseLine
(header,body) ->
2100 let (e1fvs,b1fvs,s1fvs
) =
2101 let fvs = [Ast.get_fvs
header;Ast.get_fvs
body] in
2102 match seq_fvs new2_quantified fvs with
2103 [(e1fvs,b1fvs);(s1fvs
,_)] -> (e1fvs,b1fvs,s1fvs
)
2104 | _ -> failwith
"not possible" in
2105 let (me1fvs
,mb1fvs,ms1fvs
) =
2106 let fvs = [Ast.get_mfvs
header;Ast.get_mfvs
body] in
2107 match seq_fvs new2_mquantified fvs with
2108 [(e1fvs,b1fvs);(s1fvs
,_)] -> (e1fvs,b1fvs,s1fvs
)
2109 | _ -> failwith
"not possible" in
2111 quantify guard
e1fvs (make_match header) in
2112 let new3_quantified = union b1fvs new2_quantified in
2113 let new3_mquantified = union mb1fvs new2_mquantified in
2115 statement_list body Tail
2116 new3_quantified new3_mquantified (Some
(lv,used)) llabel
2117 (Some
(lv,used)) false(*?*) guard
in
2118 quantify guard
b1fvs (make_seq [case_header; body])
2119 | Ast.OptCase
(case_line
) -> failwith
"not supported")
2121 let default_required =
2124 match Ast.unwrap case
with
2125 Ast.CaseLine
(header,_) ->
2126 (match Ast.unwrap
header with
2127 Ast.Default
(_,_) -> true
2131 then function x
-> x
2132 else function x
-> ctl_or (fallpred label
) x
in
2133 let after_pred = aftpred label
in
2134 let body after_branch
=
2137 (quantify guard
b2fvs
2140 (List.fold_left
ctl_and CTL.True
2142 (decls_exists_code
:: case_headers)));
2143 List.fold_left
ctl_or_fl no_header
2144 (decls_all_code
:: case_code)])))
2147 (rb_fvs,Ast.get_fresh
rb,Ast.get_inherited
rb,
2148 match Ast.unwrap
rb with
2149 Ast.SeqEnd
(rb) -> Ast.get_mcodekind
rb
2150 | _ -> failwith
"not possible") in
2151 let (switch_header,wrapper
) =
2154 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
2155 (ctl_and switch_header label_pred,
2156 (function body -> quantify true [lv] body))
2157 else (switch_header,function x
-> x
) in
2159 (end_control_structure b1fvs switch_header body
2160 after_pred (Some
(ctl_ex after_pred)) None
aft after label guard
)
2161 | Ast.FunDecl
(header,lbrace
,body,rbrace
) ->
2162 let (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
) =
2165 [Ast.get_fvs
header;Ast.get_fvs lbrace
;
2166 Ast.get_fvs
body;Ast.get_fvs rbrace
]
2168 [(hfvs
,b1fvs);(lbfvs
,b2fvs);(_,b3fvs);(rbfvs
,_)] ->
2169 (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
)
2170 | _ -> failwith
"not possible" in
2171 let (mhfvs
,mb1fvs,mlbfvs
,mb2fvs,mb3fvs
,mrbfvs
) =
2174 [Ast.get_mfvs
header;Ast.get_mfvs lbrace
;
2175 Ast.get_mfvs
body;Ast.get_mfvs rbrace
]
2177 [(hfvs
,b1fvs);(lbfvs
,b2fvs);(_,b3fvs);(rbfvs
,_)] ->
2178 (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
)
2179 | _ -> failwith
"not possible" in
2180 let function_header = quantify guard hfvs
(make_match header) in
2181 let start_brace = quantify guard lbfvs
(make_match lbrace
) in
2182 let stripped_rbrace =
2183 match Ast.unwrap rbrace
with
2184 Ast.SeqEnd
((data
,info,_,_)) ->
2185 Ast.rewrap rbrace
(Ast.SeqEnd
(Ast.make_mcode data
))
2186 | _ -> failwith
"unexpected close brace" in
2188 let exit = CTL.Pred
(Lib_engine.Exit
,CTL.Control
) in
2189 let errorexit = CTL.Pred
(Lib_engine.ErrorExit
,CTL.Control
) in
2190 let fake_brace = CTL.Pred
(Lib_engine.FakeBrace
,CTL.Control
) in
2192 (quantify guard rbfvs
(make_match rbrace
))
2194 (* the following finds the beginning of the fake braces,
2195 if there are any, not completely sure how this works.
2196 sse the examples sw and return *)
2197 (ctl_back_ex (ctl_not fake_brace))
2198 (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in
2199 let new_quantified3 =
2200 Common.union_set
b1fvs
2201 (Common.union_set
b2fvs (Common.union_set
b3fvs quantified
)) in
2202 let new_mquantified3 =
2203 Common.union_set
mb1fvs
2204 (Common.union_set
mb2fvs
2205 (Common.union_set mb3fvs minus_quantified
)) in
2206 let not_minus = function Ast.MINUS
(_,_,_,_) -> false | _ -> true in
2208 match (Ast.undots
body,
2209 contains_modif rbrace
or contains_pos rbrace
) with
2211 (match Ast.unwrap
body with
2212 Ast.Nest
(starter
,stmt_dots
,ender,[],false,_,_)
2213 (* perhaps could optimize for minus case too... TODO *)
2214 when not_minus (Ast.get_mcodekind starter
)
2216 (* special case for function header + body - header is unambiguous
2217 and unique, so we can just look for the nested body anywhere
2221 (CTL.FORWARD
,guard_to_strict guard
,start_brace,
2222 statement_list stmt_dots
2223 (* discards match on right brace, but don't need it *)
2224 (Guard
(make_seq_after end_brace after
))
2225 new_quantified3 new_mquantified3
2226 None llabel slabel
true guard
))
2227 | Ast.Dots
((_,i
,d,_),whencode
,_,_) when
2229 (* flow sensitive, so not optimizable *)
2230 (function Ast.WhenNotTrue
(_) | Ast.WhenNotFalse
(_) ->
2232 | _ -> true) whencode
) ->
2233 (* try to be more efficient for the case where the body is just
2234 ... Perhaps this is too much of a special case, but useful
2235 for dropping a parameter and checking that it is never used. *)
2237 Ast.MINUS
(_,_,_,_) -> None
2240 (* no nested braces, because only dots *)
2241 string2var ("p1") in
2243 CTL.Pred
(Lib_engine.Paren
pv,CTL.Control
) in
2246 [ctl_and start_brace paren_pred;
2256 Ast.WhenAlways
(s) -> prev
2257 | Ast.WhenNot
(sl
) ->
2259 statement_list sl Tail
2265 | Ast.WhenNotTrue
(_)
2266 | Ast.WhenNotFalse
(_) ->
2267 failwith
"unexpected"
2269 (Ast.WhenAny
) -> CTL.False
2270 | Ast.WhenModifier
(_) -> prev
)
2271 CTL.False whencode
))
2275 Ast.WhenAlways
(s) ->
2280 label llabel slabel
true in
2282 | Ast.WhenNot
(sl
) -> prev
2283 | Ast.WhenNotTrue
(_)
2284 | Ast.WhenNotFalse
(_) ->
2285 failwith
"unexpected"
2286 | Ast.WhenModifier
(Ast.WhenAny
) ->
2288 | Ast.WhenModifier
(_) -> prev
)
2289 CTL.True whencode
) in
2292 (make_match stripped_rbrace)
2297 (* function body is all minus, no whencode *)
2298 match Ast.undots
body with
2300 (match Ast.unwrap
body with
2302 ((_,i
,(Ast.MINUS
(_,_,_,[]) as d),_),[],_,_) ->
2303 (match (Ast.unwrap lbrace
,Ast.unwrap rbrace
) with
2304 (Ast.SeqStart
((_,_,Ast.MINUS
(_,_,_,[]),_)),
2305 Ast.SeqEnd
((_,_,Ast.MINUS
(_,_,_,[]),_)))
2306 when not
(contains_pos rbrace
) ->
2308 (* andany drops everything to the end, including close
2309 braces - not just function body, could check
2310 label to keep braces *)
2311 (ctl_and start_brace
2314 (CTL.FORWARD
,guard_to_strict guard
,CTL.True
,
2316 (make_meta_rule_elem d ([],[],[]))))))
2321 match (optim1,optim2) with
2327 quantify guard
b3fvs
2328 (statement_list body
2329 (After
(make_seq_after end_brace after
))
2330 new_quantified3 new_mquantified3 None llabel slabel
2332 quantify guard
b1fvs
2333 (make_seq [function_header; quantify guard
b2fvs body_code])
2334 | Ast.Define
(header,body) ->
2335 let (hfvs
,bfvs,bodyfvs
) =
2336 match seq_fvs quantified
[Ast.get_fvs
header;Ast.get_fvs
body]
2338 [(hfvs
,b1fvs);(bodyfvs
,_)] -> (hfvs
,b1fvs,bodyfvs
)
2339 | _ -> failwith
"not possible" in
2340 let (mhfvs
,mbfvs
,mbodyfvs
) =
2341 match seq_fvs minus_quantified
[Ast.get_mfvs
header;Ast.get_mfvs
body]
2343 [(hfvs
,b1fvs);(bodyfvs
,_)] -> (hfvs
,b1fvs,bodyfvs
)
2344 | _ -> failwith
"not possible" in
2345 let define_header = quantify guard hfvs
(make_match header) in
2347 statement_list body after
2348 (Common.union_set
bfvs quantified
)
2349 (Common.union_set mbfvs minus_quantified
)
2350 None llabel slabel
true guard
in
2351 quantify guard
bfvs (make_seq [define_header; body_code])
2352 | Ast.OptStm
(stm
) ->
2353 failwith
"OptStm should have been compiled away\n"
2354 | Ast.UniqueStm
(stm
) -> failwith
"arities not yet supported"
2355 | _ -> failwith
"not supported" in
2356 if guard
or !dots_done
2359 do_between_dots stmt
term after quantified minus_quantified
2360 label llabel slabel guard
2362 (* term is the translation of stmt *)
2363 and do_between_dots stmt
term after quantified minus_quantified
2364 label llabel slabel guard
=
2365 match Ast.get_dots_bef_aft stmt
with
2366 Ast.AddingBetweenDots
(brace_term
,n
)
2367 | Ast.DroppingBetweenDots
(brace_term
,n
) ->
2369 statement brace_term after quantified minus_quantified
2370 label llabel slabel guard
in
2371 let v = Printf.sprintf
"_r_%d" n
in
2372 let case1 = ctl_and CTL.NONSTRICT
(CTL.Ref
v) match_brace in
2373 let case2 = ctl_and CTL.NONSTRICT
(ctl_not (CTL.Ref
v)) term in
2376 (ctl_back_ex (ctl_or (truepred label
) (inlooppred label
)))
2377 (ctl_back_ex (ctl_back_ex (falsepred label
))),
2379 | Ast.NoDots
-> term
2381 (* un_process_bef_aft is because we don't want to do transformation in this
2382 code, and thus don't case about braces before or after it *)
2383 and process_bef_aft quantified minus_quantified label llabel slabel guard
=
2385 Ast.WParen
(re
,n
) ->
2386 let paren_pred = CTL.Pred
(Lib_engine.Paren n
,CTL.Control
) in
2387 let s = guard_to_strict guard
in
2388 quantify true (get_unquantified quantified
[n
])
2389 (ctl_and s (make_raw_match None guard re
) paren_pred)
2391 statement
s Tail quantified minus_quantified label llabel slabel guard
2392 | Ast.Other_dots
d ->
2393 statement_list d Tail quantified minus_quantified
2394 label llabel slabel
true guard
2396 (* --------------------------------------------------------------------- *)
2397 (* cleanup: convert AX to EX for pdots.
2398 Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2399 This is what we wanted in the first place, but it wasn't possible to make
2400 because the AX and its argument are not created in the same place.
2402 (* also cleanup XX, which is a marker for the case where the programmer
2403 specifies to change the quantifier on .... Assumed to only occur after one AX
2404 or EX, or at top level. *)
2407 let c = match c with CTL.XX
(c) -> c | _ -> c in
2409 CTL.False
-> CTL.False
2410 | CTL.True
-> CTL.True
2411 | CTL.Pred
(p
) -> CTL.Pred
(p
)
2412 | CTL.Not
(phi
) -> CTL.Not
(cleanup phi
)
2413 | CTL.Exists
(keep
,v,phi
) -> CTL.Exists
(keep
,v,cleanup phi
)
2414 | CTL.AndAny
(dir
,s,phi1
,phi2
) ->
2415 CTL.AndAny
(dir
,s,cleanup phi1
,cleanup phi2
)
2416 | CTL.HackForStmt
(dir
,s,phi1
,phi2
) ->
2417 CTL.HackForStmt
(dir
,s,cleanup phi1
,cleanup phi2
)
2418 | CTL.And
(s,phi1
,phi2
) -> CTL.And
(s,cleanup phi1
,cleanup phi2
)
2419 | CTL.Or
(phi1
,phi2
) -> CTL.Or
(cleanup phi1
,cleanup phi2
)
2420 | CTL.SeqOr
(phi1
,phi2
) -> CTL.SeqOr
(cleanup phi1
,cleanup phi2
)
2421 | CTL.Implies
(phi1
,phi2
) -> CTL.Implies
(cleanup phi1
,cleanup phi2
)
2422 | CTL.AF
(dir
,s,phi1
) -> CTL.AF
(dir
,s,cleanup phi1
)
2423 | CTL.AX
(CTL.FORWARD
,s,
2425 CTL.And
(CTL.NONSTRICT
,CTL.AU
(CTL.FORWARD
,s2
,e2
,e3
),
2426 CTL.EU
(CTL.FORWARD
,e4
,e5
)))) ->
2428 CTL.And
(CTL.NONSTRICT
,
2429 CTL.AX
(CTL.FORWARD
,s,CTL.AU
(CTL.FORWARD
,s2
,e2
,e3
)),
2430 CTL.EX
(CTL.FORWARD
,CTL.EU
(CTL.FORWARD
,e4
,e5
))))
2431 | CTL.AX
(dir
,s,CTL.XX
(phi
)) -> CTL.EX
(dir
,cleanup phi
)
2432 | CTL.EX
(dir
,CTL.XX
((CTL.AU
(_,s,_,_)) as phi
)) ->
2433 CTL.AX
(dir
,s,cleanup phi
)
2434 | CTL.XX
(phi
) -> failwith
"bad XX"
2435 | CTL.AX
(dir
,s,phi1
) -> CTL.AX
(dir
,s,cleanup phi1
)
2436 | CTL.AG
(dir
,s,phi1
) -> CTL.AG
(dir
,s,cleanup phi1
)
2437 | CTL.EF
(dir
,phi1
) -> CTL.EF
(dir
,cleanup phi1
)
2438 | CTL.EX
(dir
,phi1
) -> CTL.EX
(dir
,cleanup phi1
)
2439 | CTL.EG
(dir
,phi1
) -> CTL.EG
(dir
,cleanup phi1
)
2440 | CTL.AW
(dir
,s,phi1
,phi2
) -> CTL.AW
(dir
,s,cleanup phi1
,cleanup phi2
)
2441 | CTL.AU
(dir
,s,phi1
,phi2
) -> CTL.AU
(dir
,s,cleanup phi1
,cleanup phi2
)
2442 | CTL.EU
(dir
,phi1
,phi2
) -> CTL.EU
(dir
,cleanup phi1
,cleanup phi2
)
2443 | CTL.Let
(x,phi1
,phi2
) -> CTL.Let
(x,cleanup phi1
,cleanup phi2
)
2444 | CTL.LetR
(dir
,x,phi1
,phi2
) -> CTL.LetR
(dir
,x,cleanup phi1
,cleanup phi2
)
2445 | CTL.Ref
(s) -> CTL.Ref
(s)
2446 | CTL.Uncheck
(phi1
) -> CTL.Uncheck
(cleanup phi1
)
2447 | CTL.InnerAnd
(phi1
) -> CTL.InnerAnd
(cleanup phi1
)
2449 (* --------------------------------------------------------------------- *)
2450 (* Function declaration *)
2452 (* ua = used_after, fua = fresh_used_after, fuas = fresh_used_after_seeds *)
2454 let top_level name
((ua
,pos),fua
) (fuas
,t
) =
2455 let ua = List.filter
(function (nm,_) -> nm = name
) ua in
2457 saved := Ast.get_saved t
;
2458 let quantified = Common.minus_set
(Common.union_set
ua fuas
) pos in
2459 quantify false quantified
2460 (match Ast.unwrap t
with
2461 Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
2463 let unopt = elim_opt.V.rebuilder_statement stmt
in
2464 let unopt = preprocess_dots_e unopt in
2465 cleanup(statement
unopt VeryEnd
quantified [] None None None
false)
2466 | Ast.CODE
(stmt_dots
) ->
2467 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots
in
2468 let unopt = preprocess_dots unopt in
2469 let starts_with_dots =
2470 match Ast.undots stmt_dots
with
2472 (match Ast.unwrap
d with
2473 Ast.Dots
(_,_,_,_) | Ast.Circles
(_,_,_,_)
2474 | Ast.Stars
(_,_,_,_) -> true
2477 let starts_with_brace =
2478 match Ast.undots stmt_dots
with
2480 (match Ast.unwrap
d with
2485 statement_list unopt VeryEnd
quantified [] None None None
2488 (if starts_with_dots
2490 (* EX because there is a loop on enter/top *)
2491 ctl_and CTL.NONSTRICT
(toppred None
) (ctl_ex res)
2492 else if starts_with_brace
2494 ctl_and CTL.NONSTRICT
2495 (ctl_not(CTL.EX
(CTL.BACKWARD
,(funpred None
)))) res
2497 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords")
2499 (* --------------------------------------------------------------------- *)
2502 let asttoctlz (name
,(_,_,exists_flag
),l)
2503 (used_after,fresh_used_after
,fresh_used_after_seeds
) positions
=
2506 (match exists_flag
with
2507 Ast.Exists
-> exists := Exists
2508 | Ast.Forall
-> exists := Forall
2509 | Ast.Undetermined
->
2510 exists := if !Flag.sgrep_mode2
then Exists
else Forall
);
2512 let (l,used_after) =
2516 match Ast.unwrap t
with Ast.ERRORWORDS
(exps
) -> false | _ -> true)
2517 (List.combine
l (List.combine
used_after positions
))) in
2519 List.map2
(top_level name
)
2520 (List.combine
used_after fresh_used_after
)
2521 (List.combine fresh_used_after_seeds
l) in
2525 let asttoctl r
used_after positions
=
2527 Ast.ScriptRule
_ | Ast.InitialScriptRule
_ | Ast.FinalScriptRule
_ -> []
2528 | Ast.CocciRule
(a,b
,c,_,Ast_cocci.Normal
) ->
2529 asttoctlz (a,b
,c) used_after positions
2530 | Ast.CocciRule
(a,b
,c,_,Ast_cocci.Generated
) -> [CTL.True
]
2532 let pp_cocci_predicate (pred
,modif
) =
2533 Pretty_print_engine.pp_predicate pred
2535 let cocci_predicate_to_string (pred
,modif
) =
2536 Pretty_print_engine.predicate_to_string pred