Release coccinelle-0.1.3
[bpt/coccinelle.git] / engine / asttoctl2.ml
CommitLineData
34e49164
C
1(*
2* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
3* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
4* This file is part of Coccinelle.
5*
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.
9*
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.
14*
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/>.
17*
18* The authors reserve the right to distribute this or future versions of
19* Coccinelle under other licenses.
20*)
21
22
23(* for MINUS and CONTEXT, pos is always None in this file *)
24(*search for require*)
25(* true = don't see all matched nodes, only modified ones *)
26let onlyModif = ref true(*false*)
27
28type ex = Exists | Forall | ReverseForall
29let exists = ref Forall
30
31module Ast = Ast_cocci
32module V = Visitor_ast
33module CTL = Ast_ctl
34
35let warning s = Printf.fprintf stderr "warning: %s\n" s
36
37type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif
38type formula =
39 (cocci_predicate,Ast.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl
40
41let union = Common.union_set
42let intersect l1 l2 = List.filter (function x -> List.mem x l2) l1
43let subset l1 l2 = List.for_all (function x -> List.mem x l2) l1
44
45let foldl1 f xs = List.fold_left f (List.hd xs) (List.tl xs)
46let foldr1 f xs =
47 let xs = List.rev xs in List.fold_left f (List.hd xs) (List.tl xs)
48
49let used_after = ref ([] : Ast.meta_name list)
50let guard_to_strict guard = if guard then CTL.NONSTRICT else CTL.STRICT
51
52let saved = ref ([] : Ast.meta_name list)
53
54let string2var x = ("",x)
55
56(* --------------------------------------------------------------------- *)
57(* predicates matching various nodes in the graph *)
58
59let ctl_and s x y =
60 match (x,y) with
61 (CTL.False,_) | (_,CTL.False) -> CTL.False
62 | (CTL.True,a) | (a,CTL.True) -> a
63 | _ -> CTL.And(s,x,y)
64
65let ctl_or x y =
66 match (x,y) with
67 (CTL.True,_) | (_,CTL.True) -> CTL.True
68 | (CTL.False,a) | (a,CTL.False) -> a
69 | _ -> CTL.Or(x,y)
70
71let ctl_or_fl x y =
72 match (x,y) with
73 (CTL.True,_) | (_,CTL.True) -> CTL.True
74 | (CTL.False,a) | (a,CTL.False) -> a
75 | _ -> CTL.Or(y,x)
76
77let ctl_seqor x y =
78 match (x,y) with
79 (CTL.True,_) | (_,CTL.True) -> CTL.True
80 | (CTL.False,a) | (a,CTL.False) -> a
81 | _ -> CTL.SeqOr(x,y)
82
83let ctl_not = function
84 CTL.True -> CTL.False
85 | CTL.False -> CTL.True
86 | x -> CTL.Not(x)
87
88let ctl_ax s = function
89 CTL.True -> CTL.True
90 | CTL.False -> CTL.False
91 | x ->
92 match !exists with
93 Exists -> CTL.EX(CTL.FORWARD,x)
94 | Forall -> CTL.AX(CTL.FORWARD,s,x)
95 | ReverseForall -> failwith "not supported"
96
97let ctl_ax_absolute s = function
98 CTL.True -> CTL.True
99 | CTL.False -> CTL.False
100 | x -> CTL.AX(CTL.FORWARD,s,x)
101
102let ctl_ex = function
103 CTL.True -> CTL.True
104 | CTL.False -> CTL.False
105 | x -> CTL.EX(CTL.FORWARD,x)
106
107(* This stays being AX even for sgrep_mode, because it is used to identify
108the structure of the term, not matching the pattern. *)
109let ctl_back_ax = function
110 CTL.True -> CTL.True
111 | CTL.False -> CTL.False
112 | x -> CTL.AX(CTL.BACKWARD,CTL.NONSTRICT,x)
113
114let ctl_back_ex = function
115 CTL.True -> CTL.True
116 | CTL.False -> CTL.False
117 | x -> CTL.EX(CTL.BACKWARD,x)
118
119let ctl_ef = function
120 CTL.True -> CTL.True
121 | CTL.False -> CTL.False
122 | x -> CTL.EF(CTL.FORWARD,x)
123
124let ctl_ag s = function
125 CTL.True -> CTL.True
126 | CTL.False -> CTL.False
127 | x -> CTL.AG(CTL.FORWARD,s,x)
128
129let ctl_au s x y =
130 match (x,!exists) with
131 (CTL.True,Exists) -> CTL.EF(CTL.FORWARD,y)
132 | (CTL.True,Forall) -> CTL.AF(CTL.FORWARD,s,y)
133 | (CTL.True,ReverseForall) -> failwith "not supported"
134 | (_,Exists) -> CTL.EU(CTL.FORWARD,x,y)
135 | (_,Forall) -> CTL.AU(CTL.FORWARD,s,x,y)
136 | (_,ReverseForall) -> failwith "not supported"
137
138let ctl_anti_au s x y = (* only for ..., where the quantifier is changed *)
139 CTL.XX
140 (match (x,!exists) with
141 (CTL.True,Exists) -> CTL.AF(CTL.FORWARD,s,y)
142 | (CTL.True,Forall) -> CTL.EF(CTL.FORWARD,y)
143 | (CTL.True,ReverseForall) -> failwith "not supported"
144 | (_,Exists) -> CTL.AU(CTL.FORWARD,s,x,y)
145 | (_,Forall) -> CTL.EU(CTL.FORWARD,x,y)
146 | (_,ReverseForall) -> failwith "not supported")
147
148let ctl_uncheck = function
149 CTL.True -> CTL.True
150 | CTL.False -> CTL.False
151 | x -> CTL.Uncheck x
152
153let label_pred_maker = function
154 None -> CTL.True
155 | Some (label_var,used) ->
156 used := true;
157 CTL.Pred(Lib_engine.PrefixLabel(label_var),CTL.Control)
158
159let bclabel_pred_maker = function
160 None -> CTL.True
161 | Some (label_var,used) ->
162 used := true;
163 CTL.Pred(Lib_engine.BCLabel(label_var),CTL.Control)
164
165let predmaker guard pred label =
166 ctl_and (guard_to_strict guard) (CTL.Pred pred) (label_pred_maker label)
167
168let aftpred = predmaker false (Lib_engine.After, CTL.Control)
169let retpred = predmaker false (Lib_engine.Return, CTL.Control)
170let funpred = predmaker false (Lib_engine.FunHeader, CTL.Control)
171let toppred = predmaker false (Lib_engine.Top, CTL.Control)
172let exitpred = predmaker false (Lib_engine.ErrorExit, CTL.Control)
173let endpred = predmaker false (Lib_engine.Exit, CTL.Control)
174let gotopred = predmaker false (Lib_engine.Goto, CTL.Control)
175let inlooppred = predmaker false (Lib_engine.InLoop, CTL.Control)
176let truepred = predmaker false (Lib_engine.TrueBranch, CTL.Control)
177let falsepred = predmaker false (Lib_engine.FalseBranch, CTL.Control)
178let fallpred = predmaker false (Lib_engine.FallThrough, CTL.Control)
179
180let aftret label_var f = ctl_or (aftpred label_var) (exitpred label_var)
181
182let letctr = ref 0
183let get_let_ctr _ =
184 let cur = !letctr in
185 letctr := cur + 1;
186 Printf.sprintf "r%d" cur
187
188(* --------------------------------------------------------------------- *)
189(* --------------------------------------------------------------------- *)
190(* Eliminate OptStm *)
191
192(* for optional thing with nothing after, should check that the optional thing
193never occurs. otherwise the matching stops before it occurs *)
194let elim_opt =
195 let mcode x = x in
196 let donothing r k e = k e in
197
198 let fvlist l =
199 List.fold_left Common.union_set [] (List.map Ast.get_fvs l) in
200
201 let mfvlist l =
202 List.fold_left Common.union_set [] (List.map Ast.get_mfvs l) in
203
204 let freshlist l =
205 List.fold_left Common.union_set [] (List.map Ast.get_fresh l) in
206
207 let inheritedlist l =
208 List.fold_left Common.union_set [] (List.map Ast.get_inherited l) in
209
210 let savedlist l =
211 List.fold_left Common.union_set [] (List.map Ast.get_saved l) in
212
213 let varlists l =
214 (fvlist l, mfvlist l, freshlist l, inheritedlist l, savedlist l) in
215
216 let rec dots_list unwrapped wrapped =
217 match (unwrapped,wrapped) with
218 ([],_) -> []
219
220 | (Ast.Dots(_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest,
221 d0::s::d1::rest)
222 | (Ast.Nest(_,_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest,
223 d0::s::d1::rest) ->
224 let l = Ast.get_line stm in
225 let new_rest1 = stm :: (dots_list (u::urest) (d1::rest)) in
226 let new_rest2 = dots_list urest rest in
227 let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) =
228 varlists new_rest1 in
229 let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) =
230 varlists new_rest2 in
231 [d0;
232 {(Ast.make_term
233 (Ast.Disj
234 [{(Ast.make_term(Ast.DOTS(new_rest1))) with
235 Ast.node_line = l;
236 Ast.free_vars = fv_rest1;
237 Ast.minus_free_vars = mfv_rest1;
238 Ast.fresh_vars = fresh_rest1;
239 Ast.inherited = inherited_rest1;
240 Ast.saved_witness = s1};
241 {(Ast.make_term(Ast.DOTS(new_rest2))) with
242 Ast.node_line = l;
243 Ast.free_vars = fv_rest2;
244 Ast.minus_free_vars = mfv_rest2;
245 Ast.fresh_vars = fresh_rest2;
246 Ast.inherited = inherited_rest2;
247 Ast.saved_witness = s2}])) with
248 Ast.node_line = l;
249 Ast.free_vars = fv_rest1;
250 Ast.minus_free_vars = mfv_rest1;
251 Ast.fresh_vars = fresh_rest1;
252 Ast.inherited = inherited_rest1;
253 Ast.saved_witness = s1}]
254
255 | (Ast.OptStm(stm)::urest,_::rest) ->
256 let l = Ast.get_line stm in
257 let new_rest1 = dots_list urest rest in
258 let new_rest2 = stm::new_rest1 in
259 let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) =
260 varlists new_rest1 in
261 let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) =
262 varlists new_rest2 in
263 [{(Ast.make_term
264 (Ast.Disj
265 [{(Ast.make_term(Ast.DOTS(new_rest2))) with
266 Ast.node_line = l;
267 Ast.free_vars = fv_rest2;
268 Ast.minus_free_vars = mfv_rest2;
269 Ast.fresh_vars = fresh_rest2;
270 Ast.inherited = inherited_rest2;
271 Ast.saved_witness = s2};
272 {(Ast.make_term(Ast.DOTS(new_rest1))) with
273 Ast.node_line = l;
274 Ast.free_vars = fv_rest1;
275 Ast.minus_free_vars = mfv_rest1;
276 Ast.fresh_vars = fresh_rest1;
277 Ast.inherited = inherited_rest1;
278 Ast.saved_witness = s1}])) with
279 Ast.node_line = l;
280 Ast.free_vars = fv_rest2;
281 Ast.minus_free_vars = mfv_rest2;
282 Ast.fresh_vars = fresh_rest2;
283 Ast.inherited = inherited_rest2;
284 Ast.saved_witness = s2}]
285
286 | ([Ast.Dots(_,_,_,_);Ast.OptStm(stm)],[d1;_]) ->
287 let l = Ast.get_line stm in
288 let fv_stm = Ast.get_fvs stm in
289 let mfv_stm = Ast.get_mfvs stm in
290 let fresh_stm = Ast.get_fresh stm in
291 let inh_stm = Ast.get_inherited stm in
292 let saved_stm = Ast.get_saved stm in
293 let fv_d1 = Ast.get_fvs d1 in
294 let mfv_d1 = Ast.get_mfvs d1 in
295 let fresh_d1 = Ast.get_fresh d1 in
296 let inh_d1 = Ast.get_inherited d1 in
297 let saved_d1 = Ast.get_saved d1 in
298 let fv_both = Common.union_set fv_stm fv_d1 in
299 let mfv_both = Common.union_set mfv_stm mfv_d1 in
300 let fresh_both = Common.union_set fresh_stm fresh_d1 in
301 let inh_both = Common.union_set inh_stm inh_d1 in
302 let saved_both = Common.union_set saved_stm saved_d1 in
303 [d1;
304 {(Ast.make_term
305 (Ast.Disj
306 [{(Ast.make_term(Ast.DOTS([stm]))) with
307 Ast.node_line = l;
308 Ast.free_vars = fv_stm;
309 Ast.minus_free_vars = mfv_stm;
310 Ast.fresh_vars = fresh_stm;
311 Ast.inherited = inh_stm;
312 Ast.saved_witness = saved_stm};
313 {(Ast.make_term(Ast.DOTS([d1]))) with
314 Ast.node_line = l;
315 Ast.free_vars = fv_d1;
316 Ast.minus_free_vars = mfv_d1;
317 Ast.fresh_vars = fresh_d1;
318 Ast.inherited = inh_d1;
319 Ast.saved_witness = saved_d1}])) with
320 Ast.node_line = l;
321 Ast.free_vars = fv_both;
322 Ast.minus_free_vars = mfv_both;
323 Ast.fresh_vars = fresh_both;
324 Ast.inherited = inh_both;
325 Ast.saved_witness = saved_both}]
326
327 | ([Ast.Nest(_,_,_,_,_);Ast.OptStm(stm)],[d1;_]) ->
328 let l = Ast.get_line stm in
329 let rw = Ast.rewrap stm in
330 let rwd = Ast.rewrap stm in
331 let dots = Ast.Dots(Ast.make_mcode "...",[],[],[]) in
332 [d1;rw(Ast.Disj
333 [rwd(Ast.DOTS([stm]));
334 {(Ast.make_term(Ast.DOTS([rw dots])))
335 with Ast.node_line = l}])]
336
337 | (_::urest,stm::rest) -> stm :: (dots_list urest rest)
338 | _ -> failwith "not possible" in
339
340 let stmtdotsfn r k d =
341 let d = k d in
342 Ast.rewrap d
343 (match Ast.unwrap d with
344 Ast.DOTS(l) -> Ast.DOTS(dots_list (List.map Ast.unwrap l) l)
345 | Ast.CIRCLES(l) -> failwith "elimopt: not supported"
346 | Ast.STARS(l) -> failwith "elimopt: not supported") in
347
348 V.rebuilder
349 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
350 mcode
351 donothing donothing stmtdotsfn donothing
352 donothing donothing donothing donothing donothing donothing donothing
353 donothing donothing donothing donothing donothing
354
355(* --------------------------------------------------------------------- *)
356(* after management *)
357(* We need Guard for the following case:
358<...
359 a
360 <...
361 b
362 ...>
363...>
364foo();
365
366Here the inner <... b ...> should not go past foo. But foo is not the
367"after" of the body of the outer nest, because we don't want to search for
368it in the case where the body of the outer nest ends in something other
369than dots or a nest. *)
370
371(* what is the difference between tail and end??? *)
372
373type after = After of formula | Guard of formula | Tail | End | VeryEnd
374
375let a2n = function After x -> Guard x | a -> a
376
377let print_ctl x =
378 let pp_pred (x,_) = Pretty_print_engine.pp_predicate x in
379 let pp_meta (_,x) = Common.pp x in
380 Pretty_print_ctl.pp_ctl (pp_pred,pp_meta) false x;
381 Format.print_newline()
382
383let print_after = function
384 After ctl -> Printf.printf "After:\n"; print_ctl ctl
385 | Guard ctl -> Printf.printf "Guard:\n"; print_ctl ctl
386 | Tail -> Printf.printf "Tail\n"
387 | VeryEnd -> Printf.printf "Very End\n"
388 | End -> Printf.printf "End\n"
389
390(* --------------------------------------------------------------------- *)
391(* Top-level code *)
392
393let fresh_var _ = string2var "_v"
394let fresh_pos _ = string2var "_pos" (* must be a constant *)
395
396let fresh_metavar _ = "_S"
397
398(* fvinfo is going to end up being from the whole associated statement.
399 it would be better if it were just the free variables in d, but free_vars.ml
400 doesn't keep track of free variables on + code *)
401let make_meta_rule_elem d fvinfo =
402 let nm = fresh_metavar() in
403 Ast.make_meta_rule_elem nm d fvinfo
404
405let get_unquantified quantified vars =
406 List.filter (function x -> not (List.mem x quantified)) vars
407
408let make_seq guard l =
409 let s = guard_to_strict guard in
410 foldr1 (function rest -> function cur -> ctl_and s cur (ctl_ax s rest)) l
411
412let make_seq_after2 guard first rest =
413 let s = guard_to_strict guard in
414 match rest with
415 After rest -> ctl_and s first (ctl_ax s (ctl_ax s rest))
416 | _ -> first
417
418let make_seq_after guard first rest =
419 match rest with
420 After rest -> make_seq guard [first;rest]
421 | _ -> first
422
423let opt_and guard first rest =
424 let s = guard_to_strict guard in
425 match first with
426 None -> rest
427 | Some first -> ctl_and s first rest
428
429let and_after guard first rest =
430 let s = guard_to_strict guard in
431 match rest with After rest -> ctl_and s first rest | _ -> first
432
433let contains_modif =
434 let bind x y = x or y in
435 let option_default = false in
91eba41f 436 let mcode r (_,_,kind,metapos) =
34e49164
C
437 match kind with
438 Ast.MINUS(_,_) -> true
439 | Ast.PLUS -> failwith "not possible"
440 | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in
441 let do_nothing r k e = k e in
442 let rule_elem r k re =
443 let res = k re in
444 match Ast.unwrap re with
445 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
446 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
447 | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
448 | _ -> res in
449 let recursor =
450 V.combiner bind option_default
451 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
452 mcode
453 do_nothing do_nothing do_nothing do_nothing
454 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
455 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
456 recursor.V.combiner_rule_elem
457
91eba41f
C
458let contains_pos =
459 let bind x y = x or y in
460 let option_default = false in
461 let mcode r (_,_,kind,metapos) =
462 match metapos with
463 Ast.MetaPos(_,_,_,_,_) -> true
464 | Ast.NoMetaPos -> false in
465 let do_nothing r k e = k e in
466 let rule_elem r k re =
467 let res = k re in
468 match Ast.unwrap re with
469 Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
470 bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
471 | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
472 | _ -> res in
473 let recursor =
474 V.combiner bind option_default
475 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
476 mcode
477 do_nothing do_nothing do_nothing do_nothing
478 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
479 do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
480 recursor.V.combiner_rule_elem
481
34e49164
C
482(* code is not a DisjRuleElem *)
483let make_match label guard code =
484 let v = fresh_var() in
485 let matcher = Lib_engine.Match(code) in
486 if contains_modif code && not guard
487 then CTL.Exists(true,v,predmaker guard (matcher,CTL.Modif v) label)
488 else
489 let iso_info = !Flag.track_iso_usage && not (Ast.get_isos code = []) in
490 (match (iso_info,!onlyModif,guard,
491 intersect !used_after (Ast.get_fvs code)) with
492 (false,true,_,[]) | (_,_,true,_) ->
493 predmaker guard (matcher,CTL.Control) label
494 | _ -> CTL.Exists(true,v,predmaker guard (matcher,CTL.UnModif v) label))
495
496let make_raw_match label guard code =
497 predmaker guard (Lib_engine.Match(code),CTL.Control) label
498
499let rec seq_fvs quantified = function
500 [] -> []
501 | fv1::fvs ->
502 let t1fvs = get_unquantified quantified fv1 in
503 let termfvs =
504 List.fold_left Common.union_set []
505 (List.map (get_unquantified quantified) fvs) in
506 let bothfvs = Common.inter_set t1fvs termfvs in
507 let t1onlyfvs = Common.minus_set t1fvs bothfvs in
508 let new_quantified = Common.union_set bothfvs quantified in
509 (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs)
510
511let quantify guard =
512 List.fold_right
513 (function cur ->
514 function code -> CTL.Exists (not guard && List.mem cur !saved,cur,code))
515
516let non_saved_quantify =
517 List.fold_right
518 (function cur -> function code -> CTL.Exists (false,cur,code))
519
520let intersectll lst nested_list =
521 List.filter (function x -> List.exists (List.mem x) nested_list) lst
522
523(* --------------------------------------------------------------------- *)
524(* Count depth of braces. The translation of a closed brace appears deeply
525nested within the translation of the sequence term, so the name of the
526paren var has to take into account the names of the nested braces. On the
527other hand the close brace does not escape, so we don't have to take into
528account other paren variable names. *)
529
530(* called repetitively, which is inefficient, but less trouble than adding a
531new field to Seq and FunDecl *)
532let count_nested_braces s =
533 let bind x y = max x y in
534 let option_default = 0 in
535 let stmt_count r k s =
536 match Ast.unwrap s with
537 Ast.Seq(_,_,_,_) | Ast.FunDecl(_,_,_,_,_) -> (k s) + 1
538 | _ -> k s in
539 let donothing r k e = k e in
540 let mcode r x = 0 in
541 let recursor = V.combiner bind option_default
542 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
543 mcode
544 donothing donothing donothing donothing
545 donothing donothing donothing donothing donothing donothing
546 donothing donothing stmt_count donothing donothing donothing in
547 let res = string_of_int (recursor.V.combiner_statement s) in
548 string2var ("p"^res)
549
550let labelctr = ref 0
551let get_label_ctr _ =
552 let cur = !labelctr in
553 labelctr := cur + 1;
554 string2var (Printf.sprintf "l%d" cur)
555
556(* --------------------------------------------------------------------- *)
557(* annotate dots with before and after neighbors *)
558
559let print_bef_aft = function
560 Ast.WParen (re,n) ->
561 Printf.printf "bef/aft\n";
562 Pretty_print_cocci.rule_elem "" re;
563 Format.print_newline()
564 | Ast.Other s ->
565 Printf.printf "bef/aft\n";
566 Pretty_print_cocci.statement "" s;
567 Format.print_newline()
568 | Ast.Other_dots d ->
569 Printf.printf "bef/aft\n";
570 Pretty_print_cocci.statement_dots d;
571 Format.print_newline()
572
573(* [] can only occur if we are in a disj, where it comes from a ? In that
574case, we want to use a, which accumulates all of the previous patterns in
575their entirety. *)
576let rec get_before_elem sl a =
577 match Ast.unwrap sl with
578 Ast.DOTS(x) ->
579 let rec loop sl a =
580 match sl with
581 [] -> ([],Common.Right a)
582 | [e] ->
583 let (e,ea) = get_before_e e a in
584 ([e],Common.Left ea)
585 | e::sl ->
586 let (e,ea) = get_before_e e a in
587 let (sl,sla) = loop sl ea in
588 (e::sl,sla) in
589 let (l,a) = loop x a in
590 (Ast.rewrap sl (Ast.DOTS(l)),a)
591 | Ast.CIRCLES(x) -> failwith "not supported"
592 | Ast.STARS(x) -> failwith "not supported"
593
594and get_before sl a =
595 match get_before_elem sl a with
596 (term,Common.Left x) -> (term,x)
597 | (term,Common.Right x) -> (term,x)
598
599and get_before_whencode wc =
600 List.map
601 (function
602 Ast.WhenNot w -> let (w,_) = get_before w [] in Ast.WhenNot w
603 | Ast.WhenAlways w -> let (w,_) = get_before_e w [] in Ast.WhenAlways w
1be43e12
C
604 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
605 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
606 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
34e49164
C
607 wc
608
609and get_before_e s a =
610 match Ast.unwrap s with
611 Ast.Dots(d,w,_,aft) ->
612 (Ast.rewrap s (Ast.Dots(d,get_before_whencode w,a,aft)),a)
613 | Ast.Nest(stmt_dots,w,multi,_,aft) ->
614 let w = get_before_whencode w in
615 let (sd,_) = get_before stmt_dots a in
616 let a =
617 List.filter
618 (function
619 Ast.Other a ->
620 let unifies =
621 Unify_ast.unify_statement_dots
622 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
623 (match unifies with
624 Unify_ast.MAYBE -> false
625 | _ -> true)
626 | Ast.Other_dots a ->
627 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
628 (match unifies with
629 Unify_ast.MAYBE -> false
630 | _ -> true)
631 | _ -> true)
632 a in
633 (Ast.rewrap s (Ast.Nest(sd,w,multi,a,aft)),[Ast.Other_dots stmt_dots])
634 | Ast.Disj(stmt_dots_list) ->
635 let (dsl,dsla) =
636 List.split (List.map (function e -> get_before e a) stmt_dots_list) in
637 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
638 | Ast.Atomic(ast) ->
639 (match Ast.unwrap ast with
640 Ast.MetaStmt(_,_,_,_) -> (s,[])
641 | _ -> (s,[Ast.Other s]))
642 | Ast.Seq(lbrace,decls,body,rbrace) ->
643 let index = count_nested_braces s in
644 let (de,dea) = get_before decls [Ast.WParen(lbrace,index)] in
645 let (bd,_) = get_before body dea in
646 (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)),
647 [Ast.WParen(rbrace,index)])
648 | Ast.Define(header,body) ->
649 let (body,_) = get_before body [] in
650 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
651 | Ast.IfThen(ifheader,branch,aft) ->
652 let (br,_) = get_before_e branch [] in
653 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)), [Ast.Other s])
654 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
655 let (br1,_) = get_before_e branch1 [] in
656 let (br2,_) = get_before_e branch2 [] in
657 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
658 | Ast.While(header,body,aft) ->
659 let (bd,_) = get_before_e body [] in
660 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
661 | Ast.For(header,body,aft) ->
662 let (bd,_) = get_before_e body [] in
663 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
664 | Ast.Do(header,body,tail) ->
665 let (bd,_) = get_before_e body [] in
666 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
667 | Ast.Iterator(header,body,aft) ->
668 let (bd,_) = get_before_e body [] in
669 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
670 | Ast.Switch(header,lb,cases,rb) ->
671 let cases =
672 List.map
673 (function case_line ->
674 match Ast.unwrap case_line with
675 Ast.CaseLine(header,body) ->
676 let (body,_) = get_before body [] in
677 Ast.rewrap case_line (Ast.CaseLine(header,body))
678 | Ast.OptCase(case_line) -> failwith "not supported")
679 cases in
680 (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s])
681 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
682 let (de,dea) = get_before decls [] in
683 let (bd,_) = get_before body dea in
684 (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[])
91eba41f
C
685 | _ ->
686 Pretty_print_cocci.statement "" s; Format.print_newline();
687 failwith "get_before_e: not supported"
34e49164
C
688
689let rec get_after sl a =
690 match Ast.unwrap sl with
691 Ast.DOTS(x) ->
692 let rec loop sl =
693 match sl with
694 [] -> ([],a)
695 | e::sl ->
696 let (sl,sla) = loop sl in
697 let (e,ea) = get_after_e e sla in
698 (e::sl,ea) in
699 let (l,a) = loop x in
700 (Ast.rewrap sl (Ast.DOTS(l)),a)
701 | Ast.CIRCLES(x) -> failwith "not supported"
702 | Ast.STARS(x) -> failwith "not supported"
703
704and get_after_whencode a wc =
705 List.map
706 (function
707 Ast.WhenNot w -> let (w,_) = get_after w a (*?*) in Ast.WhenNot w
708 | Ast.WhenAlways w -> let (w,_) = get_after_e w a in Ast.WhenAlways w
1be43e12
C
709 | Ast.WhenModifier(x) -> Ast.WhenModifier(x)
710 | Ast.WhenNotTrue w -> Ast.WhenNotTrue w
711 | Ast.WhenNotFalse w -> Ast.WhenNotFalse w)
34e49164
C
712 wc
713
714and get_after_e s a =
715 match Ast.unwrap s with
716 Ast.Dots(d,w,bef,_) ->
717 (Ast.rewrap s (Ast.Dots(d,get_after_whencode a w,bef,a)),a)
718 | Ast.Nest(stmt_dots,w,multi,bef,_) ->
719 let w = get_after_whencode a w in
720 let (sd,_) = get_after stmt_dots a in
721 let a =
722 List.filter
723 (function
724 Ast.Other a ->
725 let unifies =
726 Unify_ast.unify_statement_dots
727 (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in
728 (match unifies with
729 Unify_ast.MAYBE -> false
730 | _ -> true)
731 | Ast.Other_dots a ->
732 let unifies = Unify_ast.unify_statement_dots a stmt_dots in
733 (match unifies with
734 Unify_ast.MAYBE -> false
735 | _ -> true)
736 | _ -> true)
737 a in
738 (Ast.rewrap s (Ast.Nest(sd,w,multi,bef,a)),[Ast.Other_dots stmt_dots])
739 | Ast.Disj(stmt_dots_list) ->
740 let (dsl,dsla) =
741 List.split (List.map (function e -> get_after e a) stmt_dots_list) in
742 (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla)
743 | Ast.Atomic(ast) ->
744 (match Ast.unwrap ast with
745 Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots _,i) ->
746 (* check "after" information for metavar optimization *)
747 (* if the error is not desired, could just return [], then
748 the optimization (check for EF) won't take place *)
749 List.iter
750 (function
751 Ast.Other x ->
752 (match Ast.unwrap x with
753 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) ->
754 failwith
755 "dots/nest not allowed before and after stmt metavar"
756 | _ -> ())
757 | Ast.Other_dots x ->
758 (match Ast.undots x with
759 x::_ ->
760 (match Ast.unwrap x with
761 Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) ->
762 failwith
763 ("dots/nest not allowed before and after stmt "^
764 "metavar")
765 | _ -> ())
766 | _ -> ())
767 | _ -> ())
768 a;
769 (Ast.rewrap s
770 (Ast.Atomic
771 (Ast.rewrap s
772 (Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots a,i)))),[])
773 | Ast.MetaStmt(_,_,_,_) -> (s,[])
774 | _ -> (s,[Ast.Other s]))
775 | Ast.Seq(lbrace,decls,body,rbrace) ->
776 let index = count_nested_braces s in
777 let (bd,bda) = get_after body [Ast.WParen(rbrace,index)] in
778 let (de,_) = get_after decls bda in
779 (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)),
780 [Ast.WParen(lbrace,index)])
781 | Ast.Define(header,body) ->
782 let (body,_) = get_after body a in
783 (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s])
784 | Ast.IfThen(ifheader,branch,aft) ->
785 let (br,_) = get_after_e branch a in
786 (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)),[Ast.Other s])
787 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
788 let (br1,_) = get_after_e branch1 a in
789 let (br2,_) = get_after_e branch2 a in
790 (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
791 | Ast.While(header,body,aft) ->
792 let (bd,_) = get_after_e body a in
793 (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
794 | Ast.For(header,body,aft) ->
795 let (bd,_) = get_after_e body a in
796 (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
797 | Ast.Do(header,body,tail) ->
798 let (bd,_) = get_after_e body a in
799 (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
800 | Ast.Iterator(header,body,aft) ->
801 let (bd,_) = get_after_e body a in
802 (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
803 | Ast.Switch(header,lb,cases,rb) ->
804 let cases =
805 List.map
806 (function case_line ->
807 match Ast.unwrap case_line with
808 Ast.CaseLine(header,body) ->
809 let (body,_) = get_after body [] in
810 Ast.rewrap case_line (Ast.CaseLine(header,body))
811 | Ast.OptCase(case_line) -> failwith "not supported")
812 cases in
813 (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s])
814 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
815 let (bd,bda) = get_after body [] in
816 let (de,_) = get_after decls bda in
817 (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[])
818 | _ -> failwith "get_after_e: not supported"
819
820let preprocess_dots sl =
821 let (sl,_) = get_before sl [] in
822 let (sl,_) = get_after sl [] in
823 sl
824
825let preprocess_dots_e sl =
826 let (sl,_) = get_before_e sl [] in
827 let (sl,_) = get_after_e sl [] in
828 sl
829
830(* --------------------------------------------------------------------- *)
831(* various return_related things *)
832
833let rec ends_in_return stmt_list =
834 match Ast.unwrap stmt_list with
835 Ast.DOTS(x) ->
836 (match List.rev x with
837 x::_ ->
838 (match Ast.unwrap x with
839 Ast.Atomic(x) ->
1be43e12
C
840 let rec loop x =
841 match Ast.unwrap x with
842 Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) -> true
843 | Ast.DisjRuleElem((_::_) as l) -> List.for_all loop l
844 | _ -> false in
845 loop x
34e49164
C
846 | Ast.Disj(disjs) -> List.for_all ends_in_return disjs
847 | _ -> false)
848 | _ -> false)
849 | Ast.CIRCLES(x) -> failwith "not supported"
850 | Ast.STARS(x) -> failwith "not supported"
851
852(* --------------------------------------------------------------------- *)
853(* expressions *)
854
855let exptymatch l make_match make_guard_match =
856 let pos = fresh_pos() in
857 let matches_guard_matches =
858 List.map
859 (function x ->
860 let pos = Ast.make_mcode pos in
861 (make_match (Ast.set_pos x (Some pos)),
862 make_guard_match (Ast.set_pos x (Some pos))))
863 l in
864 let (matches,guard_matches) = List.split matches_guard_matches in
865 let rec suffixes = function
866 [] -> []
867 | x::xs -> xs::(suffixes xs) in
868 let prefixes = List.rev (suffixes (List.rev guard_matches)) in
869 let info = (* not null *)
870 List.map2
871 (function matcher ->
872 function negates ->
873 CTL.Exists
874 (false,pos,
875 ctl_and CTL.NONSTRICT matcher
876 (ctl_not
877 (ctl_uncheck (List.fold_left ctl_or_fl CTL.False negates)))))
878 matches prefixes in
879 CTL.InnerAnd(List.fold_left ctl_or_fl CTL.False (List.rev info))
880
881(* code might be a DisjRuleElem, in which case we break it apart
882 code might contain an Exp or Ty
883 this one pushes the quantifier inwards *)
884let do_re_matches label guard res quantified minus_quantified =
885 let make_guard_match x =
886 let stmt_fvs = Ast.get_mfvs x in
887 let fvs = get_unquantified minus_quantified stmt_fvs in
888 non_saved_quantify fvs (make_match None true x) in
889 let make_match x =
890 let stmt_fvs = Ast.get_fvs x in
891 let fvs = get_unquantified quantified stmt_fvs in
892 quantify guard fvs (make_match None guard x) in
893 ctl_and CTL.NONSTRICT (label_pred_maker label)
894 (match List.map Ast.unwrap res with
895 [] -> failwith "unexpected empty disj"
896 | Ast.Exp(e)::rest -> exptymatch res make_match make_guard_match
897 | Ast.Ty(t)::rest -> exptymatch res make_match make_guard_match
898 | all ->
899 if List.exists (function Ast.Exp(_) | Ast.Ty(_) -> true | _ -> false)
900 all
901 then failwith "unexpected exp or ty";
902 List.fold_left ctl_seqor CTL.False
903 (List.rev (List.map make_match res)))
904
905(* code might be a DisjRuleElem, in which case we break it apart
906 code doesn't contain an Exp or Ty
907 this one is for use when it is not practical to push the quantifier inwards
908 *)
909let header_match label guard code : ('a, Ast.meta_name, 'b) CTL.generic_ctl =
910 match Ast.unwrap code with
911 Ast.DisjRuleElem(res) ->
912 let make_match = make_match None guard in
913 let orop = if guard then ctl_or else ctl_seqor in
914 ctl_and CTL.NONSTRICT (label_pred_maker label)
915 (List.fold_left orop CTL.False (List.map make_match res))
916 | _ -> make_match label guard code
917
918(* --------------------------------------------------------------------- *)
919(* control structures *)
920
921let end_control_structure fvs header body after_pred
922 after_checks no_after_checks (afvs,afresh,ainh,aft) after label guard =
923 (* aft indicates what is added after the whole if, which has to be added
924 to the endif node *)
925 let (aft_needed,after_branch) =
926 match aft with
927 Ast.CONTEXT(_,Ast.NOTHING) ->
928 (false,make_seq_after2 guard after_pred after)
929 | _ ->
930 let match_endif =
931 make_match label guard
932 (make_meta_rule_elem aft (afvs,afresh,ainh)) in
933 (true,
934 make_seq_after guard after_pred
935 (After(make_seq_after guard match_endif after))) in
936 let body = body after_branch in
937 let s = guard_to_strict guard in
938 (* the code *)
939 quantify guard fvs
940 (ctl_and s header
941 (opt_and guard
942 (match (after,aft_needed) with
943 (After _,_) (* pattern doesn't end here *)
944 | (_,true) (* + code added after *) -> after_checks
945 | _ -> no_after_checks)
946 (ctl_ax_absolute s body)))
947
948let ifthen ifheader branch ((afvs,_,_,_) as aft) after
949 quantified minus_quantified label llabel slabel recurse make_match guard =
950(* "if (test) thn" becomes:
951 if(test) & AX((TrueBranch & AX thn) v FallThrough v After)
952
953 "if (test) thn; after" becomes:
954 if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after))
955 & EX After
956*)
957 (* free variables *)
958 let (efvs,bfvs) =
959 match seq_fvs quantified
960 [Ast.get_fvs ifheader;Ast.get_fvs branch;afvs] with
961 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
962 | _ -> failwith "not possible" in
963 let new_quantified = Common.union_set bfvs quantified in
964 let (mefvs,mbfvs) =
965 match seq_fvs minus_quantified
966 [Ast.get_mfvs ifheader;Ast.get_mfvs branch;[]] with
967 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
968 | _ -> failwith "not possible" in
969 let new_mquantified = Common.union_set mbfvs minus_quantified in
970 (* if header *)
971 let if_header = quantify guard efvs (make_match ifheader) in
972 (* then branch and after *)
973 let lv = get_label_ctr() in
974 let used = ref false in
975 let true_branch =
976 make_seq guard
977 [truepred label; recurse branch Tail new_quantified new_mquantified
978 (Some (lv,used)) llabel slabel guard] in
979 let after_pred = aftpred label in
980 let or_cases after_branch =
981 ctl_or true_branch (ctl_or (fallpred label) after_branch) in
982 let (if_header,wrapper) =
983 if !used
984 then
985 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
986 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
987 (function body -> quantify true [lv] body))
988 else (if_header,function x -> x) in
989 wrapper
990 (end_control_structure bfvs if_header or_cases after_pred
991 (Some(ctl_ex after_pred)) None aft after label guard)
992
993let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after
994 quantified minus_quantified label llabel slabel recurse make_match guard =
995(* "if (test) thn else els" becomes:
996 if(test) & AX((TrueBranch & AX thn) v
997 (FalseBranch & AX (else & AX els)) v After)
998 & EX FalseBranch
999
1000 "if (test) thn else els; after" becomes:
1001 if(test) & AX((TrueBranch & AX thn) v
1002 (FalseBranch & AX (else & AX els)) v
1003 (After & AXAX after))
1004 & EX FalseBranch
1005 & EX After
1006*)
1007 (* free variables *)
1008 let (e1fvs,b1fvs,s1fvs) =
1009 match seq_fvs quantified
1010 [Ast.get_fvs ifheader;Ast.get_fvs branch1;afvs] with
1011 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
1012 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
1013 | _ -> failwith "not possible" in
1014 let (e2fvs,b2fvs,s2fvs) =
1015 (* fvs on else? *)
1016 match seq_fvs quantified
1017 [Ast.get_fvs ifheader;Ast.get_fvs branch2;afvs] with
1018 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
1019 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
1020 | _ -> failwith "not possible" in
1021 let bothfvs = union (union b1fvs b2fvs) (intersect s1fvs s2fvs) in
1022 let exponlyfvs = intersect e1fvs e2fvs in
1023 let new_quantified = union bothfvs quantified in
1024 (* minus free variables *)
1025 let (me1fvs,mb1fvs,ms1fvs) =
1026 match seq_fvs minus_quantified
1027 [Ast.get_mfvs ifheader;Ast.get_mfvs branch1;[]] with
1028 [(e1fvs,b1fvs);(s1fvs,b1afvs);_] ->
1029 (e1fvs,Common.union_set b1fvs b1afvs,s1fvs)
1030 | _ -> failwith "not possible" in
1031 let (me2fvs,mb2fvs,ms2fvs) =
1032 (* fvs on else? *)
1033 match seq_fvs minus_quantified
1034 [Ast.get_mfvs ifheader;Ast.get_mfvs branch2;[]] with
1035 [(e2fvs,b2fvs);(s2fvs,b2afvs);_] ->
1036 (e2fvs,Common.union_set b2fvs b2afvs,s2fvs)
1037 | _ -> failwith "not possible" in
1038 let mbothfvs = union (union mb1fvs mb2fvs) (intersect ms1fvs ms2fvs) in
1039 let new_mquantified = union mbothfvs minus_quantified in
1040 (* if header *)
1041 let if_header = quantify guard exponlyfvs (make_match ifheader) in
1042 (* then and else branches *)
1043 let lv = get_label_ctr() in
1044 let used = ref false in
1045 let true_branch =
1046 make_seq guard
1047 [truepred label; recurse branch1 Tail new_quantified new_mquantified
1048 (Some (lv,used)) llabel slabel guard] in
1049 let false_branch =
1050 make_seq guard
1051 [falsepred label; make_match els;
1052 recurse branch2 Tail new_quantified new_mquantified
1053 (Some (lv,used)) llabel slabel guard] in
1054 let after_pred = aftpred label in
1055 let or_cases after_branch =
1056 ctl_or true_branch (ctl_or false_branch after_branch) in
1057 let s = guard_to_strict guard in
1058 let (if_header,wrapper) =
1059 if !used
1060 then
1061 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1062 (ctl_and CTL.NONSTRICT(*???*) if_header label_pred,
1063 (function body -> quantify true [lv] body))
1064 else (if_header,function x -> x) in
1065 wrapper
1066 (end_control_structure bothfvs if_header or_cases after_pred
1067 (Some(ctl_and s (ctl_ex (falsepred label)) (ctl_ex after_pred)))
1068 (Some(ctl_ex (falsepred label)))
1069 aft after label guard)
1070
1071let forwhile header body ((afvs,_,_,_) as aft) after
1072 quantified minus_quantified label recurse make_match guard =
1073 let process _ =
1074 (* the translation in this case is similar to that of an if with no else *)
1075 (* free variables *)
1076 let (efvs,bfvs) =
1077 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body;afvs] with
1078 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1079 | _ -> failwith "not possible" in
1080 let new_quantified = Common.union_set bfvs quantified in
1081 (* minus free variables *)
1082 let (mefvs,mbfvs) =
1083 match seq_fvs minus_quantified
1084 [Ast.get_mfvs header;Ast.get_mfvs body;[]] with
1085 [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs)
1086 | _ -> failwith "not possible" in
1087 let new_mquantified = Common.union_set mbfvs minus_quantified in
1088 (* loop header *)
1089 let header = quantify guard efvs (make_match header) in
1090 let lv = get_label_ctr() in
1091 let used = ref false in
1092 let body =
1093 make_seq guard
1094 [inlooppred label;
1095 recurse body Tail new_quantified new_mquantified
1096 (Some (lv,used)) (Some (lv,used)) None guard] in
1097 let after_pred = fallpred label in
1098 let or_cases after_branch = ctl_or body after_branch in
1099 let (header,wrapper) =
1100 if !used
1101 then
1102 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
1103 (ctl_and CTL.NONSTRICT(*???*) header label_pred,
1104 (function body -> quantify true [lv] body))
1105 else (header,function x -> x) in
1106 wrapper
1107 (end_control_structure bfvs header or_cases after_pred
1108 (Some(ctl_ex after_pred)) None aft after label guard) in
1109 match (Ast.unwrap body,aft) with
1110 (Ast.Atomic(re),(_,_,_,Ast.CONTEXT(_,Ast.NOTHING))) ->
1111 (match Ast.unwrap re with
1112 Ast.MetaStmt((_,_,Ast.CONTEXT(_,Ast.NOTHING),_),
1113 Type_cocci.Unitary,_,false) ->
1114 let (efvs) =
1115 match seq_fvs quantified [Ast.get_fvs header] with
1116 [(efvs,_)] -> efvs
1117 | _ -> failwith "not possible" in
1118 quantify guard efvs (make_match header)
1119 | _ -> process())
1120 | _ -> process()
1121
1122(* --------------------------------------------------------------------- *)
1123(* statement metavariables *)
1124
1125(* issue: an S metavariable that is not an if branch/loop body
1126 should not match an if branch/loop body, so check that the labels
1127 of the nodes before the first node matched by the S are different
1128 from the label of the first node matched by the S *)
1129let sequencibility body label_pred process_bef_aft = function
1130 Ast.Sequencible | Ast.SequencibleAfterDots [] ->
1131 body
1132 (function x ->
1133 (ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1134 | Ast.SequencibleAfterDots l ->
1135 (* S appears after some dots. l is the code that comes after the S.
1136 want to search for that first, because S can match anything, while
1137 the stuff after is probably more restricted *)
1138 let afts = List.map process_bef_aft l in
1139 let ors = foldl1 ctl_or afts in
1140 ctl_and CTL.NONSTRICT
1141 (ctl_ef (ctl_and CTL.NONSTRICT ors (ctl_back_ax label_pred)))
1142 (body
1143 (function x ->
1144 ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x))
1145 | Ast.NotSequencible -> body (function x -> x)
1146
1147let svar_context_with_add_after stmt s label quantified d ast
1148 seqible after process_bef_aft guard fvinfo =
1149 let label_var = (*fresh_label_var*) string2var "_lab" in
1150 let label_pred =
1151 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
1152 let prelabel_pred =
1153 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in
1154 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
1155 let full_metamatch = matcher d in
1156 let first_metamatch =
1157 matcher
1158 (match d with
1159 Ast.CONTEXT(pos,Ast.BEFOREAFTER(bef,_)) ->
1160 Ast.CONTEXT(pos,Ast.BEFORE(bef))
1161 | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1162 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1163 let middle_metamatch =
1164 matcher
1165 (match d with
1166 Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1167 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1168 let last_metamatch =
1169 matcher
1170 (match d with
1171 Ast.CONTEXT(pos,Ast.BEFOREAFTER(_,aft)) ->
1172 Ast.CONTEXT(pos,Ast.AFTER(aft))
1173 | Ast.CONTEXT(_,_) -> d
1174 | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in
1175
1176 let rest_nodes =
1177 ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in
1178 let left_or = (* the whole statement is one node *)
1179 make_seq guard
1180 [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in
1181 let right_or = (* the statement covers multiple nodes *)
1182 make_seq guard
1183 [first_metamatch;
1184 ctl_au CTL.NONSTRICT
1185 rest_nodes
1186 (make_seq guard
1187 [ctl_and CTL.NONSTRICT last_metamatch label_pred;
1188 and_after guard
1189 (ctl_not prelabel_pred) after])] in
1190 let body f =
1191 ctl_and CTL.NONSTRICT label_pred
1192 (f (ctl_and CTL.NONSTRICT
1193 (make_raw_match label false ast) (ctl_or left_or right_or))) in
1194 let stmt_fvs = Ast.get_fvs stmt in
1195 let fvs = get_unquantified quantified stmt_fvs in
1196 quantify guard (label_var::fvs)
1197 (sequencibility body label_pred process_bef_aft seqible)
1198
1199let svar_minus_or_no_add_after stmt s label quantified d ast
1200 seqible after process_bef_aft guard fvinfo =
1201 let label_var = (*fresh_label_var*) string2var "_lab" in
1202 let label_pred =
1203 CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in
1204 let prelabel_pred =
1205 CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in
1206 let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in
1207 let pure_d =
1208 (* don't have to put anything before the beginning, so don't have to
1209 distinguish the first node. so don't have to bother about paths,
1210 just use the label. label ensures that found nodes match up with
1211 what they should because it is in the lhs of the andany. *)
1212 match d with
1213 Ast.MINUS(pos,[]) -> true
1214 | Ast.CONTEXT(pos,Ast.NOTHING) -> true
1215 | _ -> false in
1216 let ender =
1217 match (pure_d,after) with
1218 (true,Tail) | (true,End) | (true,VeryEnd) ->
1219 (* the label sharing makes it safe to use AndAny *)
1220 CTL.HackForStmt(CTL.FORWARD,CTL.NONSTRICT,
1221 ctl_and CTL.NONSTRICT label_pred
1222 (make_raw_match label false ast),
1223 ctl_and CTL.NONSTRICT (matcher d) prelabel_pred)
1224 | _ ->
1225 (* more safe but less efficient *)
1226 let first_metamatch = matcher d in
1227 let rest_metamatch =
1228 matcher
1229 (match d with
1230 Ast.MINUS(pos,_) -> Ast.MINUS(pos,[])
1231 | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING)
1232 | Ast.PLUS -> failwith "not possible") in
1233 let rest_nodes = ctl_and CTL.NONSTRICT rest_metamatch prelabel_pred in
1234 let last_node = and_after guard (ctl_not prelabel_pred) after in
1235 (ctl_and CTL.NONSTRICT (make_raw_match label false ast)
1236 (make_seq guard
1237 [first_metamatch;
1238 ctl_au CTL.NONSTRICT rest_nodes last_node])) in
1239 let body f = ctl_and CTL.NONSTRICT label_pred (f ender) in
1240 let stmt_fvs = Ast.get_fvs stmt in
1241 let fvs = get_unquantified quantified stmt_fvs in
1242 quantify guard (label_var::fvs)
1243 (sequencibility body label_pred process_bef_aft seqible)
1244
1245(* --------------------------------------------------------------------- *)
1246(* dots and nests *)
1247
1248let dots_au is_strict toend label s wrapcode x seq_after y quantifier =
1249 let matchgoto = gotopred None in
1250 let matchbreak =
1251 make_match None false
1252 (wrapcode
1253 (Ast.Break(Ast.make_mcode "break",Ast.make_mcode ";"))) in
1254 let matchcontinue =
1255 make_match None false
1256 (wrapcode
1257 (Ast.Continue(Ast.make_mcode "continue",Ast.make_mcode ";"))) in
485bce71 1258 let stop_early =
1be43e12 1259 if quantifier = Exists
485bce71 1260 then Common.Left(CTL.False)
34e49164 1261 else if toend
485bce71 1262 then Common.Left(CTL.Or(aftpred label,exitpred label))
34e49164 1263 else if is_strict
485bce71 1264 then Common.Left(aftpred label)
34e49164 1265 else
485bce71
C
1266 Common.Right
1267 (function v ->
1268 let lv = get_label_ctr() in
1269 let labelpred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1270 let preflabelpred = label_pred_maker (Some (lv,ref true)) in
1271 ctl_or (aftpred label)
1272 (quantify false [lv]
1273 (ctl_and CTL.NONSTRICT
1274 (ctl_and CTL.NONSTRICT (truepred label) labelpred)
1275 (ctl_au CTL.NONSTRICT
1276 (ctl_and CTL.NONSTRICT (ctl_not v) preflabelpred)
1277 (ctl_and CTL.NONSTRICT preflabelpred
1278 (ctl_or (retpred None)
1279 (if !Flag_matcher.only_return_is_error_exit
1280 then CTL.True
1281 else
1282 (ctl_or matchcontinue
1283 (ctl_and CTL.NONSTRICT
1284 (ctl_or matchgoto matchbreak)
1285 (ctl_ag s (ctl_not seq_after))))))))))) in
34e49164 1286 let op = if quantifier = !exists then ctl_au else ctl_anti_au in
485bce71
C
1287 let v = get_let_ctr() in
1288 op s x
1289 (match stop_early with
1290 Common.Left x -> ctl_or y x
1291 | Common.Right stop_early ->
1292 CTL.Let(v,y,ctl_or (CTL.Ref v) (stop_early (CTL.Ref v))))
34e49164
C
1293
1294let rec dots_and_nests plus nest whencodes bef aft dotcode after label
1be43e12 1295 process_bef_aft statement_list statement guard quantified wrapcode =
34e49164
C
1296 let ctl_and_ns = ctl_and CTL.NONSTRICT in
1297 (* proces bef_aft *)
1298 let shortest l =
1299 List.fold_left ctl_or_fl CTL.False (List.map process_bef_aft l) in
1300 let bef_aft = (* to be negated *)
1301 try
1302 let _ =
1303 List.find
1304 (function Ast.WhenModifier(Ast.WhenAny) -> true | _ -> false)
1305 whencodes in
1306 CTL.False
1307 with Not_found -> shortest (Common.union_set bef aft) in
1308 let is_strict =
1309 List.exists
1310 (function Ast.WhenModifier(Ast.WhenStrict) -> true | _ -> false)
1311 whencodes in
1312 let check_quantifier quant other =
1313 if List.exists
1314 (function Ast.WhenModifier(x) -> x = quant | _ -> false)
1315 whencodes
1316 then
1317 if List.exists
1318 (function Ast.WhenModifier(x) -> x = other | _ -> false)
1319 whencodes
1320 then failwith "inconsistent annotation on dots"
1321 else true
1322 else false in
1323 let quantifier =
1324 if check_quantifier Ast.WhenExists Ast.WhenForall
1325 then Exists
1326 else
1be43e12 1327 if check_quantifier Ast.WhenForall Ast.WhenExists
34e49164
C
1328 then Forall
1329 else !exists in
1330 (* the following is used when we find a goto, etc and consider accepting
1331 without finding the rest of the pattern *)
1332 let aft = shortest aft in
1333 (* process whencode *)
1334 let labelled = label_pred_maker label in
1335 let whencodes arg =
1336 let (poswhen,negwhen) =
1337 List.fold_left
1338 (function (poswhen,negwhen) ->
1339 function
1340 Ast.WhenNot whencodes ->
1341 (poswhen,ctl_or (statement_list whencodes) negwhen)
1342 | Ast.WhenAlways stm ->
1343 (ctl_and CTL.NONSTRICT (statement stm) poswhen,negwhen)
1be43e12
C
1344 | Ast.WhenModifier(_) -> (poswhen,negwhen)
1345 | Ast.WhenNotTrue(e) ->
1346 (poswhen,
1347 ctl_or (whencond_true e label guard quantified) negwhen)
1348 | Ast.WhenNotFalse(e) ->
1349 (poswhen,
1350 ctl_or (whencond_false e label guard quantified) negwhen))
34e49164
C
1351 (CTL.True,bef_aft) (List.rev whencodes) in
1352 let poswhen = ctl_and_ns arg poswhen in
1353 let negwhen =
1354(* if !exists
1355 then*)
1356 (* add in After, because it's not part of the program *)
1357 ctl_or (aftpred label) negwhen
1358 (*else negwhen*) in
1359 ctl_and_ns poswhen (ctl_not negwhen) in
1360 (* process dot code, if any *)
1361 let dotcode =
1362 match (dotcode,guard) with
1363 (None,_) | (_,true) -> CTL.True
1364 | (Some dotcode,_) -> dotcode in
1365 (* process nest code, if any *)
1366 (* whencode goes in the negated part of the nest; if no nest, just goes
1367 on the "true" in between code *)
1368 let plus_var = if plus then get_label_ctr() else string2var "" in
1369 let plus_var2 = if plus then get_label_ctr() else string2var "" in
1370 let ornest =
1371 match (nest,guard && not plus) with
1372 (None,_) | (_,true) -> whencodes CTL.True
1373 | (Some nest,false) ->
1374 let v = get_let_ctr() in
1375 let is_plus x =
1376 if plus
1377 then
1378 (* the idea is that BindGood is sort of a witness; a witness to
1379 having found the subterm in at least one place. If there is
1380 not a witness, then there is a risk that it will get thrown
1381 away, if it is merged with a node that has an empty
1382 environment. See tests/nestplus. But this all seems
1383 rather suspicious *)
1384 CTL.And(CTL.NONSTRICT,x,
1385 CTL.Exists(true,plus_var2,
1386 CTL.Pred(Lib_engine.BindGood(plus_var),
1387 CTL.Modif plus_var2)))
1388 else x in
1389 CTL.Let(v,nest,
1390 CTL.Or(is_plus (CTL.Ref v),
1391 whencodes (CTL.Not(ctl_uncheck (CTL.Ref v))))) in
1392 let plus_modifier x =
1393 if plus
1394 then
1395 CTL.Exists
1396 (false,plus_var,
1397 (CTL.And
1398 (CTL.NONSTRICT,x,
1399 CTL.Not(CTL.Pred(Lib_engine.BindBad(plus_var),CTL.Control)))))
1400 else x in
1401
1402 let ender =
1403 match after with
1404 After f -> f
1405 | Guard f -> ctl_uncheck f
1406 | VeryEnd ->
1407 let exit = endpred label in
1408 let errorexit = exitpred label in
1409 ctl_or exit errorexit
1410 (* not at all sure what the next two mean... *)
1411 | End -> CTL.True
1412 | Tail ->
1413 (match label with
1414 Some (lv,used) -> used := true;
1415 ctl_or (CTL.Pred(Lib_engine.Label lv,CTL.Control))
1416 (ctl_back_ex (ctl_or (retpred label) (gotopred label)))
1417 | None -> endpred label)
1418 (* was the following, but not clear why sgrep should allow
1419 incomplete patterns
1420 let exit = endpred label in
1421 let errorexit = exitpred label in
1422 if !exists
1423 then ctl_or exit errorexit (* end anywhere *)
1424 else exit (* end at the real end of the function *) *) in
1425 plus_modifier
1426 (dots_au is_strict ((after = Tail) or (after = VeryEnd))
1427 label (guard_to_strict guard) wrapcode
1428 (ctl_and_ns dotcode (ctl_and_ns ornest labelled))
1429 aft ender quantifier)
1430
1be43e12
C
1431and get_whencond_exps e =
1432 match Ast.unwrap e with
1433 Ast.Exp e -> [e]
1434 | Ast.DisjRuleElem(res) ->
1435 List.fold_left Common.union_set [] (List.map get_whencond_exps res)
1436 | _ -> failwith "not possible"
1437
1438and make_whencond_headers e e1 label guard quantified =
1439 let fvs = Ast.get_fvs e in
1440 let header_pred h =
1441 quantify guard (get_unquantified quantified fvs)
1442 (make_match label guard h) in
1443 let if_header e1 =
1444 header_pred
1445 (Ast.rewrap e
1446 (Ast.IfHeader
1447 (Ast.make_mcode "if",
1448 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1449 let while_header e1 =
1450 header_pred
1451 (Ast.rewrap e
1452 (Ast.WhileHeader
1453 (Ast.make_mcode "while",
1454 Ast.make_mcode "(",e1,Ast.make_mcode ")"))) in
1455 let for_header e1 =
1456 header_pred
1457 (Ast.rewrap e
1458 (Ast.ForHeader
1459 (Ast.make_mcode "for",Ast.make_mcode "(",None,Ast.make_mcode ";",
1460 Some e1,Ast.make_mcode ";",None,Ast.make_mcode ")"))) in
1461 let if_headers =
1462 List.fold_left ctl_or CTL.False (List.map if_header e1) in
1463 let while_headers =
1464 List.fold_left ctl_or CTL.False (List.map while_header e1) in
1465 let for_headers =
1466 List.fold_left ctl_or CTL.False (List.map for_header e1) in
1467 (if_headers, while_headers, for_headers)
1468
1469and whencond_true e label guard quantified =
1470 let e1 = get_whencond_exps e in
1471 let (if_headers, while_headers, for_headers) =
1472 make_whencond_headers e e1 label guard quantified in
1473 ctl_or
1474 (ctl_and CTL.NONSTRICT (truepred label) (ctl_back_ex if_headers))
1475 (ctl_and CTL.NONSTRICT
1476 (inlooppred label) (ctl_back_ex (ctl_or while_headers for_headers)))
1477
1478and whencond_false e label guard quantified =
1479 let e1 = get_whencond_exps e in
1480 let (if_headers, while_headers, for_headers) =
1481 make_whencond_headers e e1 label guard quantified in
1482 ctl_or (ctl_and CTL.NONSTRICT (falsepred label) (ctl_back_ex if_headers))
1483 (ctl_and CTL.NONSTRICT (fallpred label)
1484 (ctl_or (ctl_back_ex if_headers)
1485 (ctl_or (ctl_back_ex while_headers) (ctl_back_ex for_headers))))
1486
34e49164
C
1487(* --------------------------------------------------------------------- *)
1488(* the main translation loop *)
1489
1490let rec statement_list stmt_list after quantified minus_quantified
1491 label llabel slabel dots_before guard =
1492 let isdots x =
1493 (* include Disj to be on the safe side *)
1494 match Ast.unwrap x with
1495 Ast.Dots _ | Ast.Nest _ | Ast.Disj _ -> true | _ -> false in
1496 let compute_label l e db = if db or isdots e then l else None in
1497 match Ast.unwrap stmt_list with
1498 Ast.DOTS(x) ->
1499 let rec loop quantified minus_quantified dots_before label llabel slabel
1500 = function
1501 ([],_,_) -> (match after with After f -> f | _ -> CTL.True)
1502 | ([e],_,_) ->
1503 statement e after quantified minus_quantified
1504 (compute_label label e dots_before)
1505 llabel slabel guard
1506 | (e::sl,fv::fvs,mfv::mfvs) ->
1507 let shared = intersectll fv fvs in
1508 let unqshared = get_unquantified quantified shared in
1509 let new_quantified = Common.union_set unqshared quantified in
1510 let minus_shared = intersectll mfv mfvs in
1511 let munqshared =
1512 get_unquantified minus_quantified minus_shared in
1513 let new_mquantified =
1514 Common.union_set munqshared minus_quantified in
1515 quantify guard unqshared
1516 (statement e
1517 (After
1518 (let (label1,llabel1,slabel1) =
1519 match Ast.unwrap e with
1520 Ast.Atomic(re) ->
1521 (match Ast.unwrap re with
1522 Ast.Goto _ -> (None,None,None)
1523 | _ -> (label,llabel,slabel))
1524 | _ -> (label,llabel,slabel) in
1525 loop new_quantified new_mquantified (isdots e)
1526 label1 llabel1 slabel1
1527 (sl,fvs,mfvs)))
1528 new_quantified new_mquantified
1529 (compute_label label e dots_before) llabel slabel guard)
1530 | _ -> failwith "not possible" in
1531 loop quantified minus_quantified dots_before
1532 label llabel slabel
1533 (x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x)
1534 | Ast.CIRCLES(x) -> failwith "not supported"
1535 | Ast.STARS(x) -> failwith "not supported"
1536
1537(* llabel is the label of the enclosing loop and slabel is the label of the
1538 enclosing switch *)
1539and statement stmt after quantified minus_quantified
1540 label llabel slabel guard =
1541 let ctl_au = ctl_au CTL.NONSTRICT in
1542 let ctl_ax = ctl_ax CTL.NONSTRICT in
1543 let ctl_and = ctl_and CTL.NONSTRICT in
1544 let make_seq = make_seq guard in
1545 let make_seq_after = make_seq_after guard in
1546 let real_make_match = make_match in
1547 let make_match = header_match label guard in
1548
1549 let dots_done = ref false in (* hack for dots cases we can easily handle *)
1550
1551 let term =
1552 match Ast.unwrap stmt with
1553 Ast.Atomic(ast) ->
1554 (match Ast.unwrap ast with
1555 (* the following optimisation is not a good idea, because when S
1556 is alone, we would like it not to match a declaration.
1557 this makes more matching for things like when (...) S, but perhaps
1558 that matching is not so costly anyway *)
1559 (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*)
1560 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.BEFOREAFTER(_,_)) as d),_),
1561 keep,seqible,_)
1562 | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.AFTER(_)) as d),_),
1563 keep,seqible,_)->
1564 svar_context_with_add_after stmt s label quantified d ast seqible
1565 after
1566 (process_bef_aft quantified minus_quantified
1567 label llabel slabel true)
1568 guard
1569 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1570
1571 | Ast.MetaStmt((s,_,d,_),keep,seqible,_) ->
1572 svar_minus_or_no_add_after stmt s label quantified d ast seqible
1573 after
1574 (process_bef_aft quantified minus_quantified
1575 label llabel slabel true)
1576 guard
1577 (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt)
1578
1579 | _ ->
1580 let term =
1581 match Ast.unwrap ast with
1582 Ast.DisjRuleElem(res) ->
1583 do_re_matches label guard res quantified minus_quantified
1584 | Ast.Exp(_) | Ast.Ty(_) ->
1585 let stmt_fvs = Ast.get_fvs stmt in
1586 let fvs = get_unquantified quantified stmt_fvs in
1587 CTL.InnerAnd(quantify guard fvs (make_match ast))
1588 | _ ->
1589 let stmt_fvs = Ast.get_fvs stmt in
1590 let fvs = get_unquantified quantified stmt_fvs in
1591 quantify guard fvs (make_match ast) in
1592 match Ast.unwrap ast with
1593 Ast.Break(brk,semi) ->
1594 (match (llabel,slabel) with
1595 (_,Some(lv,used)) -> (* use switch label if there is one *)
1596 ctl_and term (bclabel_pred_maker slabel)
1597 | _ -> ctl_and term (bclabel_pred_maker llabel))
1598 | Ast.Continue(brk,semi) -> ctl_and term (bclabel_pred_maker llabel)
1599 | Ast.Return((_,info,retmc,pos),(_,_,semmc,_)) ->
1600 (* discard pattern that comes after return *)
1601 let normal_res = make_seq_after term after in
1602 (* the following code tries to propagate the modifications on
1603 return; to a close brace, in the case where the final return
1604 is absent *)
1605 let new_mc =
1606 match (retmc,semmc) with
1607 (Ast.MINUS(_,l1),Ast.MINUS(_,l2)) when !Flag.sgrep_mode2 ->
1608 (* in sgrep mode, we can propagate the - *)
1609 Some (Ast.MINUS(Ast.NoPos,l1@l2))
1610 | (Ast.MINUS(_,l1),Ast.MINUS(_,l2))
1611 | (Ast.CONTEXT(_,Ast.BEFORE(l1)),
1612 Ast.CONTEXT(_,Ast.AFTER(l2))) ->
1613 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2)))
1614 | (Ast.CONTEXT(_,Ast.BEFORE(_)),Ast.CONTEXT(_,Ast.NOTHING))
1615 | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.NOTHING)) ->
1616 Some retmc
1617 | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.AFTER(l))) ->
1618 Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l)))
1619 | _ -> None in
1620 let ret = Ast.make_mcode "return" in
1621 let edots =
1622 Ast.rewrap ast (Ast.Edots(Ast.make_mcode "...",None)) in
1623 let semi = Ast.make_mcode ";" in
1624 let simple_return =
1625 make_match(Ast.rewrap ast (Ast.Return(ret,semi))) in
1626 let return_expr =
1627 make_match(Ast.rewrap ast (Ast.ReturnExpr(ret,edots,semi))) in
1628 (match new_mc with
1629 Some new_mc ->
1630 let exit = endpred None in
1631 let mod_rbrace =
1632 Ast.rewrap ast (Ast.SeqEnd (("}",info,new_mc,pos))) in
1633 let stripped_rbrace =
1634 Ast.rewrap ast (Ast.SeqEnd(Ast.make_mcode "}")) in
1635 ctl_or normal_res
1636 (ctl_and (make_match mod_rbrace)
1637 (ctl_and
1638 (ctl_back_ax
1639 (ctl_not
1640 (ctl_uncheck
1641 (ctl_or simple_return return_expr))))
1642 (ctl_au
1643 (make_match stripped_rbrace)
1644 (* error exit not possible; it is in the middle
1645 of code, so a return is needed *)
1646 exit)))
1647 | _ ->
1648 (* some change in the middle of the return, so have to
1649 find an actual return *)
1650 normal_res)
1651 | _ ->
1652 (* should try to deal with the dots_bef_aft problem elsewhere,
1653 but don't have the courage... *)
1654 let term =
1655 if guard
1656 then term
1657 else
1658 do_between_dots stmt term End
1659 quantified minus_quantified label llabel slabel guard in
1660 dots_done := true;
1661 make_seq_after term after)
1662 | Ast.Seq(lbrace,decls,body,rbrace) ->
1663 let (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs) =
1664 match
1665 seq_fvs quantified
1666 [Ast.get_fvs lbrace;Ast.get_fvs decls;
1667 Ast.get_fvs body;Ast.get_fvs rbrace]
1668 with
1669 [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] ->
1670 (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs)
1671 | _ -> failwith "not possible" in
1672 let (mlbfvs,mb1fvs,mb2fvs,mb3fvs,mrbfvs) =
1673 match
1674 seq_fvs minus_quantified
1675 [Ast.get_mfvs lbrace;Ast.get_mfvs decls;
1676 Ast.get_mfvs body;Ast.get_mfvs rbrace]
1677 with
1678 [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] ->
1679 (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs)
1680 | _ -> failwith "not possible" in
1681 let pv = count_nested_braces stmt in
1682 let lv = get_label_ctr() in
1683 let paren_pred = CTL.Pred(Lib_engine.Paren pv,CTL.Control) in
1684 let label_pred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in
1685 let start_brace =
1686 ctl_and
1687 (quantify guard lbfvs (make_match lbrace))
1688 (ctl_and paren_pred label_pred) in
1be43e12
C
1689 let empty_rbrace =
1690 match Ast.unwrap rbrace with
1691 Ast.SeqEnd((data,info,_,pos)) ->
1692 Ast.rewrap rbrace(Ast.SeqEnd(Ast.make_mcode data))
1693 | _ -> failwith "unexpected close brace" in
34e49164
C
1694 let end_brace =
1695 (* label is not needed; paren_pred is enough *)
1be43e12
C
1696 quantify guard rbfvs
1697 (ctl_au (make_match empty_rbrace)
1698 (ctl_and
1699 (real_make_match None guard rbrace)
1700 paren_pred)) in
34e49164
C
1701 let new_quantified2 =
1702 Common.union_set b1fvs (Common.union_set b2fvs quantified) in
1703 let new_quantified3 = Common.union_set b3fvs new_quantified2 in
1704 let new_mquantified2 =
1705 Common.union_set mb1fvs (Common.union_set mb2fvs minus_quantified) in
1706 let new_mquantified3 = Common.union_set mb3fvs new_mquantified2 in
1707 let pattern_as_given =
1708 let new_quantified2 = Common.union_set [pv] new_quantified2 in
1709 let new_quantified3 = Common.union_set [pv] new_quantified3 in
1710 quantify true [pv;lv]
1711 (quantify guard b1fvs
1712 (make_seq
1713 [start_brace;
1714 quantify guard b2fvs
1715 (statement_list decls
1716 (After
1717 (quantify guard b3fvs
1718 (statement_list body
1719 (After (make_seq_after end_brace after))
1720 new_quantified3 new_mquantified3
1721 (Some (lv,ref true)) (* label mostly useful *)
1722 llabel slabel true guard)))
1723 new_quantified2 new_mquantified2
1724 (Some (lv,ref true)) llabel slabel false guard)])) in
1725 if ends_in_return body
1726 then
1727 (* matching error handling code *)
1728 (* Cases:
1729 1. The pattern as given
1730 2. A goto, and then some close braces, and then the pattern as
1731 given, but without the braces (only possible if there are no
1732 decls, and open and close braces are unmodified)
1733 3. Part of the pattern as given, then a goto, and then the rest
1734 of the pattern. For this case, we just check that all paths have
1735 a goto within the current braces. checking for a goto at every
1736 point in the pattern seems expensive and not worthwhile. *)
1737 let pattern2 =
34e49164
C
1738 let body = preprocess_dots body in (* redo, to drop braces *)
1739 make_seq
1740 [gotopred label;
1741 ctl_au
1742 (make_match empty_rbrace)
1743 (ctl_ax (* skip the destination label *)
1744 (quantify guard b3fvs
1745 (statement_list body End
1746 new_quantified3 new_mquantified3 None llabel slabel
1747 true guard)))] in
1748 let pattern3 =
1749 let new_quantified2 = Common.union_set [pv] new_quantified2 in
1750 let new_quantified3 = Common.union_set [pv] new_quantified3 in
1751 quantify true [pv;lv]
1752 (quantify guard b1fvs
1753 (make_seq
1754 [start_brace;
1755 ctl_and
1756 (CTL.AU (* want AF even for sgrep *)
1757 (CTL.FORWARD,CTL.STRICT,
1758 CTL.Pred(Lib_engine.PrefixLabel(lv),CTL.Control),
1759 ctl_and (* brace must be eventually after goto *)
1760 (gotopred (Some (lv,ref true)))
1761 (* want AF even for sgrep *)
1762 (CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace))))
1763 (quantify guard b2fvs
1764 (statement_list decls
1765 (After
1766 (quantify guard b3fvs
1767 (statement_list body Tail
1768 (*After
1769 (make_seq_after
1770 nopv_end_brace after)*)
1771 new_quantified3 new_mquantified3
1772 None llabel slabel true guard)))
1773 new_quantified2 new_mquantified2
1774 (Some (lv,ref true))
1775 llabel slabel false guard))])) in
1776 ctl_or pattern_as_given
1777 (match Ast.unwrap decls with
1778 Ast.DOTS([]) -> ctl_or pattern2 pattern3
1779 | Ast.DOTS(l) -> pattern3
1780 | _ -> failwith "circles and stars not supported")
1781 else pattern_as_given
1782 | Ast.IfThen(ifheader,branch,aft) ->
1783 ifthen ifheader branch aft after quantified minus_quantified
1784 label llabel slabel statement make_match guard
1785
1786 | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) ->
1787 ifthenelse ifheader branch1 els branch2 aft after quantified
1788 minus_quantified label llabel slabel statement make_match guard
1789
1790 | Ast.While(header,body,aft) | Ast.For(header,body,aft)
1791 | Ast.Iterator(header,body,aft) ->
1792 forwhile header body aft after quantified minus_quantified
1793 label statement make_match guard
1794
1795 | Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *)
1796 ctl_and
1797 (label_pred_maker label)
1798 (List.fold_left ctl_seqor CTL.False
1799 (List.map
1800 (function sl ->
1801 statement_list sl after quantified minus_quantified label
1802 llabel slabel true guard)
1803 stmt_dots_list))
1804
1805 | Ast.Nest(stmt_dots,whencode,multi,bef,aft) ->
1806 (* label in recursive call is None because label check is already
1807 wrapped around the corresponding code *)
1808
1809 let bfvs =
1810 match seq_fvs quantified [Ast.get_wcfvs whencode;Ast.get_fvs stmt_dots]
1811 with
1812 [(wcfvs,bothfvs);(bdfvs,_)] -> bothfvs
1813 | _ -> failwith "not possible" in
1814
1815 (* no minus version because when code doesn't contain any minus code *)
1816 let new_quantified = Common.union_set bfvs quantified in
1817
1818 quantify guard bfvs
1819 (let dots_pattern =
1820 statement_list stmt_dots (a2n after) new_quantified minus_quantified
1821 None llabel slabel true guard in
1822 dots_and_nests multi
1823 (Some dots_pattern) whencode bef aft None after label
1824 (process_bef_aft new_quantified minus_quantified
1825 None llabel slabel true)
1826 (function x ->
1827 statement_list x Tail new_quantified minus_quantified None
1828 llabel slabel true true)
1829 (function x ->
1830 statement x Tail new_quantified minus_quantified None
1831 llabel slabel true)
1be43e12
C
1832 guard quantified
1833 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x)))
34e49164
C
1834
1835 | Ast.Dots((_,i,d,_),whencodes,bef,aft) ->
1836 let dot_code =
1837 match d with
1838 Ast.MINUS(_,_) ->
1839 (* no need for the fresh metavar, but ... is a bit wierd as a
1840 variable name *)
1841 Some(make_match (make_meta_rule_elem d ([],[],[])))
1842 | _ -> None in
1843 dots_and_nests false None whencodes bef aft dot_code after label
1844 (process_bef_aft quantified minus_quantified None llabel slabel true)
1845 (function x ->
1846 statement_list x Tail quantified minus_quantified
1847 None llabel slabel true true)
1848 (function x ->
1849 statement x Tail quantified minus_quantified None llabel slabel true)
1be43e12
C
1850 guard quantified
1851 (function x -> Ast.set_fvs [] (Ast.rewrap stmt x))
34e49164
C
1852
1853 | Ast.Switch(header,lb,cases,rb) ->
1854 let rec intersect_all = function
1855 [] -> []
1856 | [x] -> x
1857 | x::xs -> intersect x (intersect_all xs) in
1858 let rec union_all l = List.fold_left union [] l in
1859 (* start normal variables *)
1860 let header_fvs = Ast.get_fvs header in
1861 let lb_fvs = Ast.get_fvs lb in
1862 let case_fvs = List.map Ast.get_fvs cases in
1863 let rb_fvs = Ast.get_fvs rb in
1864 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1865 all_casefvs,all_b3fvs,all_rbfvs) =
1866 List.fold_left
1867 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1868 all_casefvs,all_b3fvs,all_rbfvs) ->
1869 function case_fvs ->
1870 match seq_fvs quantified [header_fvs;lb_fvs;case_fvs;rb_fvs] with
1871 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
1872 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
1873 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
1874 rbfvs::all_rbfvs)
1875 | _ -> failwith "not possible")
1876 ([],[],[],[],[],[],[]) case_fvs in
1877 let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1878 all_casefvs,all_b3fvs,all_rbfvs) =
1879 (List.rev all_efvs,List.rev all_b1fvs,List.rev all_lbfvs,
1880 List.rev all_b2fvs,List.rev all_casefvs,List.rev all_b3fvs,
1881 List.rev all_rbfvs) in
1882 let exponlyfvs = intersect_all all_efvs in
1883 let lbonlyfvs = intersect_all all_lbfvs in
1884(* don't do anything with right brace. Hope there is no + code on it *)
1885(* let rbonlyfvs = intersect_all all_rbfvs in*)
1886 let b1fvs = union_all all_b1fvs in
1887 let new1_quantified = union b1fvs quantified in
1888 let b2fvs = union (union_all all_b1fvs) (intersect_all all_casefvs) in
1889 let new2_quantified = union b2fvs new1_quantified in
1890(* let b3fvs = union_all all_b3fvs in*)
1891 (* ------------------- start minus free variables *)
1892 let header_mfvs = Ast.get_mfvs header in
1893 let lb_mfvs = Ast.get_mfvs lb in
1894 let case_mfvs = List.map Ast.get_mfvs cases in
1895 let rb_mfvs = Ast.get_mfvs rb in
1896 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
1897 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
1898 List.fold_left
1899 (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs,
1900 all_casefvs,all_b3fvs,all_rbfvs) ->
1901 function case_mfvs ->
1902 match
1903 seq_fvs quantified
1904 [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with
1905 [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] ->
1906 (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs,
1907 b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs,
1908 rbfvs::all_rbfvs)
1909 | _ -> failwith "not possible")
1910 ([],[],[],[],[],[],[]) case_mfvs in
1911 let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs,
1912 all_mcasefvs,all_mb3fvs,all_mrbfvs) =
1913 (List.rev all_mefvs,List.rev all_mb1fvs,List.rev all_mlbfvs,
1914 List.rev all_mb2fvs,List.rev all_mcasefvs,List.rev all_mb3fvs,
1915 List.rev all_mrbfvs) in
1916(* don't do anything with right brace. Hope there is no + code on it *)
1917(* let rbonlyfvs = intersect_all all_rbfvs in*)
1918 let mb1fvs = union_all all_mb1fvs in
1919 let new1_mquantified = union mb1fvs quantified in
1920 let mb2fvs = union (union_all all_mb1fvs) (intersect_all all_mcasefvs) in
1921 let new2_mquantified = union mb2fvs new1_mquantified in
1922(* let b3fvs = union_all all_b3fvs in*)
1923 (* ------------------- end collection of free variables *)
1924 let switch_header = quantify guard exponlyfvs (make_match header) in
1925 let lb = quantify guard lbonlyfvs (make_match lb) in
1926(* let rb = quantify guard rbonlyfvs (make_match rb) in*)
1927 let case_headers =
1928 List.map
1929 (function case_line ->
1930 match Ast.unwrap case_line with
1931 Ast.CaseLine(header,body) ->
1932 let e1fvs =
1933 match seq_fvs new2_quantified [Ast.get_fvs header] with
1934 [(e1fvs,_)] -> e1fvs
1935 | _ -> failwith "not possible" in
1936 quantify guard e1fvs (real_make_match label true header)
1937 | Ast.OptCase(case_line) -> failwith "not supported")
1938 cases in
1939 let no_header =
1940 ctl_not (List.fold_left ctl_or_fl CTL.False case_headers) in
1941 let lv = get_label_ctr() in
1942 let used = ref false in
1943 let case_code =
1944 List.map
1945 (function case_line ->
1946 match Ast.unwrap case_line with
1947 Ast.CaseLine(header,body) ->
1948 let (e1fvs,b1fvs,s1fvs) =
1949 let fvs = [Ast.get_fvs header;Ast.get_fvs body] in
1950 match seq_fvs new2_quantified fvs with
1951 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
1952 | _ -> failwith "not possible" in
1953 let (me1fvs,mb1fvs,ms1fvs) =
1954 let fvs = [Ast.get_mfvs header;Ast.get_mfvs body] in
1955 match seq_fvs new2_mquantified fvs with
1956 [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs)
1957 | _ -> failwith "not possible" in
1958 let case_header =
1959 quantify guard e1fvs (make_match header) in
1960 let new3_quantified = union b1fvs new2_quantified in
1961 let new3_mquantified = union mb1fvs new2_mquantified in
1962 let body =
1963 statement_list body Tail
1964 new3_quantified new3_mquantified label llabel
1965 (Some (lv,used)) true(*?*) guard in
1966 quantify guard b1fvs (make_seq [case_header; body])
1967 | Ast.OptCase(case_line) -> failwith "not supported")
1968 cases in
1969 let default_required =
1970 if List.exists
1971 (function case ->
1972 match Ast.unwrap case with
1973 Ast.CaseLine(header,_) ->
1974 (match Ast.unwrap header with
1975 Ast.Default(_,_) -> true
1976 | _ -> false)
1977 | _ -> false)
1978 cases
1979 then function x -> x
1980 else function x -> ctl_or (fallpred label) x in
1981 let after_pred = aftpred label in
1982 let body after_branch =
1983 ctl_or
1984 (default_required
1985 (quantify guard b2fvs
1986 (make_seq
1987 [ctl_and lb
1988 (List.fold_left ctl_and CTL.True
1989 (List.map ctl_ex case_headers));
1990 List.fold_left ctl_or_fl no_header case_code])))
1991 after_branch in
1992 let aft =
1993 (rb_fvs,Ast.get_fresh rb,Ast.get_inherited rb,
1994 match Ast.unwrap rb with
1995 Ast.SeqEnd(rb) -> Ast.get_mcodekind rb
1996 | _ -> failwith "not possible") in
1997 let (switch_header,wrapper) =
1998 if !used
1999 then
2000 let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in
2001 (ctl_and switch_header label_pred,
2002 (function body -> quantify true [lv] body))
2003 else (switch_header,function x -> x) in
2004 wrapper
2005 (end_control_structure b1fvs switch_header body
2006 after_pred (Some(ctl_ex after_pred)) None aft after label guard)
2007 | Ast.FunDecl(header,lbrace,decls,body,rbrace) ->
2008 let (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs) =
2009 match
2010 seq_fvs quantified
2011 [Ast.get_fvs header;Ast.get_fvs lbrace;Ast.get_fvs decls;
2012 Ast.get_fvs body;Ast.get_fvs rbrace]
2013 with
2014 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] ->
2015 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs)
2016 | _ -> failwith "not possible" in
2017 let (mhfvs,mb1fvs,mlbfvs,mb2fvs,mb3fvs,mb4fvs,mrbfvs) =
2018 match
2019 seq_fvs quantified
2020 [Ast.get_mfvs header;Ast.get_mfvs lbrace;Ast.get_mfvs decls;
2021 Ast.get_mfvs body;Ast.get_mfvs rbrace]
2022 with
2023 [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] ->
2024 (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs)
2025 | _ -> failwith "not possible" in
2026 let function_header = quantify guard hfvs (make_match header) in
2027 let start_brace = quantify guard lbfvs (make_match lbrace) in
2028 let stripped_rbrace =
2029 match Ast.unwrap rbrace with
2030 Ast.SeqEnd((data,info,_,_)) ->
2031 Ast.rewrap rbrace(Ast.SeqEnd (Ast.make_mcode data))
2032 | _ -> failwith "unexpected close brace" in
2033 let end_brace =
2034 let exit = CTL.Pred (Lib_engine.Exit,CTL.Control) in
2035 let errorexit = CTL.Pred (Lib_engine.ErrorExit,CTL.Control) in
2036 let fake_brace = CTL.Pred (Lib_engine.FakeBrace,CTL.Control) in
2037 ctl_and
2038 (quantify guard rbfvs (make_match rbrace))
2039 (ctl_and
2040 (* the following finds the beginning of the fake braces,
2041 if there are any, not completely sure how this works.
2042 sse the examples sw and return *)
2043 (ctl_back_ex (ctl_not fake_brace))
2044 (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in
2045 let new_quantified3 =
2046 Common.union_set b1fvs
2047 (Common.union_set b2fvs (Common.union_set b3fvs quantified)) in
2048 let new_quantified4 = Common.union_set b4fvs new_quantified3 in
2049 let new_mquantified3 =
2050 Common.union_set mb1fvs
2051 (Common.union_set mb2fvs
2052 (Common.union_set mb3fvs minus_quantified)) in
2053 let new_mquantified4 = Common.union_set mb4fvs new_mquantified3 in
2054 let fn_nest =
91eba41f
C
2055 match (Ast.undots decls,Ast.undots body,
2056 contains_modif rbrace or contains_pos rbrace) with
34e49164
C
2057 ([],[body],false) ->
2058 (match Ast.unwrap body with
2059 Ast.Nest(stmt_dots,[],multi,_,_) ->
2060 if multi
2061 then None (* not sure how to optimize this case *)
2062 else Some (Common.Left stmt_dots)
1be43e12
C
2063 | Ast.Dots(_,whencode,_,_) when
2064 (List.for_all
2065 (* flow sensitive, so not optimizable *)
2066 (function Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2067 false
2068 | _ -> true) whencode) ->
2069 Some (Common.Right whencode)
34e49164
C
2070 | _ -> None)
2071 | _ -> None in
2072 let body_code =
2073 match fn_nest with
2074 Some (Common.Left stmt_dots) ->
2075 (* special case for function header + body - header is unambiguous
2076 and unique, so we can just look for the nested body anywhere
2077 else in the CFG *)
2078 CTL.AndAny
2079 (CTL.FORWARD,guard_to_strict guard,start_brace,
2080 statement_list stmt_dots
2081 (* discards match on right brace, but don't need it *)
2082 (Guard (make_seq_after end_brace after))
2083 new_quantified4 new_mquantified4
2084 None llabel slabel true guard)
2085 | Some (Common.Right whencode) ->
2086 (* try to be more efficient for the case where the body is just
2087 ... Perhaps this is too much of a special case, but useful
2088 for dropping a parameter and checking that it is never used. *)
2089 make_seq
2090 [start_brace;
2091 match whencode with
2092 [] -> CTL.True
2093 | _ ->
2094 let leftarg =
2095 ctl_and
2096 (ctl_not
2097 (List.fold_left
2098 (function prev ->
2099 function
2100 Ast.WhenAlways(s) -> prev
2101 | Ast.WhenNot(sl) ->
2102 let x =
2103 statement_list sl Tail
2104 new_quantified4 new_mquantified4
2105 label llabel slabel true true in
2106 ctl_or prev x
1be43e12
C
2107 | Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2108 failwith "unexpected"
34e49164
C
2109 | Ast.WhenModifier(Ast.WhenAny) -> CTL.False
2110 | Ast.WhenModifier(_) -> prev)
2111 CTL.False whencode))
2112 (List.fold_left
2113 (function prev ->
2114 function
2115 Ast.WhenAlways(s) ->
2116 let x =
2117 statement s Tail
2118 new_quantified4 new_mquantified4
2119 label llabel slabel true in
2120 ctl_and prev x
2121 | Ast.WhenNot(sl) -> prev
1be43e12
C
2122 | Ast.WhenNotTrue(_) | Ast.WhenNotFalse(_) ->
2123 failwith "unexpected"
34e49164
C
2124 | Ast.WhenModifier(Ast.WhenAny) -> CTL.True
2125 | Ast.WhenModifier(_) -> prev)
2126 CTL.True whencode) in
2127 ctl_au leftarg (make_match stripped_rbrace)]
2128 | None ->
2129 make_seq
2130 [start_brace;
2131 quantify guard b3fvs
2132 (statement_list decls
2133 (After
2134 (quantify guard b4fvs
2135 (statement_list body
2136 (After (make_seq_after end_brace after))
2137 new_quantified4 new_mquantified4
2138 None llabel slabel true guard)))
2139 new_quantified3 new_mquantified3 None llabel slabel
2140 false guard)] in
2141 quantify guard b1fvs
2142 (make_seq [function_header; quantify guard b2fvs body_code])
2143 | Ast.Define(header,body) ->
2144 let (hfvs,bfvs,bodyfvs) =
2145 match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body]
2146 with
2147 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2148 | _ -> failwith "not possible" in
2149 let (mhfvs,mbfvs,mbodyfvs) =
2150 match seq_fvs minus_quantified [Ast.get_mfvs header;Ast.get_mfvs body]
2151 with
2152 [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs)
2153 | _ -> failwith "not possible" in
2154 let define_header = quantify guard hfvs (make_match header) in
2155 let body_code =
2156 statement_list body after
2157 (Common.union_set bfvs quantified)
2158 (Common.union_set mbfvs minus_quantified)
2159 None llabel slabel true guard in
2160 quantify guard bfvs (make_seq [define_header; body_code])
2161 | Ast.OptStm(stm) ->
2162 failwith "OptStm should have been compiled away\n"
2163 | Ast.UniqueStm(stm) -> failwith "arities not yet supported"
2164 | _ -> failwith "not supported" in
2165 if guard or !dots_done
2166 then term
2167 else
2168 do_between_dots stmt term after quantified minus_quantified
2169 label llabel slabel guard
2170
2171(* term is the translation of stmt *)
2172and do_between_dots stmt term after quantified minus_quantified
2173 label llabel slabel guard =
2174 match Ast.get_dots_bef_aft stmt with
2175 Ast.AddingBetweenDots (brace_term,n)
2176 | Ast.DroppingBetweenDots (brace_term,n) ->
2177 let match_brace =
2178 statement brace_term after quantified minus_quantified
2179 label llabel slabel guard in
2180 let v = Printf.sprintf "_r_%d" n in
2181 let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in
2182 let case2 = ctl_and CTL.NONSTRICT (ctl_not (CTL.Ref v)) term in
2183 CTL.Let
2184 (v,ctl_or
2185 (ctl_back_ex (ctl_or (truepred label) (inlooppred label)))
2186 (ctl_back_ex (ctl_back_ex (falsepred label))),
2187 ctl_or case1 case2)
2188 | Ast.NoDots -> term
2189
2190(* un_process_bef_aft is because we don't want to do transformation in this
2191 code, and thus don't case about braces before or after it *)
2192and process_bef_aft quantified minus_quantified label llabel slabel guard =
2193 function
2194 Ast.WParen (re,n) ->
2195 let paren_pred = CTL.Pred (Lib_engine.Paren n,CTL.Control) in
2196 let s = guard_to_strict guard in
2197 quantify true (get_unquantified quantified [n])
2198 (ctl_and s (make_raw_match None guard re) paren_pred)
2199 | Ast.Other s ->
2200 statement s Tail quantified minus_quantified label llabel slabel guard
2201 | Ast.Other_dots d ->
2202 statement_list d Tail quantified minus_quantified
2203 label llabel slabel true guard
2204
2205(* --------------------------------------------------------------------- *)
2206(* cleanup: convert AX to EX for pdots.
2207Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2208This is what we wanted in the first place, but it wasn't possible to make
2209because the AX and its argument are not created in the same place.
2210Rather clunky... *)
2211(* also cleanup XX, which is a marker for the case where the programmer
2212specifies to change the quantifier on .... Assumed to only occur after one AX
2213or EX, or at top level. *)
2214
2215let rec cleanup c =
2216 let c = match c with CTL.XX(c) -> c | _ -> c in
2217 match c with
2218 CTL.False -> CTL.False
2219 | CTL.True -> CTL.True
2220 | CTL.Pred(p) -> CTL.Pred(p)
2221 | CTL.Not(phi) -> CTL.Not(cleanup phi)
2222 | CTL.Exists(keep,v,phi) -> CTL.Exists(keep,v,cleanup phi)
2223 | CTL.AndAny(dir,s,phi1,phi2) ->
2224 CTL.AndAny(dir,s,cleanup phi1,cleanup phi2)
2225 | CTL.HackForStmt(dir,s,phi1,phi2) ->
2226 CTL.HackForStmt(dir,s,cleanup phi1,cleanup phi2)
2227 | CTL.And(s,phi1,phi2) -> CTL.And(s,cleanup phi1,cleanup phi2)
2228 | CTL.Or(phi1,phi2) -> CTL.Or(cleanup phi1,cleanup phi2)
2229 | CTL.SeqOr(phi1,phi2) -> CTL.SeqOr(cleanup phi1,cleanup phi2)
2230 | CTL.Implies(phi1,phi2) -> CTL.Implies(cleanup phi1,cleanup phi2)
2231 | CTL.AF(dir,s,phi1) -> CTL.AF(dir,s,cleanup phi1)
2232 | CTL.AX(CTL.FORWARD,s,
2233 CTL.Let(v1,e1,
2234 CTL.And(CTL.NONSTRICT,CTL.AU(CTL.FORWARD,s2,e2,e3),
2235 CTL.EU(CTL.FORWARD,e4,e5)))) ->
2236 CTL.Let(v1,e1,
2237 CTL.And(CTL.NONSTRICT,
2238 CTL.AX(CTL.FORWARD,s,CTL.AU(CTL.FORWARD,s2,e2,e3)),
2239 CTL.EX(CTL.FORWARD,CTL.EU(CTL.FORWARD,e4,e5))))
1be43e12 2240 | CTL.AX(dir,s,CTL.XX(phi)) -> CTL.EX(dir,cleanup phi)
34e49164 2241 | CTL.EX(dir,CTL.XX((CTL.AU(_,s,_,_)) as phi)) ->
1be43e12 2242 CTL.AX(dir,s,cleanup phi)
34e49164
C
2243 | CTL.XX(phi) -> failwith "bad XX"
2244 | CTL.AX(dir,s,phi1) -> CTL.AX(dir,s,cleanup phi1)
2245 | CTL.AG(dir,s,phi1) -> CTL.AG(dir,s,cleanup phi1)
2246 | CTL.EF(dir,phi1) -> CTL.EF(dir,cleanup phi1)
2247 | CTL.EX(dir,phi1) -> CTL.EX(dir,cleanup phi1)
2248 | CTL.EG(dir,phi1) -> CTL.EG(dir,cleanup phi1)
2249 | CTL.AW(dir,s,phi1,phi2) -> CTL.AW(dir,s,cleanup phi1,cleanup phi2)
2250 | CTL.AU(dir,s,phi1,phi2) -> CTL.AU(dir,s,cleanup phi1,cleanup phi2)
2251 | CTL.EU(dir,phi1,phi2) -> CTL.EU(dir,cleanup phi1,cleanup phi2)
2252 | CTL.Let (x,phi1,phi2) -> CTL.Let (x,cleanup phi1,cleanup phi2)
2253 | CTL.LetR (dir,x,phi1,phi2) -> CTL.LetR (dir,x,cleanup phi1,cleanup phi2)
2254 | CTL.Ref(s) -> CTL.Ref(s)
2255 | CTL.Uncheck(phi1) -> CTL.Uncheck(cleanup phi1)
2256 | CTL.InnerAnd(phi1) -> CTL.InnerAnd(cleanup phi1)
2257
2258(* --------------------------------------------------------------------- *)
2259(* Function declaration *)
2260
2261let top_level name (ua,pos) t =
2262 let ua = List.filter (function (nm,_) -> nm = name) ua in
2263 used_after := ua;
2264 saved := Ast.get_saved t;
2265 let quantified = Common.minus_set ua pos in
2266 quantify false quantified
2267 (match Ast.unwrap t with
2268 Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo"
2269 | Ast.DECL(stmt) ->
2270 let unopt = elim_opt.V.rebuilder_statement stmt in
2271 let unopt = preprocess_dots_e unopt in
2272 cleanup(statement unopt VeryEnd quantified [] None None None false)
2273 | Ast.CODE(stmt_dots) ->
2274 let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in
2275 let unopt = preprocess_dots unopt in
2276 let starts_with_dots =
2277 match Ast.undots stmt_dots with
2278 d::ds ->
2279 (match Ast.unwrap d with
2280 Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
2281 | Ast.Stars(_,_,_,_) -> true
2282 | _ -> false)
2283 | _ -> false in
2284 let starts_with_brace =
2285 match Ast.undots stmt_dots with
2286 d::ds ->
2287 (match Ast.unwrap d with
2288 Ast.Seq(_) -> true
2289 | _ -> false)
2290 | _ -> false in
2291 let res =
2292 statement_list unopt VeryEnd quantified [] None None None
2293 false false in
2294 cleanup
2295 (if starts_with_dots
2296 then
2297 (* EX because there is a loop on enter/top *)
2298 ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res)
2299 else if starts_with_brace
2300 then
2301 ctl_and CTL.NONSTRICT
2302 (ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res
2303 else res)
2304 | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords")
2305
2306(* --------------------------------------------------------------------- *)
2307(* Entry points *)
2308
2309let asttoctlz (name,(_,_,exists_flag),l) used_after positions =
2310 letctr := 0;
2311 labelctr := 0;
2312 (match exists_flag with
2313 Ast.Exists -> exists := Exists
2314 | Ast.Forall -> exists := Forall
2315 | Ast.ReverseForall -> exists := ReverseForall
2316 | Ast.Undetermined ->
2317 exists := if !Flag.sgrep_mode2 then Exists else Forall);
2318
2319 let (l,used_after) =
2320 List.split
2321 (List.filter
2322 (function (t,_) ->
2323 match Ast.unwrap t with Ast.ERRORWORDS(exps) -> false | _ -> true)
2324 (List.combine l (List.combine used_after positions))) in
2325 let res = List.map2 (top_level name) used_after l in
2326 exists := Forall;
2327 res
2328
2329let asttoctl r used_after positions =
2330 match r with
2331 Ast.ScriptRule _ -> []
2332 | Ast.CocciRule (a,b,c,_) -> asttoctlz (a,b,c) used_after positions
2333
2334let pp_cocci_predicate (pred,modif) =
2335 Pretty_print_engine.pp_predicate pred
2336
2337let cocci_predicate_to_string (pred,modif) =
2338 Pretty_print_engine.predicate_to_string pred