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.
26 * Copyright 2010, INRIA, University of Copenhagen
27 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
28 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
29 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
30 * This file is part of Coccinelle.
32 * Coccinelle is free software: you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation, according to version 2 of the License.
36 * Coccinelle is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
41 * You should have received a copy of the GNU General Public License
42 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
49 (* true = don't see all matched nodes, only modified ones *)
50 let onlyModif = ref true(*false*)
51 (* set to true for line numbers in the output of ctl_engine *)
52 let line_numbers = ref false
53 (* if true, only eg if header is included in not for ...s *)
54 let simple_get_end = ref false(*true*)
56 (* Question: where do we put the existential quantifier for or. At the
57 moment, let it float inwards. *)
59 (* nest shouldn't overlap with what comes after. not checked for. *)
61 module Ast
= Ast_cocci
62 module V
= Visitor_ast
66 let warning s
= Printf.fprintf stderr
"warning: %s\n" s
68 type cocci_predicate
= Lib_engine.predicate
* string Ast_ctl.modif
70 (cocci_predicate
,string, Wrapper_ctl.info
) Ast_ctl.generic_ctl
73 let aftpred = (Lib_engine.After
,CTL.Control
)
74 let retpred = (Lib_engine.Return
,CTL.Control
)
75 let exitpred = (Lib_engine.ErrorExit
,CTL.Control
)
77 let intersect l1 l2
= List.filter
(function x
-> List.mem x l2
) l1
78 let subset l1 l2
= List.for_all
(function x
-> List.mem x l2
) l1
80 (* --------------------------------------------------------------------- *)
84 (match CTL.unwrap f
with
87 | CTL.Pred
(p
) as x
-> x
88 | CTL.Not
(phi
) -> CTL.Not
(drop_vs phi
)
89 | CTL.Exists
(v
,phi
) ->
90 (match CTL.unwrap phi
with
91 CTL.Pred
((x
,CTL.Modif v1
)) when v
= v1
-> CTL.Pred
((x
,CTL.Control
))
92 | _
-> CTL.Exists
(v
,drop_vs phi
))
93 | CTL.And
(phi1
,phi2
) -> CTL.And
(drop_vs phi1
,drop_vs phi2
)
94 | CTL.Or
(phi1
,phi2
) -> CTL.Or
(drop_vs phi1
,drop_vs phi2
)
95 | CTL.SeqOr
(phi1
,phi2
) -> CTL.SeqOr
(drop_vs phi1
,drop_vs phi2
)
96 | CTL.Implies
(phi1
,phi2
) -> CTL.Implies
(drop_vs phi1
,drop_vs phi2
)
97 | CTL.AF
(dir
,phi1
,phi2
) -> CTL.AF
(dir
,drop_vs phi1
,drop_vs phi2
)
98 | CTL.AX
(dir
,phi
) -> CTL.AX
(dir
,drop_vs phi
)
99 | CTL.AG
(dir
,phi
) -> CTL.AG
(dir
,drop_vs phi
)
100 | CTL.AU
(dir
,phi1
,phi2
,phi3
,phi4
) ->
101 CTL.AU
(dir
,drop_vs phi1
,drop_vs phi2
,drop_vs phi3
,drop_vs phi4
)
102 | CTL.EF
(dir
,phi
) -> CTL.EF
(dir
,drop_vs phi
)
103 | CTL.EX
(dir
,phi
) -> CTL.EX
(dir
,drop_vs phi
)
104 | CTL.EG
(dir
,phi
) -> CTL.EG
(dir
,drop_vs phi
)
105 | CTL.EU
(dir
,phi1
,phi2
) -> CTL.EU
(dir
,drop_vs phi1
,drop_vs phi2
)
106 | CTL.Ref
(v
) as x
-> x
107 | CTL.Let
(v
,term1
,body
) -> CTL.Let
(v
,drop_vs term1
,drop_vs body
))
109 (* --------------------------------------------------------------------- *)
111 let wrap n ctl
= (ctl
,n
)
114 wrap 0 (CTL.Or
(wrap 0 (CTL.Pred
aftpred),wrap 0 (CTL.Pred
exitpred)))
116 let wrapImplies n
(x
,y
) = wrap n
(CTL.Implies
(x
,y
))
117 let wrapExists n
(x
,y
) = wrap n
(CTL.Exists
(x
,y
))
118 let wrapAnd n
(x
,y
) = wrap n
(CTL.And
(x
,y
))
119 let wrapOr n
(x
,y
) = wrap n
(CTL.Or
(x
,y
))
120 let wrapSeqOr n
(x
,y
) = wrap n
(CTL.SeqOr
(x
,y
))
121 let wrapAU n
(x
,y
) = wrap n
(CTL.AU
(CTL.FORWARD
,x
,y
,drop_vs x
,drop_vs y
))
122 let wrapEU n
(x
,y
) = wrap n
(CTL.EU
(CTL.FORWARD
,x
,y
))
123 let wrapAX n
(x
) = wrap n
(CTL.AX
(CTL.FORWARD
,x
))
124 let wrapBackAX n
(x
) = wrap n
(CTL.AX
(CTL.BACKWARD
,x
))
125 let wrapEX n
(x
) = wrap n
(CTL.EX
(CTL.FORWARD
,x
))
126 let wrapBackEX n
(x
) = wrap n
(CTL.EX
(CTL.BACKWARD
,x
))
127 let wrapAG n
(x
) = wrap n
(CTL.AG
(CTL.FORWARD
,x
))
128 let wrapEG n
(x
) = wrap n
(CTL.EG
(CTL.FORWARD
,x
))
129 let wrapAF n
(x
) = wrap n
(CTL.AF
(CTL.FORWARD
,x
,drop_vs x
))
130 let wrapEF n
(x
) = wrap n
(CTL.EF
(CTL.FORWARD
,x
))
131 let wrapNot n
(x
) = wrap n
(CTL.Not
(x
))
132 let wrapPred n
(x
) = wrap n
(CTL.Pred
(x
))
133 let wrapLet n
(x
,y
,z
) = wrap n
(CTL.Let
(x
,y
,z
))
134 let wrapRef n
(x
) = wrap n
(CTL.Ref
(x
))
136 (* --------------------------------------------------------------------- *)
138 let get_option fn
= function
140 | Some x
-> Some
(fn x
)
142 let get_list_option fn
= function
146 (* --------------------------------------------------------------------- *)
147 (* --------------------------------------------------------------------- *)
148 (* Eliminate OptStm *)
150 (* for optional thing with nothing after, should check that the optional thing
151 never occurs. otherwise the matching stops before it occurs *)
154 let donothing r k e
= k e
in
157 List.fold_left
Common.union_set
[] (List.map
Ast.get_fvs l
) in
159 let rec dots_list unwrapped wrapped
=
160 match (unwrapped
,wrapped
) with
163 | (Ast.Dots
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
165 | (Ast.Nest
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
167 let l = Ast.get_line stm
in
168 let new_rest1 = stm
:: (dots_list (u
::urest
) (d1
::rest
)) in
169 let new_rest2 = dots_list urest rest
in
170 let fv_rest1 = fvlist new_rest1 in
171 let fv_rest2 = fvlist new_rest2 in
172 [d0
;(Ast.Disj
[(Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
);
173 (Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
)],
174 l,fv_rest1,Ast.NoDots
)]
176 | (Ast.OptStm
(stm
)::urest
,_
::rest
) ->
177 let l = Ast.get_line stm
in
178 let new_rest1 = dots_list urest rest
in
179 let new_rest2 = stm
::new_rest1 in
180 let fv_rest1 = fvlist new_rest1 in
181 let fv_rest2 = fvlist new_rest2 in
182 [(Ast.Disj
[(Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
);
183 (Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
)],
184 l,fv_rest2,Ast.NoDots
)]
186 | ([Ast.Dots
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
187 let l = Ast.get_line stm
in
188 let fv_stm = Ast.get_fvs stm
in
189 let fv_d1 = Ast.get_fvs d1
in
190 let fv_both = Common.union_set
fv_stm fv_d1 in
191 [d1
;(Ast.Disj
[(Ast.DOTS
([stm
]),l,fv_stm,Ast.NoDots
);
192 (Ast.DOTS
([d1
]),l,fv_d1,Ast.NoDots
)],
193 l,fv_both,Ast.NoDots
)]
195 | ([Ast.Nest
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
196 let l = Ast.get_line stm
in
197 let rw = Ast.rewrap stm
in
198 let rwd = Ast.rewrap stm
in
200 Ast.Dots
(("...",{ Ast.line
= 0; Ast.column
= 0 },
201 Ast.CONTEXT
(Ast.NOTHING
)),
203 [d1
;rw(Ast.Disj
[rwd(Ast.DOTS
([stm
]));
204 (Ast.DOTS
([rw dots]),l,[],Ast.NoDots
)])]
206 | (_
::urest
,stm
::rest
) -> stm
:: (dots_list urest rest
)
207 | _
-> failwith
"not possible" in
209 let stmtdotsfn r k d
=
212 (match Ast.unwrap
d with
213 Ast.DOTS
(l) -> Ast.DOTS
(dots_list (List.map
Ast.unwrap
l) l)
214 | Ast.CIRCLES
(l) -> failwith
"elimopt: not supported"
215 | Ast.STARS
(l) -> failwith
"elimopt: not supported") in
218 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
219 donothing donothing stmtdotsfn
220 donothing donothing donothing donothing donothing donothing donothing
221 donothing donothing donothing
223 (* --------------------------------------------------------------------- *)
224 (* Count depth of braces. The translation of a closed brace appears deeply
225 nested within the translation of the sequence term, so the name of the
226 paren var has to take into account the names of the nested braces. On the
227 other hand the close brace does not escape, so we don't have to take into
228 account other paren variable names. *)
230 (* called repetitively, which is inefficient, but less trouble than adding a
231 new field to Seq and FunDecl *)
232 let count_nested_braces s
=
233 let bind x y
= max x y
in
234 let option_default = 0 in
235 let stmt_count r k s
=
236 match Ast.unwrap s
with
237 Ast.Seq
(_
,_
,_
,_
,_
) | Ast.FunDecl
(_
,_
,_
,_
,_
,_
) -> (k s
) + 1
239 let donothing r k e
= k e
in
241 let recursor = V.combiner
bind option_default
242 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
243 donothing donothing donothing
244 donothing donothing donothing donothing donothing donothing
245 donothing stmt_count donothing donothing in
246 "p"^
(string_of_int
(recursor.V.combiner_statement s
))
248 (* --------------------------------------------------------------------- *)
255 Printf.sprintf
"v%d" c
258 let fresh_label_var s
=
260 labctr := !labctr + 1;
261 Printf.sprintf
"%s%d" s
c
264 let fresh_let_var _
=
267 Printf.sprintf
"l%d" c
270 let fresh_metavar _
=
272 (*sctr := !sctr + 1;*)
273 Printf.sprintf
"_S%d" c
275 let get_unquantified quantified vars
=
276 List.filter
(function x
-> not
(List.mem x quantified
)) vars
278 type after
= After
of formula
| Guard
of formula
| Tail
281 let rec loop = function
282 [] -> failwith
"not possible"
284 | x
::xs
-> wrapAnd n
(x
,wrapAX n
(loop xs
)) in
287 let make_seq_after2 n first
= function
288 After rest
-> wrapAnd n
(first
,wrapAX n
(wrapAX n rest
))
291 let make_seq_after n first
= function
292 After rest
-> make_seq n
[first
;rest
]
295 let a2n = function After f
-> Guard f
| x
-> x
297 let and_opt n first
= function
298 After rest
-> wrapAnd n
(first
,rest
)
302 let bind x y
= x
or y
in
303 let option_default = false in
304 let mcode r
(_
,_
,kind
) =
307 | Ast.PLUS
-> failwith
"not possible"
308 | Ast.CONTEXT
(info
) -> not
(info
= Ast.NOTHING
) in
309 let do_nothing r k e
= k e
in
311 V.combiner
bind option_default
312 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
313 do_nothing do_nothing do_nothing
314 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
315 do_nothing do_nothing do_nothing do_nothing in
316 recursor.V.combiner_rule_elem
318 let make_match n guard used_after code
=
320 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
322 let v = fresh_var() in
323 if contains_modif code
324 then wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.Modif
v))
327 List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs code
) in
328 if !onlyModif && not
any_used_after
329 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
330 else wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.UnModif
v))
332 let make_raw_match n code
= wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
334 let rec seq_fvs quantified
= function
337 let t1fvs = get_unquantified quantified fv1
in
339 List.fold_left
Common.union_set
[]
340 (List.map
(get_unquantified quantified
) fvs
) in
341 let bothfvs = Common.inter_set
t1fvs termfvs in
342 let t1onlyfvs = Common.minus_set
t1fvs bothfvs in
343 let new_quantified = Common.union_set
bothfvs quantified
in
344 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs
)
346 let seq_fvs2 quantified fv1 fv2
=
347 match seq_fvs quantified
[fv1
;fv2
] with
348 [(t1fvs,bfvs
);(t2fvs
,[])] -> (t1fvs,bfvs
,t2fvs
)
349 | _
-> failwith
"impossible"
351 let seq_fvs3 quantified fv1 fv2 fv3
=
352 match seq_fvs quantified
[fv1
;fv2
;fv3
] with
353 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,[])] ->
354 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
)
355 | _
-> failwith
"impossible"
357 let seq_fvs4 quantified fv1 fv2 fv3 fv4
=
358 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
] with
359 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,[])] ->
360 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
)
361 | _
-> failwith
"impossible"
363 let seq_fvs5 quantified fv1 fv2 fv3 fv4 fv5
=
364 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
;fv5
] with
365 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,b45fvs
);(t5fvs
,[])] ->
366 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
,b45fvs
,t5fvs
)
367 | _
-> failwith
"impossible"
370 List.fold_right
(function cur
-> function code
-> wrapExists n
(cur
,code
))
372 let intersectll lst nested_list
=
373 List.filter
(function x
-> List.exists
(List.mem x
) nested_list
) lst
375 (* --------------------------------------------------------------------- *)
376 (* annotate dots with before and after neighbors *)
378 let rec get_before sl a
=
379 match Ast.unwrap sl
with
385 let (e
,ea
) = get_before_e e a
in
386 let (sl
,sla
) = loop sl ea
in
388 let (l,a
) = loop x a
in
389 (Ast.rewrap sl
(Ast.DOTS
(l)),a
)
390 | Ast.CIRCLES
(x
) -> failwith
"not supported"
391 | Ast.STARS
(x
) -> failwith
"not supported"
393 and get_before_e s a
=
394 match Ast.unwrap s
with
395 Ast.Dots
(d,Ast.NoWhen
,t
) ->
396 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a
@t
)),a
)
397 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
398 let (w
,_
) = get_before w
[] in
399 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a
@t
)),a
)
400 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
401 let (w
,_
) = get_before_e w
[] in
402 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a
@t
)),a
)
403 | Ast.Nest
(stmt_dots
,w
,t
) ->
404 let (w
,_
) = List.split
(List.map
(function s
-> get_before s
[]) w
) in
405 let (sd
,_
) = get_before stmt_dots a
in
411 Unify_ast.unify_statement_dots
412 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
414 Unify_ast.MAYBE
-> false
416 | Ast.Other_dots
a ->
417 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
419 Unify_ast.MAYBE
-> false
423 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
424 | Ast.Disj
(stmt_dots_list
) ->
426 List.split
(List.map
(function e
-> get_before e
a) stmt_dots_list
) in
427 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
429 (match Ast.unwrap ast
with
430 Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
431 | _
-> (s
,[Ast.Other s
]))
432 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
433 let index = count_nested_braces s
in
434 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
435 let (bd
,_
) = get_before body dea
in
436 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
437 [Ast.WParen
(rbrace
,index)])
438 | Ast.IfThen
(ifheader
,branch
,aft
) ->
439 let (br
,_
) = get_before_e branch
[] in
440 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)), [Ast.Other s
])
441 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
442 let (br1
,_
) = get_before_e branch1
[] in
443 let (br2
,_
) = get_before_e branch2
[] in
444 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
445 | Ast.While
(header
,body
,aft
) ->
446 let (bd
,_
) = get_before_e body
[] in
447 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
448 | Ast.For
(header
,body
,aft
) ->
449 let (bd
,_
) = get_before_e body
[] in
450 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
451 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
452 let index = count_nested_braces s
in
453 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
454 let (bd
,_
) = get_before body dea
in
455 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
456 | _
-> failwith
"not supported"
458 let rec get_after sl
a =
459 match Ast.unwrap sl
with
465 let (sl
,sla
) = loop sl
in
466 let (e
,ea
) = get_after_e e sla
in
468 let (l,a) = loop x
in
469 (Ast.rewrap sl
(Ast.DOTS
(l)),a)
470 | Ast.CIRCLES
(x
) -> failwith
"not supported"
471 | Ast.STARS
(x
) -> failwith
"not supported"
473 and get_after_e s
a =
474 match Ast.unwrap s
with
475 Ast.Dots
(d,Ast.NoWhen
,t
) ->
476 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a@t
)),a)
477 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
478 let (w
,_
) = get_after w
[] in
479 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a@t
)),a)
480 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
481 let (w
,_
) = get_after_e w
[] in
482 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a@t
)),a)
483 | Ast.Nest
(stmt_dots
,w
,t
) ->
484 let (w
,_
) = List.split
(List.map
(function s
-> get_after s
[]) w
) in
485 let (sd
,_
) = get_after stmt_dots
a in
491 Unify_ast.unify_statement_dots
492 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
494 Unify_ast.MAYBE
-> false
496 | Ast.Other_dots
a ->
497 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
499 Unify_ast.MAYBE
-> false
503 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
504 | Ast.Disj
(stmt_dots_list
) ->
506 List.split
(List.map
(function e
-> get_after e
a) stmt_dots_list
) in
507 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
509 (match Ast.unwrap ast
with
510 Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots _
,i
) ->
511 (* check after information for metavar optimization *)
512 (* if the error is not desired, could just return [], then
513 the optimization (check for EF) won't take place *)
517 (match Ast.unwrap x
with
518 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
520 "dots/nest not allowed before and after stmt metavar"
522 | Ast.Other_dots x
->
523 (match Ast.undots x
with
525 (match Ast.unwrap x
with
526 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
528 ("dots/nest not allowed before and after stmt "^
537 (Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots
a,i
)))),[])
538 | Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
539 | _
-> (s
,[Ast.Other s
]))
540 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
541 let index = count_nested_braces s
in
542 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
543 let (de
,_
) = get_after decls bda
in
544 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
545 [Ast.WParen
(lbrace
,index)])
546 | Ast.IfThen
(ifheader
,branch
,aft
) ->
547 let (br
,_
) = get_after_e branch
a in
548 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)),[Ast.Other s
])
549 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
550 let (br1
,_
) = get_after_e branch1
a in
551 let (br2
,_
) = get_after_e branch2
a in
552 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
553 | Ast.While
(header
,body
,aft
) ->
554 let (bd
,_
) = get_after_e body
a in
555 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
556 | Ast.For
(header
,body
,aft
) ->
557 let (bd
,_
) = get_after_e body
a in
558 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
559 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
560 let index = count_nested_braces s
in
561 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
562 let (de
,_
) = get_after decls bda
in
563 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
564 | _
-> failwith
"not supported"
567 let preprocess_dots sl
=
568 let (sl
,_
) = get_before sl
[] in
569 let (sl
,_
) = get_after sl
[] in
572 let preprocess_dots_e sl
=
573 let (sl
,_
) = get_before_e sl
[] in
574 let (sl
,_
) = get_after_e sl
[] in
577 (* --------------------------------------------------------------------- *)
578 (* the main translation loop *)
580 let decl_to_not_decl n
dots stmt
make_match f
=
585 let md = Ast.make_meta_decl
"_d" (Ast.CONTEXT
(Ast.NOTHING
)) in
586 Ast.rewrap
md (Ast.Decl
md) in
587 wrapAU n
(make_match de,
588 wrap n
(CTL.And
(wrap n
(CTL.Not
(make_match de)), f
)))
590 let rec statement_list stmt_list used_after after quantified guard
=
591 let n = if !line_numbers then Ast.get_line stmt_list
else 0 in
592 match Ast.unwrap stmt_list
with
594 let rec loop quantified
= function
595 ([],_
) -> (match after
with After f
-> f
| _
-> wrap n CTL.True
)
596 | ([e
],_
) -> statement e used_after after quantified guard
598 let shared = intersectll fv fvs
in
599 let unqshared = get_unquantified quantified
shared in
600 let new_quantified = Common.union_set
unqshared quantified
in
602 (statement e used_after
(After
(loop new_quantified (sl
,fvs
)))
603 new_quantified guard
)
604 | _
-> failwith
"not possible" in
605 loop quantified
(x
,List.map
Ast.get_fvs x
)
606 | Ast.CIRCLES
(x
) -> failwith
"not supported"
607 | Ast.STARS
(x
) -> failwith
"not supported"
609 and statement stmt used_after after quantified guard
=
611 let n = if !line_numbers then Ast.get_line stmt
else 0 in
612 let wrapExists = wrapExists n in
613 let wrapAnd = wrapAnd n in
614 let wrapOr = wrapOr n in
615 let wrapSeqOr = wrapSeqOr n in
616 let wrapAU = wrapAU n in
617 let wrapAX = wrapAX n in
618 let wrapBackAX = wrapBackAX n in
619 let wrapEX = wrapEX n in
620 let wrapBackEX = wrapBackEX n in
621 let wrapAG = wrapAG n in
622 let wrapAF = wrapAF n in
623 let wrapEF = wrapEF n in
624 let wrapNot = wrapNot n in
625 let wrapPred = wrapPred n in
626 let make_seq = make_seq n in
627 let make_seq_after2 = make_seq_after2 n in
628 let make_seq_after = make_seq_after n in
629 let and_opt = and_opt n in
630 let quantify = quantify n in
631 let make_match = make_match n guard used_after
in
632 let make_raw_match = make_raw_match n in
634 let make_meta_rule_elem d =
635 let nm = fresh_metavar() in
636 Ast.make_meta_rule_elem nm d in
638 match Ast.unwrap stmt
with
640 (match Ast.unwrap ast
with
641 Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,_
)) as d)),seqible
,_
)
642 | Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.AFTER
(_
)) as d)),seqible
,_
) ->
643 let label_var = (*fresh_label_var*) "_lab" in
644 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
646 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
647 let matcher d = make_match (make_meta_rule_elem d) in
648 let full_metamatch = matcher d in
649 let first_metamatch =
652 Ast.CONTEXT
(Ast.BEFOREAFTER
(bef
,_
)) ->
653 Ast.CONTEXT
(Ast.BEFORE
(bef
))
654 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
655 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
656 let middle_metamatch =
659 Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
660 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
664 Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,aft
)) ->
665 Ast.CONTEXT
(Ast.AFTER
(aft
))
666 | Ast.CONTEXT
(_
) -> d
667 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
671 [full_metamatch; and_opt (wrapNot(prelabel_pred)) after
] in
675 wrapAU(middle_metamatch,
677 [wrapAnd(last_metamatch,label_pred);
678 and_opt (wrapNot(prelabel_pred)) after
])] in
681 f
(wrapAnd(make_raw_match ast
,
682 wrapOr(left_or,right_or)))) in
685 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
686 quantify (label_var::get_unquantified quantified
[s
])
689 (wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
690 | Ast.SequencibleAfterDots
l ->
692 List.map
(process_bef_aft Tail quantified used_after
n) l in
694 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
695 (List.hd
afts) (List.tl
afts) in
696 quantify (label_var::get_unquantified quantified
[s
])
697 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
700 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
701 | Ast.NotSequencible
->
702 quantify (label_var::get_unquantified quantified
[s
]) (body id))
704 | Ast.MetaStmt
((s
,i
,d),seqible
,_
) ->
705 let label_var = (*fresh_label_var*) "_lab" in
706 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
708 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
709 let matcher d = make_match (make_meta_rule_elem d) in
710 let first_metamatch = matcher d in
714 Ast.MINUS
(_
) -> Ast.MINUS
([])
715 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
716 | Ast.PLUS
-> failwith
"not possible") in
717 (* first_nodea and first_nodeb are separated here and above to
718 improve let sharing - only first_nodea is unique to this site *)
719 let first_nodeb = first_metamatch in
720 let rest_nodes = wrapAnd(rest_metamatch,prelabel_pred) in
721 let last_node = and_opt (wrapNot(prelabel_pred)) after
in
728 [first_nodeb; wrapAU(rest_nodes,last_node)])))) in
730 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
731 quantify (label_var::get_unquantified quantified
[s
])
733 (function x
-> wrapAnd(wrapNot(wrapBackAX(label_pred)),x
)))
734 | Ast.SequencibleAfterDots
l ->
736 List.map
(process_bef_aft Tail quantified used_after
n) l in
738 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
739 (List.hd
afts) (List.tl
afts) in
740 quantify (label_var::get_unquantified quantified
[s
])
741 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
744 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
745 | Ast.NotSequencible
->
746 quantify (label_var::get_unquantified quantified
[s
])
747 (body (function x
-> x
)))
749 let stmt_fvs = Ast.get_fvs stmt
in
750 let fvs = get_unquantified quantified
stmt_fvs in
751 let between_dots = Ast.get_dots_bef_aft stmt
in
752 let term = make_match ast
in
754 match between_dots with
755 Ast.BetweenDots brace_term
->
756 (match Ast.unwrap brace_term
with
757 Ast.Atomic
(brace_ast
) ->
762 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
764 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
766 make_match brace_ast
) in
772 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
774 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
778 | _
-> failwith
"not possible")
779 | Ast.NoDots
-> term in
780 make_seq_after (quantify fvs term) after
)
781 | Ast.Seq
(lbrace
,decls
,dots,body,rbrace
) ->
782 let (lbfvs
,b1fvs
,_
,b2fvs
,_
,b3fvs
,rbfvs
) =
784 (Ast.get_fvs lbrace
) (Ast.get_fvs decls
)
785 (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
786 let v = count_nested_braces stmt
in
787 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
789 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
791 wrapAnd(quantify rbfvs
(make_match rbrace
),paren_pred) in
792 let new_quantified2 =
793 Common.union_set b1fvs
(Common.union_set b2fvs quantified
) in
794 let new_quantified3 = Common.union_set b3fvs
new_quantified2 in
800 (statement_list decls used_after
802 (decl_to_not_decl n dots stmt
make_match
804 (statement_list body used_after
805 (After
(make_seq_after end_brace after
))
806 new_quantified3 guard
))))
807 new_quantified2 guard
)]))
808 | Ast.IfThen
(ifheader
,branch
,aft
) ->
810 (* "if (test) thn" becomes:
811 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
813 "if (test) thn; after" becomes:
814 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
820 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch
) in
821 let new_quantified = Common.union_set bfvs quantified
in
823 let if_header = quantify efvs
(make_match ifheader
) in
824 (* then branch and after *)
827 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
828 statement branch used_after
(a2n after
) new_quantified guard
] in
829 let fall_branch = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
830 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
831 let (aft_needed
,after_branch
) =
833 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
836 make_seq_after after_pred
838 (make_seq_after (make_match (make_meta_rule_elem aft
))
840 let or_cases = wrapOr(true_branch,wrapOr(fall_branch,after_branch
)) in
842 (match (after
,aft_needed
) with
843 (After _
,_
) (* pattern doesn't end here *)
844 | (_
,true) (* + code added after *) ->
846 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
847 | _
-> quantify bfvs
(wrapAnd(if_header, wrapAX or_cases)))
849 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
851 (* "if (test) thn else els" becomes:
852 if(test) & AX((TrueBranch & AX thn) v
853 (FalseBranch & AX (else & AX els)) v After)
856 "if (test) thn else els; after" becomes:
857 if(test) & AX((TrueBranch & AX thn) v
858 (FalseBranch & AX (else & AX els)) v
859 (After & AXAX after))
864 Note that we rely on the well-formedness of C programs. For example, we
865 do not use EX to check that there is at least one then branch, because
866 there is always one. And we do not check that there is only one then or
867 else branch, because these again are always the case in a well-formed C
870 let (e1fvs
,b1fvs
,s1fvs
) =
871 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch1
) in
872 let (e2fvs
,b2fvs
,s2fvs
) =
873 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch2
) in
876 (Common.union_set b1fvs b2fvs
)
877 (Common.inter_set s1fvs s2fvs
) in
878 let exponlyfvs = Common.inter_set e1fvs e2fvs
in
879 let new_quantified = Common.union_set
bothfvs quantified
in
881 let if_header = quantify exponlyfvs (make_match ifheader
) in
882 (* then and else branches *)
885 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
886 statement branch1 used_after
(a2n after
) new_quantified guard
] in
887 let false_pred = wrapPred(Lib_engine.FalseBranch
,CTL.Control
) in
890 [false_pred; make_match els
;
891 statement branch2 used_after
(a2n after
) new_quantified guard
] in
892 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
893 let (aft_needed
,after_branch
) =
895 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
898 make_seq_after after_pred
900 (make_seq_after (make_match (make_meta_rule_elem aft
))
902 let or_cases = wrapOr(true_branch,wrapOr(false_branch,after_branch
)) in
904 (match (after
,aft_needed
) with
905 (After _
,_
) (* pattern doesn't end here *)
906 | (_
,true) (* + code added after *) ->
910 wrapAnd(wrapAX or_cases,
911 wrapAnd(wrapEX false_pred,wrapEX after_pred))))
914 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX false_pred))))
916 | Ast.While
(header
,body,aft
) | Ast.For
(header
,body,aft
) ->
917 (* the translation in this case is similar to that of an if with no else *)
920 seq_fvs2 quantified
(Ast.get_fvs header
) (Ast.get_fvs
body) in
921 let new_quantified = Common.union_set bfvs quantified
in
923 let header = quantify efvs
(make_match header) in
926 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
927 statement
body used_after
(a2n after
) new_quantified guard
] in
928 let after_pred = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
929 let (aft_needed
,after_branch
) =
931 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
934 make_seq_after after_pred
936 (make_seq_after (make_match (make_meta_rule_elem aft
))
938 let or_cases = wrapOr(body,after_branch
) in
940 (match (after
,aft_needed
) with
941 (After _
,_
) (* pattern doesn't end here *)
942 | (_
,true) (* + code added after *) ->
944 (wrapAnd (header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
945 | _
-> quantify bfvs
(wrapAnd(header, wrapAX or_cases)))
947 | Ast.Disj
(stmt_dots_list
) ->
950 (function x
-> statement_list x used_after after quantified guard
)
952 let rec loop = function
953 [] -> wrap n CTL.True
955 | x
::xs
-> wrapSeqOr(x
,loop xs
) in
959 statement_list e used_after (a2n after) quantified true in
962 (function rest -> function cur -> wrapAnd(wrapNot(do_one cur),rest))
964 let process_one nots cur =
965 match Ast.unwrap cur with
967 let on = List.map (function x -> Ast.OrOther_dots x) nots in
968 (match Ast.unwrap x with
972 Printf.printf "a not\n";
973 Pretty_print_cocci.statement_dots x)
977 (Ast.DOTS((Ast.rewrap x (Ast.Dots(d,w,on@t)))::xs)) in
978 statement_list cur used_after after quantified guard
979 | Ast.Nest(sd,w,t) ->
982 (Ast.DOTS((Ast.rewrap x (Ast.Nest(sd,w,on@t)))::xs)) in
983 statement_list cur used_after after quantified guard
986 (statement_list cur used_after after quantified guard))
989 (statement_list cur used_after after quantified guard)
990 | _ -> failwith "CIRCLES, STARS not supported" in
991 let rec loop after = function
992 [] -> failwith "disj shouldn't be empty" (*wrap n CTL.False*)
993 | [(nots
,cur)] -> process_one nots
cur
994 | (nots
,cur)::rest
-> wrapOr(process_one nots
cur, loop after rest
) in
995 loop after
(preprocess_disj stmt_dots_list
)
997 | Ast.Nest
(stmt_dots
,whencode
,befaft
) ->
999 statement_list stmt_dots used_after
(a2n after
) quantified guard
in
1004 statement_list sl used_after
(a2n after
) quantified
true)
1006 List.fold_left
(function rest
-> function cur -> wrapOr(cur,rest
))
1007 (statement_list stmt_dots used_after
(a2n after
) quantified
true)
1009 (match (after
,guard
&&(whencode
=[])) with
1012 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1014 [] -> wrapAF(wrapOr(a,aftret))
1019 (function rest
-> function cur -> wrapOr(cur,rest
))
1021 wrapAU(left,wrapOr(a,aftret)))
1022 | (After
a,false) ->
1023 let left = wrapOr(dots_pattern,wrapNot udots_pattern) in
1025 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1033 (function rest
-> function cur -> wrapOr(cur,rest
))
1036 wrapAU(left,wrapOr(a,aftret))
1037 | (_
,true) -> wrap n CTL.True
1038 | (_
,false) -> wrapAG(wrapOr(dots_pattern,wrapNot udots_pattern)))
1039 | Ast.Dots
((_
,i
,d),whencodes,t
) ->
1043 (* no need for the fresh metavar, but ... is a bit weird as a
1045 Some
(make_match (make_meta_rule_elem d))
1048 (match whencodes with
1050 | Ast.WhenNot
whencodes ->
1052 (statement_list whencodes used_after
(a2n after
) quantified
1054 | Ast.WhenAlways s
->
1055 [statement s used_after
(a2n after
) quantified
true]) @
1057 (List.map
(process_bef_aft after quantified used_after
n) t
)) in
1059 match whencodes with
1064 (function rest
-> function cur -> wrapAnd(cur,rest
))
1067 match (dot_code,phi2) with (* add - on dots, if any *)
1069 | (Some dotcode
,None
) -> Some dotcode
1070 | (None
,Some whencode
) -> Some whencode
1071 | (Some dotcode
,Some whencode
) -> Some
(wrapAnd (dotcode
,whencode
)) in
1072 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1073 (* add in the after code to make the result *)
1074 (match (after
,phi3) with
1075 (Tail
,Some whencode
) -> wrapAU(whencode
,wrapOr(exit,aftret))
1076 | (Tail
,None
) -> wrapAF(wrapOr(exit,aftret))
1077 | (After f
,Some whencode
) | (Guard f
,Some whencode
) ->
1078 wrapAU(whencode
,wrapOr(f
,aftret))
1079 | (After f
,None
) | (Guard f
,None
) -> wrapAF(wrapOr(f
,aftret)))
1080 | Ast.FunDecl
(header,lbrace
,decls
,dots,body,rbrace
) ->
1081 let (hfvs
,b1fvs
,lbfvs
,b2fvs
,_
,b3fvs
,_
,b4fvs
,rbfvs
) =
1082 seq_fvs5 quantified
(Ast.get_fvs
header) (Ast.get_fvs lbrace
)
1083 (Ast.get_fvs decls
) (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
1084 let function_header = quantify hfvs
(make_match header) in
1085 let v = count_nested_braces stmt
in
1086 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
1088 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
1090 let stripped_rbrace =
1091 match Ast.unwrap rbrace
with
1092 Ast.SeqEnd
((data
,info
,_
)) ->
1094 (Ast.SeqEnd
((data
,info
,Ast.CONTEXT
(Ast.NOTHING
))))
1095 | _
-> failwith
"unexpected close brace" in
1096 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1097 let errorexit = wrap n (CTL.Pred
(Lib_engine.ErrorExit
,CTL.Control
)) in
1098 wrapAnd(quantify rbfvs
(make_match rbrace
),
1099 wrapAU(make_match stripped_rbrace,
1100 wrapOr(exit,errorexit))) in
1101 let new_quantified3 =
1102 Common.union_set b1fvs
1103 (Common.union_set b2fvs
(Common.union_set b3fvs quantified
)) in
1104 let new_quantified4 = Common.union_set b4fvs
new_quantified3 in
1114 (statement_list decls used_after
1116 (decl_to_not_decl n dots stmt
1119 (statement_list body used_after
1121 (make_seq_after end_brace after
))
1122 new_quantified4 guard
))))
1123 new_quantified3 guard
)])))])
1124 | Ast.OptStm
(stm
) ->
1125 failwith
"OptStm should have been compiled away\n";
1126 | Ast.UniqueStm
(stm
) ->
1127 failwith
"arities not yet supported"
1128 | Ast.MultiStm
(stm
) ->
1129 failwith
"arities not yet supported"
1130 | _
-> failwith
"not supported"
1132 and process_bef_aft after quantified used_after ln
= function
1133 Ast.WParen
(re
,n) ->
1134 let paren_pred = wrapPred ln
(Lib_engine.Paren
n,CTL.Control
) in
1135 wrapAnd ln
(make_raw_match ln re
,paren_pred)
1136 | Ast.Other s
-> statement s used_after
(a2n after
) quantified
true
1137 | Ast.Other_dots
d -> statement_list d used_after
(a2n after
) quantified
true
1138 | Ast.OrOther_dots
d -> statement_list d used_after Tail quantified
true
1140 (* Returns a triple for each disj element. The first element of the triple is
1141 Some v if the triple element needs a name, and None otherwise. The second
1142 element is a list of names whose negations should be conjuncted with the
1143 term. The third element is the original term *)
1144 and (preprocess_disj
:
1145 Ast.statement
Ast.dots list
->
1146 (Ast.statement
Ast.dots list
* Ast.statement
Ast.dots) list
) =
1152 List.map
(function r
-> Unify_ast.unify_statement_dots
cur r
) rest
in
1153 let processed = preprocess_disj rest
in
1154 if List.exists
(function Unify_ast.MAYBE
-> true | _
-> false) template
1158 (function ((nots,r
) as x
) ->
1159 function Unify_ast.MAYBE
-> (cur::nots,r
) | Unify_ast.NO
-> x
)
1161 else ([], cur) :: processed
1163 (* --------------------------------------------------------------------- *)
1165 Phase 1: Use a hash table to identify formulas that appear more than once.
1166 Phase 2: Replace terms by variables.
1167 Phase 3: Drop lets to the point as close as possible to the uses of their
1171 (Hashtbl.create
(50) :
1172 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1173 int ref (* count *) * string ref (* name *) * bool ref (* processed *))
1178 try Hashtbl.find
formula_table phi
1180 let c = (ref 0,ref "",ref false) in
1181 Hashtbl.add
formula_table phi
c;
1185 let rec collect_duplicates f
=
1187 match CTL.unwrap f
with
1191 | CTL.Not
(phi
) -> collect_duplicates phi
1192 | CTL.Exists
(v,phi
) -> collect_duplicates phi
1193 | CTL.And
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1194 | CTL.Or
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1195 | CTL.SeqOr
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1196 | CTL.Implies
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1197 | CTL.AF
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1198 | CTL.AX
(_
,phi
) -> collect_duplicates phi
1199 | CTL.AG
(_
,phi
) -> collect_duplicates phi
1200 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1201 collect_duplicates phi1
; collect_duplicates phi2;
1202 collect_duplicates phi3; collect_duplicates phi4
1203 | CTL.EF
(_
,phi
) -> collect_duplicates phi
1204 | CTL.EX
(_
,phi
) -> collect_duplicates phi
1205 | CTL.EG
(_
,phi
) -> collect_duplicates phi
1206 | CTL.EU
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1207 | CTL.Uncheck
(phi
) -> collect_duplicates phi
1208 | _
-> failwith
"not possible"
1210 let assign_variables _
=
1212 (function formula
->
1213 function (cell
,str
,_
) -> if !cell
> 1 then str
:= fresh_let_var())
1216 let rec replace_formulas dec f
=
1217 let (ct
,name
,treated
) = Hashtbl.find
formula_table f
in
1218 let real_ct = !ct
- dec
in
1225 let (acc
,new_f
) = replace_subformulas
(dec
+ (real_ct - 1)) f
in
1226 ((!name
,new_f
) :: acc
, CTL.rewrap f
(CTL.Ref
!name
))
1228 else ([],CTL.rewrap f
(CTL.Ref
!name
))
1229 else replace_subformulas dec f
1231 and replace_subformulas dec f
=
1232 match CTL.unwrap f
with
1234 | CTL.True
-> ([],f
)
1235 | CTL.Pred
(p
) -> ([],f
)
1237 let (acc
,new_phi
) = replace_formulas dec phi
in
1238 (acc
,CTL.rewrap f
(CTL.Not
(new_phi
)))
1239 | CTL.Exists
(v,phi
) ->
1240 let (acc
,new_phi
) = replace_formulas dec phi
in
1241 (acc
,CTL.rewrap f
(CTL.Exists
(v,new_phi
)))
1242 | CTL.And
(phi1
,phi2) ->
1243 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1244 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1245 (acc1
@acc2
,CTL.rewrap f
(CTL.And
(new_phi1
,new_phi2
)))
1246 | CTL.Or
(phi1
,phi2) ->
1247 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1248 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1249 (acc1
@acc2
,CTL.rewrap f
(CTL.Or
(new_phi1
,new_phi2
)))
1250 | CTL.SeqOr
(phi1
,phi2) ->
1251 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1252 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1253 (acc1
@acc2
,CTL.rewrap f
(CTL.SeqOr
(new_phi1
,new_phi2
)))
1254 | CTL.Implies
(phi1
,phi2) ->
1255 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1256 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1257 (acc1
@acc2
,CTL.rewrap f
(CTL.Implies
(new_phi1
,new_phi2
)))
1258 | CTL.AF
(dir
,phi1
,phi2) ->
1259 let (acc
,new_phi1
) = replace_formulas dec phi1
in
1260 let (acc
,new_phi2
) = replace_formulas dec
phi2 in
1261 (acc
,CTL.rewrap f
(CTL.AF
(dir
,new_phi1
,new_phi2
)))
1262 | CTL.AX
(dir
,phi
) ->
1263 let (acc
,new_phi
) = replace_formulas dec phi
in
1264 (acc
,CTL.rewrap f
(CTL.AX
(dir
,new_phi
)))
1265 | CTL.AG
(dir
,phi
) ->
1266 let (acc
,new_phi
) = replace_formulas dec phi
in
1267 (acc
,CTL.rewrap f
(CTL.AG
(dir
,new_phi
)))
1268 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1269 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1270 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1271 let (acc3
,new_phi3
) = replace_formulas dec
phi3 in
1272 let (acc4
,new_phi4
) = replace_formulas dec phi4
in
1273 (acc1
@acc2
@acc3
@acc4
,
1274 CTL.rewrap f
(CTL.AU
(dir
,new_phi1
,new_phi2
,new_phi3
,new_phi4
)))
1275 | CTL.EF
(dir
,phi
) ->
1276 let (acc
,new_phi
) = replace_formulas dec phi
in
1277 (acc
,CTL.rewrap f
(CTL.EF
(dir
,new_phi
)))
1278 | CTL.EX
(dir
,phi
) ->
1279 let (acc
,new_phi
) = replace_formulas dec phi
in
1280 (acc
,CTL.rewrap f
(CTL.EX
(dir
,new_phi
)))
1281 | CTL.EG
(dir
,phi
) ->
1282 let (acc
,new_phi
) = replace_formulas dec phi
in
1283 (acc
,CTL.rewrap f
(CTL.EG
(dir
,new_phi
)))
1284 | CTL.EU
(dir
,phi1
,phi2) ->
1285 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1286 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1287 (acc1
@acc2
,CTL.rewrap f
(CTL.EU
(dir
,new_phi1
,new_phi2
)))
1288 | _
-> failwith
"not possible"
1291 (Hashtbl.create
(50) :
1292 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1293 string list
(* fvs *) *
1294 string list
(* intersection of fvs of subterms *))
1298 try let (fvs,_
) = Hashtbl.find
ctlfv_table f
in fvs
1300 let ((fvs,_
) as res
) =
1301 match CTL.unwrap f
with
1302 CTL.False
| CTL.True
| CTL.Pred
(_
) -> ([],[])
1303 | CTL.Not
(phi
) | CTL.Exists
(_
,phi
)
1304 | CTL.AX
(_
,phi
) | CTL.AG
(_
,phi
)
1305 | CTL.EF
(_
,phi
) | CTL.EX
(_
,phi
) | CTL.EG
(_
,phi
) -> (ctl_fvs phi
,[])
1306 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1307 let phi1fvs = ctl_fvs phi1
in
1308 let phi2fvs = ctl_fvs phi2 in
1309 (* phi3 has the same fvs as phi1 and phi4 as phi2 *)
1310 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1311 | CTL.And
(phi1
,phi2) | CTL.Or
(phi1
,phi2) | CTL.SeqOr
(phi1
,phi2)
1312 | CTL.Implies
(phi1
,phi2) | CTL.AF
(_
,phi1
,phi2) | CTL.EU
(_
,phi1
,phi2) ->
1313 let phi1fvs = ctl_fvs phi1
in
1314 let phi2fvs = ctl_fvs phi2 in
1315 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1316 | CTL.Ref
(v) -> ([v],[v])
1317 | CTL.Let
(v,term,body) ->
1318 let phi1fvs = ctl_fvs term in
1319 let phi2fvs = Common.minus_set
(ctl_fvs body) [v] in
1320 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs) in
1321 Hashtbl.add
ctlfv_table f res
;
1324 let rev_order_bindings b
=
1327 (function (nm,term) ->
1328 let (fvs,_
) = Hashtbl.find
ctlfv_table term in (nm,fvs,term))
1330 let rec loop bound
= function
1333 let (now_bound
,still_unbound
) =
1334 List.partition
(function (_
,fvs,_
) -> subset fvs bound
)
1336 let get_names = List.map
(function (x
,_
,_
) -> x
) in
1337 now_bound
@ (loop ((get_names now_bound
) @ bound
) still_unbound
) in
1340 let drop_bindings b f
= (* innermost bindings first in b *)
1341 let process_binary f ffvs inter
nm term fail
=
1342 if List.mem
nm inter
1343 then CTL.rewrap f
(CTL.Let
(nm,term,f
))
1344 else CTL.rewrap f
(fail
()) in
1346 let _ = ctl_fvs f
in Hashtbl.find
ctlfv_table f
in
1347 let rec drop_one nm term f
=
1348 match CTL.unwrap f
with
1352 | CTL.Not
(phi
) -> CTL.rewrap f
(CTL.Not
(drop_one nm term phi
))
1353 | CTL.Exists
(v,phi
) -> CTL.rewrap f
(CTL.Exists
(v,drop_one nm term phi
))
1354 | CTL.And
(phi1
,phi2) ->
1355 let (ffvs
,inter
) = find_fvs f
in
1356 process_binary f ffvs inter
nm term
1357 (function _ -> CTL.And
(drop_one nm term phi1
,drop_one nm term phi2))
1358 | CTL.Or
(phi1
,phi2) ->
1359 let (ffvs
,inter
) = find_fvs f
in
1360 process_binary f ffvs inter
nm term
1361 (function _ -> CTL.Or
(drop_one nm term phi1
,drop_one nm term phi2))
1362 | CTL.SeqOr
(phi1
,phi2) ->
1363 let (ffvs
,inter
) = find_fvs f
in
1364 process_binary f ffvs inter
nm term
1366 CTL.SeqOr
(drop_one nm term phi1
,drop_one nm term phi2))
1367 | CTL.Implies
(phi1
,phi2) ->
1368 let (ffvs
,inter
) = find_fvs f
in
1369 process_binary f ffvs inter
nm term
1371 CTL.Implies
(drop_one nm term phi1
,drop_one nm term phi2))
1372 | CTL.AF
(dir
,phi1
,phi2) ->
1373 let (ffvs
,inter
) = find_fvs f
in
1374 process_binary f ffvs inter
nm term
1376 CTL.AF
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1377 | CTL.AX
(dir
,phi
) ->
1378 CTL.rewrap f
(CTL.AX
(dir
,drop_one nm term phi
))
1379 | CTL.AG
(dir
,phi
) -> CTL.rewrap f
(CTL.AG
(dir
,drop_one nm term phi
))
1380 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1381 let (ffvs
,inter
) = find_fvs f
in
1382 process_binary f ffvs inter
nm term
1384 CTL.AU
(dir
,drop_one nm term phi1
,drop_one nm term phi2,
1385 drop_one nm term phi3,drop_one nm term phi4
))
1386 | CTL.EF
(dir
,phi
) -> CTL.rewrap f
(CTL.EF
(dir
,drop_one nm term phi
))
1387 | CTL.EX
(dir
,phi
) ->
1388 CTL.rewrap f
(CTL.EX
(dir
,drop_one nm term phi
))
1389 | CTL.EG
(dir
,phi
) -> CTL.rewrap f
(CTL.EG
(dir
,drop_one nm term phi
))
1390 | CTL.EU
(dir
,phi1
,phi2) ->
1391 let (ffvs
,inter
) = find_fvs f
in
1392 process_binary f ffvs inter
nm term
1394 CTL.EU
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1395 | (CTL.Ref
(v) as x
) -> process_binary f
[v] [v] nm term (function _ -> x
)
1396 | CTL.Let
(v,term1
,body) ->
1397 let (ffvs
,inter
) = find_fvs f
in
1398 process_binary f ffvs inter
nm term
1400 CTL.Let
(v,drop_one nm term term1
,drop_one nm term body)) in
1402 (function processed -> function (nm,_,term) -> drop_one nm term processed)
1406 failwith
"this code should not be used!!!"(*;
1407 Hashtbl.clear formula_table;
1408 Hashtbl.clear ctlfv_table;
1409 (* create a count of the number of occurrences of each subformula *)
1410 collect_duplicates f
;
1411 (* give names to things that appear more than once *)
1413 (* replace duplicated formulas by their variables *)
1414 let (bindings
,new_f
) = replace_formulas 0 f
in
1415 (* collect fvs of terms in bindings and new_f *)
1416 List.iter
(function f
-> let _ = ctl_fvs f
in ())
1417 (new_f
::(List.map
(function (_,term) -> term) bindings
));
1418 (* sort bindings with uses before defs *)
1419 let bindings = rev_order_bindings bindings in
1420 (* insert bindings as lets into the formula *)
1421 let res = drop_bindings bindings new_f
in
1424 (* --------------------------------------------------------------------- *)
1425 (* Function declaration *)
1427 let top_level used_after t
=
1428 match Ast.unwrap t
with
1429 Ast.DECL
(decl
) -> failwith
"not supported decl"
1430 | Ast.INCLUDE
(inc
,s
) ->
1431 (* no indication of whether inc or s is modified *)
1432 wrap 0 (CTL.Pred
((Lib_engine.Include
(inc
,s
),CTL.Control
)))
1433 | Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
1434 | Ast.FUNCTION
(stmt
) ->
1435 (*Printf.printf "orig\n";
1436 Pretty_print_cocci.statement "" stmt;
1437 Format.print_newline();*)
1438 let unopt = elim_opt.V.rebuilder_statement stmt
in
1439 (*Printf.printf "unopt\n";
1440 Pretty_print_cocci.statement "" unopt;
1441 Format.print_newline();*)
1442 let unopt = preprocess_dots_e unopt in
1444 (statement
unopt used_after Tail
[] false)
1445 | Ast.CODE
(stmt_dots
) ->
1446 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots
in
1447 let unopt = preprocess_dots unopt in
1449 (statement_list unopt used_after Tail
[] false)
1450 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords"
1452 (* --------------------------------------------------------------------- *)
1456 let bind x y
= x
or y
in
1457 let option_default = false in
1458 let mcode r x
= false in
1459 let statement r k s
=
1460 match Ast.unwrap s
with Ast.Dots
(_,_,_) -> true | _ -> k s
in
1461 let continue r k e
= k e
in
1462 let stop r k e
= false in
1464 V.combiner
bind option_default
1465 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1466 continue continue continue
1467 stop stop stop stop stop stop stop statement continue continue in
1468 res.V.combiner_top_level
1470 (* --------------------------------------------------------------------- *)
1473 let asttoctl l used_after
=
1480 match Ast.unwrap t
with Ast.ERRORWORDS
(exps
) -> false | _ -> true)
1482 List.map2
top_level used_after
l
1484 let pp_cocci_predicate (pred
,modif
) =
1485 Pretty_print_engine.pp_predicate pred
1487 let cocci_predicate_to_string (pred
,modif
) =
1488 Pretty_print_engine.predicate_to_string pred