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