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 (CTL.True
,_
) | (_
,CTL.True
) -> CTL.True
82 | (CTL.False
,a
) | (a
,CTL.False
) -> a
85 let ctl_not = function
87 | CTL.False
-> CTL.True
90 let ctl_ax s
= function
92 | CTL.False
-> CTL.False
95 Exists
-> CTL.EX
(CTL.FORWARD
,x
)
96 | Forall
-> CTL.AX
(CTL.FORWARD
,s
,x
)
98 let ctl_ax_absolute s
= function
100 | CTL.False
-> CTL.False
101 | x
-> CTL.AX
(CTL.FORWARD
,s
,x
)
103 let ctl_ex = function
105 | CTL.False
-> CTL.False
106 | x
-> CTL.EX
(CTL.FORWARD
,x
)
108 (* This stays being AX even for sgrep_mode, because it is used to identify
109 the structure of the term, not matching the pattern. *)
110 let ctl_back_ax = function
112 | CTL.False
-> CTL.False
113 | x
-> CTL.AX
(CTL.BACKWARD
,CTL.NONSTRICT
,x
)
115 let ctl_back_ex = function
117 | CTL.False
-> CTL.False
118 | x
-> CTL.EX
(CTL.BACKWARD
,x
)
120 let ctl_ef = function
122 | CTL.False
-> CTL.False
123 | x
-> CTL.EF
(CTL.FORWARD
,x
)
125 let ctl_ag s
= function
127 | CTL.False
-> CTL.False
128 | x
-> CTL.AG
(CTL.FORWARD
,s
,x
)
131 match (x
,!exists) with
132 (CTL.True
,Exists
) -> CTL.EF
(CTL.FORWARD
,y
)
133 | (CTL.True
,Forall
) -> CTL.AF
(CTL.FORWARD
,s
,y
)
134 | (_
,Exists
) -> CTL.EU
(CTL.FORWARD
,x
,y
)
135 | (_
,Forall
) -> CTL.AU
(CTL.FORWARD
,s
,x
,y
)
137 let ctl_anti_au s x y
= (* only for ..., where the quantifier is changed *)
139 (match (x
,!exists) with
140 (CTL.True
,Exists
) -> CTL.AF
(CTL.FORWARD
,s
,y
)
141 | (CTL.True
,Forall
) -> CTL.EF
(CTL.FORWARD
,y
)
142 | (_
,Exists
) -> CTL.AU
(CTL.FORWARD
,s
,x
,y
)
143 | (_
,Forall
) -> CTL.EU
(CTL.FORWARD
,x
,y
))
145 let ctl_uncheck = function
147 | CTL.False
-> CTL.False
150 let label_pred_maker = function
152 | Some
(label_var
,used
) ->
154 CTL.Pred
(Lib_engine.PrefixLabel
(label_var
),CTL.Control
)
156 let bclabel_pred_maker = function
158 | Some
(label_var
,used
) ->
160 CTL.Pred
(Lib_engine.BCLabel
(label_var
),CTL.Control
)
162 (* label used to be used here, but it is not used; label is only needed after
164 let predmaker guard pred label
= CTL.Pred pred
166 let aftpred = predmaker false (Lib_engine.After
, CTL.Control
)
167 let retpred = predmaker false (Lib_engine.Return
, CTL.Control
)
168 let funpred = predmaker false (Lib_engine.FunHeader
, CTL.Control
)
169 let toppred = predmaker false (Lib_engine.Top
, CTL.Control
)
170 let exitpred = predmaker false (Lib_engine.ErrorExit
, CTL.Control
)
171 let endpred = predmaker false (Lib_engine.Exit
, CTL.Control
)
172 let gotopred = predmaker false (Lib_engine.Goto
, CTL.Control
)
173 let inlooppred = predmaker false (Lib_engine.InLoop
, CTL.Control
)
174 let truepred = predmaker false (Lib_engine.TrueBranch
, CTL.Control
)
175 let falsepred = predmaker false (Lib_engine.FalseBranch
, CTL.Control
)
176 let fallpred = predmaker false (Lib_engine.FallThrough
, CTL.Control
)
177 let loopfallpred = predmaker false (Lib_engine.LoopFallThrough
, CTL.Control
)
179 (*let aftret label_var =
180 ctl_or (aftpred label_var)
181 (ctl_or (loopfallpred label_var) (exitpred label_var))*)
187 Printf.sprintf
"r%d" cur
189 (* --------------------------------------------------------------------- *)
190 (* --------------------------------------------------------------------- *)
191 (* Eliminate OptStm *)
193 (* for optional thing with nothing after, should check that the optional thing
194 never occurs. otherwise the matching stops before it occurs *)
197 let donothing r k e
= k e
in
200 List.fold_left
Common.union_set
[] (List.map
Ast.get_fvs l
) in
203 List.fold_left
Common.union_set
[] (List.map
Ast.get_mfvs l
) in
206 List.fold_left
Common.union_set
[] (List.map
Ast.get_fresh l
) in
208 let inheritedlist l
=
209 List.fold_left
Common.union_set
[] (List.map
Ast.get_inherited l
) in
212 List.fold_left
Common.union_set
[] (List.map
Ast.get_saved l
) in
215 (fvlist l
, mfvlist l
, freshlist l
, inheritedlist l
, savedlist l
) in
217 let rec dots_list unwrapped wrapped
=
218 match (unwrapped
,wrapped
) with
221 | (Ast.Dots
(_
,_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
,_
) as u
)::urest
,
223 | (Ast.Nest
(_
,_
,_
,_
,_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
,_
) as u
)
225 d0
::s
::d1
::rest
) -> (* why no case for nest as u? *)
226 let l = Ast.get_line stm
in
227 let new_rest1 = stm
:: (dots_list (u
::urest
) (d1
::rest
)) in
228 let new_rest2 = dots_list urest rest
in
229 let (fv_rest1
,mfv_rest1
,fresh_rest1
,inherited_rest1
,s1
) =
230 varlists new_rest1 in
231 let (fv_rest2
,mfv_rest2
,fresh_rest2
,inherited_rest2
,s2
) =
232 varlists new_rest2 in
236 [{(Ast.make_term
(Ast.DOTS
(new_rest1))) with
238 Ast.free_vars
= fv_rest1
;
239 Ast.minus_free_vars
= mfv_rest1
;
240 Ast.fresh_vars
= fresh_rest1
;
241 Ast.inherited
= inherited_rest1
;
242 Ast.saved_witness
= s1
};
243 {(Ast.make_term
(Ast.DOTS
(new_rest2))) with
245 Ast.free_vars
= fv_rest2
;
246 Ast.minus_free_vars
= mfv_rest2
;
247 Ast.fresh_vars
= fresh_rest2
;
248 Ast.inherited
= inherited_rest2
;
249 Ast.saved_witness
= s2
}])) with
251 Ast.free_vars
= fv_rest1
;
252 Ast.minus_free_vars
= mfv_rest1
;
253 Ast.fresh_vars
= fresh_rest1
;
254 Ast.inherited
= inherited_rest1
;
255 Ast.saved_witness
= s1
}]
257 | (Ast.OptStm
(stm
)::urest
,_
::rest
) ->
258 let l = Ast.get_line stm
in
259 let new_rest1 = dots_list urest rest
in
260 let new_rest2 = stm
::new_rest1 in
261 let (fv_rest1
,mfv_rest1
,fresh_rest1
,inherited_rest1
,s1
) =
262 varlists new_rest1 in
263 let (fv_rest2
,mfv_rest2
,fresh_rest2
,inherited_rest2
,s2
) =
264 varlists new_rest2 in
267 [{(Ast.make_term
(Ast.DOTS
(new_rest2))) with
269 Ast.free_vars
= fv_rest2
;
270 Ast.minus_free_vars
= mfv_rest2
;
271 Ast.fresh_vars
= fresh_rest2
;
272 Ast.inherited
= inherited_rest2
;
273 Ast.saved_witness
= s2
};
274 {(Ast.make_term
(Ast.DOTS
(new_rest1))) with
276 Ast.free_vars
= fv_rest1
;
277 Ast.minus_free_vars
= mfv_rest1
;
278 Ast.fresh_vars
= fresh_rest1
;
279 Ast.inherited
= inherited_rest1
;
280 Ast.saved_witness
= s1
}])) with
282 Ast.free_vars
= fv_rest2
;
283 Ast.minus_free_vars
= mfv_rest2
;
284 Ast.fresh_vars
= fresh_rest2
;
285 Ast.inherited
= inherited_rest2
;
286 Ast.saved_witness
= s2
}]
288 | ([Ast.Dots
(_
,_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
289 let l = Ast.get_line stm
in
290 let fv_stm = Ast.get_fvs stm
in
291 let mfv_stm = Ast.get_mfvs stm
in
292 let fresh_stm = Ast.get_fresh stm
in
293 let inh_stm = Ast.get_inherited stm
in
294 let saved_stm = Ast.get_saved stm
in
295 let fv_d1 = Ast.get_fvs d1
in
296 let mfv_d1 = Ast.get_mfvs d1
in
297 let fresh_d1 = Ast.get_fresh d1
in
298 let inh_d1 = Ast.get_inherited d1
in
299 let saved_d1 = Ast.get_saved d1
in
300 let fv_both = Common.union_set
fv_stm fv_d1 in
301 let mfv_both = Common.union_set
mfv_stm mfv_d1 in
302 let fresh_both = Common.union_set
fresh_stm fresh_d1 in
303 let inh_both = Common.union_set
inh_stm inh_d1 in
304 let saved_both = Common.union_set
saved_stm saved_d1 in
308 [{(Ast.make_term
(Ast.DOTS
([stm
]))) with
310 Ast.free_vars
= fv_stm;
311 Ast.minus_free_vars
= mfv_stm;
312 Ast.fresh_vars
= fresh_stm;
313 Ast.inherited
= inh_stm;
314 Ast.saved_witness
= saved_stm};
315 {(Ast.make_term
(Ast.DOTS
([d1
]))) with
317 Ast.free_vars
= fv_d1;
318 Ast.minus_free_vars
= mfv_d1;
319 Ast.fresh_vars
= fresh_d1;
320 Ast.inherited
= inh_d1;
321 Ast.saved_witness
= saved_d1}])) with
323 Ast.free_vars
= fv_both;
324 Ast.minus_free_vars
= mfv_both;
325 Ast.fresh_vars
= fresh_both;
326 Ast.inherited
= inh_both;
327 Ast.saved_witness
= saved_both}]
329 | ([Ast.Nest
(_
,_
,_
,_
,_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
330 let l = Ast.get_line stm
in
331 let rw = Ast.rewrap stm
in
332 let rwd = Ast.rewrap stm
in
333 let dots = Ast.Dots
(Ast.make_mcode
"...",[],[],[]) in
335 [rwd(Ast.DOTS
([stm
]));
336 {(Ast.make_term
(Ast.DOTS
([rw dots])))
337 with Ast.node_line
= l}])]
339 | (_
::urest
,stm
::rest
) -> stm
:: (dots_list urest rest
)
340 | _
-> failwith
"not possible" in
342 let stmtdotsfn r k d
=
345 (match Ast.unwrap
d with
346 Ast.DOTS
(l) -> Ast.DOTS
(dots_list (List.map
Ast.unwrap
l) l)
347 | Ast.CIRCLES
(l) -> failwith
"elimopt: not supported"
348 | Ast.STARS
(l) -> failwith
"elimopt: not supported") in
351 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
352 donothing donothing stmtdotsfn donothing
353 donothing donothing donothing donothing donothing donothing donothing
354 donothing donothing donothing donothing donothing
356 (* --------------------------------------------------------------------- *)
357 (* after management *)
358 (* We need Guard for the following case:
367 Here the inner <... b ...> should not go past foo. But foo is not the
368 "after" of the body of the outer nest, because we don't want to search for
369 it in the case where the body of the outer nest ends in something other
370 than dots or a nest. *)
372 (* what is the difference between tail and end??? *)
374 type after
= After
of formula
| Guard
of formula
| Tail
| End
| VeryEnd
376 let a2n = function After x
-> Guard x
| a
-> a
379 let pp_pred (x
,_
) = Pretty_print_engine.pp_predicate x
in
380 let pp_meta (_
,x
) = Common.pp x
in
381 Pretty_print_ctl.pp_ctl
(pp_pred,pp_meta) false x
;
382 Format.print_newline
()
384 let print_after = function
385 After ctl
-> Printf.printf
"After:\n"; print_ctl ctl
386 | Guard ctl
-> Printf.printf
"Guard:\n"; print_ctl ctl
387 | Tail
-> Printf.printf
"Tail\n"
388 | VeryEnd
-> Printf.printf
"Very End\n"
389 | End
-> Printf.printf
"End\n"
391 (* --------------------------------------------------------------------- *)
394 let fresh_var _
= string2var "_v"
395 let fresh_pos _
= string2var "_pos" (* must be a constant *)
397 let fresh_metavar _
= "_S"
399 (* fvinfo is going to end up being from the whole associated statement.
400 it would be better if it were just the free variables in d, but free_vars.ml
401 doesn't keep track of free variables on + code *)
402 let make_meta_rule_elem d fvinfo
=
403 let nm = fresh_metavar() in
404 Ast.make_meta_rule_elem nm d fvinfo
406 let get_unquantified quantified vars
=
407 List.filter
(function x
-> not
(List.mem x quantified
)) vars
409 let make_seq guard
l =
410 let s = guard_to_strict guard
in
411 foldr1 (function rest
-> function cur -> ctl_and s cur (ctl_ax s rest
)) l
413 let make_seq_after2 guard first rest
=
414 let s = guard_to_strict guard
in
416 After rest
-> ctl_and s first
(ctl_ax s (ctl_ax s rest
))
419 let make_seq_after guard first rest
=
421 After rest
-> make_seq guard
[first
;rest
]
424 let opt_and guard first rest
=
425 let s = guard_to_strict guard
in
428 | Some first
-> ctl_and s first rest
430 let and_after guard first rest
=
431 let s = guard_to_strict guard
in
432 match rest
with After rest
-> ctl_and s first rest
| _
-> first
435 let bind x y
= x
or y
in
436 let option_default = false in
437 let mcode r
(_
,_
,kind
,metapos
) =
439 Ast.MINUS
(_
,_
,_
,_
) -> true
440 | Ast.PLUS _
-> failwith
"not possible"
441 | Ast.CONTEXT
(_
,info
) -> not
(info
= Ast.NOTHING
) in
442 let do_nothing r k e
= k e
in
443 let rule_elem r k re
=
445 match Ast.unwrap re
with
446 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
447 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
448 | Ast.Decl
(bef
,_
,decl
) -> bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
452 match Ast.unwrap i
with
453 Ast.InitList
(allminus
,_
,_
,_
,_
) -> allminus
or res
456 V.combiner
bind option_default
457 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
458 do_nothing do_nothing do_nothing do_nothing
459 do_nothing do_nothing do_nothing do_nothing init do_nothing
460 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
461 recursor.V.combiner_rule_elem
464 let bind x y
= x
or y
in
465 let option_default = false in
466 let mcode r
(_
,_
,kind
,metapos
) =
468 Ast.MetaPos
(_
,_
,_
,_
,_
) -> true
469 | Ast.NoMetaPos
-> false in
470 let do_nothing r k e
= k e
in
471 let rule_elem r k re
=
473 match Ast.unwrap re
with
474 Ast.FunHeader
(bef
,_
,fninfo
,name
,lp
,params
,rp
) ->
475 bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
476 | Ast.Decl
(bef
,_
,decl
) -> bind (mcode r
((),(),bef
,Ast.NoMetaPos
)) res
479 V.combiner
bind option_default
480 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
481 do_nothing do_nothing do_nothing do_nothing
482 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
483 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
484 recursor.V.combiner_rule_elem
486 (* code is not a DisjRuleElem *)
487 let make_match label guard code
=
488 let v = fresh_var() in
489 let matcher = Lib_engine.Match
(code
) in
490 if contains_modif code
&& not guard
491 then CTL.Exists
(true,v,predmaker guard
(matcher,CTL.Modif
v) label
)
493 let iso_info = !Flag.track_iso_usage
&& not
(Ast.get_isos code
= []) in
494 (match (iso_info,!onlyModif,guard
,
495 intersect !used_after (Ast.get_fvs code
)) with
496 (false,true,_
,[]) | (_
,_
,true,_
) ->
497 predmaker guard
(matcher,CTL.Control
) label
498 | _
-> CTL.Exists
(true,v,predmaker guard
(matcher,CTL.UnModif
v) label
))
500 let make_raw_match label guard code
=
501 predmaker guard
(Lib_engine.Match
(code
),CTL.Control
) label
503 let rec seq_fvs quantified
= function
506 let t1fvs = get_unquantified quantified fv1
in
508 List.fold_left
Common.union_set
[]
509 (List.map
(get_unquantified quantified
) fvs
) in
510 let bothfvs = Common.inter_set
t1fvs termfvs in
511 let t1onlyfvs = Common.minus_set
t1fvs bothfvs in
512 let new_quantified = Common.union_set
bothfvs quantified
in
513 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs
)
518 function code
-> CTL.Exists
(not guard
&& List.mem
cur !saved,cur,code
))
520 let non_saved_quantify =
522 (function cur -> function code
-> CTL.Exists
(false,cur,code
))
524 let intersectll lst nested_list
=
525 List.filter
(function x
-> List.exists (List.mem x
) nested_list
) lst
527 (* --------------------------------------------------------------------- *)
528 (* Count depth of braces. The translation of a closed brace appears deeply
529 nested within the translation of the sequence term, so the name of the
530 paren var has to take into account the names of the nested braces. On the
531 other hand the close brace does not escape, so we don't have to take into
532 account other paren variable names. *)
534 (* called repetitively, which is inefficient, but less trouble than adding a
535 new field to Seq and FunDecl *)
536 let count_nested_braces s =
537 let bind x y
= max x y
in
538 let option_default = 0 in
539 let stmt_count r k
s =
540 match Ast.unwrap
s with
541 Ast.Seq
(_
,_
,_
) | Ast.FunDecl
(_
,_
,_
,_
) -> (k
s) + 1
543 let donothing r k e
= k e
in
545 let recursor = V.combiner
bind option_default
546 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
547 donothing donothing donothing donothing
548 donothing donothing donothing donothing donothing donothing
549 donothing donothing stmt_count donothing donothing donothing in
550 let res = string_of_int
(recursor.V.combiner_statement
s) in
554 let get_label_ctr _
=
555 let cur = !labelctr in
557 string2var (Printf.sprintf
"l%d" cur)
559 (* --------------------------------------------------------------------- *)
560 (* annotate dots with before and after neighbors *)
562 let print_bef_aft = function
564 Printf.printf
"bef/aft\n";
565 Pretty_print_cocci.rule_elem "" re
;
566 Format.print_newline
()
568 Printf.printf
"bef/aft\n";
569 Pretty_print_cocci.statement
"" s;
570 Format.print_newline
()
571 | Ast.Other_dots
d ->
572 Printf.printf
"bef/aft\n";
573 Pretty_print_cocci.statement_dots
d;
574 Format.print_newline
()
576 (* [] can only occur if we are in a disj, where it comes from a ? In that
577 case, we want to use a, which accumulates all of the previous patterns in
579 let rec get_before_elem sl a
=
580 match Ast.unwrap sl
with
584 [] -> ([],Common.Right a
)
586 let (e
,ea
) = get_before_e e a
in
589 let (e
,ea
) = get_before_e e a
in
590 let (sl
,sla
) = loop sl ea
in
592 let (l,a
) = loop x a
in
593 (Ast.rewrap sl
(Ast.DOTS
(l)),a
)
594 | Ast.CIRCLES
(x
) -> failwith
"not supported"
595 | Ast.STARS
(x
) -> failwith
"not supported"
597 and get_before sl a
=
598 match get_before_elem sl a
with
599 (term
,Common.Left x
) -> (term
,x
)
600 | (term
,Common.Right x
) -> (term
,x
)
602 and get_before_whencode wc
=
605 Ast.WhenNot w
-> let (w
,_
) = get_before w
[] in Ast.WhenNot w
606 | Ast.WhenAlways w
-> let (w
,_
) = get_before_e w
[] in Ast.WhenAlways w
607 | Ast.WhenModifier
(x
) -> Ast.WhenModifier
(x
)
608 | Ast.WhenNotTrue w
-> Ast.WhenNotTrue w
609 | Ast.WhenNotFalse w
-> Ast.WhenNotFalse w
)
612 and get_before_e
s a
=
613 match Ast.unwrap
s with
614 Ast.Dots
(d,w
,_
,aft
) ->
615 (Ast.rewrap
s (Ast.Dots
(d,get_before_whencode w
,a
,aft
)),a
)
616 | Ast.Nest
(starter
,stmt_dots
,ender
,w
,multi
,_
,aft
) ->
617 let w = get_before_whencode
w in
618 let (sd
,_
) = get_before stmt_dots a
in
620 got rid of this, don't want to let nests overshoot
625 Unify_ast.unify_statement_dots
626 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
628 Unify_ast.MAYBE -> false
630 | Ast.Other_dots a ->
631 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
633 Unify_ast.MAYBE -> false
637 (Ast.rewrap
s (Ast.Nest
(starter
,sd
,ender
,w,multi
,a,aft
)),
638 [Ast.Other_dots stmt_dots
])
639 | Ast.Disj
(stmt_dots_list
) ->
641 List.split
(List.map
(function e
-> get_before e
a) stmt_dots_list
) in
642 (Ast.rewrap
s (Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
644 (match Ast.unwrap ast
with
645 Ast.MetaStmt
(_
,_
,_
,_
) -> (s,[])
646 | _
-> (s,[Ast.Other
s]))
647 | Ast.Seq
(lbrace
,body
,rbrace
) ->
648 let index = count_nested_braces s in
649 let (bd
,_
) = get_before body
[Ast.WParen
(lbrace
,index)] in
650 (Ast.rewrap
s (Ast.Seq
(lbrace
,bd
,rbrace
)),[Ast.WParen
(rbrace
,index)])
651 | Ast.Define
(header
,body
) ->
652 let (body
,_
) = get_before body
[] in
653 (Ast.rewrap
s (Ast.Define
(header
,body
)), [Ast.Other
s])
654 | Ast.IfThen
(ifheader
,branch
,aft
) ->
655 let (br
,_
) = get_before_e branch
[] in
656 (Ast.rewrap
s (Ast.IfThen
(ifheader
,br
,aft
)), [Ast.Other
s])
657 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
658 let (br1
,_
) = get_before_e branch1
[] in
659 let (br2
,_
) = get_before_e branch2
[] in
660 (Ast.rewrap
s (Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other
s])
661 | Ast.While
(header
,body
,aft
) ->
662 let (bd
,_
) = get_before_e body
[] in
663 (Ast.rewrap
s (Ast.While
(header
,bd
,aft
)),[Ast.Other
s])
664 | Ast.For
(header
,body
,aft
) ->
665 let (bd
,_
) = get_before_e body
[] in
666 (Ast.rewrap
s (Ast.For
(header
,bd
,aft
)),[Ast.Other
s])
667 | Ast.Do
(header
,body
,tail
) ->
668 let (bd
,_
) = get_before_e body
[] in
669 (Ast.rewrap
s (Ast.Do
(header
,bd
,tail
)),[Ast.Other
s])
670 | Ast.Iterator
(header
,body
,aft
) ->
671 let (bd
,_
) = get_before_e body
[] in
672 (Ast.rewrap
s (Ast.Iterator
(header
,bd
,aft
)),[Ast.Other
s])
673 | Ast.Switch
(header
,lb
,decls
,cases
,rb
) ->
674 let index = count_nested_braces s in
675 let (de
,dea
) = get_before decls
[Ast.WParen
(lb
,index)] in
678 (function case_line
->
679 match Ast.unwrap case_line
with
680 Ast.CaseLine
(header
,body
) ->
681 let (body
,_
) = get_before body
[] in
682 Ast.rewrap case_line
(Ast.CaseLine
(header
,body
))
683 | Ast.OptCase
(case_line
) -> failwith
"not supported")
685 (Ast.rewrap
s (Ast.Switch
(header
,lb
,de
,cases,rb
)),
686 [Ast.WParen
(rb
,index)])
687 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
688 let (bd
,_
) = get_before body
[] in
689 (Ast.rewrap
s (Ast.FunDecl
(header
,lbrace
,bd
,rbrace
)),[])
691 Pretty_print_cocci.statement
"" s; Format.print_newline
();
692 failwith
"get_before_e: not supported"
694 let rec get_after sl
a =
695 match Ast.unwrap sl
with
701 let (sl
,sla
) = loop sl
in
702 let (e
,ea
) = get_after_e e sla
in
704 let (l,a) = loop x
in
705 (Ast.rewrap sl
(Ast.DOTS
(l)),a)
706 | Ast.CIRCLES
(x
) -> failwith
"not supported"
707 | Ast.STARS
(x
) -> failwith
"not supported"
709 and get_after_whencode
a wc
=
712 Ast.WhenNot
w -> let (w,_
) = get_after w a (*?*) in Ast.WhenNot
w
713 | Ast.WhenAlways
w -> let (w,_
) = get_after_e
w a in Ast.WhenAlways
w
714 | Ast.WhenModifier
(x
) -> Ast.WhenModifier
(x
)
715 | Ast.WhenNotTrue
w -> Ast.WhenNotTrue
w
716 | Ast.WhenNotFalse
w -> Ast.WhenNotFalse
w)
719 and get_after_e
s a =
720 match Ast.unwrap
s with
721 Ast.Dots
(d,w,bef
,_
) ->
722 (Ast.rewrap
s (Ast.Dots
(d,get_after_whencode
a w,bef
,a)),a)
723 | Ast.Nest
(starter
,stmt_dots
,ender
,w,multi
,bef
,_
) ->
724 let w = get_after_whencode
a w in
725 let (sd
,_
) = get_after stmt_dots
a in
727 got rid of this. don't want to let nests overshoot
732 Unify_ast.unify_statement_dots
733 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
735 Unify_ast.MAYBE -> false
737 | Ast.Other_dots a ->
738 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
740 Unify_ast.MAYBE -> false
744 (Ast.rewrap
s (Ast.Nest
(starter
,sd
,ender
,w,multi
,bef
,a)),
745 [Ast.Other_dots stmt_dots
])
746 | Ast.Disj
(stmt_dots_list
) ->
748 List.split
(List.map
(function e
-> get_after e
a) stmt_dots_list
) in
749 (Ast.rewrap
s (Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
751 (match Ast.unwrap ast
with
752 Ast.MetaStmt
(nm,keep
,Ast.SequencibleAfterDots _
,i
) ->
753 (* check "after" information for metavar optimization *)
754 (* if the error is not desired, could just return [], then
755 the optimization (check for EF) won't take place *)
759 (match Ast.unwrap x
with
760 Ast.Dots
(_
,_
,_
,_
) | Ast.Nest
(_
,_
,_
,_
,_
,_
,_
) ->
762 "dots/nest not allowed before and after stmt metavar"
764 | Ast.Other_dots x
->
765 (match Ast.undots x
with
767 (match Ast.unwrap x
with
768 Ast.Dots
(_
,_
,_
,_
) | Ast.Nest
(_
,_
,_
,_
,_
,_
,_
) ->
770 ("dots/nest not allowed before and after stmt "^
779 (Ast.MetaStmt
(nm,keep
,Ast.SequencibleAfterDots
a,i
)))),[])
780 | Ast.MetaStmt
(_
,_
,_
,_
) -> (s,[])
781 | _
-> (s,[Ast.Other
s]))
782 | Ast.Seq
(lbrace
,body
,rbrace
) ->
783 let index = count_nested_braces s in
784 let (bd
,_
) = get_after body
[Ast.WParen
(rbrace
,index)] in
785 (Ast.rewrap
s (Ast.Seq
(lbrace
,bd
,rbrace
)),
786 [Ast.WParen
(lbrace
,index)])
787 | Ast.Define
(header
,body
) ->
788 let (body
,_
) = get_after body
a in
789 (Ast.rewrap
s (Ast.Define
(header
,body
)), [Ast.Other
s])
790 | Ast.IfThen
(ifheader
,branch
,aft
) ->
791 let (br
,_
) = get_after_e branch
a in
792 (Ast.rewrap
s (Ast.IfThen
(ifheader
,br
,aft
)),[Ast.Other
s])
793 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
794 let (br1
,_
) = get_after_e branch1
a in
795 let (br2
,_
) = get_after_e branch2
a in
796 (Ast.rewrap
s (Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other
s])
797 | Ast.While
(header
,body
,aft
) ->
798 let (bd
,_
) = get_after_e body
a in
799 (Ast.rewrap
s (Ast.While
(header
,bd
,aft
)),[Ast.Other
s])
800 | Ast.For
(header
,body
,aft
) ->
801 let (bd
,_
) = get_after_e body
a in
802 (Ast.rewrap
s (Ast.For
(header
,bd
,aft
)),[Ast.Other
s])
803 | Ast.Do
(header
,body
,tail
) ->
804 let (bd
,_
) = get_after_e body
a in
805 (Ast.rewrap
s (Ast.Do
(header
,bd
,tail
)),[Ast.Other
s])
806 | Ast.Iterator
(header
,body
,aft
) ->
807 let (bd
,_
) = get_after_e body
a in
808 (Ast.rewrap
s (Ast.Iterator
(header
,bd
,aft
)),[Ast.Other
s])
809 | Ast.Switch
(header
,lb
,decls
,cases,rb
) ->
810 let index = count_nested_braces s in
813 (function case_line
->
814 match Ast.unwrap case_line
with
815 Ast.CaseLine
(header
,body
) ->
816 let (body
,_
) = get_after body
[Ast.WParen
(rb
,index)] in
817 Ast.rewrap case_line
(Ast.CaseLine
(header
,body
))
818 | Ast.OptCase
(case_line
) -> failwith
"not supported")
820 let (de
,_
) = get_after decls
[] in
821 (Ast.rewrap
s (Ast.Switch
(header
,lb
,de
,cases,rb
)),[Ast.WParen
(lb
,index)])
822 | Ast.FunDecl
(header
,lbrace
,body
,rbrace
) ->
823 let (bd
,_
) = get_after body
[] in
824 (Ast.rewrap
s (Ast.FunDecl
(header
,lbrace
,bd
,rbrace
)),[])
825 | _
-> failwith
"get_after_e: not supported"
827 let preprocess_dots sl
=
828 let (sl
,_
) = get_before sl
[] in
829 let (sl
,_
) = get_after sl
[] in
832 let preprocess_dots_e sl
=
833 let (sl
,_
) = get_before_e sl
[] in
834 let (sl
,_
) = get_after_e sl
[] in
837 (* --------------------------------------------------------------------- *)
838 (* various return_related things *)
840 let rec ends_in_return stmt_list
=
841 match Ast.unwrap stmt_list
with
843 (match List.rev x
with
845 (match Ast.unwrap x
with
848 match Ast.unwrap x
with
849 Ast.Return
(_
,_
) | Ast.ReturnExpr
(_
,_
,_
) -> true
850 | Ast.DisjRuleElem
((_
::_
) as l) -> List.for_all
loop l
853 | Ast.Disj
(disjs
) -> List.for_all
ends_in_return disjs
856 | Ast.CIRCLES
(x
) -> failwith
"not supported"
857 | Ast.STARS
(x
) -> failwith
"not supported"
859 (* --------------------------------------------------------------------- *)
862 let exptymatch l make_match make_guard_match
=
863 let pos = fresh_pos() in
864 let matches_guard_matches =
867 let pos = Ast.make_mcode
pos in
868 (make_match (Ast.set_pos x
(Some
pos)),
869 make_guard_match
(Ast.set_pos x
(Some
pos))))
871 let (matches
,guard_matches
) = List.split
matches_guard_matches in
872 let rec suffixes = function
874 | x
::xs -> xs::(suffixes xs) in
876 (* normally, we check that an expression does not match something
877 earlier in the disjunction (calculated as prefixes). But for large
878 disjunctions, this can result in a very big CTL formula. So we
879 give the user the option to say he doesn't want this feature, if that is
881 if !Flag_matcher.no_safe_expressions
882 then List.map
(function _
-> []) matches
883 else List.rev
(suffixes (List.rev guard_matches
)) in
884 let info = (* not null *)
890 ctl_and CTL.NONSTRICT
matcher
892 (ctl_uncheck (List.fold_left
ctl_or_fl CTL.False negates
)))))
894 CTL.InnerAnd
(List.fold_left
ctl_or_fl CTL.False
(List.rev
info))
896 (* code might be a DisjRuleElem, in which case we break it apart
897 code might contain an Exp or Ty
898 this one pushes the quantifier inwards *)
899 let do_re_matches label guard
res quantified minus_quantified
=
900 let make_guard_match x
=
901 let stmt_fvs = Ast.get_mfvs x
in
902 let fvs = get_unquantified minus_quantified
stmt_fvs in
903 non_saved_quantify fvs (make_match None
true x
) in
905 let stmt_fvs = Ast.get_fvs x
in
906 let fvs = get_unquantified quantified
stmt_fvs in
907 quantify guard
fvs (make_match None guard x
) in
908 (* label used to be used here, but it is not use; label is only needed after
910 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
911 (match List.map
Ast.unwrap
res with
912 [] -> failwith
"unexpected empty disj"
913 | Ast.Exp
(e
)::rest
-> exptymatch res make_match make_guard_match
914 | Ast.Ty
(t
)::rest
-> exptymatch res make_match make_guard_match
916 if List.exists (function Ast.Exp
(_
) | Ast.Ty
(_
) -> true | _
-> false)
918 then failwith
"unexpected exp or ty";
919 List.fold_left
ctl_seqor CTL.False
(List.map
make_match res))
921 (* code might be a DisjRuleElem, in which case we break it apart
922 code doesn't contain an Exp or Ty
923 this one is for use when it is not practical to push the quantifier inwards
925 let header_match label guard code
: ('
a, Ast.meta_name
, 'b
) CTL.generic_ctl
=
926 match Ast.unwrap code
with
927 Ast.DisjRuleElem
(res) ->
928 let make_match = make_match None guard
in
929 let orop = if guard
then ctl_or else ctl_seqor in
930 (* label used to be used here, but it is not use; label is only needed after
932 ctl_and CTL.NONSTRICT (label_pred_maker label) *)
933 (List.fold_left
orop CTL.False
(List.map
make_match res))
934 | _
-> make_match label guard code
936 (* --------------------------------------------------------------------- *)
937 (* control structures *)
939 let end_control_structure fvs header body after_pred
940 after_checks no_after_checks
(afvs
,afresh
,ainh
,aft
) after label guard
=
941 (* aft indicates what is added after the whole if, which has to be added
943 let (aft_needed
,after_branch
) =
945 Ast.CONTEXT
(_
,Ast.NOTHING
) ->
946 (false,make_seq_after2 guard after_pred after
)
949 make_match label guard
950 (make_meta_rule_elem aft
(afvs
,afresh
,ainh
)) in
952 make_seq_after guard after_pred
953 (After
(make_seq_after guard
match_endif after
))) in
954 let body = body after_branch
in
955 let s = guard_to_strict guard
in
960 (match (after
,aft_needed
) with
961 (After _
,_
) (* pattern doesn't end here *)
962 | (_
,true) (* + code added after *) -> after_checks
963 | _
-> no_after_checks
)
964 (ctl_ax_absolute s body)))
966 let ifthen ifheader branch
((afvs
,_
,_
,_
) as aft
) after
967 quantified minus_quantified label llabel slabel recurse
make_match guard
=
968 (* "if (test) thn" becomes:
969 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
971 "if (test) thn; after" becomes:
972 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
977 match seq_fvs quantified
978 [Ast.get_fvs ifheader
;Ast.get_fvs branch
;afvs
] with
979 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
980 | _
-> failwith
"not possible" in
981 let new_quantified = Common.union_set bfvs quantified
in
983 match seq_fvs minus_quantified
984 [Ast.get_mfvs ifheader
;Ast.get_mfvs branch
;[]] with
985 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
986 | _
-> failwith
"not possible" in
987 let new_mquantified = Common.union_set mbfvs minus_quantified
in
989 let if_header = quantify guard efvs
(make_match ifheader
) in
990 (* then branch and after *)
991 let lv = get_label_ctr() in
992 let used = ref false in
994 (* no point to put a label on truepred etc; it is local to this construct
995 so it must have the same label *)
997 [truepred None
; recurse branch Tail
new_quantified new_mquantified
998 (Some
(lv,used)) llabel slabel guard
] in
999 let after_pred = aftpred None
in
1000 let or_cases after_branch
=
1001 ctl_or true_branch (ctl_or (fallpred None
) after_branch
) in
1002 let (if_header,wrapper
) =
1005 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1006 (ctl_and CTL.NONSTRICT
(*???*) if_header label_pred,
1007 (function body -> quantify true [lv] body))
1008 else (if_header,function x
-> x
) in
1010 (end_control_structure bfvs
if_header or_cases after_pred
1011 (Some
(ctl_ex after_pred)) None aft after label guard
)
1013 let ifthenelse ifheader branch1 els branch2
((afvs
,_
,_
,_
) as aft
) after
1014 quantified minus_quantified label llabel slabel recurse
make_match guard
=
1015 (* "if (test) thn else els" becomes:
1016 if(test) & AX((TrueBranch & AX thn) v
1017 (FalseBranch & AX (else & AX els)) v After)
1020 "if (test) thn else els; after" becomes:
1021 if(test) & AX((TrueBranch & AX thn) v
1022 (FalseBranch & AX (else & AX els)) v
1023 (After & AXAX after))
1027 (* free variables *)
1028 let (e1fvs
,b1fvs
,s1fvs
) =
1029 match seq_fvs quantified
1030 [Ast.get_fvs ifheader
;Ast.get_fvs branch1
;afvs
] with
1031 [(e1fvs
,b1fvs
);(s1fvs
,b1afvs
);_
] ->
1032 (e1fvs
,Common.union_set b1fvs b1afvs
,s1fvs
)
1033 | _
-> failwith
"not possible" in
1034 let (e2fvs
,b2fvs
,s2fvs
) =
1036 (* just combine with the else branch. no point to have separate
1037 quantifier, since there is only one possible control-flow path *)
1038 let else_fvs = Common.union_set
(Ast.get_fvs els
) (Ast.get_fvs branch2
) in
1039 match seq_fvs quantified
[Ast.get_fvs ifheader
;else_fvs;afvs
] with
1040 [(e2fvs
,b2fvs
);(s2fvs
,b2afvs
);_
] ->
1041 (e2fvs
,Common.union_set b2fvs b2afvs
,s2fvs
)
1042 | _
-> failwith
"not possible" in
1043 let bothfvs = union (union b1fvs b2fvs
) (intersect s1fvs s2fvs
) in
1044 let exponlyfvs = intersect e1fvs e2fvs
in
1045 let new_quantified = union bothfvs quantified
in
1046 (* minus free variables *)
1047 let (me1fvs
,mb1fvs
,ms1fvs
) =
1048 match seq_fvs minus_quantified
1049 [Ast.get_mfvs ifheader
;Ast.get_mfvs branch1
;[]] with
1050 [(e1fvs
,b1fvs
);(s1fvs
,b1afvs
);_
] ->
1051 (e1fvs
,Common.union_set b1fvs b1afvs
,s1fvs
)
1052 | _
-> failwith
"not possible" in
1053 let (me2fvs
,mb2fvs
,ms2fvs
) =
1055 (* just combine with the else branch. no point to have separate
1056 quantifier, since there is only one possible control-flow path *)
1058 Common.union_set
(Ast.get_mfvs els
) (Ast.get_mfvs branch2
) in
1059 match seq_fvs minus_quantified
[Ast.get_mfvs ifheader
;else_mfvs;[]] with
1060 [(e2fvs
,b2fvs
);(s2fvs
,b2afvs
);_
] ->
1061 (e2fvs
,Common.union_set b2fvs b2afvs
,s2fvs
)
1062 | _
-> failwith
"not possible" in
1063 let mbothfvs = union (union mb1fvs mb2fvs
) (intersect ms1fvs ms2fvs
) in
1064 let new_mquantified = union mbothfvs minus_quantified
in
1066 let if_header = quantify guard
exponlyfvs (make_match ifheader
) in
1067 (* then and else branches *)
1068 let lv = get_label_ctr() in
1069 let used = ref false in
1072 [truepred None
; recurse branch1 Tail
new_quantified new_mquantified
1073 (Some
(lv,used)) llabel slabel guard
] in
1078 (Common.minus_set
(Ast.get_fvs els
) new_quantified)
1079 (header_match None guard els
);
1080 recurse branch2 Tail
new_quantified new_mquantified
1081 (Some
(lv,used)) llabel slabel guard
] in
1082 let after_pred = aftpred None
in
1083 let or_cases after_branch
=
1084 ctl_or true_branch (ctl_or false_branch after_branch
) in
1085 let s = guard_to_strict guard
in
1086 let (if_header,wrapper
) =
1089 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1090 (ctl_and CTL.NONSTRICT
(*???*) if_header label_pred,
1091 (function body -> quantify true [lv] body))
1092 else (if_header,function x
-> x
) in
1094 (end_control_structure bothfvs if_header or_cases after_pred
1095 (Some
(ctl_and s (ctl_ex (falsepred None
)) (ctl_ex after_pred)))
1096 (Some
(ctl_ex (falsepred None
)))
1097 aft after label guard
)
1099 let forwhile header
body ((afvs
,_
,_
,_
) as aft
) after
1100 quantified minus_quantified label recurse
make_match guard
=
1102 (* the translation in this case is similar to that of an if with no else *)
1103 (* free variables *)
1105 match seq_fvs quantified
[Ast.get_fvs header
;Ast.get_fvs
body;afvs
] with
1106 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
1107 | _
-> failwith
"not possible" in
1108 let new_quantified = Common.union_set bfvs quantified
in
1109 (* minus free variables *)
1111 match seq_fvs minus_quantified
1112 [Ast.get_mfvs header
;Ast.get_mfvs
body;[]] with
1113 [(efvs
,b1fvs
);(_
,b2fvs
);_
] -> (efvs
,Common.union_set b1fvs b2fvs
)
1114 | _
-> failwith
"not possible" in
1115 let new_mquantified = Common.union_set mbfvs minus_quantified
in
1117 let header = quantify guard efvs
(make_match header) in
1118 let lv = get_label_ctr() in
1119 let used = ref false in
1123 recurse
body Tail
new_quantified new_mquantified
1124 (Some
(lv,used)) (Some
(lv,used)) None guard
] in
1125 let after_pred = loopfallpred None
in
1126 let or_cases after_branch
= ctl_or body after_branch
in
1127 let (header,wrapper
) =
1130 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
1131 (ctl_and CTL.NONSTRICT
(*???*) header label_pred,
1132 (function body -> quantify true [lv] body))
1133 else (header,function x
-> x
) in
1135 (end_control_structure bfvs
header or_cases after_pred
1136 (Some
(ctl_ex after_pred)) None aft after label guard
) in
1137 match (Ast.unwrap
body,aft
) with
1138 (Ast.Atomic
(re
),(_
,_
,_
,Ast.CONTEXT
(_
,Ast.NOTHING
))) ->
1139 (match Ast.unwrap re
with
1140 Ast.MetaStmt
((_
,_
,Ast.CONTEXT
(_
,Ast.NOTHING
),_
),
1141 Type_cocci.Unitary
,_
,false)
1142 when after
= Tail
or after
= End
or after
= VeryEnd
->
1144 match seq_fvs quantified
[Ast.get_fvs
header] with
1146 | _
-> failwith
"not possible" in
1147 quantify guard efvs
(make_match header)
1151 (* --------------------------------------------------------------------- *)
1152 (* statement metavariables *)
1154 (* issue: an S metavariable that is not an if branch/loop body
1155 should not match an if branch/loop body, so check that the labels
1156 of the nodes before the first node matched by the S are different
1157 from the label of the first node matched by the S *)
1158 let sequencibility body label_pred process_bef_aft
= function
1159 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
1162 (ctl_and CTL.NONSTRICT
(ctl_not (ctl_back_ax label_pred)) x
))
1163 | Ast.SequencibleAfterDots
l ->
1164 (* S appears after some dots. l is the code that comes after the S.
1165 want to search for that first, because S can match anything, while
1166 the stuff after is probably more restricted *)
1167 let afts = List.map process_bef_aft
l in
1168 let ors = foldl1 ctl_or afts in
1169 ctl_and CTL.NONSTRICT
1170 (ctl_ef (ctl_and CTL.NONSTRICT
ors (ctl_back_ax label_pred)))
1173 ctl_and CTL.NONSTRICT
(ctl_not (ctl_back_ax label_pred)) x
))
1174 | Ast.NotSequencible
-> body (function x
-> x
)
1176 let svar_context_with_add_after stmt
s label quantified
d ast
1177 seqible after process_bef_aft guard fvinfo
=
1178 let label_var = (*fresh_label_var*) string2var "_lab" in
1180 CTL.Pred
(Lib_engine.Label
(label_var),CTL.Control
) in
1181 (*let prelabel_pred =
1182 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in*)
1183 let matcher d = make_match None guard
(make_meta_rule_elem d fvinfo
) in
1184 let full_metamatch = matcher d in
1185 let first_metamatch =
1188 Ast.CONTEXT
(pos,Ast.BEFOREAFTER
(bef
,_
,c
)) ->
1189 Ast.CONTEXT
(pos,Ast.BEFORE
(bef
,c
))
1190 | Ast.CONTEXT
(pos,_
) -> Ast.CONTEXT
(pos,Ast.NOTHING
)
1191 | Ast.MINUS
(_
,_
,_
,_
) | Ast.PLUS _
-> failwith
"not possible") in
1193 let middle_metamatch =
1196 Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1197 | Ast.MINUS(_,_,_,_) | Ast.PLUS _ -> failwith "not possible") in
1199 let last_metamatch =
1202 Ast.CONTEXT
(pos,Ast.BEFOREAFTER
(_
,aft
,c
)) ->
1203 Ast.CONTEXT
(pos,Ast.AFTER
(aft
,c
))
1204 | Ast.CONTEXT
(_
,_
) -> d
1205 | Ast.MINUS
(_
,_
,_
,_
) | Ast.PLUS _
-> failwith
"not possible") in
1209 ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in
1212 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1213 let left_or = (* the whole statement is one node *)
1214 make_seq_after guard
1215 (ctl_and CTL.NONSTRICT
(ctl_not (ctl_ex to_end)) full_metamatch) after
in
1216 let right_or = (* the statement covers multiple nodes *)
1217 ctl_and CTL.NONSTRICT
1220 [to_end; make_seq_after guard
last_metamatch after
]))
1226 [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in
1230 ctl_au CTL.NONSTRICT
1233 [ctl_and CTL.NONSTRICT last_metamatch label_pred;
1235 (ctl_not prelabel_pred) after])] in
1239 ctl_and CTL.NONSTRICT
label_pred
1240 (f
(ctl_and CTL.NONSTRICT
1241 (make_raw_match label
false ast
) (ctl_or left_or right_or))) in
1242 let stmt_fvs = Ast.get_fvs stmt
in
1243 let fvs = get_unquantified quantified
stmt_fvs in
1244 quantify guard
(label_var::fvs)
1245 (sequencibility body label_pred process_bef_aft seqible
)
1247 let svar_minus_or_no_add_after stmt
s label quantified
d ast
1248 seqible after process_bef_aft guard fvinfo
=
1249 let label_var = (*fresh_label_var*) string2var "_lab" in
1251 CTL.Pred
(Lib_engine.Label
(label_var),CTL.Control
) in
1253 CTL.Pred
(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
1254 let matcher d = make_match None guard
(make_meta_rule_elem d fvinfo
) in
1256 match (d,after
) with
1257 (Ast.PLUS _
, _
) -> failwith
"not possible"
1258 | (Ast.CONTEXT
(pos,Ast.NOTHING
),(Tail
|End
|VeryEnd
)) ->
1259 (* just match the root. don't care about label; always ok *)
1260 make_raw_match None
false ast
1261 | (Ast.CONTEXT
(pos,Ast.BEFORE
(_
,_
)),(Tail
|End
|VeryEnd
)) ->
1262 ctl_and CTL.NONSTRICT
1263 (make_raw_match None
false ast
) (* statement *)
1264 (matcher d) (* transformation *)
1265 | (Ast.CONTEXT
(pos,(Ast.NOTHING
|Ast.BEFORE
(_
,_
))),(After
a | Guard
a)) ->
1266 (* This case and the MINUS one couldprobably be merged, if
1267 HackForStmt were to notice when its arguments are trivial *)
1268 let first_metamatch = matcher d in
1269 (* try to follow after link *)
1270 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1272 ctl_ex(make_seq guard
[to_end; CTL.True
; a]) in
1274 make_seq_after guard
(ctl_not (ctl_ex to_end)) after
in
1275 ctl_and CTL.NONSTRICT
(make_raw_match label
false ast
)
1276 (ctl_and CTL.NONSTRICT
1277 first_metamatch (ctl_or is_compound not_compound))
1278 | (Ast.CONTEXT
(pos,(Ast.AFTER _
|Ast.BEFOREAFTER _
)),_
) ->
1279 failwith
"not possible"
1280 | (Ast.MINUS
(pos,inst
,adj
,l),after
) ->
1281 let (first_metamatch,last_metamatch,rest_metamatch
) =
1283 [] -> (matcher(Ast.CONTEXT
(pos,Ast.NOTHING
)),CTL.True
,matcher d)
1285 matcher(Ast.MINUS
(pos,inst
,adj
,[])),
1286 ctl_and CTL.NONSTRICT
1287 (ctl_not (make_raw_match label
false ast
))
1288 (matcher(Ast.MINUS
(pos,inst
,adj
,[])))) in
1289 (* try to follow after link *)
1290 let to_end = ctl_or (aftpred None
) (loopfallpred None
) in
1294 [to_end; make_seq_after guard
last_metamatch after
]) in
1296 make_seq_after guard
(ctl_not (ctl_ex to_end)) after
in
1297 ctl_and CTL.NONSTRICT
1298 (ctl_and CTL.NONSTRICT
(make_raw_match label
false ast
)
1299 (ctl_and CTL.NONSTRICT
1300 first_metamatch (ctl_or is_compound not_compound)))
1301 (* don't have to put anything before the beginning, so don't have to
1302 distinguish the first node. so don't have to bother about paths,
1303 just use the label. label ensures that found nodes match up with
1304 what they should because it is in the lhs of the andany. *)
1305 (CTL.HackForStmt
(CTL.FORWARD
,CTL.NONSTRICT
,
1306 ctl_and CTL.NONSTRICT
label_pred
1307 (make_raw_match label
false ast
),
1308 ctl_and CTL.NONSTRICT rest_metamatch
prelabel_pred))
1310 let body f
= ctl_and CTL.NONSTRICT
label_pred (f
ender) in
1311 let stmt_fvs = Ast.get_fvs stmt
in
1312 let fvs = get_unquantified quantified
stmt_fvs in
1313 quantify guard
(label_var::fvs)
1314 (sequencibility body label_pred process_bef_aft seqible
)
1316 (* --------------------------------------------------------------------- *)
1317 (* dots and nests *)
1319 let dots_au is_strict toend label
s wrapcode n x seq_after y quantifier
=
1320 let matchgoto = gotopred None
in
1322 make_match None
false
1324 (Ast.Break
(Ast.make_mcode
"break",Ast.make_mcode
";"))) in
1326 make_match None
false
1328 (Ast.Continue
(Ast.make_mcode
"continue",Ast.make_mcode
";"))) in
1330 if quantifier
= Exists
1331 then Common.Left
(CTL.False
)
1333 then Common.Left
(CTL.Or
(aftpred label
,exitpred label
))
1335 then Common.Left
(aftpred label
)
1338 (function vx
-> function v ->
1339 (* vx is the contents of the nest, if any. we can only stop early
1340 if we find neither the ending code nor the nest contents in
1341 the if branch. not sure if this is a good idea. *)
1342 let lv = get_label_ctr() in
1343 let labelpred = CTL.Pred
(Lib_engine.Label
lv,CTL.Control
) in
1344 let preflabelpred = label_pred_maker (Some
(lv,ref true)) in
1346 (* Rather a special case. But if the code afterwards is just
1347 a } then there is no point checking after a goto that it does
1349 (* this optimization doesn't work. probably depends on whether
1350 the destination of the break/goto is local or more global than
1352 match seq_after
with
1354 let is_paren = function
1355 CTL.Pred
(Lib_engine.Paren _
,_
) -> true
1357 is_paren e1
or is_paren e2
1359 ctl_or (aftpred label
)
1360 (quantify false [lv]
1361 (ctl_and CTL.NONSTRICT
1362 (ctl_and CTL.NONSTRICT
(truepred label
) labelpred)
1363 (ctl_au CTL.NONSTRICT
1364 (ctl_and CTL.NONSTRICT
(ctl_not v)
1365 (ctl_and CTL.NONSTRICT vx
preflabelpred))
1366 (ctl_and CTL.NONSTRICT
preflabelpred
1367 (if !Flag_matcher.only_return_is_error_exit
1369 (ctl_and CTL.NONSTRICT
1370 (retpred None
) (ctl_not seq_after
))
1373 (ctl_and CTL.NONSTRICT
1374 (ctl_or (retpred None
) matchcontinue)
1375 (ctl_not seq_after
))
1376 (ctl_and CTL.NONSTRICT
1377 (ctl_or matchgoto matchbreak)
1379 (* an optim that failed see defn is_paren
1380 and tests/makes_a_loop *)
1384 (ctl_not seq_after
))))))))))) in
1385 let op = if quantifier
= !exists then ctl_au else ctl_anti_au in
1386 let v = get_let_ctr() in
1388 (match stop_early with
1389 Common.Left x1
-> ctl_or y x1
1390 | Common.Right
stop_early ->
1393 (ctl_and CTL.NONSTRICT
(label_pred_maker label
)
1394 (stop_early n
(CTL.Ref
v)))))
1396 let rec dots_and_nests plus nest whencodes bef aft dotcode after label
1397 process_bef_aft statement_list statement guard quantified wrapcode
=
1398 let ctl_and_ns = ctl_and CTL.NONSTRICT
in
1399 (* proces bef_aft *)
1401 List.fold_left
ctl_or_fl CTL.False
(List.map process_bef_aft
l) in
1402 let bef_aft = (* to be negated *)
1406 (function Ast.WhenModifier
(Ast.WhenAny
) -> true | _ -> false)
1409 with Not_found
-> shortest (Common.union_set bef aft
) in
1412 (function Ast.WhenModifier
(Ast.WhenStrict
) -> true | _ -> false)
1414 let check_quantifier quant other
=
1416 (function Ast.WhenModifier
(x
) -> x
= quant
| _ -> false)
1420 (function Ast.WhenModifier
(x
) -> x
= other
| _ -> false)
1422 then failwith
"inconsistent annotation on dots"
1426 if check_quantifier Ast.WhenExists
Ast.WhenForall
1429 if check_quantifier Ast.WhenForall
Ast.WhenExists
1432 (* the following is used when we find a goto, etc and consider accepting
1433 without finding the rest of the pattern *)
1434 let aft = shortest aft in
1435 (* process whencode *)
1436 let labelled = label_pred_maker label
in
1438 let (poswhen
,negwhen
) =
1440 (function (poswhen
,negwhen
) ->
1442 Ast.WhenNot
whencodes ->
1443 (poswhen
,ctl_or (statement_list
whencodes) negwhen
)
1444 | Ast.WhenAlways stm
->
1445 (ctl_and CTL.NONSTRICT
(statement stm
) poswhen
,negwhen
)
1446 | Ast.WhenModifier
(_) -> (poswhen
,negwhen
)
1447 | Ast.WhenNotTrue
(e
) ->
1449 ctl_or (whencond_true e label guard quantified
) negwhen
)
1450 | Ast.WhenNotFalse
(e
) ->
1452 ctl_or (whencond_false e label guard quantified
) negwhen
))
1453 (CTL.True
,CTL.False
(*bef_aft*)) (List.rev
whencodes) in
1454 (*bef_aft modifies arg so that inside of a nest can't cause the next
1455 to overshoot its boundaries, eg a() <...f()...> b() where f is
1456 a metavariable and the whole thing matches code in a loop;
1457 don't want f to match eg b(), allowing to go around the loop again*)
1458 let poswhen = ctl_and_ns arg
poswhen in
1462 (* add in After, because it's not part of the program *)
1463 ctl_or (aftpred label
) negwhen
1465 ctl_and_ns poswhen (ctl_not negwhen) in
1466 (* process dot code, if any *)
1468 match (dotcode,guard
) with
1469 (None
,_) | (_,true) -> CTL.True
1470 | (Some
dotcode,_) -> dotcode in
1471 (* process nest code, if any *)
1472 (* whencode goes in the negated part of the nest; if no nest, just goes
1473 on the "true" in between code *)
1474 let plus_var = if plus
then get_label_ctr() else string2var "" in
1475 let plus_var2 = if plus
then get_label_ctr() else string2var "" in
1476 let (ornest
,just_nest
) =
1477 (* just_nest is used when considering whether to stop early, to continue
1478 to collect nest information in the if branch *)
1479 match (nest
,guard
&& not plus
) with
1480 (None
,_) | (_,true) -> (whencodes CTL.True
,CTL.True
)
1481 | (Some nest
,false) ->
1482 let v = get_let_ctr() in
1486 (* the idea is that BindGood is sort of a witness; a witness to
1487 having found the subterm in at least one place. If there is
1488 not a witness, then there is a risk that it will get thrown
1489 away, if it is merged with a node that has an empty
1490 environment. See tests/nestplus. But this all seems
1491 rather suspicious *)
1492 CTL.And
(CTL.NONSTRICT
,x
,
1493 CTL.Exists
(true,plus_var2,
1494 CTL.Pred
(Lib_engine.BindGood
(plus_var),
1495 CTL.Modif
plus_var2)))
1499 CTL.Or
(is_plus (CTL.Ref
v),
1500 whencodes (CTL.Not
(ctl_uncheck (CTL.Ref
v))))) in
1502 let plus_modifier x
=
1509 CTL.Not
(CTL.Pred
(Lib_engine.BindBad
(plus_var),CTL.Control
)))))
1514 (* label within dots is taken care of elsewhere. the next two lines
1515 put the label on the code following dots *)
1516 After f
-> ctl_and (guard_to_strict guard
) f
labelled
1518 (* actually, label should be None based on the only use of Guard... *)
1519 assert (label
= None
);
1520 ctl_and CTL.NONSTRICT
(ctl_uncheck f
) labelled
1522 let exit = endpred label
in
1523 let errorexit = exitpred label
in
1524 ctl_or exit errorexit
1525 (* not at all sure what the next two mean... *)
1529 Some
(lv,used) -> used := true;
1530 ctl_or (CTL.Pred
(Lib_engine.Label
lv,CTL.Control
))
1531 (ctl_back_ex (ctl_or (retpred label
) (gotopred label
)))
1532 | None
-> endpred label
)
1533 (* was the following, but not clear why sgrep should allow
1535 let exit = endpred label in
1536 let errorexit = exitpred label in
1538 then ctl_or exit errorexit (* end anywhere *)
1539 else exit (* end at the real end of the function *) *)
in
1541 (dots_au is_strict ((after
= Tail
) or (after
= VeryEnd
))
1542 label
(guard_to_strict guard
) wrapcode just_nest
1544 (ctl_and_ns (ctl_and_ns (ctl_not bef_aft) ornest
) labelled))
1545 aft ender quantifier)
1547 and get_whencond_exps e
=
1548 match Ast.unwrap e
with
1550 | Ast.DisjRuleElem
(res) ->
1551 List.fold_left
Common.union_set
[] (List.map get_whencond_exps
res)
1552 | _ -> failwith
"not possible"
1554 and make_whencond_headers e e1 label guard quantified
=
1555 let fvs = Ast.get_fvs e
in
1557 quantify guard
(get_unquantified quantified
fvs)
1558 (make_match label guard h
) in
1563 (Ast.make_mcode
"if",
1564 Ast.make_mcode
"(",e1
,Ast.make_mcode
")"))) in
1565 let while_header e1
=
1569 (Ast.make_mcode
"while",
1570 Ast.make_mcode
"(",e1
,Ast.make_mcode
")"))) in
1575 (Ast.make_mcode
"for",Ast.make_mcode
"(",None
,Ast.make_mcode
";",
1576 Some e1
,Ast.make_mcode
";",None
,Ast.make_mcode
")"))) in
1578 List.fold_left
ctl_or CTL.False
(List.map
if_header e1
) in
1580 List.fold_left
ctl_or CTL.False
(List.map
while_header e1
) in
1582 List.fold_left
ctl_or CTL.False
(List.map
for_header e1
) in
1583 (if_headers, while_headers, for_headers)
1585 and whencond_true e label guard quantified
=
1586 let e1 = get_whencond_exps e
in
1587 let (if_headers, while_headers, for_headers) =
1588 make_whencond_headers e
e1 label guard quantified
in
1590 (ctl_and CTL.NONSTRICT
(truepred label
) (ctl_back_ex if_headers))
1591 (ctl_and CTL.NONSTRICT
1592 (inlooppred label
) (ctl_back_ex (ctl_or while_headers for_headers)))
1594 and whencond_false e label guard quantified
=
1595 let e1 = get_whencond_exps e
in
1596 let (if_headers, while_headers, for_headers) =
1597 make_whencond_headers e
e1 label guard quantified
in
1599 ctl_or (ctl_and CTL.NONSTRICT
(falsepred label
) (ctl_back_ex if_headers))
1600 (* if without else *)
1601 (ctl_or (ctl_and CTL.NONSTRICT
(fallpred label
) (ctl_back_ex if_headers))
1602 (* failure of loop test *)
1603 (ctl_and CTL.NONSTRICT
(loopfallpred label
)
1604 (ctl_or (ctl_back_ex while_headers) (ctl_back_ex for_headers))))
1606 (* --------------------------------------------------------------------- *)
1607 (* the main translation loop *)
1609 let rec statement_list stmt_list after quantified minus_quantified
1610 label llabel slabel dots_before guard
=
1612 (* include Disj to be on the safe side *)
1613 match Ast.unwrap x
with
1614 Ast.Dots
_ | Ast.Nest
_ | Ast.Disj
_ -> true | _ -> false in
1615 let compute_label l e db
= if db
or isdots e
then l else None
in
1616 match Ast.unwrap stmt_list
with
1618 let rec loop quantified minus_quantified dots_before label llabel slabel
1620 ([],_,_) -> (match after
with After f
-> f
| _ -> CTL.True
)
1622 statement e after quantified minus_quantified
1623 (compute_label label e dots_before
)
1625 | (e
::sl
,fv
::fvs,mfv
::mfvs
) ->
1626 let shared = intersectll fv
fvs in
1627 let unqshared = get_unquantified quantified
shared in
1628 let new_quantified = Common.union_set
unqshared quantified
in
1629 let minus_shared = intersectll mfv mfvs
in
1631 get_unquantified minus_quantified
minus_shared in
1632 let new_mquantified =
1633 Common.union_set
munqshared minus_quantified
in
1634 quantify guard
unqshared
1637 (let (label1
,llabel1
,slabel1
) =
1638 match Ast.unwrap e
with
1640 (match Ast.unwrap re
with
1641 Ast.Goto
_ -> (None
,None
,None
)
1642 | _ -> (label
,llabel
,slabel
))
1643 | _ -> (label
,llabel
,slabel
) in
1644 loop new_quantified new_mquantified (isdots e
)
1645 label1 llabel1 slabel1
1647 new_quantified new_mquantified
1648 (compute_label label e dots_before
) llabel slabel guard
)
1649 | _ -> failwith
"not possible" in
1650 loop quantified minus_quantified dots_before
1652 (x
,List.map
Ast.get_fvs x
,List.map
Ast.get_mfvs x
)
1653 | Ast.CIRCLES
(x
) -> failwith
"not supported"
1654 | Ast.STARS
(x
) -> failwith
"not supported"
1656 (* llabel is the label of the enclosing loop and slabel is the label of the
1658 and statement stmt after quantified minus_quantified
1659 label llabel slabel guard
=
1660 let ctl_au = ctl_au CTL.NONSTRICT
in
1661 let ctl_ax = ctl_ax CTL.NONSTRICT
in
1662 let ctl_and = ctl_and CTL.NONSTRICT
in
1663 let make_seq = make_seq guard
in
1664 let make_seq_after = make_seq_after guard
in
1665 let real_make_match = make_match in
1666 let make_match = header_match label guard
in
1668 let dots_done = ref false in (* hack for dots cases we can easily handle *)
1671 match Ast.unwrap stmt
with
1673 (match Ast.unwrap ast
with
1674 (* the following optimisation is not a good idea, because when S
1675 is alone, we would like it not to match a declaration.
1676 this makes more matching for things like when (...) S, but perhaps
1677 that matching is not so costly anyway *)
1678 (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*)
1679 | Ast.MetaStmt
((s,_,(Ast.CONTEXT
(_,Ast.BEFOREAFTER
(_,_,_)) as d),_),
1681 | Ast.MetaStmt
((s,_,(Ast.CONTEXT
(_,Ast.AFTER
(_,_)) as d),_),
1683 svar_context_with_add_after stmt
s label quantified
d ast seqible
1685 (process_bef_aft quantified minus_quantified
1686 label llabel slabel
true)
1688 (Ast.get_fvs stmt
, Ast.get_fresh stmt
, Ast.get_inherited stmt
)
1690 | Ast.MetaStmt
((s,_,d,_),keep
,seqible
,_) ->
1691 svar_minus_or_no_add_after stmt
s label quantified
d ast seqible
1693 (process_bef_aft quantified minus_quantified
1694 label llabel slabel
true)
1696 (Ast.get_fvs stmt
, Ast.get_fresh stmt
, Ast.get_inherited stmt
)
1700 match Ast.unwrap ast
with
1701 Ast.DisjRuleElem
(res) ->
1702 do_re_matches label guard
res quantified minus_quantified
1703 | Ast.Exp
(_) | Ast.Ty
(_) ->
1704 let stmt_fvs = Ast.get_fvs stmt
in
1705 let fvs = get_unquantified quantified
stmt_fvs in
1706 CTL.InnerAnd
(quantify guard
fvs (make_match ast
))
1708 let stmt_fvs = Ast.get_fvs stmt
in
1709 let fvs = get_unquantified quantified
stmt_fvs in
1710 quantify guard
fvs (make_match ast
) in
1711 match Ast.unwrap ast
with
1712 Ast.Break
(brk
,semi
) ->
1713 (match (llabel
,slabel
) with
1714 (_,Some
(lv,used)) -> (* use switch label if there is one *)
1715 ctl_and term (bclabel_pred_maker slabel
)
1716 | _ -> ctl_and term (bclabel_pred_maker llabel
))
1717 | Ast.Continue
(brk
,semi
) -> ctl_and term (bclabel_pred_maker llabel
)
1718 | Ast.Return
((_,info,retmc
,pos),(_,_,semmc
,_)) ->
1719 (* discard pattern that comes after return *)
1720 let normal_res = make_seq_after term after
in
1721 (* the following code tries to propagate the modifications on
1722 return; to a close brace, in the case where the final return
1725 match (retmc
,semmc
) with
1726 (Ast.MINUS
(_,inst1
,adj1
,l1
),Ast.MINUS
(_,_,_,l2
))
1727 when !Flag.sgrep_mode2
->
1728 (* in sgrep mode, we can propagate the - *)
1729 Some
(Ast.MINUS
(Ast.NoPos
,inst1
,adj1
,l1
@l2
))
1730 | (Ast.MINUS
(_,_,_,l1
),Ast.MINUS
(_,_,_,l2
)) ->
1731 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l1
@l2
,Ast.ONE
)))
1732 | (Ast.CONTEXT
(_,Ast.BEFORE
(l1
,c1
)),
1733 Ast.CONTEXT
(_,Ast.AFTER
(l2
,c2
))) ->
1734 (if not
(c1
= c2
) then failwith
"bad + code");
1735 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l1
@l2
,c1
)))
1736 | (Ast.CONTEXT
(_,Ast.BEFORE
(_)),Ast.CONTEXT
(_,Ast.NOTHING
))
1737 | (Ast.CONTEXT
(_,Ast.NOTHING
),Ast.CONTEXT
(_,Ast.NOTHING
)) ->
1739 | (Ast.CONTEXT
(_,Ast.NOTHING
),
1740 Ast.CONTEXT
(_,Ast.AFTER
(l,c
))) ->
1741 Some
(Ast.CONTEXT
(Ast.NoPos
,Ast.BEFORE
(l,c
)))
1743 let ret = Ast.make_mcode
"return" in
1745 Ast.rewrap ast
(Ast.Edots
(Ast.make_mcode
"...",None
)) in
1746 let semi = Ast.make_mcode
";" in
1748 make_match(Ast.rewrap ast
(Ast.Return
(ret,semi))) in
1750 make_match(Ast.rewrap ast
(Ast.ReturnExpr
(ret,edots,semi))) in
1753 let exit = endpred None
in
1755 Ast.rewrap ast
(Ast.SeqEnd
(("}",info,new_mc,pos))) in
1756 let stripped_rbrace =
1757 Ast.rewrap ast
(Ast.SeqEnd
(Ast.make_mcode
"}")) in
1759 (ctl_and (make_match mod_rbrace)
1764 (ctl_or simple_return return_expr))))
1766 (make_match stripped_rbrace)
1767 (* error exit not possible; it is in the middle
1768 of code, so a return is needed *)
1771 (* some change in the middle of the return, so have to
1772 find an actual return *)
1775 (* should try to deal with the dots_bef_aft problem elsewhere,
1776 but don't have the courage... *)
1781 do_between_dots stmt
term End
1782 quantified minus_quantified label llabel slabel guard
in
1784 make_seq_after term after
)
1785 | Ast.Seq
(lbrace
,body,rbrace
) ->
1786 let (lbfvs
,b1fvs
,b2fvs
,rbfvs
) =
1789 [Ast.get_fvs lbrace
;
1790 Ast.get_fvs
body;Ast.get_fvs rbrace
]
1792 [(lbfvs
,b1fvs
);(_,b2fvs
);(rbfvs
,_)] ->
1793 (lbfvs
,b1fvs
,b2fvs
,rbfvs
)
1794 | _ -> failwith
"not possible" in
1795 let (mlbfvs
,mb1fvs
,mb2fvs
,mrbfvs
) =
1797 seq_fvs minus_quantified
1798 [Ast.get_mfvs lbrace
;
1799 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)
1822 (real_make_match None guard rbrace
)
1824 let new_quantified2 =
1825 Common.union_set b1fvs
(Common.union_set b2fvs quantified
) in
1826 let new_mquantified2 =
1827 Common.union_set mb1fvs
(Common.union_set mb2fvs minus_quantified
) in
1828 let pattern_as_given =
1829 let new_quantified2 = Common.union_set
[pv] new_quantified2 in
1830 quantify true [pv;lv]
1831 (quantify guard b1fvs
1835 (if !exists = Exists
then CTL.False
else (aftpred label
))
1836 (quantify guard b2fvs
1837 (statement_list body
1838 (After
(make_seq_after end_brace after
))
1839 new_quantified2 new_mquantified2
1840 (Some
(lv,ref true))
1841 llabel slabel
false guard
)))])) in
1842 if ends_in_return body
1844 (* matching error handling code *)
1846 1. The pattern as given
1847 2. A goto, and then some close braces, and then the pattern as
1848 given, but without the braces (only possible if there are no
1849 decls, and open and close braces are unmodified)
1850 3. Part of the pattern as given, then a goto, and then the rest
1851 of the pattern. For this case, we just check that all paths have
1852 a goto within the current braces. checking for a goto at every
1853 point in the pattern seems expensive and not worthwhile. *)
1855 let body = preprocess_dots body in (* redo, to drop braces *)
1859 (make_match empty_rbrace)
1860 (ctl_ax (* skip the destination label *)
1861 (quantify guard b2fvs
1862 (statement_list body End
1863 new_quantified2 new_mquantified2 None llabel slabel
1866 let new_quantified2 = Common.union_set
[pv] new_quantified2 in
1867 quantify true [pv;lv]
1868 (quantify guard b1fvs
1872 (CTL.AU
(* want AF even for sgrep *)
1873 (CTL.FORWARD
,CTL.STRICT
,
1874 CTL.Pred
(Lib_engine.PrefixLabel
(lv),CTL.Control
),
1875 ctl_and (* brace must be eventually after goto *)
1876 (gotopred (Some
(lv,ref true)))
1877 (* want AF even for sgrep *)
1878 (CTL.AF
(CTL.FORWARD
,CTL.STRICT
,end_brace))))
1879 (quantify guard b2fvs
1880 (statement_list body Tail
1881 new_quantified2 new_mquantified2
1882 None
(*no label because past the goto*)
1883 llabel slabel
false guard
))])) in
1884 ctl_or pattern_as_given (ctl_or pattern2 pattern3)
1885 else pattern_as_given
1886 | Ast.IfThen
(ifheader
,branch
,aft) ->
1887 ifthen ifheader branch
aft after quantified minus_quantified
1888 label llabel slabel statement
make_match guard
1890 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft) ->
1891 ifthenelse ifheader branch1 els branch2
aft after quantified
1892 minus_quantified label llabel slabel statement
make_match guard
1894 | Ast.While
(header,body,aft) | Ast.For
(header,body,aft)
1895 | Ast.Iterator
(header,body,aft) ->
1896 forwhile header body aft after quantified minus_quantified
1897 label statement
make_match guard
1899 | Ast.Disj
(stmt_dots_list
) -> (* list shouldn't be empty *)
1900 (*ctl_and seems pointless, disjuncts see label too
1901 (label_pred_maker label)*)
1902 (List.fold_left
ctl_seqor CTL.False
1905 statement_list sl after quantified minus_quantified label
1906 llabel slabel
true guard
)
1909 | Ast.Nest
(starter
,stmt_dots
,ender,whencode
,multi
,bef
,aft) ->
1910 (* label in recursive call is None because label check is already
1911 wrapped around the corresponding code *)
1914 match seq_fvs quantified
[Ast.get_wcfvs whencode
;Ast.get_fvs stmt_dots
]
1916 [(wcfvs
,bothfvs);(bdfvs
,_)] -> bothfvs
1917 | _ -> failwith
"not possible" in
1919 (* no minus version because when code doesn't contain any minus code *)
1920 let new_quantified = Common.union_set
bfvs quantified
in
1923 match Ast.get_mcodekind starter
with (*ender must have the same mcode*)
1924 Ast.MINUS
(_,_,_,_) as d ->
1925 (* no need for the fresh metavar, but ... is a bit weird as a
1927 Some
(make_match (make_meta_rule_elem d ([],[],[])))
1932 statement_list stmt_dots
(a2n after
) new_quantified minus_quantified
1933 None llabel slabel
true guard
in
1934 dots_and_nests multi
1935 (Some
dots_pattern) whencode bef
aft dot_code after label
1936 (process_bef_aft
new_quantified minus_quantified
1937 None llabel slabel
true)
1939 statement_list x Tail
new_quantified minus_quantified None
1940 llabel slabel
true true)
1942 statement x Tail
new_quantified minus_quantified None
1945 (function x
-> Ast.set_fvs
[] (Ast.rewrap stmt x
)))
1947 | Ast.Dots
((_,i
,d,_),whencodes,bef
,aft) ->
1950 Ast.MINUS
(_,_,_,_) ->
1951 (* no need for the fresh metavar, but ... is a bit weird as a
1953 Some
(make_match (make_meta_rule_elem d ([],[],[])))
1955 dots_and_nests false None
whencodes bef
aft dot_code after label
1956 (process_bef_aft quantified minus_quantified None llabel slabel
true)
1958 statement_list x Tail quantified minus_quantified
1959 None llabel slabel
true true)
1961 statement x Tail quantified minus_quantified None llabel slabel
true)
1963 (function x
-> Ast.set_fvs
[] (Ast.rewrap stmt x
))
1965 | Ast.Switch
(header,lb
,decls
,cases,rb
) ->
1966 let rec intersect_all = function
1969 | x
::xs -> intersect x
(intersect_all xs) in
1970 let rec intersect_all2 = function (* pairwise *)
1975 (function elem
-> List.exists (List.mem elem
) xs)
1977 Common.union_set
front (intersect_all2 xs) in
1978 let rec union_all l = List.fold_left
union [] l in
1979 (* start normal variables *)
1980 let header_fvs = Ast.get_fvs
header in
1981 let lb_fvs = Ast.get_fvs lb
in
1982 let decl_fvs = union_all (List.map
Ast.get_fvs
(Ast.undots decls
)) in
1983 let case_fvs = List.map
Ast.get_fvs
cases in
1984 let rb_fvs = Ast.get_fvs rb
in
1985 let (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
1986 all_casefvs
,all_b3fvs
,all_rbfvs
) =
1988 (function (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
1989 all_casefvs
,all_b3fvs
,all_rbfvs
) ->
1990 function case_fvs ->
1991 match seq_fvs quantified
[header_fvs;lb_fvs;case_fvs;rb_fvs] with
1992 [(efvs
,b1fvs
);(lbfvs
,b2fvs
);(casefvs
,b3fvs
);(rbfvs
,_)] ->
1993 (efvs
::all_efvs
,b1fvs
::all_b1fvs
,lbfvs
::all_lbfvs
,
1994 b2fvs
::all_b2fvs
,casefvs
::all_casefvs
,b3fvs
::all_b3fvs
,
1996 | _ -> failwith
"not possible")
1997 ([],[],[],[],[],[],[]) (decl_fvs :: case_fvs) in
1998 let (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
1999 all_casefvs
,all_b3fvs
,all_rbfvs
) =
2000 (List.rev all_efvs
,List.rev all_b1fvs
,List.rev all_lbfvs
,
2001 List.rev all_b2fvs
,List.rev all_casefvs
,List.rev all_b3fvs
,
2002 List.rev all_rbfvs
) in
2003 let exponlyfvs = intersect_all all_efvs
in
2004 let lbonlyfvs = intersect_all all_lbfvs
in
2005 (* don't do anything with right brace. Hope there is no + code on it *)
2006 (* let rbonlyfvs = intersect_all all_rbfvs in*)
2007 let b1fvs = union_all all_b1fvs
in
2008 let new1_quantified = union b1fvs quantified
in
2010 union (union_all all_b2fvs
) (intersect_all2 all_casefvs
) in
2011 let new2_quantified = union b2fvs new1_quantified in
2012 (* let b3fvs = union_all all_b3fvs in*)
2013 (* ------------------- start minus free variables *)
2014 let header_mfvs = Ast.get_mfvs
header in
2015 let lb_mfvs = Ast.get_mfvs lb
in
2016 let decl_mfvs = union_all (List.map
Ast.get_mfvs
(Ast.undots decls
)) in
2017 let case_mfvs = List.map
Ast.get_mfvs
cases in
2018 let rb_mfvs = Ast.get_mfvs rb
in
2019 let (all_mefvs
,all_mb1fvs
,all_mlbfvs
,all_mb2fvs
,
2020 all_mcasefvs
,all_mb3fvs
,all_mrbfvs
) =
2022 (function (all_efvs
,all_b1fvs
,all_lbfvs
,all_b2fvs
,
2023 all_casefvs
,all_b3fvs
,all_rbfvs
) ->
2024 function case_mfvs ->
2027 [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with
2028 [(efvs
,b1fvs);(lbfvs
,b2fvs);(casefvs
,b3fvs);(rbfvs
,_)] ->
2029 (efvs
::all_efvs
,b1fvs::all_b1fvs
,lbfvs
::all_lbfvs
,
2030 b2fvs::all_b2fvs
,casefvs
::all_casefvs
,b3fvs::all_b3fvs
,
2032 | _ -> failwith
"not possible")
2033 ([],[],[],[],[],[],[]) (decl_mfvs::case_mfvs) in
2034 let (all_mefvs
,all_mb1fvs
,all_mlbfvs
,all_mb2fvs
,
2035 all_mcasefvs
,all_mb3fvs
,all_mrbfvs
) =
2036 (List.rev all_mefvs
,List.rev all_mb1fvs
,List.rev all_mlbfvs
,
2037 List.rev all_mb2fvs
,List.rev all_mcasefvs
,List.rev all_mb3fvs
,
2038 List.rev all_mrbfvs
) in
2039 (* don't do anything with right brace. Hope there is no + code on it *)
2040 (* let rbonlyfvs = intersect_all all_rbfvs in*)
2041 let mb1fvs = union_all all_mb1fvs
in
2042 let new1_mquantified = union mb1fvs quantified
in
2044 union (union_all all_mb2fvs
) (intersect_all2 all_mcasefvs
) in
2045 let new2_mquantified = union mb2fvs new1_mquantified in
2046 (* let b3fvs = union_all all_b3fvs in*)
2047 (* ------------------- end collection of free variables *)
2048 let switch_header = quantify guard
exponlyfvs (make_match header) in
2049 let lb = quantify guard
lbonlyfvs (make_match lb) in
2050 (* let rb = quantify guard rbonlyfvs (make_match rb) in*)
2053 (function case_line
->
2054 match Ast.unwrap case_line
with
2055 Ast.CaseLine
(header,body) ->
2057 match seq_fvs new2_quantified [Ast.get_fvs
header] with
2058 [(e1fvs,_)] -> e1fvs
2059 | _ -> failwith
"not possible" in
2060 quantify guard
e1fvs (real_make_match label
true header)
2061 | Ast.OptCase
(case_line
) -> failwith
"not supported")
2063 let lv = get_label_ctr() in
2064 let used = ref false in
2065 let (decls_exists_code
,decls_all_code
) =
2066 (*don't really understand this*)
2067 if (Ast.undots decls
) = []
2068 then (CTL.True
,CTL.False
)
2071 statement_list decls Tail
2072 new2_quantified new2_mquantified (Some
(lv,used)) llabel None
2077 (List.fold_left
ctl_or_fl CTL.False
2078 (List.map
ctl_uncheck
2079 (decls_all_code
::case_headers))) in
2082 (function case_line
->
2083 match Ast.unwrap case_line
with
2084 Ast.CaseLine
(header,body) ->
2085 let (e1fvs,b1fvs,s1fvs
) =
2086 let fvs = [Ast.get_fvs
header;Ast.get_fvs
body] in
2087 match seq_fvs new2_quantified fvs with
2088 [(e1fvs,b1fvs);(s1fvs
,_)] -> (e1fvs,b1fvs,s1fvs
)
2089 | _ -> failwith
"not possible" in
2090 let (me1fvs
,mb1fvs,ms1fvs
) =
2091 let fvs = [Ast.get_mfvs
header;Ast.get_mfvs
body] in
2092 match seq_fvs new2_mquantified fvs with
2093 [(e1fvs,b1fvs);(s1fvs
,_)] -> (e1fvs,b1fvs,s1fvs
)
2094 | _ -> failwith
"not possible" in
2096 quantify guard
e1fvs (make_match header) in
2097 let new3_quantified = union b1fvs new2_quantified in
2098 let new3_mquantified = union mb1fvs new2_mquantified in
2100 statement_list body Tail
2101 new3_quantified new3_mquantified (Some
(lv,used)) llabel
2102 (Some
(lv,used)) false(*?*) guard
in
2103 quantify guard
b1fvs (make_seq [case_header; body])
2104 | Ast.OptCase
(case_line
) -> failwith
"not supported")
2106 let default_required =
2109 match Ast.unwrap case
with
2110 Ast.CaseLine
(header,_) ->
2111 (match Ast.unwrap
header with
2112 Ast.Default
(_,_) -> true
2116 then function x
-> x
2117 else function x
-> ctl_or (fallpred label
) x
in
2118 let after_pred = aftpred label
in
2119 let body after_branch
=
2122 (quantify guard
b2fvs
2125 (List.fold_left
ctl_and CTL.True
2127 (decls_exists_code
:: case_headers)));
2128 List.fold_left
ctl_or_fl no_header
2129 (decls_all_code
:: case_code)])))
2132 (rb_fvs,Ast.get_fresh
rb,Ast.get_inherited
rb,
2133 match Ast.unwrap
rb with
2134 Ast.SeqEnd
(rb) -> Ast.get_mcodekind
rb
2135 | _ -> failwith
"not possible") in
2136 let (switch_header,wrapper
) =
2139 let label_pred = CTL.Pred
(Lib_engine.Label
(lv),CTL.Control
) in
2140 (ctl_and switch_header label_pred,
2141 (function body -> quantify true [lv] body))
2142 else (switch_header,function x
-> x
) in
2144 (end_control_structure b1fvs switch_header body
2145 after_pred (Some
(ctl_ex after_pred)) None
aft after label guard
)
2146 | Ast.FunDecl
(header,lbrace
,body,rbrace
) ->
2147 let (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
) =
2150 [Ast.get_fvs
header;Ast.get_fvs lbrace
;
2151 Ast.get_fvs
body;Ast.get_fvs rbrace
]
2153 [(hfvs
,b1fvs);(lbfvs
,b2fvs);(_,b3fvs);(rbfvs
,_)] ->
2154 (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
)
2155 | _ -> failwith
"not possible" in
2156 let (mhfvs
,mb1fvs,mlbfvs
,mb2fvs,mb3fvs
,mrbfvs
) =
2159 [Ast.get_mfvs
header;Ast.get_mfvs lbrace
;
2160 Ast.get_mfvs
body;Ast.get_mfvs rbrace
]
2162 [(hfvs
,b1fvs);(lbfvs
,b2fvs);(_,b3fvs);(rbfvs
,_)] ->
2163 (hfvs
,b1fvs,lbfvs
,b2fvs,b3fvs,rbfvs
)
2164 | _ -> failwith
"not possible" in
2165 let function_header = quantify guard hfvs
(make_match header) in
2166 let start_brace = quantify guard lbfvs
(make_match lbrace
) in
2167 let stripped_rbrace =
2168 match Ast.unwrap rbrace
with
2169 Ast.SeqEnd
((data
,info,_,_)) ->
2170 Ast.rewrap rbrace
(Ast.SeqEnd
(Ast.make_mcode data
))
2171 | _ -> failwith
"unexpected close brace" in
2173 let exit = CTL.Pred
(Lib_engine.Exit
,CTL.Control
) in
2174 let errorexit = CTL.Pred
(Lib_engine.ErrorExit
,CTL.Control
) in
2175 let fake_brace = CTL.Pred
(Lib_engine.FakeBrace
,CTL.Control
) in
2177 (quantify guard rbfvs
(make_match rbrace
))
2179 (* the following finds the beginning of the fake braces,
2180 if there are any, not completely sure how this works.
2181 sse the examples sw and return *)
2182 (ctl_back_ex (ctl_not fake_brace))
2183 (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in
2184 let new_quantified3 =
2185 Common.union_set
b1fvs
2186 (Common.union_set
b2fvs (Common.union_set
b3fvs quantified
)) in
2187 let new_mquantified3 =
2188 Common.union_set
mb1fvs
2189 (Common.union_set
mb2fvs
2190 (Common.union_set mb3fvs minus_quantified
)) in
2191 let not_minus = function Ast.MINUS
(_,_,_,_) -> false | _ -> true in
2193 match (Ast.undots
body,
2194 contains_modif rbrace
or contains_pos rbrace
) with
2196 (match Ast.unwrap
body with
2197 Ast.Nest
(starter
,stmt_dots
,ender,[],false,_,_)
2198 (* perhaps could optimize for minus case too... TODO *)
2199 when not_minus (Ast.get_mcodekind starter
)
2201 (* special case for function header + body - header is unambiguous
2202 and unique, so we can just look for the nested body anywhere
2206 (CTL.FORWARD
,guard_to_strict guard
,start_brace,
2207 statement_list stmt_dots
2208 (* discards match on right brace, but don't need it *)
2209 (Guard
(make_seq_after end_brace after
))
2210 new_quantified3 new_mquantified3
2211 None llabel slabel
true guard
))
2212 | Ast.Dots
((_,i
,d,_),whencode
,_,_) when
2214 (* flow sensitive, so not optimizable *)
2215 (function Ast.WhenNotTrue
(_) | Ast.WhenNotFalse
(_) ->
2217 | _ -> true) whencode
) ->
2218 (* try to be more efficient for the case where the body is just
2219 ... Perhaps this is too much of a special case, but useful
2220 for dropping a parameter and checking that it is never used. *)
2222 Ast.MINUS
(_,_,_,_) -> None
2225 (* no nested braces, because only dots *)
2226 string2var ("p1") in
2228 CTL.Pred
(Lib_engine.Paren
pv,CTL.Control
) in
2231 [ctl_and start_brace paren_pred;
2241 Ast.WhenAlways
(s) -> prev
2242 | Ast.WhenNot
(sl
) ->
2244 statement_list sl Tail
2250 | Ast.WhenNotTrue
(_)
2251 | Ast.WhenNotFalse
(_) ->
2252 failwith
"unexpected"
2254 (Ast.WhenAny
) -> CTL.False
2255 | Ast.WhenModifier
(_) -> prev
)
2256 CTL.False whencode
))
2260 Ast.WhenAlways
(s) ->
2265 label llabel slabel
true in
2267 | Ast.WhenNot
(sl
) -> prev
2268 | Ast.WhenNotTrue
(_)
2269 | Ast.WhenNotFalse
(_) ->
2270 failwith
"unexpected"
2271 | Ast.WhenModifier
(Ast.WhenAny
) ->
2273 | Ast.WhenModifier
(_) -> prev
)
2274 CTL.True whencode
) in
2277 (make_match stripped_rbrace)
2282 (* function body is all minus, no whencode *)
2283 match Ast.undots
body with
2285 (match Ast.unwrap
body with
2287 ((_,i
,(Ast.MINUS
(_,_,_,[]) as d),_),[],_,_) ->
2288 (match (Ast.unwrap lbrace
,Ast.unwrap rbrace
) with
2289 (Ast.SeqStart
((_,_,Ast.MINUS
(_,_,_,[]),_)),
2290 Ast.SeqEnd
((_,_,Ast.MINUS
(_,_,_,[]),_)))
2291 when not
(contains_pos rbrace
) ->
2293 (* andany drops everything to the end, including close
2294 braces - not just function body, could check
2295 label to keep braces *)
2296 (ctl_and start_brace
2299 (CTL.FORWARD
,guard_to_strict guard
,CTL.True
,
2301 (make_meta_rule_elem d ([],[],[]))))))
2306 match (optim1,optim2) with
2312 quantify guard
b3fvs
2313 (statement_list body
2314 (After
(make_seq_after end_brace after
))
2315 new_quantified3 new_mquantified3 None llabel slabel
2317 quantify guard
b1fvs
2318 (make_seq [function_header; quantify guard
b2fvs body_code])
2319 | Ast.Define
(header,body) ->
2320 let (hfvs
,bfvs,bodyfvs
) =
2321 match seq_fvs quantified
[Ast.get_fvs
header;Ast.get_fvs
body]
2323 [(hfvs
,b1fvs);(bodyfvs
,_)] -> (hfvs
,b1fvs,bodyfvs
)
2324 | _ -> failwith
"not possible" in
2325 let (mhfvs
,mbfvs
,mbodyfvs
) =
2326 match seq_fvs minus_quantified
[Ast.get_mfvs
header;Ast.get_mfvs
body]
2328 [(hfvs
,b1fvs);(bodyfvs
,_)] -> (hfvs
,b1fvs,bodyfvs
)
2329 | _ -> failwith
"not possible" in
2330 let define_header = quantify guard hfvs
(make_match header) in
2332 statement_list body after
2333 (Common.union_set
bfvs quantified
)
2334 (Common.union_set mbfvs minus_quantified
)
2335 None llabel slabel
true guard
in
2336 quantify guard
bfvs (make_seq [define_header; body_code])
2337 | Ast.OptStm
(stm
) ->
2338 failwith
"OptStm should have been compiled away\n"
2339 | Ast.UniqueStm
(stm
) -> failwith
"arities not yet supported"
2340 | _ -> failwith
"not supported" in
2341 if guard
or !dots_done
2344 do_between_dots stmt
term after quantified minus_quantified
2345 label llabel slabel guard
2347 (* term is the translation of stmt *)
2348 and do_between_dots stmt
term after quantified minus_quantified
2349 label llabel slabel guard
=
2350 match Ast.get_dots_bef_aft stmt
with
2351 Ast.AddingBetweenDots
(brace_term
,n
)
2352 | Ast.DroppingBetweenDots
(brace_term
,n
) ->
2354 statement brace_term after quantified minus_quantified
2355 label llabel slabel guard
in
2356 let v = Printf.sprintf
"_r_%d" n
in
2357 let case1 = ctl_and CTL.NONSTRICT
(CTL.Ref
v) match_brace in
2358 let case2 = ctl_and CTL.NONSTRICT
(ctl_not (CTL.Ref
v)) term in
2361 (ctl_back_ex (ctl_or (truepred label
) (inlooppred label
)))
2362 (ctl_back_ex (ctl_back_ex (falsepred label
))),
2364 | Ast.NoDots
-> term
2366 (* un_process_bef_aft is because we don't want to do transformation in this
2367 code, and thus don't case about braces before or after it *)
2368 and process_bef_aft quantified minus_quantified label llabel slabel guard
=
2370 Ast.WParen
(re
,n
) ->
2371 let paren_pred = CTL.Pred
(Lib_engine.Paren n
,CTL.Control
) in
2372 let s = guard_to_strict guard
in
2373 quantify true (get_unquantified quantified
[n
])
2374 (ctl_and s (make_raw_match None guard re
) paren_pred)
2376 statement
s Tail quantified minus_quantified label llabel slabel guard
2377 | Ast.Other_dots
d ->
2378 statement_list d Tail quantified minus_quantified
2379 label llabel slabel
true guard
2381 (* --------------------------------------------------------------------- *)
2382 (* cleanup: convert AX to EX for pdots.
2383 Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2384 This is what we wanted in the first place, but it wasn't possible to make
2385 because the AX and its argument are not created in the same place.
2387 (* also cleanup XX, which is a marker for the case where the programmer
2388 specifies to change the quantifier on .... Assumed to only occur after one AX
2389 or EX, or at top level. *)
2392 let c = match c with CTL.XX
(c) -> c | _ -> c in
2394 CTL.False
-> CTL.False
2395 | CTL.True
-> CTL.True
2396 | CTL.Pred
(p
) -> CTL.Pred
(p
)
2397 | CTL.Not
(phi
) -> CTL.Not
(cleanup phi
)
2398 | CTL.Exists
(keep
,v,phi
) -> CTL.Exists
(keep
,v,cleanup phi
)
2399 | CTL.AndAny
(dir
,s,phi1
,phi2
) ->
2400 CTL.AndAny
(dir
,s,cleanup phi1
,cleanup phi2
)
2401 | CTL.HackForStmt
(dir
,s,phi1
,phi2
) ->
2402 CTL.HackForStmt
(dir
,s,cleanup phi1
,cleanup phi2
)
2403 | CTL.And
(s,phi1
,phi2
) -> CTL.And
(s,cleanup phi1
,cleanup phi2
)
2404 | CTL.Or
(phi1
,phi2
) -> CTL.Or
(cleanup phi1
,cleanup phi2
)
2405 | CTL.SeqOr
(phi1
,phi2
) -> CTL.SeqOr
(cleanup phi1
,cleanup phi2
)
2406 | CTL.Implies
(phi1
,phi2
) -> CTL.Implies
(cleanup phi1
,cleanup phi2
)
2407 | CTL.AF
(dir
,s,phi1
) -> CTL.AF
(dir
,s,cleanup phi1
)
2408 | CTL.AX
(CTL.FORWARD
,s,
2410 CTL.And
(CTL.NONSTRICT
,CTL.AU
(CTL.FORWARD
,s2
,e2
,e3
),
2411 CTL.EU
(CTL.FORWARD
,e4
,e5
)))) ->
2413 CTL.And
(CTL.NONSTRICT
,
2414 CTL.AX
(CTL.FORWARD
,s,CTL.AU
(CTL.FORWARD
,s2
,e2
,e3
)),
2415 CTL.EX
(CTL.FORWARD
,CTL.EU
(CTL.FORWARD
,e4
,e5
))))
2416 | CTL.AX
(dir
,s,CTL.XX
(phi
)) -> CTL.EX
(dir
,cleanup phi
)
2417 | CTL.EX
(dir
,CTL.XX
((CTL.AU
(_,s,_,_)) as phi
)) ->
2418 CTL.AX
(dir
,s,cleanup phi
)
2419 | CTL.XX
(phi
) -> failwith
"bad XX"
2420 | CTL.AX
(dir
,s,phi1
) -> CTL.AX
(dir
,s,cleanup phi1
)
2421 | CTL.AG
(dir
,s,phi1
) -> CTL.AG
(dir
,s,cleanup phi1
)
2422 | CTL.EF
(dir
,phi1
) -> CTL.EF
(dir
,cleanup phi1
)
2423 | CTL.EX
(dir
,phi1
) -> CTL.EX
(dir
,cleanup phi1
)
2424 | CTL.EG
(dir
,phi1
) -> CTL.EG
(dir
,cleanup phi1
)
2425 | CTL.AW
(dir
,s,phi1
,phi2
) -> CTL.AW
(dir
,s,cleanup phi1
,cleanup phi2
)
2426 | CTL.AU
(dir
,s,phi1
,phi2
) -> CTL.AU
(dir
,s,cleanup phi1
,cleanup phi2
)
2427 | CTL.EU
(dir
,phi1
,phi2
) -> CTL.EU
(dir
,cleanup phi1
,cleanup phi2
)
2428 | CTL.Let
(x,phi1
,phi2
) -> CTL.Let
(x,cleanup phi1
,cleanup phi2
)
2429 | CTL.LetR
(dir
,x,phi1
,phi2
) -> CTL.LetR
(dir
,x,cleanup phi1
,cleanup phi2
)
2430 | CTL.Ref
(s) -> CTL.Ref
(s)
2431 | CTL.Uncheck
(phi1
) -> CTL.Uncheck
(cleanup phi1
)
2432 | CTL.InnerAnd
(phi1
) -> CTL.InnerAnd
(cleanup phi1
)
2434 (* --------------------------------------------------------------------- *)
2435 (* Function declaration *)
2437 (* ua = used_after, fua = fresh_used_after, fuas = fresh_used_after_seeds *)
2439 let top_level name
((ua
,pos),fua
) (fuas
,t
) =
2440 let ua = List.filter
(function (nm,_) -> nm = name
) ua in
2442 saved := Ast.get_saved t
;
2443 let quantified = Common.minus_set
(Common.union_set
ua fuas
) pos in
2444 quantify false quantified
2445 (match Ast.unwrap t
with
2446 Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
2448 let unopt = elim_opt.V.rebuilder_statement stmt
in
2449 let unopt = preprocess_dots_e unopt in
2450 cleanup(statement
unopt VeryEnd
quantified [] None None None
false)
2451 | Ast.CODE
(stmt_dots
) ->
2452 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots
in
2453 let unopt = preprocess_dots unopt in
2454 let starts_with_dots =
2455 match Ast.undots stmt_dots
with
2457 (match Ast.unwrap
d with
2458 Ast.Dots
(_,_,_,_) | Ast.Circles
(_,_,_,_)
2459 | Ast.Stars
(_,_,_,_) -> true
2462 let starts_with_brace =
2463 match Ast.undots stmt_dots
with
2465 (match Ast.unwrap
d with
2470 statement_list unopt VeryEnd
quantified [] None None None
2473 (if starts_with_dots
2475 (* EX because there is a loop on enter/top *)
2476 ctl_and CTL.NONSTRICT
(toppred None
) (ctl_ex res)
2477 else if starts_with_brace
2479 ctl_and CTL.NONSTRICT
2480 (ctl_not(CTL.EX
(CTL.BACKWARD
,(funpred None
)))) res
2482 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords")
2484 (* --------------------------------------------------------------------- *)
2487 let asttoctlz (name
,(_,_,exists_flag
),l)
2488 (used_after,fresh_used_after
,fresh_used_after_seeds
) positions
=
2491 (match exists_flag
with
2492 Ast.Exists
-> exists := Exists
2493 | Ast.Forall
-> exists := Forall
2494 | Ast.Undetermined
->
2495 exists := if !Flag.sgrep_mode2
then Exists
else Forall
);
2497 let (l,used_after) =
2501 match Ast.unwrap t
with Ast.ERRORWORDS
(exps
) -> false | _ -> true)
2502 (List.combine
l (List.combine
used_after positions
))) in
2504 List.map2
(top_level name
)
2505 (List.combine
used_after fresh_used_after
)
2506 (List.combine fresh_used_after_seeds
l) in
2510 let asttoctl r
used_after positions
=
2512 Ast.ScriptRule
_ | Ast.InitialScriptRule
_ | Ast.FinalScriptRule
_ -> []
2513 | Ast.CocciRule
(a,b
,c,_,Ast_cocci.Normal
) ->
2514 asttoctlz (a,b
,c) used_after positions
2515 | Ast.CocciRule
(a,b
,c,_,Ast_cocci.Generated
) -> [CTL.True
]
2517 let pp_cocci_predicate (pred
,modif
) =
2518 Pretty_print_engine.pp_predicate pred
2520 let cocci_predicate_to_string (pred
,modif
) =
2521 Pretty_print_engine.predicate_to_string pred