2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
5 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
6 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
7 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
8 * This file is part of Coccinelle.
10 * Coccinelle is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, according to version 2 of the License.
14 * Coccinelle is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
29 * Copyright 2012, INRIA
30 * Julia Lawall, Gilles Muller
31 * Copyright 2010-2011, INRIA, University of Copenhagen
32 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
33 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
34 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
35 * This file is part of Coccinelle.
37 * Coccinelle is free software: you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation, according to version 2 of the License.
41 * Coccinelle is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
49 * The authors reserve the right to distribute this or future versions of
50 * Coccinelle under other licenses.
55 (* true = don't see all matched nodes, only modified ones *)
56 let onlyModif = ref true(*false*)
57 (* set to true for line numbers in the output of ctl_engine *)
58 let line_numbers = ref false
59 (* if true, only eg if header is included in not for ...s *)
60 let simple_get_end = ref false(*true*)
62 (* Question: where do we put the existential quantifier for or. At the
63 moment, let it float inwards. *)
65 (* nest shouldn't overlap with what comes after. not checked for. *)
67 module Ast
= Ast_cocci
68 module V
= Visitor_ast
72 let warning s
= Printf.fprintf stderr
"warning: %s\n" s
74 type cocci_predicate
= Lib_engine.predicate
* string Ast_ctl.modif
76 (cocci_predicate
,string, Wrapper_ctl.info
) Ast_ctl.generic_ctl
79 let aftpred = (Lib_engine.After
,CTL.Control
)
80 let retpred = (Lib_engine.Return
,CTL.Control
)
81 let exitpred = (Lib_engine.ErrorExit
,CTL.Control
)
83 let intersect l1 l2
= List.filter
(function x
-> List.mem x l2
) l1
84 let subset l1 l2
= List.for_all
(function x
-> List.mem x l2
) l1
86 (* --------------------------------------------------------------------- *)
90 (match CTL.unwrap f
with
93 | CTL.Pred
(p
) as x
-> x
94 | CTL.Not
(phi
) -> CTL.Not
(drop_vs phi
)
95 | CTL.Exists
(v
,phi
) ->
96 (match CTL.unwrap phi
with
97 CTL.Pred
((x
,CTL.Modif v1
)) when v
= v1
-> CTL.Pred
((x
,CTL.Control
))
98 | _
-> CTL.Exists
(v
,drop_vs phi
))
99 | CTL.And
(phi1
,phi2
) -> CTL.And
(drop_vs phi1
,drop_vs phi2
)
100 | CTL.Or
(phi1
,phi2
) -> CTL.Or
(drop_vs phi1
,drop_vs phi2
)
101 | CTL.SeqOr
(phi1
,phi2
) -> CTL.SeqOr
(drop_vs phi1
,drop_vs phi2
)
102 | CTL.Implies
(phi1
,phi2
) -> CTL.Implies
(drop_vs phi1
,drop_vs phi2
)
103 | CTL.AF
(dir
,phi1
,phi2
) -> CTL.AF
(dir
,drop_vs phi1
,drop_vs phi2
)
104 | CTL.AX
(dir
,phi
) -> CTL.AX
(dir
,drop_vs phi
)
105 | CTL.AG
(dir
,phi
) -> CTL.AG
(dir
,drop_vs phi
)
106 | CTL.AU
(dir
,phi1
,phi2
,phi3
,phi4
) ->
107 CTL.AU
(dir
,drop_vs phi1
,drop_vs phi2
,drop_vs phi3
,drop_vs phi4
)
108 | CTL.EF
(dir
,phi
) -> CTL.EF
(dir
,drop_vs phi
)
109 | CTL.EX
(dir
,phi
) -> CTL.EX
(dir
,drop_vs phi
)
110 | CTL.EG
(dir
,phi
) -> CTL.EG
(dir
,drop_vs phi
)
111 | CTL.EU
(dir
,phi1
,phi2
) -> CTL.EU
(dir
,drop_vs phi1
,drop_vs phi2
)
112 | CTL.Ref
(v
) as x
-> x
113 | CTL.Let
(v
,term1
,body
) -> CTL.Let
(v
,drop_vs term1
,drop_vs body
))
115 (* --------------------------------------------------------------------- *)
117 let wrap n ctl
= (ctl
,n
)
120 wrap 0 (CTL.Or
(wrap 0 (CTL.Pred
aftpred),wrap 0 (CTL.Pred
exitpred)))
122 let wrapImplies n
(x
,y
) = wrap n
(CTL.Implies
(x
,y
))
123 let wrapExists n
(x
,y
) = wrap n
(CTL.Exists
(x
,y
))
124 let wrapAnd n
(x
,y
) = wrap n
(CTL.And
(x
,y
))
125 let wrapOr n
(x
,y
) = wrap n
(CTL.Or
(x
,y
))
126 let wrapSeqOr n
(x
,y
) = wrap n
(CTL.SeqOr
(x
,y
))
127 let wrapAU n
(x
,y
) = wrap n
(CTL.AU
(CTL.FORWARD
,x
,y
,drop_vs x
,drop_vs y
))
128 let wrapEU n
(x
,y
) = wrap n
(CTL.EU
(CTL.FORWARD
,x
,y
))
129 let wrapAX n
(x
) = wrap n
(CTL.AX
(CTL.FORWARD
,x
))
130 let wrapBackAX n
(x
) = wrap n
(CTL.AX
(CTL.BACKWARD
,x
))
131 let wrapEX n
(x
) = wrap n
(CTL.EX
(CTL.FORWARD
,x
))
132 let wrapBackEX n
(x
) = wrap n
(CTL.EX
(CTL.BACKWARD
,x
))
133 let wrapAG n
(x
) = wrap n
(CTL.AG
(CTL.FORWARD
,x
))
134 let wrapEG n
(x
) = wrap n
(CTL.EG
(CTL.FORWARD
,x
))
135 let wrapAF n
(x
) = wrap n
(CTL.AF
(CTL.FORWARD
,x
,drop_vs x
))
136 let wrapEF n
(x
) = wrap n
(CTL.EF
(CTL.FORWARD
,x
))
137 let wrapNot n
(x
) = wrap n
(CTL.Not
(x
))
138 let wrapPred n
(x
) = wrap n
(CTL.Pred
(x
))
139 let wrapLet n
(x
,y
,z
) = wrap n
(CTL.Let
(x
,y
,z
))
140 let wrapRef n
(x
) = wrap n
(CTL.Ref
(x
))
142 (* --------------------------------------------------------------------- *)
144 let get_option fn
= function
146 | Some x
-> Some
(fn x
)
148 let get_list_option fn
= function
152 (* --------------------------------------------------------------------- *)
153 (* --------------------------------------------------------------------- *)
154 (* Eliminate OptStm *)
156 (* for optional thing with nothing after, should check that the optional thing
157 never occurs. otherwise the matching stops before it occurs *)
160 let donothing r k e
= k e
in
163 List.fold_left
Common.union_set
[] (List.map
Ast.get_fvs l
) in
165 let rec dots_list unwrapped wrapped
=
166 match (unwrapped
,wrapped
) with
169 | (Ast.Dots
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
171 | (Ast.Nest
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
173 let l = Ast.get_line stm
in
174 let new_rest1 = stm
:: (dots_list (u
::urest
) (d1
::rest
)) in
175 let new_rest2 = dots_list urest rest
in
176 let fv_rest1 = fvlist new_rest1 in
177 let fv_rest2 = fvlist new_rest2 in
178 [d0
;(Ast.Disj
[(Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
);
179 (Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
)],
180 l,fv_rest1,Ast.NoDots
)]
182 | (Ast.OptStm
(stm
)::urest
,_
::rest
) ->
183 let l = Ast.get_line stm
in
184 let new_rest1 = dots_list urest rest
in
185 let new_rest2 = stm
::new_rest1 in
186 let fv_rest1 = fvlist new_rest1 in
187 let fv_rest2 = fvlist new_rest2 in
188 [(Ast.Disj
[(Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
);
189 (Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
)],
190 l,fv_rest2,Ast.NoDots
)]
192 | ([Ast.Dots
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
193 let l = Ast.get_line stm
in
194 let fv_stm = Ast.get_fvs stm
in
195 let fv_d1 = Ast.get_fvs d1
in
196 let fv_both = Common.union_set
fv_stm fv_d1 in
197 [d1
;(Ast.Disj
[(Ast.DOTS
([stm
]),l,fv_stm,Ast.NoDots
);
198 (Ast.DOTS
([d1
]),l,fv_d1,Ast.NoDots
)],
199 l,fv_both,Ast.NoDots
)]
201 | ([Ast.Nest
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
202 let l = Ast.get_line stm
in
203 let rw = Ast.rewrap stm
in
204 let rwd = Ast.rewrap stm
in
206 Ast.Dots
(("...",{ Ast.line
= 0; Ast.column
= 0 },
207 Ast.CONTEXT
(Ast.NOTHING
)),
209 [d1
;rw(Ast.Disj
[rwd(Ast.DOTS
([stm
]));
210 (Ast.DOTS
([rw dots]),l,[],Ast.NoDots
)])]
212 | (_
::urest
,stm
::rest
) -> stm
:: (dots_list urest rest
)
213 | _
-> failwith
"not possible" in
215 let stmtdotsfn r k d
=
218 (match Ast.unwrap
d with
219 Ast.DOTS
(l) -> Ast.DOTS
(dots_list (List.map
Ast.unwrap
l) l)
220 | Ast.CIRCLES
(l) -> failwith
"elimopt: not supported"
221 | Ast.STARS
(l) -> failwith
"elimopt: not supported") in
224 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
225 donothing donothing stmtdotsfn
226 donothing donothing donothing donothing donothing donothing donothing
227 donothing donothing donothing
229 (* --------------------------------------------------------------------- *)
230 (* Count depth of braces. The translation of a closed brace appears deeply
231 nested within the translation of the sequence term, so the name of the
232 paren var has to take into account the names of the nested braces. On the
233 other hand the close brace does not escape, so we don't have to take into
234 account other paren variable names. *)
236 (* called repetitively, which is inefficient, but less trouble than adding a
237 new field to Seq and FunDecl *)
238 let count_nested_braces s
=
239 let bind x y
= max x y
in
240 let option_default = 0 in
241 let stmt_count r k s
=
242 match Ast.unwrap s
with
243 Ast.Seq
(_
,_
,_
,_
,_
) | Ast.FunDecl
(_
,_
,_
,_
,_
,_
) -> (k s
) + 1
245 let donothing r k e
= k e
in
247 let recursor = V.combiner
bind option_default
248 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
249 donothing donothing donothing
250 donothing donothing donothing donothing donothing donothing
251 donothing stmt_count donothing donothing in
252 "p"^
(string_of_int
(recursor.V.combiner_statement s
))
254 (* --------------------------------------------------------------------- *)
261 Printf.sprintf
"v%d" c
264 let fresh_label_var s
=
266 labctr := !labctr + 1;
267 Printf.sprintf
"%s%d" s
c
270 let fresh_let_var _
=
273 Printf.sprintf
"l%d" c
276 let fresh_metavar _
=
278 (*sctr := !sctr + 1;*)
279 Printf.sprintf
"_S%d" c
281 let get_unquantified quantified vars
=
282 List.filter
(function x
-> not
(List.mem x quantified
)) vars
284 type after
= After
of formula
| Guard
of formula
| Tail
287 let rec loop = function
288 [] -> failwith
"not possible"
290 | x
::xs
-> wrapAnd n
(x
,wrapAX n
(loop xs
)) in
293 let make_seq_after2 n first
= function
294 After rest
-> wrapAnd n
(first
,wrapAX n
(wrapAX n rest
))
297 let make_seq_after n first
= function
298 After rest
-> make_seq n
[first
;rest
]
301 let a2n = function After f
-> Guard f
| x
-> x
303 let and_opt n first
= function
304 After rest
-> wrapAnd n
(first
,rest
)
308 let bind x y
= x
or y
in
309 let option_default = false in
310 let mcode r
(_
,_
,kind
) =
313 | Ast.PLUS
-> failwith
"not possible"
314 | Ast.CONTEXT
(info
) -> not
(info
= Ast.NOTHING
) in
315 let do_nothing r k e
= k e
in
317 V.combiner
bind option_default
318 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
319 do_nothing do_nothing do_nothing
320 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
321 do_nothing do_nothing do_nothing do_nothing in
322 recursor.V.combiner_rule_elem
324 let make_match n guard used_after code
=
326 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
328 let v = fresh_var() in
329 if contains_modif code
330 then wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.Modif
v))
333 List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs code
) in
334 if !onlyModif && not
any_used_after
335 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
336 else wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.UnModif
v))
338 let make_raw_match n code
= wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
340 let rec seq_fvs quantified
= function
343 let t1fvs = get_unquantified quantified fv1
in
345 List.fold_left
Common.union_set
[]
346 (List.map
(get_unquantified quantified
) fvs
) in
347 let bothfvs = Common.inter_set
t1fvs termfvs in
348 let t1onlyfvs = Common.minus_set
t1fvs bothfvs in
349 let new_quantified = Common.union_set
bothfvs quantified
in
350 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs
)
352 let seq_fvs2 quantified fv1 fv2
=
353 match seq_fvs quantified
[fv1
;fv2
] with
354 [(t1fvs,bfvs
);(t2fvs
,[])] -> (t1fvs,bfvs
,t2fvs
)
355 | _
-> failwith
"impossible"
357 let seq_fvs3 quantified fv1 fv2 fv3
=
358 match seq_fvs quantified
[fv1
;fv2
;fv3
] with
359 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,[])] ->
360 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
)
361 | _
-> failwith
"impossible"
363 let seq_fvs4 quantified fv1 fv2 fv3 fv4
=
364 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
] with
365 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,[])] ->
366 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
)
367 | _
-> failwith
"impossible"
369 let seq_fvs5 quantified fv1 fv2 fv3 fv4 fv5
=
370 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
;fv5
] with
371 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,b45fvs
);(t5fvs
,[])] ->
372 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
,b45fvs
,t5fvs
)
373 | _
-> failwith
"impossible"
376 List.fold_right
(function cur
-> function code
-> wrapExists n
(cur
,code
))
378 let intersectll lst nested_list
=
379 List.filter
(function x
-> List.exists
(List.mem x
) nested_list
) lst
381 (* --------------------------------------------------------------------- *)
382 (* annotate dots with before and after neighbors *)
384 let rec get_before sl a
=
385 match Ast.unwrap sl
with
391 let (e
,ea
) = get_before_e e a
in
392 let (sl
,sla
) = loop sl ea
in
394 let (l,a
) = loop x a
in
395 (Ast.rewrap sl
(Ast.DOTS
(l)),a
)
396 | Ast.CIRCLES
(x
) -> failwith
"not supported"
397 | Ast.STARS
(x
) -> failwith
"not supported"
399 and get_before_e s a
=
400 match Ast.unwrap s
with
401 Ast.Dots
(d,Ast.NoWhen
,t
) ->
402 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a
@t
)),a
)
403 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
404 let (w
,_
) = get_before w
[] in
405 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a
@t
)),a
)
406 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
407 let (w
,_
) = get_before_e w
[] in
408 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a
@t
)),a
)
409 | Ast.Nest
(stmt_dots
,w
,t
) ->
410 let (w
,_
) = List.split
(List.map
(function s
-> get_before s
[]) w
) in
411 let (sd
,_
) = get_before stmt_dots a
in
417 Unify_ast.unify_statement_dots
418 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
420 Unify_ast.MAYBE
-> false
422 | Ast.Other_dots
a ->
423 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
425 Unify_ast.MAYBE
-> false
429 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
430 | Ast.Disj
(stmt_dots_list
) ->
432 List.split
(List.map
(function e
-> get_before e
a) stmt_dots_list
) in
433 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
435 (match Ast.unwrap ast
with
436 Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
437 | _
-> (s
,[Ast.Other s
]))
438 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
439 let index = count_nested_braces s
in
440 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
441 let (bd
,_
) = get_before body dea
in
442 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
443 [Ast.WParen
(rbrace
,index)])
444 | Ast.IfThen
(ifheader
,branch
,aft
) ->
445 let (br
,_
) = get_before_e branch
[] in
446 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)), [Ast.Other s
])
447 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
448 let (br1
,_
) = get_before_e branch1
[] in
449 let (br2
,_
) = get_before_e branch2
[] in
450 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
451 | Ast.While
(header
,body
,aft
) ->
452 let (bd
,_
) = get_before_e body
[] in
453 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
454 | Ast.For
(header
,body
,aft
) ->
455 let (bd
,_
) = get_before_e body
[] in
456 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
457 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
458 let index = count_nested_braces s
in
459 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
460 let (bd
,_
) = get_before body dea
in
461 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
462 | _
-> failwith
"not supported"
464 let rec get_after sl
a =
465 match Ast.unwrap sl
with
471 let (sl
,sla
) = loop sl
in
472 let (e
,ea
) = get_after_e e sla
in
474 let (l,a) = loop x
in
475 (Ast.rewrap sl
(Ast.DOTS
(l)),a)
476 | Ast.CIRCLES
(x
) -> failwith
"not supported"
477 | Ast.STARS
(x
) -> failwith
"not supported"
479 and get_after_e s
a =
480 match Ast.unwrap s
with
481 Ast.Dots
(d,Ast.NoWhen
,t
) ->
482 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a@t
)),a)
483 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
484 let (w
,_
) = get_after w
[] in
485 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a@t
)),a)
486 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
487 let (w
,_
) = get_after_e w
[] in
488 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a@t
)),a)
489 | Ast.Nest
(stmt_dots
,w
,t
) ->
490 let (w
,_
) = List.split
(List.map
(function s
-> get_after s
[]) w
) in
491 let (sd
,_
) = get_after stmt_dots
a in
497 Unify_ast.unify_statement_dots
498 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
500 Unify_ast.MAYBE
-> false
502 | Ast.Other_dots
a ->
503 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
505 Unify_ast.MAYBE
-> false
509 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
510 | Ast.Disj
(stmt_dots_list
) ->
512 List.split
(List.map
(function e
-> get_after e
a) stmt_dots_list
) in
513 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
515 (match Ast.unwrap ast
with
516 Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots _
,i
) ->
517 (* check after information for metavar optimization *)
518 (* if the error is not desired, could just return [], then
519 the optimization (check for EF) won't take place *)
523 (match Ast.unwrap x
with
524 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
526 "dots/nest not allowed before and after stmt metavar"
528 | Ast.Other_dots x
->
529 (match Ast.undots x
with
531 (match Ast.unwrap x
with
532 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
534 ("dots/nest not allowed before and after stmt "^
543 (Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots
a,i
)))),[])
544 | Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
545 | _
-> (s
,[Ast.Other s
]))
546 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
547 let index = count_nested_braces s
in
548 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
549 let (de
,_
) = get_after decls bda
in
550 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
551 [Ast.WParen
(lbrace
,index)])
552 | Ast.IfThen
(ifheader
,branch
,aft
) ->
553 let (br
,_
) = get_after_e branch
a in
554 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)),[Ast.Other s
])
555 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
556 let (br1
,_
) = get_after_e branch1
a in
557 let (br2
,_
) = get_after_e branch2
a in
558 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
559 | Ast.While
(header
,body
,aft
) ->
560 let (bd
,_
) = get_after_e body
a in
561 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
562 | Ast.For
(header
,body
,aft
) ->
563 let (bd
,_
) = get_after_e body
a in
564 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
565 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
566 let index = count_nested_braces s
in
567 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
568 let (de
,_
) = get_after decls bda
in
569 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
570 | _
-> failwith
"not supported"
573 let preprocess_dots sl
=
574 let (sl
,_
) = get_before sl
[] in
575 let (sl
,_
) = get_after sl
[] in
578 let preprocess_dots_e sl
=
579 let (sl
,_
) = get_before_e sl
[] in
580 let (sl
,_
) = get_after_e sl
[] in
583 (* --------------------------------------------------------------------- *)
584 (* the main translation loop *)
586 let decl_to_not_decl n
dots stmt
make_match f
=
591 let md = Ast.make_meta_decl
"_d" (Ast.CONTEXT
(Ast.NOTHING
)) in
592 Ast.rewrap
md (Ast.Decl
md) in
593 wrapAU n
(make_match de,
594 wrap n
(CTL.And
(wrap n
(CTL.Not
(make_match de)), f
)))
596 let rec statement_list stmt_list used_after after quantified guard
=
597 let n = if !line_numbers then Ast.get_line stmt_list
else 0 in
598 match Ast.unwrap stmt_list
with
600 let rec loop quantified
= function
601 ([],_
) -> (match after
with After f
-> f
| _
-> wrap n CTL.True
)
602 | ([e
],_
) -> statement e used_after after quantified guard
604 let shared = intersectll fv fvs
in
605 let unqshared = get_unquantified quantified
shared in
606 let new_quantified = Common.union_set
unqshared quantified
in
608 (statement e used_after
(After
(loop new_quantified (sl
,fvs
)))
609 new_quantified guard
)
610 | _
-> failwith
"not possible" in
611 loop quantified
(x
,List.map
Ast.get_fvs x
)
612 | Ast.CIRCLES
(x
) -> failwith
"not supported"
613 | Ast.STARS
(x
) -> failwith
"not supported"
615 and statement stmt used_after after quantified guard
=
617 let n = if !line_numbers then Ast.get_line stmt
else 0 in
618 let wrapExists = wrapExists n in
619 let wrapAnd = wrapAnd n in
620 let wrapOr = wrapOr n in
621 let wrapSeqOr = wrapSeqOr n in
622 let wrapAU = wrapAU n in
623 let wrapAX = wrapAX n in
624 let wrapBackAX = wrapBackAX n in
625 let wrapEX = wrapEX n in
626 let wrapBackEX = wrapBackEX n in
627 let wrapAG = wrapAG n in
628 let wrapAF = wrapAF n in
629 let wrapEF = wrapEF n in
630 let wrapNot = wrapNot n in
631 let wrapPred = wrapPred n in
632 let make_seq = make_seq n in
633 let make_seq_after2 = make_seq_after2 n in
634 let make_seq_after = make_seq_after n in
635 let and_opt = and_opt n in
636 let quantify = quantify n in
637 let make_match = make_match n guard used_after
in
638 let make_raw_match = make_raw_match n in
640 let make_meta_rule_elem d =
641 let nm = fresh_metavar() in
642 Ast.make_meta_rule_elem nm d in
644 match Ast.unwrap stmt
with
646 (match Ast.unwrap ast
with
647 Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,_
)) as d)),seqible
,_
)
648 | Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.AFTER
(_
)) as d)),seqible
,_
) ->
649 let label_var = (*fresh_label_var*) "_lab" in
650 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
652 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
653 let matcher d = make_match (make_meta_rule_elem d) in
654 let full_metamatch = matcher d in
655 let first_metamatch =
658 Ast.CONTEXT
(Ast.BEFOREAFTER
(bef
,_
)) ->
659 Ast.CONTEXT
(Ast.BEFORE
(bef
))
660 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
661 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
662 let middle_metamatch =
665 Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
666 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
670 Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,aft
)) ->
671 Ast.CONTEXT
(Ast.AFTER
(aft
))
672 | Ast.CONTEXT
(_
) -> d
673 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
677 [full_metamatch; and_opt (wrapNot(prelabel_pred)) after
] in
681 wrapAU(middle_metamatch,
683 [wrapAnd(last_metamatch,label_pred);
684 and_opt (wrapNot(prelabel_pred)) after
])] in
687 f
(wrapAnd(make_raw_match ast
,
688 wrapOr(left_or,right_or)))) in
691 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
692 quantify (label_var::get_unquantified quantified
[s
])
695 (wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
696 | Ast.SequencibleAfterDots
l ->
698 List.map
(process_bef_aft Tail quantified used_after
n) l in
700 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
701 (List.hd
afts) (List.tl
afts) in
702 quantify (label_var::get_unquantified quantified
[s
])
703 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
706 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
707 | Ast.NotSequencible
->
708 quantify (label_var::get_unquantified quantified
[s
]) (body id))
710 | Ast.MetaStmt
((s
,i
,d),seqible
,_
) ->
711 let label_var = (*fresh_label_var*) "_lab" in
712 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
714 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
715 let matcher d = make_match (make_meta_rule_elem d) in
716 let first_metamatch = matcher d in
720 Ast.MINUS
(_
) -> Ast.MINUS
([])
721 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
722 | Ast.PLUS
-> failwith
"not possible") in
723 (* first_nodea and first_nodeb are separated here and above to
724 improve let sharing - only first_nodea is unique to this site *)
725 let first_nodeb = first_metamatch in
726 let rest_nodes = wrapAnd(rest_metamatch,prelabel_pred) in
727 let last_node = and_opt (wrapNot(prelabel_pred)) after
in
734 [first_nodeb; wrapAU(rest_nodes,last_node)])))) in
736 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
737 quantify (label_var::get_unquantified quantified
[s
])
739 (function x
-> wrapAnd(wrapNot(wrapBackAX(label_pred)),x
)))
740 | Ast.SequencibleAfterDots
l ->
742 List.map
(process_bef_aft Tail quantified used_after
n) l in
744 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
745 (List.hd
afts) (List.tl
afts) in
746 quantify (label_var::get_unquantified quantified
[s
])
747 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
750 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
751 | Ast.NotSequencible
->
752 quantify (label_var::get_unquantified quantified
[s
])
753 (body (function x
-> x
)))
755 let stmt_fvs = Ast.get_fvs stmt
in
756 let fvs = get_unquantified quantified
stmt_fvs in
757 let between_dots = Ast.get_dots_bef_aft stmt
in
758 let term = make_match ast
in
760 match between_dots with
761 Ast.BetweenDots brace_term
->
762 (match Ast.unwrap brace_term
with
763 Ast.Atomic
(brace_ast
) ->
768 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
770 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
772 make_match brace_ast
) in
778 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
780 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
784 | _
-> failwith
"not possible")
785 | Ast.NoDots
-> term in
786 make_seq_after (quantify fvs term) after
)
787 | Ast.Seq
(lbrace
,decls
,dots,body,rbrace
) ->
788 let (lbfvs
,b1fvs
,_
,b2fvs
,_
,b3fvs
,rbfvs
) =
790 (Ast.get_fvs lbrace
) (Ast.get_fvs decls
)
791 (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
792 let v = count_nested_braces stmt
in
793 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
795 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
797 wrapAnd(quantify rbfvs
(make_match rbrace
),paren_pred) in
798 let new_quantified2 =
799 Common.union_set b1fvs
(Common.union_set b2fvs quantified
) in
800 let new_quantified3 = Common.union_set b3fvs
new_quantified2 in
806 (statement_list decls used_after
808 (decl_to_not_decl n dots stmt
make_match
810 (statement_list body used_after
811 (After
(make_seq_after end_brace after
))
812 new_quantified3 guard
))))
813 new_quantified2 guard
)]))
814 | Ast.IfThen
(ifheader
,branch
,aft
) ->
816 (* "if (test) thn" becomes:
817 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
819 "if (test) thn; after" becomes:
820 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
826 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch
) in
827 let new_quantified = Common.union_set bfvs quantified
in
829 let if_header = quantify efvs
(make_match ifheader
) in
830 (* then branch and after *)
833 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
834 statement branch used_after
(a2n after
) new_quantified guard
] in
835 let fall_branch = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
836 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
837 let (aft_needed
,after_branch
) =
839 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
842 make_seq_after after_pred
844 (make_seq_after (make_match (make_meta_rule_elem aft
))
846 let or_cases = wrapOr(true_branch,wrapOr(fall_branch,after_branch
)) in
848 (match (after
,aft_needed
) with
849 (After _
,_
) (* pattern doesn't end here *)
850 | (_
,true) (* + code added after *) ->
852 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
853 | _
-> quantify bfvs
(wrapAnd(if_header, wrapAX or_cases)))
855 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
857 (* "if (test) thn else els" becomes:
858 if(test) & AX((TrueBranch & AX thn) v
859 (FalseBranch & AX (else & AX els)) v After)
862 "if (test) thn else els; after" becomes:
863 if(test) & AX((TrueBranch & AX thn) v
864 (FalseBranch & AX (else & AX els)) v
865 (After & AXAX after))
870 Note that we rely on the well-formedness of C programs. For example, we
871 do not use EX to check that there is at least one then branch, because
872 there is always one. And we do not check that there is only one then or
873 else branch, because these again are always the case in a well-formed C
876 let (e1fvs
,b1fvs
,s1fvs
) =
877 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch1
) in
878 let (e2fvs
,b2fvs
,s2fvs
) =
879 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch2
) in
882 (Common.union_set b1fvs b2fvs
)
883 (Common.inter_set s1fvs s2fvs
) in
884 let exponlyfvs = Common.inter_set e1fvs e2fvs
in
885 let new_quantified = Common.union_set
bothfvs quantified
in
887 let if_header = quantify exponlyfvs (make_match ifheader
) in
888 (* then and else branches *)
891 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
892 statement branch1 used_after
(a2n after
) new_quantified guard
] in
893 let false_pred = wrapPred(Lib_engine.FalseBranch
,CTL.Control
) in
896 [false_pred; make_match els
;
897 statement branch2 used_after
(a2n after
) new_quantified guard
] in
898 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
899 let (aft_needed
,after_branch
) =
901 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
904 make_seq_after after_pred
906 (make_seq_after (make_match (make_meta_rule_elem aft
))
908 let or_cases = wrapOr(true_branch,wrapOr(false_branch,after_branch
)) in
910 (match (after
,aft_needed
) with
911 (After _
,_
) (* pattern doesn't end here *)
912 | (_
,true) (* + code added after *) ->
916 wrapAnd(wrapAX or_cases,
917 wrapAnd(wrapEX false_pred,wrapEX after_pred))))
920 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX false_pred))))
922 | Ast.While
(header
,body,aft
) | Ast.For
(header
,body,aft
) ->
923 (* the translation in this case is similar to that of an if with no else *)
926 seq_fvs2 quantified
(Ast.get_fvs header
) (Ast.get_fvs
body) in
927 let new_quantified = Common.union_set bfvs quantified
in
929 let header = quantify efvs
(make_match header) in
932 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
933 statement
body used_after
(a2n after
) new_quantified guard
] in
934 let after_pred = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
935 let (aft_needed
,after_branch
) =
937 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
940 make_seq_after after_pred
942 (make_seq_after (make_match (make_meta_rule_elem aft
))
944 let or_cases = wrapOr(body,after_branch
) in
946 (match (after
,aft_needed
) with
947 (After _
,_
) (* pattern doesn't end here *)
948 | (_
,true) (* + code added after *) ->
950 (wrapAnd (header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
951 | _
-> quantify bfvs
(wrapAnd(header, wrapAX or_cases)))
953 | Ast.Disj
(stmt_dots_list
) ->
956 (function x
-> statement_list x used_after after quantified guard
)
958 let rec loop = function
959 [] -> wrap n CTL.True
961 | x
::xs
-> wrapSeqOr(x
,loop xs
) in
965 statement_list e used_after (a2n after) quantified true in
968 (function rest -> function cur -> wrapAnd(wrapNot(do_one cur),rest))
970 let process_one nots cur =
971 match Ast.unwrap cur with
973 let on = List.map (function x -> Ast.OrOther_dots x) nots in
974 (match Ast.unwrap x with
978 Printf.printf "a not\n";
979 Pretty_print_cocci.statement_dots x)
983 (Ast.DOTS((Ast.rewrap x (Ast.Dots(d,w,on@t)))::xs)) in
984 statement_list cur used_after after quantified guard
985 | Ast.Nest(sd,w,t) ->
988 (Ast.DOTS((Ast.rewrap x (Ast.Nest(sd,w,on@t)))::xs)) in
989 statement_list cur used_after after quantified guard
992 (statement_list cur used_after after quantified guard))
995 (statement_list cur used_after after quantified guard)
996 | _ -> failwith "CIRCLES, STARS not supported" in
997 let rec loop after = function
998 [] -> failwith "disj shouldn't be empty" (*wrap n CTL.False*)
999 | [(nots
,cur)] -> process_one nots
cur
1000 | (nots
,cur)::rest
-> wrapOr(process_one nots
cur, loop after rest
) in
1001 loop after
(preprocess_disj stmt_dots_list
)
1003 | Ast.Nest
(stmt_dots
,whencode
,befaft
) ->
1005 statement_list stmt_dots used_after
(a2n after
) quantified guard
in
1010 statement_list sl used_after
(a2n after
) quantified
true)
1012 List.fold_left
(function rest
-> function cur -> wrapOr(cur,rest
))
1013 (statement_list stmt_dots used_after
(a2n after
) quantified
true)
1015 (match (after
,guard
&&(whencode
=[])) with
1018 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1020 [] -> wrapAF(wrapOr(a,aftret))
1025 (function rest
-> function cur -> wrapOr(cur,rest
))
1027 wrapAU(left,wrapOr(a,aftret)))
1028 | (After
a,false) ->
1029 let left = wrapOr(dots_pattern,wrapNot udots_pattern) in
1031 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1039 (function rest
-> function cur -> wrapOr(cur,rest
))
1042 wrapAU(left,wrapOr(a,aftret))
1043 | (_
,true) -> wrap n CTL.True
1044 | (_
,false) -> wrapAG(wrapOr(dots_pattern,wrapNot udots_pattern)))
1045 | Ast.Dots
((_
,i
,d),whencodes,t
) ->
1049 (* no need for the fresh metavar, but ... is a bit weird as a
1051 Some
(make_match (make_meta_rule_elem d))
1054 (match whencodes with
1056 | Ast.WhenNot
whencodes ->
1058 (statement_list whencodes used_after
(a2n after
) quantified
1060 | Ast.WhenAlways s
->
1061 [statement s used_after
(a2n after
) quantified
true]) @
1063 (List.map
(process_bef_aft after quantified used_after
n) t
)) in
1065 match whencodes with
1070 (function rest
-> function cur -> wrapAnd(cur,rest
))
1073 match (dot_code,phi2) with (* add - on dots, if any *)
1075 | (Some dotcode
,None
) -> Some dotcode
1076 | (None
,Some whencode
) -> Some whencode
1077 | (Some dotcode
,Some whencode
) -> Some
(wrapAnd (dotcode
,whencode
)) in
1078 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1079 (* add in the after code to make the result *)
1080 (match (after
,phi3) with
1081 (Tail
,Some whencode
) -> wrapAU(whencode
,wrapOr(exit,aftret))
1082 | (Tail
,None
) -> wrapAF(wrapOr(exit,aftret))
1083 | (After f
,Some whencode
) | (Guard f
,Some whencode
) ->
1084 wrapAU(whencode
,wrapOr(f
,aftret))
1085 | (After f
,None
) | (Guard f
,None
) -> wrapAF(wrapOr(f
,aftret)))
1086 | Ast.FunDecl
(header,lbrace
,decls
,dots,body,rbrace
) ->
1087 let (hfvs
,b1fvs
,lbfvs
,b2fvs
,_
,b3fvs
,_
,b4fvs
,rbfvs
) =
1088 seq_fvs5 quantified
(Ast.get_fvs
header) (Ast.get_fvs lbrace
)
1089 (Ast.get_fvs decls
) (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
1090 let function_header = quantify hfvs
(make_match header) in
1091 let v = count_nested_braces stmt
in
1092 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
1094 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
1096 let stripped_rbrace =
1097 match Ast.unwrap rbrace
with
1098 Ast.SeqEnd
((data
,info
,_
)) ->
1100 (Ast.SeqEnd
((data
,info
,Ast.CONTEXT
(Ast.NOTHING
))))
1101 | _
-> failwith
"unexpected close brace" in
1102 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1103 let errorexit = wrap n (CTL.Pred
(Lib_engine.ErrorExit
,CTL.Control
)) in
1104 wrapAnd(quantify rbfvs
(make_match rbrace
),
1105 wrapAU(make_match stripped_rbrace,
1106 wrapOr(exit,errorexit))) in
1107 let new_quantified3 =
1108 Common.union_set b1fvs
1109 (Common.union_set b2fvs
(Common.union_set b3fvs quantified
)) in
1110 let new_quantified4 = Common.union_set b4fvs
new_quantified3 in
1120 (statement_list decls used_after
1122 (decl_to_not_decl n dots stmt
1125 (statement_list body used_after
1127 (make_seq_after end_brace after
))
1128 new_quantified4 guard
))))
1129 new_quantified3 guard
)])))])
1130 | Ast.OptStm
(stm
) ->
1131 failwith
"OptStm should have been compiled away\n";
1132 | Ast.UniqueStm
(stm
) ->
1133 failwith
"arities not yet supported"
1134 | Ast.MultiStm
(stm
) ->
1135 failwith
"arities not yet supported"
1136 | _
-> failwith
"not supported"
1138 and process_bef_aft after quantified used_after ln
= function
1139 Ast.WParen
(re
,n) ->
1140 let paren_pred = wrapPred ln
(Lib_engine.Paren
n,CTL.Control
) in
1141 wrapAnd ln
(make_raw_match ln re
,paren_pred)
1142 | Ast.Other s
-> statement s used_after
(a2n after
) quantified
true
1143 | Ast.Other_dots
d -> statement_list d used_after
(a2n after
) quantified
true
1144 | Ast.OrOther_dots
d -> statement_list d used_after Tail quantified
true
1146 (* Returns a triple for each disj element. The first element of the triple is
1147 Some v if the triple element needs a name, and None otherwise. The second
1148 element is a list of names whose negations should be conjuncted with the
1149 term. The third element is the original term *)
1150 and (preprocess_disj
:
1151 Ast.statement
Ast.dots list
->
1152 (Ast.statement
Ast.dots list
* Ast.statement
Ast.dots) list
) =
1158 List.map
(function r
-> Unify_ast.unify_statement_dots
cur r
) rest
in
1159 let processed = preprocess_disj rest
in
1160 if List.exists
(function Unify_ast.MAYBE
-> true | _
-> false) template
1164 (function ((nots,r
) as x
) ->
1165 function Unify_ast.MAYBE
-> (cur::nots,r
) | Unify_ast.NO
-> x
)
1167 else ([], cur) :: processed
1169 (* --------------------------------------------------------------------- *)
1171 Phase 1: Use a hash table to identify formulas that appear more than once.
1172 Phase 2: Replace terms by variables.
1173 Phase 3: Drop lets to the point as close as possible to the uses of their
1177 (Hashtbl.create
(50) :
1178 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1179 int ref (* count *) * string ref (* name *) * bool ref (* processed *))
1184 try Hashtbl.find
formula_table phi
1186 let c = (ref 0,ref "",ref false) in
1187 Hashtbl.add
formula_table phi
c;
1191 let rec collect_duplicates f
=
1193 match CTL.unwrap f
with
1197 | CTL.Not
(phi
) -> collect_duplicates phi
1198 | CTL.Exists
(v,phi
) -> collect_duplicates phi
1199 | CTL.And
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1200 | CTL.Or
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1201 | CTL.SeqOr
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1202 | CTL.Implies
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1203 | CTL.AF
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1204 | CTL.AX
(_
,phi
) -> collect_duplicates phi
1205 | CTL.AG
(_
,phi
) -> collect_duplicates phi
1206 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1207 collect_duplicates phi1
; collect_duplicates phi2;
1208 collect_duplicates phi3; collect_duplicates phi4
1209 | CTL.EF
(_
,phi
) -> collect_duplicates phi
1210 | CTL.EX
(_
,phi
) -> collect_duplicates phi
1211 | CTL.EG
(_
,phi
) -> collect_duplicates phi
1212 | CTL.EU
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1213 | CTL.Uncheck
(phi
) -> collect_duplicates phi
1214 | _
-> failwith
"not possible"
1216 let assign_variables _
=
1218 (function formula
->
1219 function (cell
,str
,_
) -> if !cell
> 1 then str
:= fresh_let_var())
1222 let rec replace_formulas dec f
=
1223 let (ct
,name
,treated
) = Hashtbl.find
formula_table f
in
1224 let real_ct = !ct
- dec
in
1231 let (acc
,new_f
) = replace_subformulas
(dec
+ (real_ct - 1)) f
in
1232 ((!name
,new_f
) :: acc
, CTL.rewrap f
(CTL.Ref
!name
))
1234 else ([],CTL.rewrap f
(CTL.Ref
!name
))
1235 else replace_subformulas dec f
1237 and replace_subformulas dec f
=
1238 match CTL.unwrap f
with
1240 | CTL.True
-> ([],f
)
1241 | CTL.Pred
(p
) -> ([],f
)
1243 let (acc
,new_phi
) = replace_formulas dec phi
in
1244 (acc
,CTL.rewrap f
(CTL.Not
(new_phi
)))
1245 | CTL.Exists
(v,phi
) ->
1246 let (acc
,new_phi
) = replace_formulas dec phi
in
1247 (acc
,CTL.rewrap f
(CTL.Exists
(v,new_phi
)))
1248 | CTL.And
(phi1
,phi2) ->
1249 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1250 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1251 (acc1
@acc2
,CTL.rewrap f
(CTL.And
(new_phi1
,new_phi2
)))
1252 | CTL.Or
(phi1
,phi2) ->
1253 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1254 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1255 (acc1
@acc2
,CTL.rewrap f
(CTL.Or
(new_phi1
,new_phi2
)))
1256 | CTL.SeqOr
(phi1
,phi2) ->
1257 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1258 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1259 (acc1
@acc2
,CTL.rewrap f
(CTL.SeqOr
(new_phi1
,new_phi2
)))
1260 | CTL.Implies
(phi1
,phi2) ->
1261 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1262 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1263 (acc1
@acc2
,CTL.rewrap f
(CTL.Implies
(new_phi1
,new_phi2
)))
1264 | CTL.AF
(dir
,phi1
,phi2) ->
1265 let (acc
,new_phi1
) = replace_formulas dec phi1
in
1266 let (acc
,new_phi2
) = replace_formulas dec
phi2 in
1267 (acc
,CTL.rewrap f
(CTL.AF
(dir
,new_phi1
,new_phi2
)))
1268 | CTL.AX
(dir
,phi
) ->
1269 let (acc
,new_phi
) = replace_formulas dec phi
in
1270 (acc
,CTL.rewrap f
(CTL.AX
(dir
,new_phi
)))
1271 | CTL.AG
(dir
,phi
) ->
1272 let (acc
,new_phi
) = replace_formulas dec phi
in
1273 (acc
,CTL.rewrap f
(CTL.AG
(dir
,new_phi
)))
1274 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1275 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1276 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1277 let (acc3
,new_phi3
) = replace_formulas dec
phi3 in
1278 let (acc4
,new_phi4
) = replace_formulas dec phi4
in
1279 (acc1
@acc2
@acc3
@acc4
,
1280 CTL.rewrap f
(CTL.AU
(dir
,new_phi1
,new_phi2
,new_phi3
,new_phi4
)))
1281 | CTL.EF
(dir
,phi
) ->
1282 let (acc
,new_phi
) = replace_formulas dec phi
in
1283 (acc
,CTL.rewrap f
(CTL.EF
(dir
,new_phi
)))
1284 | CTL.EX
(dir
,phi
) ->
1285 let (acc
,new_phi
) = replace_formulas dec phi
in
1286 (acc
,CTL.rewrap f
(CTL.EX
(dir
,new_phi
)))
1287 | CTL.EG
(dir
,phi
) ->
1288 let (acc
,new_phi
) = replace_formulas dec phi
in
1289 (acc
,CTL.rewrap f
(CTL.EG
(dir
,new_phi
)))
1290 | CTL.EU
(dir
,phi1
,phi2) ->
1291 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1292 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1293 (acc1
@acc2
,CTL.rewrap f
(CTL.EU
(dir
,new_phi1
,new_phi2
)))
1294 | _
-> failwith
"not possible"
1297 (Hashtbl.create
(50) :
1298 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1299 string list
(* fvs *) *
1300 string list
(* intersection of fvs of subterms *))
1304 try let (fvs,_
) = Hashtbl.find
ctlfv_table f
in fvs
1306 let ((fvs,_
) as res
) =
1307 match CTL.unwrap f
with
1308 CTL.False
| CTL.True
| CTL.Pred
(_
) -> ([],[])
1309 | CTL.Not
(phi
) | CTL.Exists
(_
,phi
)
1310 | CTL.AX
(_
,phi
) | CTL.AG
(_
,phi
)
1311 | CTL.EF
(_
,phi
) | CTL.EX
(_
,phi
) | CTL.EG
(_
,phi
) -> (ctl_fvs phi
,[])
1312 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1313 let phi1fvs = ctl_fvs phi1
in
1314 let phi2fvs = ctl_fvs phi2 in
1315 (* phi3 has the same fvs as phi1 and phi4 as phi2 *)
1316 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1317 | CTL.And
(phi1
,phi2) | CTL.Or
(phi1
,phi2) | CTL.SeqOr
(phi1
,phi2)
1318 | CTL.Implies
(phi1
,phi2) | CTL.AF
(_
,phi1
,phi2) | CTL.EU
(_
,phi1
,phi2) ->
1319 let phi1fvs = ctl_fvs phi1
in
1320 let phi2fvs = ctl_fvs phi2 in
1321 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1322 | CTL.Ref
(v) -> ([v],[v])
1323 | CTL.Let
(v,term,body) ->
1324 let phi1fvs = ctl_fvs term in
1325 let phi2fvs = Common.minus_set
(ctl_fvs body) [v] in
1326 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs) in
1327 Hashtbl.add
ctlfv_table f res
;
1330 let rev_order_bindings b
=
1333 (function (nm,term) ->
1334 let (fvs,_
) = Hashtbl.find
ctlfv_table term in (nm,fvs,term))
1336 let rec loop bound
= function
1339 let (now_bound
,still_unbound
) =
1340 List.partition
(function (_
,fvs,_
) -> subset fvs bound
)
1342 let get_names = List.map
(function (x
,_
,_
) -> x
) in
1343 now_bound
@ (loop ((get_names now_bound
) @ bound
) still_unbound
) in
1346 let drop_bindings b f
= (* innermost bindings first in b *)
1347 let process_binary f ffvs inter
nm term fail
=
1348 if List.mem
nm inter
1349 then CTL.rewrap f
(CTL.Let
(nm,term,f
))
1350 else CTL.rewrap f
(fail
()) in
1352 let _ = ctl_fvs f
in Hashtbl.find
ctlfv_table f
in
1353 let rec drop_one nm term f
=
1354 match CTL.unwrap f
with
1358 | CTL.Not
(phi
) -> CTL.rewrap f
(CTL.Not
(drop_one nm term phi
))
1359 | CTL.Exists
(v,phi
) -> CTL.rewrap f
(CTL.Exists
(v,drop_one nm term phi
))
1360 | CTL.And
(phi1
,phi2) ->
1361 let (ffvs
,inter
) = find_fvs f
in
1362 process_binary f ffvs inter
nm term
1363 (function _ -> CTL.And
(drop_one nm term phi1
,drop_one nm term phi2))
1364 | CTL.Or
(phi1
,phi2) ->
1365 let (ffvs
,inter
) = find_fvs f
in
1366 process_binary f ffvs inter
nm term
1367 (function _ -> CTL.Or
(drop_one nm term phi1
,drop_one nm term phi2))
1368 | CTL.SeqOr
(phi1
,phi2) ->
1369 let (ffvs
,inter
) = find_fvs f
in
1370 process_binary f ffvs inter
nm term
1372 CTL.SeqOr
(drop_one nm term phi1
,drop_one nm term phi2))
1373 | CTL.Implies
(phi1
,phi2) ->
1374 let (ffvs
,inter
) = find_fvs f
in
1375 process_binary f ffvs inter
nm term
1377 CTL.Implies
(drop_one nm term phi1
,drop_one nm term phi2))
1378 | CTL.AF
(dir
,phi1
,phi2) ->
1379 let (ffvs
,inter
) = find_fvs f
in
1380 process_binary f ffvs inter
nm term
1382 CTL.AF
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1383 | CTL.AX
(dir
,phi
) ->
1384 CTL.rewrap f
(CTL.AX
(dir
,drop_one nm term phi
))
1385 | CTL.AG
(dir
,phi
) -> CTL.rewrap f
(CTL.AG
(dir
,drop_one nm term phi
))
1386 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1387 let (ffvs
,inter
) = find_fvs f
in
1388 process_binary f ffvs inter
nm term
1390 CTL.AU
(dir
,drop_one nm term phi1
,drop_one nm term phi2,
1391 drop_one nm term phi3,drop_one nm term phi4
))
1392 | CTL.EF
(dir
,phi
) -> CTL.rewrap f
(CTL.EF
(dir
,drop_one nm term phi
))
1393 | CTL.EX
(dir
,phi
) ->
1394 CTL.rewrap f
(CTL.EX
(dir
,drop_one nm term phi
))
1395 | CTL.EG
(dir
,phi
) -> CTL.rewrap f
(CTL.EG
(dir
,drop_one nm term phi
))
1396 | CTL.EU
(dir
,phi1
,phi2) ->
1397 let (ffvs
,inter
) = find_fvs f
in
1398 process_binary f ffvs inter
nm term
1400 CTL.EU
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1401 | (CTL.Ref
(v) as x
) -> process_binary f
[v] [v] nm term (function _ -> x
)
1402 | CTL.Let
(v,term1
,body) ->
1403 let (ffvs
,inter
) = find_fvs f
in
1404 process_binary f ffvs inter
nm term
1406 CTL.Let
(v,drop_one nm term term1
,drop_one nm term body)) in
1408 (function processed -> function (nm,_,term) -> drop_one nm term processed)
1412 failwith
"this code should not be used!!!"(*;
1413 Hashtbl.clear formula_table;
1414 Hashtbl.clear ctlfv_table;
1415 (* create a count of the number of occurrences of each subformula *)
1416 collect_duplicates f
;
1417 (* give names to things that appear more than once *)
1419 (* replace duplicated formulas by their variables *)
1420 let (bindings
,new_f
) = replace_formulas 0 f
in
1421 (* collect fvs of terms in bindings and new_f *)
1422 List.iter
(function f
-> let _ = ctl_fvs f
in ())
1423 (new_f
::(List.map
(function (_,term) -> term) bindings
));
1424 (* sort bindings with uses before defs *)
1425 let bindings = rev_order_bindings bindings in
1426 (* insert bindings as lets into the formula *)
1427 let res = drop_bindings bindings new_f
in
1430 (* --------------------------------------------------------------------- *)
1431 (* Function declaration *)
1433 let top_level used_after t
=
1434 match Ast.unwrap t
with
1435 Ast.DECL
(decl
) -> failwith
"not supported decl"
1436 | Ast.INCLUDE
(inc
,s
) ->
1437 (* no indication of whether inc or s is modified *)
1438 wrap 0 (CTL.Pred
((Lib_engine.Include
(inc
,s
),CTL.Control
)))
1439 | Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
1440 | Ast.FUNCTION
(stmt
) ->
1441 (*Printf.printf "orig\n";
1442 Pretty_print_cocci.statement "" stmt;
1443 Format.print_newline();*)
1444 let unopt = elim_opt.V.rebuilder_statement stmt
in
1445 (*Printf.printf "unopt\n";
1446 Pretty_print_cocci.statement "" unopt;
1447 Format.print_newline();*)
1448 let unopt = preprocess_dots_e unopt in
1450 (statement
unopt used_after Tail
[] false)
1451 | Ast.CODE
(stmt_dots
) ->
1452 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots
in
1453 let unopt = preprocess_dots unopt in
1455 (statement_list unopt used_after Tail
[] false)
1456 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords"
1458 (* --------------------------------------------------------------------- *)
1462 let bind x y
= x
or y
in
1463 let option_default = false in
1464 let mcode r x
= false in
1465 let statement r k s
=
1466 match Ast.unwrap s
with Ast.Dots
(_,_,_) -> true | _ -> k s
in
1467 let continue r k e
= k e
in
1468 let stop r k e
= false in
1470 V.combiner
bind option_default
1471 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1472 continue continue continue
1473 stop stop stop stop stop stop stop statement continue continue in
1474 res.V.combiner_top_level
1476 (* --------------------------------------------------------------------- *)
1479 let asttoctl l used_after
=
1486 match Ast.unwrap t
with Ast.ERRORWORDS
(exps
) -> false | _ -> true)
1488 List.map2
top_level used_after
l
1490 let pp_cocci_predicate (pred
,modif
) =
1491 Pretty_print_engine.pp_predicate pred
1493 let cocci_predicate_to_string (pred
,modif
) =
1494 Pretty_print_engine.predicate_to_string pred