2 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
4 * This file is part of Coccinelle.
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
24 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
25 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
26 * This file is part of Coccinelle.
28 * Coccinelle is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, according to version 2 of the License.
32 * Coccinelle is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public License
38 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
40 * The authors reserve the right to distribute this or future versions of
41 * Coccinelle under other licenses.
45 (* true = don't see all matched nodes, only modified ones *)
46 let onlyModif = ref true(*false*)
47 (* set to true for line numbers in the output of ctl_engine *)
48 let line_numbers = ref false
49 (* if true, only eg if header is included in not for ...s *)
50 let simple_get_end = ref false(*true*)
52 (* Question: where do we put the existential quantifier for or. At the
53 moment, let it float inwards. *)
55 (* nest shouldn't overlap with what comes after. not checked for. *)
57 module Ast
= Ast_cocci
58 module V
= Visitor_ast
62 let warning s
= Printf.fprintf stderr
"warning: %s\n" s
64 type cocci_predicate
= Lib_engine.predicate
* string Ast_ctl.modif
66 (cocci_predicate
,string, Wrapper_ctl.info
) Ast_ctl.generic_ctl
69 let aftpred = (Lib_engine.After
,CTL.Control
)
70 let retpred = (Lib_engine.Return
,CTL.Control
)
71 let exitpred = (Lib_engine.ErrorExit
,CTL.Control
)
73 let intersect l1 l2
= List.filter
(function x
-> List.mem x l2
) l1
74 let subset l1 l2
= List.for_all
(function x
-> List.mem x l2
) l1
76 (* --------------------------------------------------------------------- *)
80 (match CTL.unwrap f
with
83 | CTL.Pred
(p
) as x
-> x
84 | CTL.Not
(phi
) -> CTL.Not
(drop_vs phi
)
85 | CTL.Exists
(v
,phi
) ->
86 (match CTL.unwrap phi
with
87 CTL.Pred
((x
,CTL.Modif v1
)) when v
= v1
-> CTL.Pred
((x
,CTL.Control
))
88 | _
-> CTL.Exists
(v
,drop_vs phi
))
89 | CTL.And
(phi1
,phi2
) -> CTL.And
(drop_vs phi1
,drop_vs phi2
)
90 | CTL.Or
(phi1
,phi2
) -> CTL.Or
(drop_vs phi1
,drop_vs phi2
)
91 | CTL.SeqOr
(phi1
,phi2
) -> CTL.SeqOr
(drop_vs phi1
,drop_vs phi2
)
92 | CTL.Implies
(phi1
,phi2
) -> CTL.Implies
(drop_vs phi1
,drop_vs phi2
)
93 | CTL.AF
(dir
,phi1
,phi2
) -> CTL.AF
(dir
,drop_vs phi1
,drop_vs phi2
)
94 | CTL.AX
(dir
,phi
) -> CTL.AX
(dir
,drop_vs phi
)
95 | CTL.AG
(dir
,phi
) -> CTL.AG
(dir
,drop_vs phi
)
96 | CTL.AU
(dir
,phi1
,phi2
,phi3
,phi4
) ->
97 CTL.AU
(dir
,drop_vs phi1
,drop_vs phi2
,drop_vs phi3
,drop_vs phi4
)
98 | CTL.EF
(dir
,phi
) -> CTL.EF
(dir
,drop_vs phi
)
99 | CTL.EX
(dir
,phi
) -> CTL.EX
(dir
,drop_vs phi
)
100 | CTL.EG
(dir
,phi
) -> CTL.EG
(dir
,drop_vs phi
)
101 | CTL.EU
(dir
,phi1
,phi2
) -> CTL.EU
(dir
,drop_vs phi1
,drop_vs phi2
)
102 | CTL.Ref
(v
) as x
-> x
103 | CTL.Let
(v
,term1
,body
) -> CTL.Let
(v
,drop_vs term1
,drop_vs body
))
105 (* --------------------------------------------------------------------- *)
107 let wrap n ctl
= (ctl
,n
)
110 wrap 0 (CTL.Or
(wrap 0 (CTL.Pred
aftpred),wrap 0 (CTL.Pred
exitpred)))
112 let wrapImplies n
(x
,y
) = wrap n
(CTL.Implies
(x
,y
))
113 let wrapExists n
(x
,y
) = wrap n
(CTL.Exists
(x
,y
))
114 let wrapAnd n
(x
,y
) = wrap n
(CTL.And
(x
,y
))
115 let wrapOr n
(x
,y
) = wrap n
(CTL.Or
(x
,y
))
116 let wrapSeqOr n
(x
,y
) = wrap n
(CTL.SeqOr
(x
,y
))
117 let wrapAU n
(x
,y
) = wrap n
(CTL.AU
(CTL.FORWARD
,x
,y
,drop_vs x
,drop_vs y
))
118 let wrapEU n
(x
,y
) = wrap n
(CTL.EU
(CTL.FORWARD
,x
,y
))
119 let wrapAX n
(x
) = wrap n
(CTL.AX
(CTL.FORWARD
,x
))
120 let wrapBackAX n
(x
) = wrap n
(CTL.AX
(CTL.BACKWARD
,x
))
121 let wrapEX n
(x
) = wrap n
(CTL.EX
(CTL.FORWARD
,x
))
122 let wrapBackEX n
(x
) = wrap n
(CTL.EX
(CTL.BACKWARD
,x
))
123 let wrapAG n
(x
) = wrap n
(CTL.AG
(CTL.FORWARD
,x
))
124 let wrapEG n
(x
) = wrap n
(CTL.EG
(CTL.FORWARD
,x
))
125 let wrapAF n
(x
) = wrap n
(CTL.AF
(CTL.FORWARD
,x
,drop_vs x
))
126 let wrapEF n
(x
) = wrap n
(CTL.EF
(CTL.FORWARD
,x
))
127 let wrapNot n
(x
) = wrap n
(CTL.Not
(x
))
128 let wrapPred n
(x
) = wrap n
(CTL.Pred
(x
))
129 let wrapLet n
(x
,y
,z
) = wrap n
(CTL.Let
(x
,y
,z
))
130 let wrapRef n
(x
) = wrap n
(CTL.Ref
(x
))
132 (* --------------------------------------------------------------------- *)
134 let get_option fn
= function
136 | Some x
-> Some
(fn x
)
138 let get_list_option fn
= function
142 (* --------------------------------------------------------------------- *)
143 (* --------------------------------------------------------------------- *)
144 (* Eliminate OptStm *)
146 (* for optional thing with nothing after, should check that the optional thing
147 never occurs. otherwise the matching stops before it occurs *)
150 let donothing r k e
= k e
in
153 List.fold_left
Common.union_set
[] (List.map
Ast.get_fvs l
) in
155 let rec dots_list unwrapped wrapped
=
156 match (unwrapped
,wrapped
) with
159 | (Ast.Dots
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
161 | (Ast.Nest
(_
,_
,_
)::Ast.OptStm
(stm
)::(Ast.Dots
(_
,_
,_
) as u
)::urest
,
163 let l = Ast.get_line stm
in
164 let new_rest1 = stm
:: (dots_list (u
::urest
) (d1
::rest
)) in
165 let new_rest2 = dots_list urest rest
in
166 let fv_rest1 = fvlist new_rest1 in
167 let fv_rest2 = fvlist new_rest2 in
168 [d0
;(Ast.Disj
[(Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
);
169 (Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
)],
170 l,fv_rest1,Ast.NoDots
)]
172 | (Ast.OptStm
(stm
)::urest
,_
::rest
) ->
173 let l = Ast.get_line stm
in
174 let new_rest1 = dots_list urest rest
in
175 let new_rest2 = stm
::new_rest1 in
176 let fv_rest1 = fvlist new_rest1 in
177 let fv_rest2 = fvlist new_rest2 in
178 [(Ast.Disj
[(Ast.DOTS
(new_rest2),l,fv_rest2,Ast.NoDots
);
179 (Ast.DOTS
(new_rest1),l,fv_rest1,Ast.NoDots
)],
180 l,fv_rest2,Ast.NoDots
)]
182 | ([Ast.Dots
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
183 let l = Ast.get_line stm
in
184 let fv_stm = Ast.get_fvs stm
in
185 let fv_d1 = Ast.get_fvs d1
in
186 let fv_both = Common.union_set
fv_stm fv_d1 in
187 [d1
;(Ast.Disj
[(Ast.DOTS
([stm
]),l,fv_stm,Ast.NoDots
);
188 (Ast.DOTS
([d1
]),l,fv_d1,Ast.NoDots
)],
189 l,fv_both,Ast.NoDots
)]
191 | ([Ast.Nest
(_
,_
,_
);Ast.OptStm
(stm
)],[d1
;_
]) ->
192 let l = Ast.get_line stm
in
193 let rw = Ast.rewrap stm
in
194 let rwd = Ast.rewrap stm
in
196 Ast.Dots
(("...",{ Ast.line
= 0; Ast.column
= 0 },
197 Ast.CONTEXT
(Ast.NOTHING
)),
199 [d1
;rw(Ast.Disj
[rwd(Ast.DOTS
([stm
]));
200 (Ast.DOTS
([rw dots]),l,[],Ast.NoDots
)])]
202 | (_
::urest
,stm
::rest
) -> stm
:: (dots_list urest rest
)
203 | _
-> failwith
"not possible" in
205 let stmtdotsfn r k d
=
208 (match Ast.unwrap
d with
209 Ast.DOTS
(l) -> Ast.DOTS
(dots_list (List.map
Ast.unwrap
l) l)
210 | Ast.CIRCLES
(l) -> failwith
"elimopt: not supported"
211 | Ast.STARS
(l) -> failwith
"elimopt: not supported") in
214 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
215 donothing donothing stmtdotsfn
216 donothing donothing donothing donothing donothing donothing donothing
217 donothing donothing donothing
219 (* --------------------------------------------------------------------- *)
220 (* Count depth of braces. The translation of a closed brace appears deeply
221 nested within the translation of the sequence term, so the name of the
222 paren var has to take into account the names of the nested braces. On the
223 other hand the close brace does not escape, so we don't have to take into
224 account other paren variable names. *)
226 (* called repetitively, which is inefficient, but less trouble than adding a
227 new field to Seq and FunDecl *)
228 let count_nested_braces s
=
229 let bind x y
= max x y
in
230 let option_default = 0 in
231 let stmt_count r k s
=
232 match Ast.unwrap s
with
233 Ast.Seq
(_
,_
,_
,_
,_
) | Ast.FunDecl
(_
,_
,_
,_
,_
,_
) -> (k s
) + 1
235 let donothing r k e
= k e
in
237 let recursor = V.combiner
bind option_default
238 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
239 donothing donothing donothing
240 donothing donothing donothing donothing donothing donothing
241 donothing stmt_count donothing donothing in
242 "p"^
(string_of_int
(recursor.V.combiner_statement s
))
244 (* --------------------------------------------------------------------- *)
251 Printf.sprintf
"v%d" c
254 let fresh_label_var s
=
256 labctr := !labctr + 1;
257 Printf.sprintf
"%s%d" s
c
260 let fresh_let_var _
=
263 Printf.sprintf
"l%d" c
266 let fresh_metavar _
=
268 (*sctr := !sctr + 1;*)
269 Printf.sprintf
"_S%d" c
271 let get_unquantified quantified vars
=
272 List.filter
(function x
-> not
(List.mem x quantified
)) vars
274 type after
= After
of formula
| Guard
of formula
| Tail
277 let rec loop = function
278 [] -> failwith
"not possible"
280 | x
::xs
-> wrapAnd n
(x
,wrapAX n
(loop xs
)) in
283 let make_seq_after2 n first
= function
284 After rest
-> wrapAnd n
(first
,wrapAX n
(wrapAX n rest
))
287 let make_seq_after n first
= function
288 After rest
-> make_seq n
[first
;rest
]
291 let a2n = function After f
-> Guard f
| x
-> x
293 let and_opt n first
= function
294 After rest
-> wrapAnd n
(first
,rest
)
298 let bind x y
= x
or y
in
299 let option_default = false in
300 let mcode r
(_
,_
,kind
) =
303 | Ast.PLUS
-> failwith
"not possible"
304 | Ast.CONTEXT
(info
) -> not
(info
= Ast.NOTHING
) in
305 let do_nothing r k e
= k e
in
307 V.combiner
bind option_default
308 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
309 do_nothing do_nothing do_nothing
310 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
311 do_nothing do_nothing do_nothing do_nothing in
312 recursor.V.combiner_rule_elem
314 let make_match n guard used_after code
=
316 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
318 let v = fresh_var() in
319 if contains_modif code
320 then wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.Modif
v))
323 List.exists
(function x
-> List.mem x used_after
) (Ast.get_fvs code
) in
324 if !onlyModif && not
any_used_after
325 then wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
326 else wrapExists n
(v,wrapPred n
(Lib_engine.Match
(code
),CTL.UnModif
v))
328 let make_raw_match n code
= wrapPred n
(Lib_engine.Match
(code
),CTL.Control
)
330 let rec seq_fvs quantified
= function
333 let t1fvs = get_unquantified quantified fv1
in
335 List.fold_left
Common.union_set
[]
336 (List.map
(get_unquantified quantified
) fvs
) in
337 let bothfvs = Common.inter_set
t1fvs termfvs in
338 let t1onlyfvs = Common.minus_set
t1fvs bothfvs in
339 let new_quantified = Common.union_set
bothfvs quantified
in
340 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs
)
342 let seq_fvs2 quantified fv1 fv2
=
343 match seq_fvs quantified
[fv1
;fv2
] with
344 [(t1fvs,bfvs
);(t2fvs
,[])] -> (t1fvs,bfvs
,t2fvs
)
345 | _
-> failwith
"impossible"
347 let seq_fvs3 quantified fv1 fv2 fv3
=
348 match seq_fvs quantified
[fv1
;fv2
;fv3
] with
349 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,[])] ->
350 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
)
351 | _
-> failwith
"impossible"
353 let seq_fvs4 quantified fv1 fv2 fv3 fv4
=
354 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
] with
355 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,[])] ->
356 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
)
357 | _
-> failwith
"impossible"
359 let seq_fvs5 quantified fv1 fv2 fv3 fv4 fv5
=
360 match seq_fvs quantified
[fv1
;fv2
;fv3
;fv4
;fv5
] with
361 [(t1fvs,b12fvs
);(t2fvs
,b23fvs
);(t3fvs
,b34fvs
);(t4fvs
,b45fvs
);(t5fvs
,[])] ->
362 (t1fvs,b12fvs
,t2fvs
,b23fvs
,t3fvs
,b34fvs
,t4fvs
,b45fvs
,t5fvs
)
363 | _
-> failwith
"impossible"
366 List.fold_right
(function cur
-> function code
-> wrapExists n
(cur
,code
))
368 let intersectll lst nested_list
=
369 List.filter
(function x
-> List.exists
(List.mem x
) nested_list
) lst
371 (* --------------------------------------------------------------------- *)
372 (* annotate dots with before and after neighbors *)
374 let rec get_before sl a
=
375 match Ast.unwrap sl
with
381 let (e
,ea
) = get_before_e e a
in
382 let (sl
,sla
) = loop sl ea
in
384 let (l,a
) = loop x a
in
385 (Ast.rewrap sl
(Ast.DOTS
(l)),a
)
386 | Ast.CIRCLES
(x
) -> failwith
"not supported"
387 | Ast.STARS
(x
) -> failwith
"not supported"
389 and get_before_e s a
=
390 match Ast.unwrap s
with
391 Ast.Dots
(d,Ast.NoWhen
,t
) ->
392 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a
@t
)),a
)
393 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
394 let (w
,_
) = get_before w
[] in
395 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a
@t
)),a
)
396 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
397 let (w
,_
) = get_before_e w
[] in
398 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a
@t
)),a
)
399 | Ast.Nest
(stmt_dots
,w
,t
) ->
400 let (w
,_
) = List.split
(List.map
(function s
-> get_before s
[]) w
) in
401 let (sd
,_
) = get_before stmt_dots a
in
407 Unify_ast.unify_statement_dots
408 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
410 Unify_ast.MAYBE
-> false
412 | Ast.Other_dots
a ->
413 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
415 Unify_ast.MAYBE
-> false
419 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
420 | Ast.Disj
(stmt_dots_list
) ->
422 List.split
(List.map
(function e
-> get_before e
a) stmt_dots_list
) in
423 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
425 (match Ast.unwrap ast
with
426 Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
427 | _
-> (s
,[Ast.Other s
]))
428 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
429 let index = count_nested_braces s
in
430 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
431 let (bd
,_
) = get_before body dea
in
432 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
433 [Ast.WParen
(rbrace
,index)])
434 | Ast.IfThen
(ifheader
,branch
,aft
) ->
435 let (br
,_
) = get_before_e branch
[] in
436 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)), [Ast.Other s
])
437 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
438 let (br1
,_
) = get_before_e branch1
[] in
439 let (br2
,_
) = get_before_e branch2
[] in
440 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
441 | Ast.While
(header
,body
,aft
) ->
442 let (bd
,_
) = get_before_e body
[] in
443 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
444 | Ast.For
(header
,body
,aft
) ->
445 let (bd
,_
) = get_before_e body
[] in
446 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
447 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
448 let index = count_nested_braces s
in
449 let (de
,dea
) = get_before decls
[Ast.WParen
(lbrace
,index)] in
450 let (bd
,_
) = get_before body dea
in
451 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
452 | _
-> failwith
"not supported"
454 let rec get_after sl
a =
455 match Ast.unwrap sl
with
461 let (sl
,sla
) = loop sl
in
462 let (e
,ea
) = get_after_e e sla
in
464 let (l,a) = loop x
in
465 (Ast.rewrap sl
(Ast.DOTS
(l)),a)
466 | Ast.CIRCLES
(x
) -> failwith
"not supported"
467 | Ast.STARS
(x
) -> failwith
"not supported"
469 and get_after_e s
a =
470 match Ast.unwrap s
with
471 Ast.Dots
(d,Ast.NoWhen
,t
) ->
472 (Ast.rewrap s
(Ast.Dots
(d,Ast.NoWhen
,a@t
)),a)
473 | Ast.Dots
(d,Ast.WhenNot w
,t
) ->
474 let (w
,_
) = get_after w
[] in
475 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenNot w
,a@t
)),a)
476 | Ast.Dots
(d,Ast.WhenAlways w
,t
) ->
477 let (w
,_
) = get_after_e w
[] in
478 (Ast.rewrap s
(Ast.Dots
(d,Ast.WhenAlways w
,a@t
)),a)
479 | Ast.Nest
(stmt_dots
,w
,t
) ->
480 let (w
,_
) = List.split
(List.map
(function s
-> get_after s
[]) w
) in
481 let (sd
,_
) = get_after stmt_dots
a in
487 Unify_ast.unify_statement_dots
488 (Ast.rewrap s
(Ast.DOTS
([a]))) stmt_dots
in
490 Unify_ast.MAYBE
-> false
492 | Ast.Other_dots
a ->
493 let unifies = Unify_ast.unify_statement_dots
a stmt_dots
in
495 Unify_ast.MAYBE
-> false
499 (Ast.rewrap s
(Ast.Nest
(sd
,w
,a@t
)),[Ast.Other_dots stmt_dots
])
500 | Ast.Disj
(stmt_dots_list
) ->
502 List.split
(List.map
(function e
-> get_after e
a) stmt_dots_list
) in
503 (Ast.rewrap s
(Ast.Disj
(dsl
)),List.fold_left
Common.union_set
[] dsla
)
505 (match Ast.unwrap ast
with
506 Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots _
,i
) ->
507 (* check after information for metavar optimization *)
508 (* if the error is not desired, could just return [], then
509 the optimization (check for EF) won't take place *)
513 (match Ast.unwrap x
with
514 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
516 "dots/nest not allowed before and after stmt metavar"
518 | Ast.Other_dots x
->
519 (match Ast.undots x
with
521 (match Ast.unwrap x
with
522 Ast.Dots
(_
,_
,_
) | Ast.Nest
(_
,_
,_
) ->
524 ("dots/nest not allowed before and after stmt "^
533 (Ast.MetaStmt
(nm
,Ast.SequencibleAfterDots
a,i
)))),[])
534 | Ast.MetaStmt
(_
,_
,_
) -> (s
,[])
535 | _
-> (s
,[Ast.Other s
]))
536 | Ast.Seq
(lbrace
,decls
,dots,body
,rbrace
) ->
537 let index = count_nested_braces s
in
538 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
539 let (de
,_
) = get_after decls bda
in
540 (Ast.rewrap s
(Ast.Seq
(lbrace
,de
,dots,bd
,rbrace
)),
541 [Ast.WParen
(lbrace
,index)])
542 | Ast.IfThen
(ifheader
,branch
,aft
) ->
543 let (br
,_
) = get_after_e branch
a in
544 (Ast.rewrap s
(Ast.IfThen
(ifheader
,br
,aft
)),[Ast.Other s
])
545 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
546 let (br1
,_
) = get_after_e branch1
a in
547 let (br2
,_
) = get_after_e branch2
a in
548 (Ast.rewrap s
(Ast.IfThenElse
(ifheader
,br1
,els
,br2
,aft
)),[Ast.Other s
])
549 | Ast.While
(header
,body
,aft
) ->
550 let (bd
,_
) = get_after_e body
a in
551 (Ast.rewrap s
(Ast.While
(header
,bd
,aft
)),[Ast.Other s
])
552 | Ast.For
(header
,body
,aft
) ->
553 let (bd
,_
) = get_after_e body
a in
554 (Ast.rewrap s
(Ast.For
(header
,bd
,aft
)),[Ast.Other s
])
555 | Ast.FunDecl
(header
,lbrace
,decls
,dots,body
,rbrace
) ->
556 let index = count_nested_braces s
in
557 let (bd
,bda
) = get_after body
[Ast.WParen
(rbrace
,index)] in
558 let (de
,_
) = get_after decls bda
in
559 (Ast.rewrap s
(Ast.FunDecl
(header
,lbrace
,de
,dots,bd
,rbrace
)),[])
560 | _
-> failwith
"not supported"
563 let preprocess_dots sl
=
564 let (sl
,_
) = get_before sl
[] in
565 let (sl
,_
) = get_after sl
[] in
568 let preprocess_dots_e sl
=
569 let (sl
,_
) = get_before_e sl
[] in
570 let (sl
,_
) = get_after_e sl
[] in
573 (* --------------------------------------------------------------------- *)
574 (* the main translation loop *)
576 let decl_to_not_decl n
dots stmt
make_match f
=
581 let md = Ast.make_meta_decl
"_d" (Ast.CONTEXT
(Ast.NOTHING
)) in
582 Ast.rewrap
md (Ast.Decl
md) in
583 wrapAU n
(make_match de,
584 wrap n
(CTL.And
(wrap n
(CTL.Not
(make_match de)), f
)))
586 let rec statement_list stmt_list used_after after quantified guard
=
587 let n = if !line_numbers then Ast.get_line stmt_list
else 0 in
588 match Ast.unwrap stmt_list
with
590 let rec loop quantified
= function
591 ([],_
) -> (match after
with After f
-> f
| _
-> wrap n CTL.True
)
592 | ([e
],_
) -> statement e used_after after quantified guard
594 let shared = intersectll fv fvs
in
595 let unqshared = get_unquantified quantified
shared in
596 let new_quantified = Common.union_set
unqshared quantified
in
598 (statement e used_after
(After
(loop new_quantified (sl
,fvs
)))
599 new_quantified guard
)
600 | _
-> failwith
"not possible" in
601 loop quantified
(x
,List.map
Ast.get_fvs x
)
602 | Ast.CIRCLES
(x
) -> failwith
"not supported"
603 | Ast.STARS
(x
) -> failwith
"not supported"
605 and statement stmt used_after after quantified guard
=
607 let n = if !line_numbers then Ast.get_line stmt
else 0 in
608 let wrapExists = wrapExists n in
609 let wrapAnd = wrapAnd n in
610 let wrapOr = wrapOr n in
611 let wrapSeqOr = wrapSeqOr n in
612 let wrapAU = wrapAU n in
613 let wrapAX = wrapAX n in
614 let wrapBackAX = wrapBackAX n in
615 let wrapEX = wrapEX n in
616 let wrapBackEX = wrapBackEX n in
617 let wrapAG = wrapAG n in
618 let wrapAF = wrapAF n in
619 let wrapEF = wrapEF n in
620 let wrapNot = wrapNot n in
621 let wrapPred = wrapPred n in
622 let make_seq = make_seq n in
623 let make_seq_after2 = make_seq_after2 n in
624 let make_seq_after = make_seq_after n in
625 let and_opt = and_opt n in
626 let quantify = quantify n in
627 let make_match = make_match n guard used_after
in
628 let make_raw_match = make_raw_match n in
630 let make_meta_rule_elem d =
631 let nm = fresh_metavar() in
632 Ast.make_meta_rule_elem nm d in
634 match Ast.unwrap stmt
with
636 (match Ast.unwrap ast
with
637 Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,_
)) as d)),seqible
,_
)
638 | Ast.MetaStmt
((s
,i
,(Ast.CONTEXT
(Ast.AFTER
(_
)) as d)),seqible
,_
) ->
639 let label_var = (*fresh_label_var*) "_lab" in
640 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
642 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
643 let matcher d = make_match (make_meta_rule_elem d) in
644 let full_metamatch = matcher d in
645 let first_metamatch =
648 Ast.CONTEXT
(Ast.BEFOREAFTER
(bef
,_
)) ->
649 Ast.CONTEXT
(Ast.BEFORE
(bef
))
650 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
651 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
652 let middle_metamatch =
655 Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
656 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
660 Ast.CONTEXT
(Ast.BEFOREAFTER
(_
,aft
)) ->
661 Ast.CONTEXT
(Ast.AFTER
(aft
))
662 | Ast.CONTEXT
(_
) -> d
663 | Ast.MINUS
(_
) | Ast.PLUS
-> failwith
"not possible") in
667 [full_metamatch; and_opt (wrapNot(prelabel_pred)) after
] in
671 wrapAU(middle_metamatch,
673 [wrapAnd(last_metamatch,label_pred);
674 and_opt (wrapNot(prelabel_pred)) after
])] in
677 f
(wrapAnd(make_raw_match ast
,
678 wrapOr(left_or,right_or)))) in
681 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
682 quantify (label_var::get_unquantified quantified
[s
])
685 (wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
686 | Ast.SequencibleAfterDots
l ->
688 List.map
(process_bef_aft Tail quantified used_after
n) l in
690 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
691 (List.hd
afts) (List.tl
afts) in
692 quantify (label_var::get_unquantified quantified
[s
])
693 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
696 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
697 | Ast.NotSequencible
->
698 quantify (label_var::get_unquantified quantified
[s
]) (body id))
700 | Ast.MetaStmt
((s
,i
,d),seqible
,_
) ->
701 let label_var = (*fresh_label_var*) "_lab" in
702 let label_pred = wrapPred(Lib_engine.Label
(label_var),CTL.Control
) in
704 wrapPred(Lib_engine.PrefixLabel
(label_var),CTL.Control
) in
705 let matcher d = make_match (make_meta_rule_elem d) in
706 let first_metamatch = matcher d in
710 Ast.MINUS
(_
) -> Ast.MINUS
([])
711 | Ast.CONTEXT
(_
) -> Ast.CONTEXT
(Ast.NOTHING
)
712 | Ast.PLUS
-> failwith
"not possible") in
713 (* first_nodea and first_nodeb are separated here and above to
714 improve let sharing - only first_nodea is unique to this site *)
715 let first_nodeb = first_metamatch in
716 let rest_nodes = wrapAnd(rest_metamatch,prelabel_pred) in
717 let last_node = and_opt (wrapNot(prelabel_pred)) after
in
724 [first_nodeb; wrapAU(rest_nodes,last_node)])))) in
726 Ast.Sequencible
| Ast.SequencibleAfterDots
[] ->
727 quantify (label_var::get_unquantified quantified
[s
])
729 (function x
-> wrapAnd(wrapNot(wrapBackAX(label_pred)),x
)))
730 | Ast.SequencibleAfterDots
l ->
732 List.map
(process_bef_aft Tail quantified used_after
n) l in
734 List.fold_left
(function x
-> function y
-> wrapOr(x
,y
))
735 (List.hd
afts) (List.tl
afts) in
736 quantify (label_var::get_unquantified quantified
[s
])
737 (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))),
740 wrapAnd(wrapNot(wrapBackAX(label_pred)),x
))))
741 | Ast.NotSequencible
->
742 quantify (label_var::get_unquantified quantified
[s
])
743 (body (function x
-> x
)))
745 let stmt_fvs = Ast.get_fvs stmt
in
746 let fvs = get_unquantified quantified
stmt_fvs in
747 let between_dots = Ast.get_dots_bef_aft stmt
in
748 let term = make_match ast
in
750 match between_dots with
751 Ast.BetweenDots brace_term
->
752 (match Ast.unwrap brace_term
with
753 Ast.Atomic
(brace_ast
) ->
758 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
760 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
762 make_match brace_ast
) in
768 (wrapPred(Lib_engine.TrueBranch
,CTL.Control
)),
770 (wrapBackEX(wrapPred(Lib_engine.FalseBranch
,
774 | _
-> failwith
"not possible")
775 | Ast.NoDots
-> term in
776 make_seq_after (quantify fvs term) after
)
777 | Ast.Seq
(lbrace
,decls
,dots,body,rbrace
) ->
778 let (lbfvs
,b1fvs
,_
,b2fvs
,_
,b3fvs
,rbfvs
) =
780 (Ast.get_fvs lbrace
) (Ast.get_fvs decls
)
781 (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
782 let v = count_nested_braces stmt
in
783 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
785 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
787 wrapAnd(quantify rbfvs
(make_match rbrace
),paren_pred) in
788 let new_quantified2 =
789 Common.union_set b1fvs
(Common.union_set b2fvs quantified
) in
790 let new_quantified3 = Common.union_set b3fvs
new_quantified2 in
796 (statement_list decls used_after
798 (decl_to_not_decl n dots stmt
make_match
800 (statement_list body used_after
801 (After
(make_seq_after end_brace after
))
802 new_quantified3 guard
))))
803 new_quantified2 guard
)]))
804 | Ast.IfThen
(ifheader
,branch
,aft
) ->
806 (* "if (test) thn" becomes:
807 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
809 "if (test) thn; after" becomes:
810 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
816 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch
) in
817 let new_quantified = Common.union_set bfvs quantified
in
819 let if_header = quantify efvs
(make_match ifheader
) in
820 (* then branch and after *)
823 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
824 statement branch used_after
(a2n after
) new_quantified guard
] in
825 let fall_branch = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
826 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
827 let (aft_needed
,after_branch
) =
829 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
832 make_seq_after after_pred
834 (make_seq_after (make_match (make_meta_rule_elem aft
))
836 let or_cases = wrapOr(true_branch,wrapOr(fall_branch,after_branch
)) in
838 (match (after
,aft_needed
) with
839 (After _
,_
) (* pattern doesn't end here *)
840 | (_
,true) (* + code added after *) ->
842 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
843 | _
-> quantify bfvs
(wrapAnd(if_header, wrapAX or_cases)))
845 | Ast.IfThenElse
(ifheader
,branch1
,els
,branch2
,aft
) ->
847 (* "if (test) thn else els" becomes:
848 if(test) & AX((TrueBranch & AX thn) v
849 (FalseBranch & AX (else & AX els)) v After)
852 "if (test) thn else els; after" becomes:
853 if(test) & AX((TrueBranch & AX thn) v
854 (FalseBranch & AX (else & AX els)) v
855 (After & AXAX after))
860 Note that we rely on the well-formedness of C programs. For example, we
861 do not use EX to check that there is at least one then branch, because
862 there is always one. And we do not check that there is only one then or
863 else branch, because these again are always the case in a well-formed C
866 let (e1fvs
,b1fvs
,s1fvs
) =
867 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch1
) in
868 let (e2fvs
,b2fvs
,s2fvs
) =
869 seq_fvs2 quantified
(Ast.get_fvs ifheader
) (Ast.get_fvs branch2
) in
872 (Common.union_set b1fvs b2fvs
)
873 (Common.inter_set s1fvs s2fvs
) in
874 let exponlyfvs = Common.inter_set e1fvs e2fvs
in
875 let new_quantified = Common.union_set
bothfvs quantified
in
877 let if_header = quantify exponlyfvs (make_match ifheader
) in
878 (* then and else branches *)
881 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
882 statement branch1 used_after
(a2n after
) new_quantified guard
] in
883 let false_pred = wrapPred(Lib_engine.FalseBranch
,CTL.Control
) in
886 [false_pred; make_match els
;
887 statement branch2 used_after
(a2n after
) new_quantified guard
] in
888 let after_pred = wrapPred(Lib_engine.After
,CTL.Control
) in
889 let (aft_needed
,after_branch
) =
891 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
894 make_seq_after after_pred
896 (make_seq_after (make_match (make_meta_rule_elem aft
))
898 let or_cases = wrapOr(true_branch,wrapOr(false_branch,after_branch
)) in
900 (match (after
,aft_needed
) with
901 (After _
,_
) (* pattern doesn't end here *)
902 | (_
,true) (* + code added after *) ->
906 wrapAnd(wrapAX or_cases,
907 wrapAnd(wrapEX false_pred,wrapEX after_pred))))
910 (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX false_pred))))
912 | Ast.While
(header
,body,aft
) | Ast.For
(header
,body,aft
) ->
913 (* the translation in this case is similar to that of an if with no else *)
916 seq_fvs2 quantified
(Ast.get_fvs header
) (Ast.get_fvs
body) in
917 let new_quantified = Common.union_set bfvs quantified
in
919 let header = quantify efvs
(make_match header) in
922 [wrapPred(Lib_engine.TrueBranch
,CTL.Control
);
923 statement
body used_after
(a2n after
) new_quantified guard
] in
924 let after_pred = wrapPred(Lib_engine.FallThrough
,CTL.Control
) in
925 let (aft_needed
,after_branch
) =
927 Ast.CONTEXT
(Ast.NOTHING
) -> (false,make_seq_after2 after_pred after
)
930 make_seq_after after_pred
932 (make_seq_after (make_match (make_meta_rule_elem aft
))
934 let or_cases = wrapOr(body,after_branch
) in
936 (match (after
,aft_needed
) with
937 (After _
,_
) (* pattern doesn't end here *)
938 | (_
,true) (* + code added after *) ->
940 (wrapAnd (header, wrapAnd(wrapAX or_cases, wrapEX after_pred)))
941 | _
-> quantify bfvs
(wrapAnd(header, wrapAX or_cases)))
943 | Ast.Disj
(stmt_dots_list
) ->
946 (function x
-> statement_list x used_after after quantified guard
)
948 let rec loop = function
949 [] -> wrap n CTL.True
951 | x
::xs
-> wrapSeqOr(x
,loop xs
) in
955 statement_list e used_after (a2n after) quantified true in
958 (function rest -> function cur -> wrapAnd(wrapNot(do_one cur),rest))
960 let process_one nots cur =
961 match Ast.unwrap cur with
963 let on = List.map (function x -> Ast.OrOther_dots x) nots in
964 (match Ast.unwrap x with
968 Printf.printf "a not\n";
969 Pretty_print_cocci.statement_dots x)
973 (Ast.DOTS((Ast.rewrap x (Ast.Dots(d,w,on@t)))::xs)) in
974 statement_list cur used_after after quantified guard
975 | Ast.Nest(sd,w,t) ->
978 (Ast.DOTS((Ast.rewrap x (Ast.Nest(sd,w,on@t)))::xs)) in
979 statement_list cur used_after after quantified guard
982 (statement_list cur used_after after quantified guard))
985 (statement_list cur used_after after quantified guard)
986 | _ -> failwith "CIRCLES, STARS not supported" in
987 let rec loop after = function
988 [] -> failwith "disj shouldn't be empty" (*wrap n CTL.False*)
989 | [(nots
,cur)] -> process_one nots
cur
990 | (nots
,cur)::rest
-> wrapOr(process_one nots
cur, loop after rest
) in
991 loop after
(preprocess_disj stmt_dots_list
)
993 | Ast.Nest
(stmt_dots
,whencode
,befaft
) ->
995 statement_list stmt_dots used_after
(a2n after
) quantified guard
in
1000 statement_list sl used_after
(a2n after
) quantified
true)
1002 List.fold_left
(function rest
-> function cur -> wrapOr(cur,rest
))
1003 (statement_list stmt_dots used_after
(a2n after
) quantified
true)
1005 (match (after
,guard
&&(whencode
=[])) with
1008 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1010 [] -> wrapAF(wrapOr(a,aftret))
1015 (function rest
-> function cur -> wrapOr(cur,rest
))
1017 wrapAU(left,wrapOr(a,aftret)))
1018 | (After
a,false) ->
1019 let left = wrapOr(dots_pattern,wrapNot udots_pattern) in
1021 List.map
(process_bef_aft after quantified used_after
n) befaft
in
1029 (function rest
-> function cur -> wrapOr(cur,rest
))
1032 wrapAU(left,wrapOr(a,aftret))
1033 | (_
,true) -> wrap n CTL.True
1034 | (_
,false) -> wrapAG(wrapOr(dots_pattern,wrapNot udots_pattern)))
1035 | Ast.Dots
((_
,i
,d),whencodes,t
) ->
1039 (* no need for the fresh metavar, but ... is a bit weird as a
1041 Some
(make_match (make_meta_rule_elem d))
1044 (match whencodes with
1046 | Ast.WhenNot
whencodes ->
1048 (statement_list whencodes used_after
(a2n after
) quantified
1050 | Ast.WhenAlways s
->
1051 [statement s used_after
(a2n after
) quantified
true]) @
1053 (List.map
(process_bef_aft after quantified used_after
n) t
)) in
1055 match whencodes with
1060 (function rest
-> function cur -> wrapAnd(cur,rest
))
1063 match (dot_code,phi2) with (* add - on dots, if any *)
1065 | (Some dotcode
,None
) -> Some dotcode
1066 | (None
,Some whencode
) -> Some whencode
1067 | (Some dotcode
,Some whencode
) -> Some
(wrapAnd (dotcode
,whencode
)) in
1068 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1069 (* add in the after code to make the result *)
1070 (match (after
,phi3) with
1071 (Tail
,Some whencode
) -> wrapAU(whencode
,wrapOr(exit,aftret))
1072 | (Tail
,None
) -> wrapAF(wrapOr(exit,aftret))
1073 | (After f
,Some whencode
) | (Guard f
,Some whencode
) ->
1074 wrapAU(whencode
,wrapOr(f
,aftret))
1075 | (After f
,None
) | (Guard f
,None
) -> wrapAF(wrapOr(f
,aftret)))
1076 | Ast.FunDecl
(header,lbrace
,decls
,dots,body,rbrace
) ->
1077 let (hfvs
,b1fvs
,lbfvs
,b2fvs
,_
,b3fvs
,_
,b4fvs
,rbfvs
) =
1078 seq_fvs5 quantified
(Ast.get_fvs
header) (Ast.get_fvs lbrace
)
1079 (Ast.get_fvs decls
) (Ast.get_fvs
body) (Ast.get_fvs rbrace
) in
1080 let function_header = quantify hfvs
(make_match header) in
1081 let v = count_nested_braces stmt
in
1082 let paren_pred = wrapPred(Lib_engine.Paren
v,CTL.Control
) in
1084 wrapAnd(quantify lbfvs
(make_match lbrace
),paren_pred) in
1086 let stripped_rbrace =
1087 match Ast.unwrap rbrace
with
1088 Ast.SeqEnd
((data
,info
,_
)) ->
1090 (Ast.SeqEnd
((data
,info
,Ast.CONTEXT
(Ast.NOTHING
))))
1091 | _
-> failwith
"unexpected close brace" in
1092 let exit = wrap n (CTL.Pred
(Lib_engine.Exit
,CTL.Control
)) in
1093 let errorexit = wrap n (CTL.Pred
(Lib_engine.ErrorExit
,CTL.Control
)) in
1094 wrapAnd(quantify rbfvs
(make_match rbrace
),
1095 wrapAU(make_match stripped_rbrace,
1096 wrapOr(exit,errorexit))) in
1097 let new_quantified3 =
1098 Common.union_set b1fvs
1099 (Common.union_set b2fvs
(Common.union_set b3fvs quantified
)) in
1100 let new_quantified4 = Common.union_set b4fvs
new_quantified3 in
1110 (statement_list decls used_after
1112 (decl_to_not_decl n dots stmt
1115 (statement_list body used_after
1117 (make_seq_after end_brace after
))
1118 new_quantified4 guard
))))
1119 new_quantified3 guard
)])))])
1120 | Ast.OptStm
(stm
) ->
1121 failwith
"OptStm should have been compiled away\n";
1122 | Ast.UniqueStm
(stm
) ->
1123 failwith
"arities not yet supported"
1124 | Ast.MultiStm
(stm
) ->
1125 failwith
"arities not yet supported"
1126 | _
-> failwith
"not supported"
1128 and process_bef_aft after quantified used_after ln
= function
1129 Ast.WParen
(re
,n) ->
1130 let paren_pred = wrapPred ln
(Lib_engine.Paren
n,CTL.Control
) in
1131 wrapAnd ln
(make_raw_match ln re
,paren_pred)
1132 | Ast.Other s
-> statement s used_after
(a2n after
) quantified
true
1133 | Ast.Other_dots
d -> statement_list d used_after
(a2n after
) quantified
true
1134 | Ast.OrOther_dots
d -> statement_list d used_after Tail quantified
true
1136 (* Returns a triple for each disj element. The first element of the triple is
1137 Some v if the triple element needs a name, and None otherwise. The second
1138 element is a list of names whose negations should be conjuncted with the
1139 term. The third element is the original term *)
1140 and (preprocess_disj
:
1141 Ast.statement
Ast.dots list
->
1142 (Ast.statement
Ast.dots list
* Ast.statement
Ast.dots) list
) =
1148 List.map
(function r
-> Unify_ast.unify_statement_dots
cur r
) rest
in
1149 let processed = preprocess_disj rest
in
1150 if List.exists
(function Unify_ast.MAYBE
-> true | _
-> false) template
1154 (function ((nots,r
) as x
) ->
1155 function Unify_ast.MAYBE
-> (cur::nots,r
) | Unify_ast.NO
-> x
)
1157 else ([], cur) :: processed
1159 (* --------------------------------------------------------------------- *)
1161 Phase 1: Use a hash table to identify formulas that appear more than once.
1162 Phase 2: Replace terms by variables.
1163 Phase 3: Drop lets to the point as close as possible to the uses of their
1167 (Hashtbl.create
(50) :
1168 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1169 int ref (* count *) * string ref (* name *) * bool ref (* processed *))
1174 try Hashtbl.find
formula_table phi
1176 let c = (ref 0,ref "",ref false) in
1177 Hashtbl.add
formula_table phi
c;
1181 let rec collect_duplicates f
=
1183 match CTL.unwrap f
with
1187 | CTL.Not
(phi
) -> collect_duplicates phi
1188 | CTL.Exists
(v,phi
) -> collect_duplicates phi
1189 | CTL.And
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1190 | CTL.Or
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1191 | CTL.SeqOr
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1192 | CTL.Implies
(phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1193 | CTL.AF
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1194 | CTL.AX
(_
,phi
) -> collect_duplicates phi
1195 | CTL.AG
(_
,phi
) -> collect_duplicates phi
1196 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1197 collect_duplicates phi1
; collect_duplicates phi2;
1198 collect_duplicates phi3; collect_duplicates phi4
1199 | CTL.EF
(_
,phi
) -> collect_duplicates phi
1200 | CTL.EX
(_
,phi
) -> collect_duplicates phi
1201 | CTL.EG
(_
,phi
) -> collect_duplicates phi
1202 | CTL.EU
(_
,phi1
,phi2) -> collect_duplicates phi1
; collect_duplicates phi2
1203 | CTL.Uncheck
(phi
) -> collect_duplicates phi
1204 | _
-> failwith
"not possible"
1206 let assign_variables _
=
1208 (function formula
->
1209 function (cell
,str
,_
) -> if !cell
> 1 then str
:= fresh_let_var())
1212 let rec replace_formulas dec f
=
1213 let (ct
,name
,treated
) = Hashtbl.find
formula_table f
in
1214 let real_ct = !ct
- dec
in
1221 let (acc
,new_f
) = replace_subformulas
(dec
+ (real_ct - 1)) f
in
1222 ((!name
,new_f
) :: acc
, CTL.rewrap f
(CTL.Ref
!name
))
1224 else ([],CTL.rewrap f
(CTL.Ref
!name
))
1225 else replace_subformulas dec f
1227 and replace_subformulas dec f
=
1228 match CTL.unwrap f
with
1230 | CTL.True
-> ([],f
)
1231 | CTL.Pred
(p
) -> ([],f
)
1233 let (acc
,new_phi
) = replace_formulas dec phi
in
1234 (acc
,CTL.rewrap f
(CTL.Not
(new_phi
)))
1235 | CTL.Exists
(v,phi
) ->
1236 let (acc
,new_phi
) = replace_formulas dec phi
in
1237 (acc
,CTL.rewrap f
(CTL.Exists
(v,new_phi
)))
1238 | CTL.And
(phi1
,phi2) ->
1239 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1240 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1241 (acc1
@acc2
,CTL.rewrap f
(CTL.And
(new_phi1
,new_phi2
)))
1242 | CTL.Or
(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.Or
(new_phi1
,new_phi2
)))
1246 | CTL.SeqOr
(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.SeqOr
(new_phi1
,new_phi2
)))
1250 | CTL.Implies
(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.Implies
(new_phi1
,new_phi2
)))
1254 | CTL.AF
(dir
,phi1
,phi2) ->
1255 let (acc
,new_phi1
) = replace_formulas dec phi1
in
1256 let (acc
,new_phi2
) = replace_formulas dec
phi2 in
1257 (acc
,CTL.rewrap f
(CTL.AF
(dir
,new_phi1
,new_phi2
)))
1258 | CTL.AX
(dir
,phi
) ->
1259 let (acc
,new_phi
) = replace_formulas dec phi
in
1260 (acc
,CTL.rewrap f
(CTL.AX
(dir
,new_phi
)))
1261 | CTL.AG
(dir
,phi
) ->
1262 let (acc
,new_phi
) = replace_formulas dec phi
in
1263 (acc
,CTL.rewrap f
(CTL.AG
(dir
,new_phi
)))
1264 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1265 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1266 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1267 let (acc3
,new_phi3
) = replace_formulas dec
phi3 in
1268 let (acc4
,new_phi4
) = replace_formulas dec phi4
in
1269 (acc1
@acc2
@acc3
@acc4
,
1270 CTL.rewrap f
(CTL.AU
(dir
,new_phi1
,new_phi2
,new_phi3
,new_phi4
)))
1271 | CTL.EF
(dir
,phi
) ->
1272 let (acc
,new_phi
) = replace_formulas dec phi
in
1273 (acc
,CTL.rewrap f
(CTL.EF
(dir
,new_phi
)))
1274 | CTL.EX
(dir
,phi
) ->
1275 let (acc
,new_phi
) = replace_formulas dec phi
in
1276 (acc
,CTL.rewrap f
(CTL.EX
(dir
,new_phi
)))
1277 | CTL.EG
(dir
,phi
) ->
1278 let (acc
,new_phi
) = replace_formulas dec phi
in
1279 (acc
,CTL.rewrap f
(CTL.EG
(dir
,new_phi
)))
1280 | CTL.EU
(dir
,phi1
,phi2) ->
1281 let (acc1
,new_phi1
) = replace_formulas dec phi1
in
1282 let (acc2
,new_phi2
) = replace_formulas dec
phi2 in
1283 (acc1
@acc2
,CTL.rewrap f
(CTL.EU
(dir
,new_phi1
,new_phi2
)))
1284 | _
-> failwith
"not possible"
1287 (Hashtbl.create
(50) :
1288 ((cocci_predicate
,string,Wrapper_ctl.info
) CTL.generic_ctl
,
1289 string list
(* fvs *) *
1290 string list
(* intersection of fvs of subterms *))
1294 try let (fvs,_
) = Hashtbl.find
ctlfv_table f
in fvs
1296 let ((fvs,_
) as res
) =
1297 match CTL.unwrap f
with
1298 CTL.False
| CTL.True
| CTL.Pred
(_
) -> ([],[])
1299 | CTL.Not
(phi
) | CTL.Exists
(_
,phi
)
1300 | CTL.AX
(_
,phi
) | CTL.AG
(_
,phi
)
1301 | CTL.EF
(_
,phi
) | CTL.EX
(_
,phi
) | CTL.EG
(_
,phi
) -> (ctl_fvs phi
,[])
1302 | CTL.AU
(_
,phi1
,phi2,phi3,phi4
) ->
1303 let phi1fvs = ctl_fvs phi1
in
1304 let phi2fvs = ctl_fvs phi2 in
1305 (* phi3 has the same fvs as phi1 and phi4 as phi2 *)
1306 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1307 | CTL.And
(phi1
,phi2) | CTL.Or
(phi1
,phi2) | CTL.SeqOr
(phi1
,phi2)
1308 | CTL.Implies
(phi1
,phi2) | CTL.AF
(_
,phi1
,phi2) | CTL.EU
(_
,phi1
,phi2) ->
1309 let phi1fvs = ctl_fvs phi1
in
1310 let phi2fvs = ctl_fvs phi2 in
1311 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs)
1312 | CTL.Ref
(v) -> ([v],[v])
1313 | CTL.Let
(v,term,body) ->
1314 let phi1fvs = ctl_fvs term in
1315 let phi2fvs = Common.minus_set
(ctl_fvs body) [v] in
1316 (Common.union_set
phi1fvs phi2fvs,intersect phi1fvs phi2fvs) in
1317 Hashtbl.add
ctlfv_table f res
;
1320 let rev_order_bindings b
=
1323 (function (nm,term) ->
1324 let (fvs,_
) = Hashtbl.find
ctlfv_table term in (nm,fvs,term))
1326 let rec loop bound
= function
1329 let (now_bound
,still_unbound
) =
1330 List.partition
(function (_
,fvs,_
) -> subset fvs bound
)
1332 let get_names = List.map
(function (x
,_
,_
) -> x
) in
1333 now_bound
@ (loop ((get_names now_bound
) @ bound
) still_unbound
) in
1336 let drop_bindings b f
= (* innermost bindings first in b *)
1337 let process_binary f ffvs inter
nm term fail
=
1338 if List.mem
nm inter
1339 then CTL.rewrap f
(CTL.Let
(nm,term,f
))
1340 else CTL.rewrap f
(fail
()) in
1342 let _ = ctl_fvs f
in Hashtbl.find
ctlfv_table f
in
1343 let rec drop_one nm term f
=
1344 match CTL.unwrap f
with
1348 | CTL.Not
(phi
) -> CTL.rewrap f
(CTL.Not
(drop_one nm term phi
))
1349 | CTL.Exists
(v,phi
) -> CTL.rewrap f
(CTL.Exists
(v,drop_one nm term phi
))
1350 | CTL.And
(phi1
,phi2) ->
1351 let (ffvs
,inter
) = find_fvs f
in
1352 process_binary f ffvs inter
nm term
1353 (function _ -> CTL.And
(drop_one nm term phi1
,drop_one nm term phi2))
1354 | CTL.Or
(phi1
,phi2) ->
1355 let (ffvs
,inter
) = find_fvs f
in
1356 process_binary f ffvs inter
nm term
1357 (function _ -> CTL.Or
(drop_one nm term phi1
,drop_one nm term phi2))
1358 | CTL.SeqOr
(phi1
,phi2) ->
1359 let (ffvs
,inter
) = find_fvs f
in
1360 process_binary f ffvs inter
nm term
1362 CTL.SeqOr
(drop_one nm term phi1
,drop_one nm term phi2))
1363 | CTL.Implies
(phi1
,phi2) ->
1364 let (ffvs
,inter
) = find_fvs f
in
1365 process_binary f ffvs inter
nm term
1367 CTL.Implies
(drop_one nm term phi1
,drop_one nm term phi2))
1368 | CTL.AF
(dir
,phi1
,phi2) ->
1369 let (ffvs
,inter
) = find_fvs f
in
1370 process_binary f ffvs inter
nm term
1372 CTL.AF
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1373 | CTL.AX
(dir
,phi
) ->
1374 CTL.rewrap f
(CTL.AX
(dir
,drop_one nm term phi
))
1375 | CTL.AG
(dir
,phi
) -> CTL.rewrap f
(CTL.AG
(dir
,drop_one nm term phi
))
1376 | CTL.AU
(dir
,phi1
,phi2,phi3,phi4
) ->
1377 let (ffvs
,inter
) = find_fvs f
in
1378 process_binary f ffvs inter
nm term
1380 CTL.AU
(dir
,drop_one nm term phi1
,drop_one nm term phi2,
1381 drop_one nm term phi3,drop_one nm term phi4
))
1382 | CTL.EF
(dir
,phi
) -> CTL.rewrap f
(CTL.EF
(dir
,drop_one nm term phi
))
1383 | CTL.EX
(dir
,phi
) ->
1384 CTL.rewrap f
(CTL.EX
(dir
,drop_one nm term phi
))
1385 | CTL.EG
(dir
,phi
) -> CTL.rewrap f
(CTL.EG
(dir
,drop_one nm term phi
))
1386 | CTL.EU
(dir
,phi1
,phi2) ->
1387 let (ffvs
,inter
) = find_fvs f
in
1388 process_binary f ffvs inter
nm term
1390 CTL.EU
(dir
,drop_one nm term phi1
,drop_one nm term phi2))
1391 | (CTL.Ref
(v) as x
) -> process_binary f
[v] [v] nm term (function _ -> x
)
1392 | CTL.Let
(v,term1
,body) ->
1393 let (ffvs
,inter
) = find_fvs f
in
1394 process_binary f ffvs inter
nm term
1396 CTL.Let
(v,drop_one nm term term1
,drop_one nm term body)) in
1398 (function processed -> function (nm,_,term) -> drop_one nm term processed)
1402 failwith
"this code should not be used!!!"(*;
1403 Hashtbl.clear formula_table;
1404 Hashtbl.clear ctlfv_table;
1405 (* create a count of the number of occurrences of each subformula *)
1406 collect_duplicates f
;
1407 (* give names to things that appear more than once *)
1409 (* replace duplicated formulas by their variables *)
1410 let (bindings
,new_f
) = replace_formulas 0 f
in
1411 (* collect fvs of terms in bindings and new_f *)
1412 List.iter
(function f
-> let _ = ctl_fvs f
in ())
1413 (new_f
::(List.map
(function (_,term) -> term) bindings
));
1414 (* sort bindings with uses before defs *)
1415 let bindings = rev_order_bindings bindings in
1416 (* insert bindings as lets into the formula *)
1417 let res = drop_bindings bindings new_f
in
1420 (* --------------------------------------------------------------------- *)
1421 (* Function declaration *)
1423 let top_level used_after t
=
1424 match Ast.unwrap t
with
1425 Ast.DECL
(decl
) -> failwith
"not supported decl"
1426 | Ast.INCLUDE
(inc
,s
) ->
1427 (* no indication of whether inc or s is modified *)
1428 wrap 0 (CTL.Pred
((Lib_engine.Include
(inc
,s
),CTL.Control
)))
1429 | Ast.FILEINFO
(old_file
,new_file
) -> failwith
"not supported fileinfo"
1430 | Ast.FUNCTION
(stmt
) ->
1431 (*Printf.printf "orig\n";
1432 Pretty_print_cocci.statement "" stmt;
1433 Format.print_newline();*)
1434 let unopt = elim_opt.V.rebuilder_statement stmt
in
1435 (*Printf.printf "unopt\n";
1436 Pretty_print_cocci.statement "" unopt;
1437 Format.print_newline();*)
1438 let unopt = preprocess_dots_e unopt in
1440 (statement
unopt used_after Tail
[] false)
1441 | Ast.CODE
(stmt_dots
) ->
1442 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots
in
1443 let unopt = preprocess_dots unopt in
1445 (statement_list unopt used_after Tail
[] false)
1446 | Ast.ERRORWORDS
(exps
) -> failwith
"not supported errorwords"
1448 (* --------------------------------------------------------------------- *)
1452 let bind x y
= x
or y
in
1453 let option_default = false in
1454 let mcode r x
= false in
1455 let statement r k s
=
1456 match Ast.unwrap s
with Ast.Dots
(_,_,_) -> true | _ -> k s
in
1457 let continue r k e
= k e
in
1458 let stop r k e
= false in
1460 V.combiner
bind option_default
1461 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1462 continue continue continue
1463 stop stop stop stop stop stop stop statement continue continue in
1464 res.V.combiner_top_level
1466 (* --------------------------------------------------------------------- *)
1469 let asttoctl l used_after
=
1476 match Ast.unwrap t
with Ast.ERRORWORDS
(exps
) -> false | _ -> true)
1478 List.map2
top_level used_after
l
1480 let pp_cocci_predicate (pred
,modif
) =
1481 Pretty_print_engine.pp_predicate pred
1483 let cocci_predicate_to_string (pred
,modif
) =
1484 Pretty_print_engine.predicate_to_string pred