46e77e23424f5444581a48da5e332e1a08c422b9
[bpt/coccinelle.git] / parsing_cocci / iso_pattern.ml
1 (*
2 * Copyright 2005-2009, 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 (* Potential problem: offset of mcode is not updated when an iso is
24 instantiated, implying that a term may end up with many mcodes with the
25 same offset. On the other hand, at the moment offset only seems to be used
26 before this phase. Furthermore add_dot_binding relies on the offset to
27 remain the same between matching an iso and instantiating it with bindings. *)
28
29 (* --------------------------------------------------------------------- *)
30 (* match a SmPL expression against a SmPL abstract syntax tree,
31 either - or + *)
32
33 module Ast = Ast_cocci
34 module Ast0 = Ast0_cocci
35 module V0 = Visitor_ast0
36 module VT0 = Visitor_ast0_types
37
38 let current_rule = ref ""
39
40 (* --------------------------------------------------------------------- *)
41
42 type isomorphism =
43 Ast_cocci.metavar list * Ast0_cocci.anything list list * string (* name *)
44
45 let strip_info =
46 let mcode (term,_,_,_,_) =
47 (term,Ast0.NONE,Ast0.default_info(),Ast0.PLUS,ref Ast0.NoMetaPos) in
48 let donothing r k e =
49 let x = k e in
50 {(Ast0.wrap (Ast0.unwrap x)) with
51 Ast0.mcodekind = ref Ast0.PLUS;
52 Ast0.true_if_test = x.Ast0.true_if_test} in
53 V0.flat_rebuilder
54 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
55 donothing donothing donothing donothing donothing donothing
56 donothing donothing donothing donothing donothing donothing donothing
57 donothing donothing
58
59 let anything_equal = function
60 (Ast0.DotsExprTag(d1),Ast0.DotsExprTag(d2)) ->
61 failwith "not a possible variable binding" (*not sure why these are pbs*)
62 | (Ast0.DotsInitTag(d1),Ast0.DotsInitTag(d2)) ->
63 failwith "not a possible variable binding"
64 | (Ast0.DotsParamTag(d1),Ast0.DotsParamTag(d2)) ->
65 failwith "not a possible variable binding"
66 | (Ast0.DotsStmtTag(d1),Ast0.DotsStmtTag(d2)) ->
67 (strip_info.VT0.rebuilder_rec_statement_dots d1) =
68 (strip_info.VT0.rebuilder_rec_statement_dots d2)
69 | (Ast0.DotsDeclTag(d1),Ast0.DotsDeclTag(d2)) ->
70 failwith "not a possible variable binding"
71 | (Ast0.DotsCaseTag(d1),Ast0.DotsCaseTag(d2)) ->
72 failwith "not a possible variable binding"
73 | (Ast0.IdentTag(d1),Ast0.IdentTag(d2)) ->
74 (strip_info.VT0.rebuilder_rec_ident d1) = (strip_info.VT0.rebuilder_rec_ident d2)
75 | (Ast0.ExprTag(d1),Ast0.ExprTag(d2)) ->
76 (strip_info.VT0.rebuilder_rec_expression d1) =
77 (strip_info.VT0.rebuilder_rec_expression d2)
78 | (Ast0.ArgExprTag(_),_) | (_,Ast0.ArgExprTag(_)) ->
79 failwith "not possible - only in isos1"
80 | (Ast0.TestExprTag(_),_) | (_,Ast0.TestExprTag(_)) ->
81 failwith "not possible - only in isos1"
82 | (Ast0.TypeCTag(d1),Ast0.TypeCTag(d2)) ->
83 (strip_info.VT0.rebuilder_rec_typeC d1) =
84 (strip_info.VT0.rebuilder_rec_typeC d2)
85 | (Ast0.InitTag(d1),Ast0.InitTag(d2)) ->
86 (strip_info.VT0.rebuilder_rec_initialiser d1) =
87 (strip_info.VT0.rebuilder_rec_initialiser d2)
88 | (Ast0.ParamTag(d1),Ast0.ParamTag(d2)) ->
89 (strip_info.VT0.rebuilder_rec_parameter d1) =
90 (strip_info.VT0.rebuilder_rec_parameter d2)
91 | (Ast0.DeclTag(d1),Ast0.DeclTag(d2)) ->
92 (strip_info.VT0.rebuilder_rec_declaration d1) =
93 (strip_info.VT0.rebuilder_rec_declaration d2)
94 | (Ast0.StmtTag(d1),Ast0.StmtTag(d2)) ->
95 (strip_info.VT0.rebuilder_rec_statement d1) =
96 (strip_info.VT0.rebuilder_rec_statement d2)
97 | (Ast0.CaseLineTag(d1),Ast0.CaseLineTag(d2)) ->
98 (strip_info.VT0.rebuilder_rec_case_line d1) =
99 (strip_info.VT0.rebuilder_rec_case_line d2)
100 | (Ast0.TopTag(d1),Ast0.TopTag(d2)) ->
101 (strip_info.VT0.rebuilder_rec_top_level d1) =
102 (strip_info.VT0.rebuilder_rec_top_level d2)
103 | (Ast0.IsoWhenTTag(_),_) | (_,Ast0.IsoWhenTTag(_)) ->
104 failwith "only for isos within iso phase"
105 | (Ast0.IsoWhenFTag(_),_) | (_,Ast0.IsoWhenFTag(_)) ->
106 failwith "only for isos within iso phase"
107 | (Ast0.IsoWhenTag(_),_) | (_,Ast0.IsoWhenTag(_)) ->
108 failwith "only for isos within iso phase"
109 | _ -> false
110
111 let term (var1,_,_,_,_) = var1
112 let dot_term (var1,_,info,_,_) =
113 ("", var1 ^ (string_of_int info.Ast0.pos_info.Ast0.offset))
114
115
116 type reason =
117 NotPure of Ast0.pure * (string * string) * Ast0.anything
118 | NotPureLength of (string * string)
119 | ContextRequired of Ast0.anything
120 | NonMatch
121 | Braces of Ast0.statement
122 | Position of string * string
123 | TypeMatch of reason list
124
125 let rec interpret_reason name line reason printer =
126 Printf.printf
127 "warning: iso %s does not match the code below on line %d\n" name line;
128 printer(); Format.print_newline();
129 match reason with
130 NotPure(Ast0.Pure,(_,var),nonpure) ->
131 Printf.printf
132 "pure metavariable %s is matched against the following nonpure code:\n"
133 var;
134 Unparse_ast0.unparse_anything nonpure
135 | NotPure(Ast0.Context,(_,var),nonpure) ->
136 Printf.printf
137 "context metavariable %s is matched against the following\nnoncontext code:\n"
138 var;
139 Unparse_ast0.unparse_anything nonpure
140 | NotPure(Ast0.PureContext,(_,var),nonpure) ->
141 Printf.printf
142 "pure context metavariable %s is matched against the following\nnonpure or noncontext code:\n"
143 var;
144 Unparse_ast0.unparse_anything nonpure
145 | NotPureLength((_,var)) ->
146 Printf.printf
147 "pure metavariable %s is matched against too much or too little code\n"
148 var;
149 | ContextRequired(term) ->
150 Printf.printf
151 "the following code matched is not uniformly minus or context,\nor contains a disjunction:\n";
152 Unparse_ast0.unparse_anything term
153 | Braces(s) ->
154 Printf.printf "braces must be all minus (plus code allowed) or all\ncontext (plus code not allowed in the body) to match:\n";
155 Unparse_ast0.statement "" s;
156 Format.print_newline()
157 | Position(rule,name) ->
158 Printf.printf "position variable %s.%s conflicts with an isomorphism\n"
159 rule name;
160 | TypeMatch reason_list ->
161 List.iter (function r -> interpret_reason name line r printer)
162 reason_list
163 | _ -> failwith "not possible"
164
165 type 'a either = OK of 'a | Fail of reason
166
167 let add_binding var exp bindings =
168 let var = term var in
169 let attempt bindings =
170 try
171 let cur = List.assoc var bindings in
172 if anything_equal(exp,cur) then [bindings] else []
173 with Not_found -> [((var,exp)::bindings)] in
174 match List.concat(List.map attempt bindings) with
175 [] -> Fail NonMatch
176 | x -> OK x
177
178 let add_dot_binding var exp bindings =
179 let var = dot_term var in
180 let attempt bindings =
181 try
182 let cur = List.assoc var bindings in
183 if anything_equal(exp,cur) then [bindings] else []
184 with Not_found -> [((var,exp)::bindings)] in
185 match List.concat(List.map attempt bindings) with
186 [] -> Fail NonMatch
187 | x -> OK x
188
189 (* multi-valued *)
190 let add_multi_dot_binding var exp bindings =
191 let var = dot_term var in
192 let attempt bindings = [((var,exp)::bindings)] in
193 match List.concat(List.map attempt bindings) with
194 [] -> Fail NonMatch
195 | x -> OK x
196
197 let rec nub ls =
198 match ls with
199 [] -> []
200 | (x::xs) when (List.mem x xs) -> nub xs
201 | (x::xs) -> x::(nub xs)
202
203 (* --------------------------------------------------------------------- *)
204
205 let init_env = [[]]
206
207 let debug str m binding =
208 let res = m binding in
209 (match res with
210 None -> Printf.printf "%s: failed\n" str
211 | Some binding ->
212 List.iter
213 (function binding ->
214 Printf.printf "%s: %s\n" str
215 (String.concat " " (List.map (function (x,_) -> x) binding)))
216 binding);
217 res
218
219 let conjunct_bindings
220 (m1 : 'binding -> 'binding either)
221 (m2 : 'binding -> 'binding either)
222 (binding : 'binding) : 'binding either =
223 match m1 binding with Fail(reason) -> Fail(reason) | OK binding -> m2 binding
224
225 let rec conjunct_many_bindings = function
226 [] -> failwith "not possible"
227 | [x] -> x
228 | x::xs -> conjunct_bindings x (conjunct_many_bindings xs)
229
230 let mcode_equal (x,_,_,_,_) (y,_,_,_,_) = x = y
231
232 let return b binding = if b then OK binding else Fail NonMatch
233 let return_false reason binding = Fail reason
234
235 let match_option f t1 t2 =
236 match (t1,t2) with
237 (Some t1, Some t2) -> f t1 t2
238 | (None, None) -> return true
239 | _ -> return false
240
241 let bool_match_option f t1 t2 =
242 match (t1,t2) with
243 (Some t1, Some t2) -> f t1 t2
244 | (None, None) -> true
245 | _ -> false
246
247 (* context_required is for the example
248 if (
249 + (int * )
250 x == NULL)
251 where we can't change x == NULL to eg NULL == x. So there can either be
252 nothing attached to the root or the term has to be all removed.
253 if would be nice if we knew more about the relationship between the - and +
254 code, because in the case where the + code is a separate statement in a
255 sequence, this is not a problem. Perhaps something could be done in
256 insert_plus
257
258 The example seems strange. Why isn't the cast attached to x?
259 *)
260 let is_context e =
261 !Flag.sgrep_mode2 or (* everything is context for sgrep *)
262 (match Ast0.get_mcodekind e with
263 Ast0.CONTEXT(cell) -> true
264 | _ -> false)
265
266 (* needs a special case when there is a Disj or an empty DOTS
267 the following stops at the statement level, and gives true if one
268 statement is replaced by another *)
269 let rec is_pure_context s =
270 !Flag.sgrep_mode2 or (* everything is context for sgrep *)
271 (match Ast0.unwrap s with
272 Ast0.Disj(starter,statement_dots_list,mids,ender) ->
273 List.for_all
274 (function x ->
275 match Ast0.undots x with
276 [s] -> is_pure_context s
277 | _ -> false (* could we do better? *))
278 statement_dots_list
279 | _ ->
280 (match Ast0.get_mcodekind s with
281 Ast0.CONTEXT(mc) ->
282 (match !mc with
283 (Ast.NOTHING,_,_) -> true
284 | _ -> false)
285 | Ast0.MINUS(mc) ->
286 (match !mc with
287 (* do better for the common case of replacing a stmt by another one *)
288 ([[Ast.StatementTag(s)]],_) ->
289 (match Ast.unwrap s with
290 Ast.IfThen(_,_,_) -> false (* potentially dangerous *)
291 | _ -> true)
292 | (_,_) -> false)
293 | _ -> false))
294
295 let is_minus e =
296 match Ast0.get_mcodekind e with Ast0.MINUS(cell) -> true | _ -> false
297
298 let match_list matcher is_list_matcher do_list_match la lb =
299 let rec loop = function
300 ([],[]) -> return true
301 | ([x],lb) when is_list_matcher x -> do_list_match x lb
302 | (x::xs,y::ys) -> conjunct_bindings (matcher x y) (loop (xs,ys))
303 | _ -> return false in
304 loop (la,lb)
305
306 let match_maker checks_needed context_required whencode_allowed =
307
308 let check_mcode pmc cmc binding =
309 if checks_needed
310 then
311 match Ast0.get_pos cmc with
312 (Ast0.MetaPos (name,_,_)) as x ->
313 (match Ast0.get_pos pmc with
314 Ast0.MetaPos (name1,_,_) ->
315 add_binding name1 (Ast0.MetaPosTag x) binding
316 | Ast0.NoMetaPos ->
317 let (rule,name) = Ast0.unwrap_mcode name in
318 Fail (Position(rule,name)))
319 | Ast0.NoMetaPos -> OK binding
320 else OK binding in
321
322 let match_dots matcher is_list_matcher do_list_match d1 d2 =
323 match (Ast0.unwrap d1, Ast0.unwrap d2) with
324 (Ast0.DOTS(la),Ast0.DOTS(lb))
325 | (Ast0.CIRCLES(la),Ast0.CIRCLES(lb))
326 | (Ast0.STARS(la),Ast0.STARS(lb)) ->
327 match_list matcher is_list_matcher (do_list_match d2) la lb
328 | _ -> return false in
329
330 let is_elist_matcher el =
331 match Ast0.unwrap el with Ast0.MetaExprList(_,_,_) -> true | _ -> false in
332
333 let is_plist_matcher pl =
334 match Ast0.unwrap pl with Ast0.MetaParamList(_,_,_) -> true | _ -> false in
335
336 let is_slist_matcher pl =
337 match Ast0.unwrap pl with Ast0.MetaStmtList(_,_) -> true | _ -> false in
338
339 let no_list _ = false in
340
341 let build_dots pattern data =
342 match Ast0.unwrap pattern with
343 Ast0.DOTS(_) -> Ast0.rewrap pattern (Ast0.DOTS(data))
344 | Ast0.CIRCLES(_) -> Ast0.rewrap pattern (Ast0.CIRCLES(data))
345 | Ast0.STARS(_) -> Ast0.rewrap pattern (Ast0.STARS(data)) in
346
347 let pure_sp_code =
348 let bind = Ast0.lub_pure in
349 let option_default = Ast0.Context in
350 let pure_mcodekind mc =
351 if !Flag.sgrep_mode2
352 then Ast0.PureContext
353 else
354 match mc with
355 Ast0.CONTEXT(mc) ->
356 (match !mc with
357 (Ast.NOTHING,_,_) -> Ast0.PureContext
358 | _ -> Ast0.Context)
359 | Ast0.MINUS(mc) ->
360 (match !mc with ([],_) -> Ast0.Pure | _ -> Ast0.Impure)
361 | _ -> Ast0.Impure in
362 let donothing r k e =
363 bind (pure_mcodekind (Ast0.get_mcodekind e)) (k e) in
364
365 let mcode m = pure_mcodekind (Ast0.get_mcode_mcodekind m) in
366
367 (* a case for everything that has a metavariable *)
368 (* pure is supposed to match only unitary metavars, not anything that
369 contains only unitary metavars *)
370 let ident r k i =
371 bind (bind (pure_mcodekind (Ast0.get_mcodekind i)) (k i))
372 (match Ast0.unwrap i with
373 Ast0.MetaId(name,_,pure) | Ast0.MetaFunc(name,_,pure)
374 | Ast0.MetaLocalFunc(name,_,pure) -> pure
375 | _ -> Ast0.Impure) in
376
377 let expression r k e =
378 bind (bind (pure_mcodekind (Ast0.get_mcodekind e)) (k e))
379 (match Ast0.unwrap e with
380 Ast0.MetaErr(name,_,pure)
381 | Ast0.MetaExpr(name,_,_,_,pure) | Ast0.MetaExprList(name,_,pure) ->
382 pure
383 | _ -> Ast0.Impure) in
384
385 let typeC r k t =
386 bind (bind (pure_mcodekind (Ast0.get_mcodekind t)) (k t))
387 (match Ast0.unwrap t with
388 Ast0.MetaType(name,pure) -> pure
389 | _ -> Ast0.Impure) in
390
391 let init r k t =
392 bind (bind (pure_mcodekind (Ast0.get_mcodekind t)) (k t))
393 (match Ast0.unwrap t with
394 Ast0.MetaInit(name,pure) -> pure
395 | _ -> Ast0.Impure) in
396
397 let param r k p =
398 bind (bind (pure_mcodekind (Ast0.get_mcodekind p)) (k p))
399 (match Ast0.unwrap p with
400 Ast0.MetaParam(name,pure) | Ast0.MetaParamList(name,_,pure) -> pure
401 | _ -> Ast0.Impure) in
402
403 let stmt r k s =
404 bind (bind (pure_mcodekind (Ast0.get_mcodekind s)) (k s))
405 (match Ast0.unwrap s with
406 Ast0.MetaStmt(name,pure) | Ast0.MetaStmtList(name,pure) -> pure
407 | _ -> Ast0.Impure) in
408
409 V0.flat_combiner bind option_default
410 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
411 donothing donothing donothing donothing donothing donothing
412 ident expression typeC init param donothing stmt donothing
413 donothing in
414
415 let add_pure_list_binding name pure is_pure builder1 builder2 lst =
416 match (checks_needed,pure) with
417 (true,Ast0.Pure) | (true,Ast0.Context) | (true,Ast0.PureContext) ->
418 (match lst with
419 [x] ->
420 if (Ast0.lub_pure (is_pure x) pure) = pure
421 then add_binding name (builder1 lst)
422 else return_false (NotPure (pure,term name,builder1 lst))
423 | _ -> return_false (NotPureLength (term name)))
424 | (false,_) | (_,Ast0.Impure) -> add_binding name (builder2 lst) in
425
426 let add_pure_binding name pure is_pure builder x =
427 match (checks_needed,pure) with
428 (true,Ast0.Pure) | (true,Ast0.Context) | (true,Ast0.PureContext) ->
429 if (Ast0.lub_pure (is_pure x) pure) = pure
430 then add_binding name (builder x)
431 else return_false (NotPure (pure,term name, builder x))
432 | (false,_) | (_,Ast0.Impure) -> add_binding name (builder x) in
433
434 let do_elist_match builder el lst =
435 match Ast0.unwrap el with
436 Ast0.MetaExprList(name,lenname,pure) ->
437 (*how to handle lenname? should it be an option type and always None?*)
438 failwith "expr list pattern not supported in iso"
439 (*add_pure_list_binding name pure
440 pure_sp_code.V0.combiner_expression
441 (function lst -> Ast0.ExprTag(List.hd lst))
442 (function lst -> Ast0.DotsExprTag(build_dots builder lst))
443 lst*)
444 | _ -> failwith "not possible" in
445
446 let do_plist_match builder pl lst =
447 match Ast0.unwrap pl with
448 Ast0.MetaParamList(name,lename,pure) ->
449 failwith "param list pattern not supported in iso"
450 (*add_pure_list_binding name pure
451 pure_sp_code.V0.combiner_parameter
452 (function lst -> Ast0.ParamTag(List.hd lst))
453 (function lst -> Ast0.DotsParamTag(build_dots builder lst))
454 lst*)
455 | _ -> failwith "not possible" in
456
457 let do_slist_match builder sl lst =
458 match Ast0.unwrap sl with
459 Ast0.MetaStmtList(name,pure) ->
460 add_pure_list_binding name pure
461 pure_sp_code.VT0.combiner_rec_statement
462 (function lst -> Ast0.StmtTag(List.hd lst))
463 (function lst -> Ast0.DotsStmtTag(build_dots builder lst))
464 lst
465 | _ -> failwith "not possible" in
466
467 let do_nolist_match _ _ = failwith "not possible" in
468
469 let rec match_ident pattern id =
470 match Ast0.unwrap pattern with
471 Ast0.MetaId(name,_,pure) ->
472 (add_pure_binding name pure pure_sp_code.VT0.combiner_rec_ident
473 (function id -> Ast0.IdentTag id) id)
474 | Ast0.MetaFunc(name,_,pure) -> failwith "metafunc not supported"
475 | Ast0.MetaLocalFunc(name,_,pure) -> failwith "metalocalfunc not supported"
476 | up ->
477 if not(checks_needed) or not(context_required) or is_context id
478 then
479 match (up,Ast0.unwrap id) with
480 (Ast0.Id(namea),Ast0.Id(nameb)) ->
481 if mcode_equal namea nameb
482 then check_mcode namea nameb
483 else return false
484 | (Ast0.OptIdent(ida),Ast0.OptIdent(idb))
485 | (Ast0.UniqueIdent(ida),Ast0.UniqueIdent(idb)) ->
486 match_ident ida idb
487 | (_,Ast0.OptIdent(idb))
488 | (_,Ast0.UniqueIdent(idb)) -> match_ident pattern idb
489 | _ -> return false
490 else return_false (ContextRequired (Ast0.IdentTag id)) in
491
492 (* should we do something about matching metavars against ...? *)
493 let rec match_expr pattern expr =
494 match Ast0.unwrap pattern with
495 Ast0.MetaExpr(name,_,ty,form,pure) ->
496 let form_ok =
497 match (form,expr) with
498 (Ast.ANY,_) -> true
499 | (Ast.CONST,e) ->
500 let rec matches e =
501 match Ast0.unwrap e with
502 Ast0.Constant(c) -> true
503 | Ast0.Cast(lp,ty,rp,e) -> matches e
504 | Ast0.SizeOfExpr(se,exp) -> true
505 | Ast0.SizeOfType(se,lp,ty,rp) -> true
506 | Ast0.MetaExpr(nm,_,_,Ast.CONST,p) ->
507 (Ast0.lub_pure p pure) = pure
508 | _ -> false in
509 matches e
510 | (Ast.ID,e) | (Ast.LocalID,e) ->
511 let rec matches e =
512 match Ast0.unwrap e with
513 Ast0.Ident(c) -> true
514 | Ast0.Cast(lp,ty,rp,e) -> matches e
515 | Ast0.MetaExpr(nm,_,_,Ast.ID,p) ->
516 (Ast0.lub_pure p pure) = pure
517 | _ -> false in
518 matches e in
519 if form_ok
520 then
521 match ty with
522 Some ts ->
523 if List.exists
524 (function Type_cocci.MetaType(_,_,_) -> true | _ -> false)
525 ts
526 then
527 (match ts with
528 [Type_cocci.MetaType(tyname,_,_)] ->
529 let expty =
530 match (Ast0.unwrap expr,Ast0.get_type expr) with
531 (* easier than updating type inferencer to manage multiple
532 types *)
533 (Ast0.MetaExpr(_,_,Some tts,_,_),_) -> Some tts
534 | (_,Some ty) -> Some [ty]
535 | _ -> None in
536 (match expty with
537 Some expty ->
538 let tyname = Ast0.rewrap_mcode name tyname in
539 conjunct_bindings
540 (add_pure_binding name pure
541 pure_sp_code.VT0.combiner_rec_expression
542 (function expr -> Ast0.ExprTag expr)
543 expr)
544 (function bindings ->
545 let attempts =
546 List.map
547 (function expty ->
548 (try
549 add_pure_binding tyname Ast0.Impure
550 (function _ -> Ast0.Impure)
551 (function ty -> Ast0.TypeCTag ty)
552 (Ast0.rewrap expr
553 (Ast0.reverse_type expty))
554 bindings
555 with Ast0.TyConv ->
556 Printf.printf
557 "warning: unconvertible type";
558 return false bindings))
559 expty in
560 if List.exists
561 (function Fail _ -> false | OK x -> true)
562 attempts
563 then
564 (* not sure why this is ok. can there be more
565 than one OK? *)
566 OK (List.concat
567 (List.map
568 (function Fail _ -> [] | OK x -> x)
569 attempts))
570 else
571 Fail
572 (TypeMatch
573 (List.map
574 (function
575 Fail r -> r
576 | OK x -> failwith "not possible")
577 attempts)))
578 | _ ->
579 (*Printf.printf
580 "warning: type metavar can only match one type";*)
581 return false)
582 | _ ->
583 failwith
584 "mixture of metatype and other types not supported")
585 else
586 let expty = Ast0.get_type expr in
587 if List.exists (function t -> Type_cocci.compatible t expty) ts
588 then
589 add_pure_binding name pure
590 pure_sp_code.VT0.combiner_rec_expression
591 (function expr -> Ast0.ExprTag expr)
592 expr
593 else return false
594 | None ->
595 add_pure_binding name pure pure_sp_code.VT0.combiner_rec_expression
596 (function expr -> Ast0.ExprTag expr)
597 expr
598 else return false
599 | Ast0.MetaErr(namea,_,pure) -> failwith "metaerr not supported"
600 | Ast0.MetaExprList(_,_,_) -> failwith "metaexprlist not supported"
601 | up ->
602 if not(checks_needed) or not(context_required) or is_context expr
603 then
604 match (up,Ast0.unwrap expr) with
605 (Ast0.Ident(ida),Ast0.Ident(idb)) ->
606 match_ident ida idb
607 | (Ast0.Constant(consta),Ast0.Constant(constb)) ->
608 if mcode_equal consta constb
609 then check_mcode consta constb
610 else return false
611 | (Ast0.FunCall(fna,lp1,argsa,rp1),Ast0.FunCall(fnb,lp,argsb,rp)) ->
612 conjunct_many_bindings
613 [check_mcode lp1 lp; check_mcode rp1 rp; match_expr fna fnb;
614 match_dots match_expr is_elist_matcher do_elist_match
615 argsa argsb]
616 | (Ast0.Assignment(lefta,opa,righta,_),
617 Ast0.Assignment(leftb,opb,rightb,_)) ->
618 if mcode_equal opa opb
619 then
620 conjunct_many_bindings
621 [check_mcode opa opb; match_expr lefta leftb;
622 match_expr righta rightb]
623 else return false
624 | (Ast0.CondExpr(exp1a,lp1,exp2a,rp1,exp3a),
625 Ast0.CondExpr(exp1b,lp,exp2b,rp,exp3b)) ->
626 conjunct_many_bindings
627 [check_mcode lp1 lp; check_mcode rp1 rp;
628 match_expr exp1a exp1b; match_option match_expr exp2a exp2b;
629 match_expr exp3a exp3b]
630 | (Ast0.Postfix(expa,opa),Ast0.Postfix(expb,opb)) ->
631 if mcode_equal opa opb
632 then
633 conjunct_bindings (check_mcode opa opb) (match_expr expa expb)
634 else return false
635 | (Ast0.Infix(expa,opa),Ast0.Infix(expb,opb)) ->
636 if mcode_equal opa opb
637 then
638 conjunct_bindings (check_mcode opa opb) (match_expr expa expb)
639 else return false
640 | (Ast0.Unary(expa,opa),Ast0.Unary(expb,opb)) ->
641 if mcode_equal opa opb
642 then
643 conjunct_bindings (check_mcode opa opb) (match_expr expa expb)
644 else return false
645 | (Ast0.Binary(lefta,opa,righta),Ast0.Binary(leftb,opb,rightb)) ->
646 if mcode_equal opa opb
647 then
648 conjunct_many_bindings
649 [check_mcode opa opb; match_expr lefta leftb;
650 match_expr righta rightb]
651 else return false
652 | (Ast0.Paren(lp1,expa,rp1),Ast0.Paren(lp,expb,rp)) ->
653 conjunct_many_bindings
654 [check_mcode lp1 lp; check_mcode rp1 rp; match_expr expa expb]
655 | (Ast0.ArrayAccess(exp1a,lb1,exp2a,rb1),
656 Ast0.ArrayAccess(exp1b,lb,exp2b,rb)) ->
657 conjunct_many_bindings
658 [check_mcode lb1 lb; check_mcode rb1 rb;
659 match_expr exp1a exp1b; match_expr exp2a exp2b]
660 | (Ast0.RecordAccess(expa,opa,fielda),
661 Ast0.RecordAccess(expb,op,fieldb))
662 | (Ast0.RecordPtAccess(expa,opa,fielda),
663 Ast0.RecordPtAccess(expb,op,fieldb)) ->
664 conjunct_many_bindings
665 [check_mcode opa op; match_expr expa expb;
666 match_ident fielda fieldb]
667 | (Ast0.Cast(lp1,tya,rp1,expa),Ast0.Cast(lp,tyb,rp,expb)) ->
668 conjunct_many_bindings
669 [check_mcode lp1 lp; check_mcode rp1 rp;
670 match_typeC tya tyb; match_expr expa expb]
671 | (Ast0.SizeOfExpr(szf1,expa),Ast0.SizeOfExpr(szf,expb)) ->
672 conjunct_bindings (check_mcode szf1 szf) (match_expr expa expb)
673 | (Ast0.SizeOfType(szf1,lp1,tya,rp1),
674 Ast0.SizeOfType(szf,lp,tyb,rp)) ->
675 conjunct_many_bindings
676 [check_mcode lp1 lp; check_mcode rp1 rp;
677 check_mcode szf1 szf; match_typeC tya tyb]
678 | (Ast0.TypeExp(tya),Ast0.TypeExp(tyb)) ->
679 match_typeC tya tyb
680 | (Ast0.EComma(cm1),Ast0.EComma(cm)) -> check_mcode cm1 cm
681 | (Ast0.DisjExpr(_,expsa,_,_),_) ->
682 failwith "not allowed in the pattern of an isomorphism"
683 | (Ast0.NestExpr(_,exp_dotsa,_,_,_),_) ->
684 failwith "not allowed in the pattern of an isomorphism"
685 | (Ast0.Edots(d,None),Ast0.Edots(d1,None))
686 | (Ast0.Ecircles(d,None),Ast0.Ecircles(d1,None))
687 | (Ast0.Estars(d,None),Ast0.Estars(d1,None)) -> check_mcode d d1
688 | (Ast0.Edots(ed,None),Ast0.Edots(ed1,Some wc))
689 | (Ast0.Ecircles(ed,None),Ast0.Ecircles(ed1,Some wc))
690 | (Ast0.Estars(ed,None),Ast0.Estars(ed1,Some wc)) ->
691 (* hope that mcode of edots is unique somehow *)
692 conjunct_bindings (check_mcode ed ed1)
693 (let (edots_whencode_allowed,_,_) = whencode_allowed in
694 if edots_whencode_allowed
695 then add_dot_binding ed (Ast0.ExprTag wc)
696 else
697 (Printf.printf
698 "warning: not applying iso because of whencode";
699 return false))
700 | (Ast0.Edots(_,Some _),_) | (Ast0.Ecircles(_,Some _),_)
701 | (Ast0.Estars(_,Some _),_) ->
702 failwith "whencode not allowed in a pattern1"
703 | (Ast0.OptExp(expa),Ast0.OptExp(expb))
704 | (Ast0.UniqueExp(expa),Ast0.UniqueExp(expb)) -> match_expr expa expb
705 | (_,Ast0.OptExp(expb))
706 | (_,Ast0.UniqueExp(expb)) -> match_expr pattern expb
707 | _ -> return false
708 else return_false (ContextRequired (Ast0.ExprTag expr))
709
710 (* the special case for function types prevents the eg T X; -> T X = E; iso
711 from applying, which doesn't seem very relevant, but it also avoids a
712 mysterious bug that is obtained with eg int attach(...); *)
713 and match_typeC pattern t =
714 match Ast0.unwrap pattern with
715 Ast0.MetaType(name,pure) ->
716 (match Ast0.unwrap t with
717 Ast0.FunctionType(tya,lp1a,paramsa,rp1a) -> return false
718 | _ ->
719 add_pure_binding name pure pure_sp_code.VT0.combiner_rec_typeC
720 (function ty -> Ast0.TypeCTag ty)
721 t)
722 | up ->
723 if not(checks_needed) or not(context_required) or is_context t
724 then
725 match (up,Ast0.unwrap t) with
726 (Ast0.ConstVol(cva,tya),Ast0.ConstVol(cvb,tyb)) ->
727 if mcode_equal cva cvb
728 then
729 conjunct_bindings (check_mcode cva cvb) (match_typeC tya tyb)
730 else return false
731 | (Ast0.BaseType(tya,stringsa),Ast0.BaseType(tyb,stringsb)) ->
732 if tya = tyb
733 then
734 match_list check_mcode
735 (function _ -> false) (function _ -> failwith "")
736 stringsa stringsb
737 else return false
738 | (Ast0.Signed(signa,tya),Ast0.Signed(signb,tyb)) ->
739 if mcode_equal signa signb
740 then
741 conjunct_bindings (check_mcode signa signb)
742 (match_option match_typeC tya tyb)
743 else return false
744 | (Ast0.Pointer(tya,star1),Ast0.Pointer(tyb,star)) ->
745 conjunct_bindings (check_mcode star1 star) (match_typeC tya tyb)
746 | (Ast0.FunctionPointer(tya,lp1a,stara,rp1a,lp2a,paramsa,rp2a),
747 Ast0.FunctionPointer(tyb,lp1b,starb,rp1b,lp2b,paramsb,rp2b)) ->
748 conjunct_many_bindings
749 [check_mcode stara starb; check_mcode lp1a lp1b;
750 check_mcode rp1a rp1b; check_mcode lp2a lp2b;
751 check_mcode rp2a rp2b; match_typeC tya tyb;
752 match_dots match_param is_plist_matcher
753 do_plist_match paramsa paramsb]
754 | (Ast0.FunctionType(tya,lp1a,paramsa,rp1a),
755 Ast0.FunctionType(tyb,lp1b,paramsb,rp1b)) ->
756 conjunct_many_bindings
757 [check_mcode lp1a lp1b; check_mcode rp1a rp1b;
758 match_option match_typeC tya tyb;
759 match_dots match_param is_plist_matcher do_plist_match
760 paramsa paramsb]
761 | (Ast0.Array(tya,lb1,sizea,rb1),Ast0.Array(tyb,lb,sizeb,rb)) ->
762 conjunct_many_bindings
763 [check_mcode lb1 lb; check_mcode rb1 rb;
764 match_typeC tya tyb; match_option match_expr sizea sizeb]
765 | (Ast0.EnumName(kinda,namea),Ast0.EnumName(kindb,nameb)) ->
766 conjunct_bindings (check_mcode kinda kindb)
767 (match_ident namea nameb)
768 | (Ast0.StructUnionName(kinda,Some namea),
769 Ast0.StructUnionName(kindb,Some nameb)) ->
770 if mcode_equal kinda kindb
771 then
772 conjunct_bindings (check_mcode kinda kindb)
773 (match_ident namea nameb)
774 else return false
775 | (Ast0.StructUnionDef(tya,lb1,declsa,rb1),
776 Ast0.StructUnionDef(tyb,lb,declsb,rb)) ->
777 conjunct_many_bindings
778 [check_mcode lb1 lb; check_mcode rb1 rb;
779 match_typeC tya tyb;
780 match_dots match_decl no_list do_nolist_match declsa declsb]
781 | (Ast0.TypeName(namea),Ast0.TypeName(nameb)) ->
782 if mcode_equal namea nameb
783 then check_mcode namea nameb
784 else return false
785 | (Ast0.DisjType(_,typesa,_,_),Ast0.DisjType(_,typesb,_,_)) ->
786 failwith "not allowed in the pattern of an isomorphism"
787 | (Ast0.OptType(tya),Ast0.OptType(tyb))
788 | (Ast0.UniqueType(tya),Ast0.UniqueType(tyb)) -> match_typeC tya tyb
789 | (_,Ast0.OptType(tyb))
790 | (_,Ast0.UniqueType(tyb)) -> match_typeC pattern tyb
791 | _ -> return false
792 else return_false (ContextRequired (Ast0.TypeCTag t))
793
794 and match_decl pattern d =
795 if not(checks_needed) or not(context_required) or is_context d
796 then
797 match (Ast0.unwrap pattern,Ast0.unwrap d) with
798 (Ast0.Init(stga,tya,ida,eq1,inia,sc1),
799 Ast0.Init(stgb,tyb,idb,eq,inib,sc)) ->
800 if bool_match_option mcode_equal stga stgb
801 then
802 conjunct_many_bindings
803 [check_mcode eq1 eq; check_mcode sc1 sc;
804 match_option check_mcode stga stgb;
805 match_typeC tya tyb; match_ident ida idb;
806 match_init inia inib]
807 else return false
808 | (Ast0.UnInit(stga,tya,ida,sc1),Ast0.UnInit(stgb,tyb,idb,sc)) ->
809 if bool_match_option mcode_equal stga stgb
810 then
811 conjunct_many_bindings
812 [check_mcode sc1 sc; match_option check_mcode stga stgb;
813 match_typeC tya tyb; match_ident ida idb]
814 else return false
815 | (Ast0.MacroDecl(namea,lp1,argsa,rp1,sc1),
816 Ast0.MacroDecl(nameb,lp,argsb,rp,sc)) ->
817 conjunct_many_bindings
818 [match_ident namea nameb;
819 check_mcode lp1 lp; check_mcode rp1 rp;
820 check_mcode sc1 sc;
821 match_dots match_expr is_elist_matcher do_elist_match
822 argsa argsb]
823 | (Ast0.TyDecl(tya,sc1),Ast0.TyDecl(tyb,sc)) ->
824 conjunct_bindings (check_mcode sc1 sc) (match_typeC tya tyb)
825 | (Ast0.Typedef(stga,tya,ida,sc1),Ast0.Typedef(stgb,tyb,idb,sc)) ->
826 conjunct_bindings (check_mcode sc1 sc)
827 (conjunct_bindings (match_typeC tya tyb) (match_typeC ida idb))
828 | (Ast0.DisjDecl(_,declsa,_,_),Ast0.DisjDecl(_,declsb,_,_)) ->
829 failwith "not allowed in the pattern of an isomorphism"
830 | (Ast0.Ddots(d1,None),Ast0.Ddots(d,None)) -> check_mcode d1 d
831 | (Ast0.Ddots(dd,None),Ast0.Ddots(d,Some wc)) ->
832 conjunct_bindings (check_mcode dd d)
833 (* hope that mcode of ddots is unique somehow *)
834 (let (ddots_whencode_allowed,_,_) = whencode_allowed in
835 if ddots_whencode_allowed
836 then add_dot_binding dd (Ast0.DeclTag wc)
837 else
838 (Printf.printf "warning: not applying iso because of whencode";
839 return false))
840 | (Ast0.Ddots(_,Some _),_) ->
841 failwith "whencode not allowed in a pattern1"
842
843 | (Ast0.OptDecl(decla),Ast0.OptDecl(declb))
844 | (Ast0.UniqueDecl(decla),Ast0.UniqueDecl(declb)) ->
845 match_decl decla declb
846 | (_,Ast0.OptDecl(declb))
847 | (_,Ast0.UniqueDecl(declb)) ->
848 match_decl pattern declb
849 | _ -> return false
850 else return_false (ContextRequired (Ast0.DeclTag d))
851
852 and match_init pattern i =
853 match Ast0.unwrap pattern with
854 Ast0.MetaInit(name,pure) ->
855 add_pure_binding name pure pure_sp_code.VT0.combiner_rec_initialiser
856 (function ini -> Ast0.InitTag ini)
857 i
858 | up ->
859 if not(checks_needed) or not(context_required) or is_context i
860 then
861 match (up,Ast0.unwrap i) with
862 (Ast0.InitExpr(expa),Ast0.InitExpr(expb)) ->
863 match_expr expa expb
864 | (Ast0.InitList(lb1,initlista,rb1),Ast0.InitList(lb,initlistb,rb))
865 ->
866 conjunct_many_bindings
867 [check_mcode lb1 lb; check_mcode rb1 rb;
868 match_dots match_init no_list do_nolist_match
869 initlista initlistb]
870 | (Ast0.InitGccExt(designators1,e1,inia),
871 Ast0.InitGccExt(designators2,e2,inib)) ->
872 conjunct_many_bindings
873 [match_list match_designator
874 (function _ -> false) (function _ -> failwith "")
875 designators1 designators2;
876 check_mcode e1 e2;
877 match_init inia inib]
878 | (Ast0.InitGccName(namea,c1,inia),Ast0.InitGccName(nameb,c,inib)) ->
879 conjunct_many_bindings
880 [check_mcode c1 c; match_ident namea nameb;
881 match_init inia inib]
882 | (Ast0.IComma(c1),Ast0.IComma(c)) -> check_mcode c1 c
883 | (Ast0.Idots(d1,None),Ast0.Idots(d,None)) -> check_mcode d1 d
884 | (Ast0.Idots(id,None),Ast0.Idots(d,Some wc)) ->
885 conjunct_bindings (check_mcode id d)
886 (* hope that mcode of edots is unique somehow *)
887 (let (_,idots_whencode_allowed,_) = whencode_allowed in
888 if idots_whencode_allowed
889 then add_dot_binding id (Ast0.InitTag wc)
890 else
891 (Printf.printf
892 "warning: not applying iso because of whencode";
893 return false))
894 | (Ast0.Idots(_,Some _),_) ->
895 failwith "whencode not allowed in a pattern2"
896 | (Ast0.OptIni(ia),Ast0.OptIni(ib))
897 | (Ast0.UniqueIni(ia),Ast0.UniqueIni(ib)) -> match_init ia ib
898 | (_,Ast0.OptIni(ib))
899 | (_,Ast0.UniqueIni(ib)) -> match_init pattern ib
900 | _ -> return false
901 else return_false (ContextRequired (Ast0.InitTag i))
902
903 and match_designator pattern d =
904 match (pattern,d) with
905 (Ast0.DesignatorField(dota,ida),Ast0.DesignatorField(dotb,idb)) ->
906 conjunct_bindings (check_mcode dota dotb) (match_ident ida idb)
907 | (Ast0.DesignatorIndex(lba,expa,rba),
908 Ast0.DesignatorIndex(lbb,expb,rbb)) ->
909 conjunct_many_bindings
910 [check_mcode lba lbb; match_expr expa expb;
911 check_mcode rba rbb]
912 | (Ast0.DesignatorRange(lba,mina,dotsa,maxa,rba),
913 Ast0.DesignatorRange(lbb,minb,dotsb,maxb,rbb)) ->
914 conjunct_many_bindings
915 [check_mcode lba lbb; match_expr mina minb;
916 check_mcode dotsa dotsb; match_expr maxa maxb;
917 check_mcode rba rbb]
918 | _ -> return false
919
920 and match_param pattern p =
921 match Ast0.unwrap pattern with
922 Ast0.MetaParam(name,pure) ->
923 add_pure_binding name pure pure_sp_code.VT0.combiner_rec_parameter
924 (function p -> Ast0.ParamTag p)
925 p
926 | Ast0.MetaParamList(name,_,pure) -> failwith "metaparamlist not supported"
927 | up ->
928 if not(checks_needed) or not(context_required) or is_context p
929 then
930 match (up,Ast0.unwrap p) with
931 (Ast0.VoidParam(tya),Ast0.VoidParam(tyb)) -> match_typeC tya tyb
932 | (Ast0.Param(tya,ida),Ast0.Param(tyb,idb)) ->
933 conjunct_bindings (match_typeC tya tyb)
934 (match_option match_ident ida idb)
935 | (Ast0.PComma(c1),Ast0.PComma(c)) -> check_mcode c1 c
936 | (Ast0.Pdots(d1),Ast0.Pdots(d))
937 | (Ast0.Pcircles(d1),Ast0.Pcircles(d)) -> check_mcode d1 d
938 | (Ast0.OptParam(parama),Ast0.OptParam(paramb))
939 | (Ast0.UniqueParam(parama),Ast0.UniqueParam(paramb)) ->
940 match_param parama paramb
941 | (_,Ast0.OptParam(paramb))
942 | (_,Ast0.UniqueParam(paramb)) -> match_param pattern paramb
943 | _ -> return false
944 else return_false (ContextRequired (Ast0.ParamTag p))
945
946 and match_statement pattern s =
947 match Ast0.unwrap pattern with
948 Ast0.MetaStmt(name,pure) ->
949 (match Ast0.unwrap s with
950 Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) ->
951 return false (* ... is not a single statement *)
952 | _ ->
953 add_pure_binding name pure pure_sp_code.VT0.combiner_rec_statement
954 (function ty -> Ast0.StmtTag ty)
955 s)
956 | Ast0.MetaStmtList(name,pure) -> failwith "metastmtlist not supported"
957 | up ->
958 if not(checks_needed) or not(context_required) or is_context s
959 then
960 match (up,Ast0.unwrap s) with
961 (Ast0.FunDecl(_,fninfoa,namea,lp1,paramsa,rp1,lb1,bodya,rb1),
962 Ast0.FunDecl(_,fninfob,nameb,lp,paramsb,rp,lb,bodyb,rb)) ->
963 conjunct_many_bindings
964 [check_mcode lp1 lp; check_mcode rp1 rp;
965 check_mcode lb1 lb; check_mcode rb1 rb;
966 match_fninfo fninfoa fninfob; match_ident namea nameb;
967 match_dots match_param is_plist_matcher do_plist_match
968 paramsa paramsb;
969 match_dots match_statement is_slist_matcher do_slist_match
970 bodya bodyb]
971 | (Ast0.Decl(_,decla),Ast0.Decl(_,declb)) ->
972 match_decl decla declb
973 | (Ast0.Seq(lb1,bodya,rb1),Ast0.Seq(lb,bodyb,rb)) ->
974 (* seqs can only match if they are all minus (plus code
975 allowed) or all context (plus code not allowed in the body).
976 we could be more permissive if the expansions of the isos are
977 also all seqs, but this would be hard to check except at top
978 level, and perhaps not worth checking even in that case.
979 Overall, the issue is that braces are used where single
980 statements are required, and something not satisfying these
981 conditions can cause a single statement to become a
982 non-single statement after the transformation.
983
984 example: if { ... -foo(); ... }
985 if we let the sequence convert to just -foo();
986 then we produce invalid code. For some reason,
987 single_statement can't deal with this case, perhaps because
988 it starts introducing too many braces? don't remember the
989 exact problem...
990 *)
991 conjunct_bindings (check_mcode lb1 lb)
992 (conjunct_bindings (check_mcode rb1 rb)
993 (if not(checks_needed) or is_minus s or
994 (is_context s &&
995 List.for_all is_pure_context (Ast0.undots bodyb))
996 then
997 match_dots match_statement is_slist_matcher do_slist_match
998 bodya bodyb
999 else return_false (Braces(s))))
1000 | (Ast0.ExprStatement(expa,sc1),Ast0.ExprStatement(expb,sc)) ->
1001 conjunct_bindings (check_mcode sc1 sc) (match_expr expa expb)
1002 | (Ast0.IfThen(if1,lp1,expa,rp1,branch1a,_),
1003 Ast0.IfThen(if2,lp2,expb,rp2,branch1b,_)) ->
1004 conjunct_many_bindings
1005 [check_mcode if1 if2; check_mcode lp1 lp2;
1006 check_mcode rp1 rp2;
1007 match_expr expa expb;
1008 match_statement branch1a branch1b]
1009 | (Ast0.IfThenElse(if1,lp1,expa,rp1,branch1a,e1,branch2a,_),
1010 Ast0.IfThenElse(if2,lp2,expb,rp2,branch1b,e2,branch2b,_)) ->
1011 conjunct_many_bindings
1012 [check_mcode if1 if2; check_mcode lp1 lp2;
1013 check_mcode rp1 rp2; check_mcode e1 e2;
1014 match_expr expa expb;
1015 match_statement branch1a branch1b;
1016 match_statement branch2a branch2b]
1017 | (Ast0.While(w1,lp1,expa,rp1,bodya,_),
1018 Ast0.While(w,lp,expb,rp,bodyb,_)) ->
1019 conjunct_many_bindings
1020 [check_mcode w1 w; check_mcode lp1 lp;
1021 check_mcode rp1 rp; match_expr expa expb;
1022 match_statement bodya bodyb]
1023 | (Ast0.Do(d1,bodya,w1,lp1,expa,rp1,_),
1024 Ast0.Do(d,bodyb,w,lp,expb,rp,_)) ->
1025 conjunct_many_bindings
1026 [check_mcode d1 d; check_mcode w1 w; check_mcode lp1 lp;
1027 check_mcode rp1 rp; match_statement bodya bodyb;
1028 match_expr expa expb]
1029 | (Ast0.For(f1,lp1,e1a,sc1a,e2a,sc2a,e3a,rp1,bodya,_),
1030 Ast0.For(f,lp,e1b,sc1b,e2b,sc2b,e3b,rp,bodyb,_)) ->
1031 conjunct_many_bindings
1032 [check_mcode f1 f; check_mcode lp1 lp; check_mcode sc1a sc1b;
1033 check_mcode sc2a sc2b; check_mcode rp1 rp;
1034 match_option match_expr e1a e1b;
1035 match_option match_expr e2a e2b;
1036 match_option match_expr e3a e3b;
1037 match_statement bodya bodyb]
1038 | (Ast0.Iterator(nma,lp1,argsa,rp1,bodya,_),
1039 Ast0.Iterator(nmb,lp,argsb,rp,bodyb,_)) ->
1040 conjunct_many_bindings
1041 [match_ident nma nmb;
1042 check_mcode lp1 lp; check_mcode rp1 rp;
1043 match_dots match_expr is_elist_matcher do_elist_match
1044 argsa argsb;
1045 match_statement bodya bodyb]
1046 | (Ast0.Switch(s1,lp1,expa,rp1,lb1,casesa,rb1),
1047 Ast0.Switch(s,lp,expb,rp,lb,casesb,rb)) ->
1048 conjunct_many_bindings
1049 [check_mcode s1 s; check_mcode lp1 lp; check_mcode rp1 rp;
1050 check_mcode lb1 lb; check_mcode rb1 rb;
1051 match_expr expa expb;
1052 match_dots match_case_line no_list do_nolist_match
1053 casesa casesb]
1054 | (Ast0.Break(b1,sc1),Ast0.Break(b,sc))
1055 | (Ast0.Continue(b1,sc1),Ast0.Continue(b,sc)) ->
1056 conjunct_bindings (check_mcode b1 b) (check_mcode sc1 sc)
1057 | (Ast0.Label(l1,c1),Ast0.Label(l2,c)) ->
1058 conjunct_bindings (match_ident l1 l2) (check_mcode c1 c)
1059 | (Ast0.Goto(g1,l1,sc1),Ast0.Goto(g,l2,sc)) ->
1060 conjunct_many_bindings
1061 [check_mcode g1 g; check_mcode sc1 sc; match_ident l1 l2]
1062 | (Ast0.Return(r1,sc1),Ast0.Return(r,sc)) ->
1063 conjunct_bindings (check_mcode r1 r) (check_mcode sc1 sc)
1064 | (Ast0.ReturnExpr(r1,expa,sc1),Ast0.ReturnExpr(r,expb,sc)) ->
1065 conjunct_many_bindings
1066 [check_mcode r1 r; check_mcode sc1 sc; match_expr expa expb]
1067 | (Ast0.Disj(_,statement_dots_lista,_,_),_) ->
1068 failwith "disj not supported in patterns"
1069 | (Ast0.Nest(_,stmt_dotsa,_,_,_),_) ->
1070 failwith "nest not supported in patterns"
1071 | (Ast0.Exp(expa),Ast0.Exp(expb)) -> match_expr expa expb
1072 | (Ast0.TopExp(expa),Ast0.TopExp(expb)) -> match_expr expa expb
1073 | (Ast0.Exp(expa),Ast0.TopExp(expb)) -> match_expr expa expb
1074 | (Ast0.TopInit(inita),Ast0.TopInit(initb)) -> match_init inita initb
1075 | (Ast0.Ty(tya),Ast0.Ty(tyb)) -> match_typeC tya tyb
1076 | (Ast0.Dots(d,[]),Ast0.Dots(d1,wc))
1077 | (Ast0.Circles(d,[]),Ast0.Circles(d1,wc))
1078 | (Ast0.Stars(d,[]),Ast0.Stars(d1,wc)) ->
1079 (match wc with
1080 [] -> check_mcode d d1
1081 | _ ->
1082 let (_,_,dots_whencode_allowed) = whencode_allowed in
1083 if dots_whencode_allowed
1084 then
1085 conjunct_bindings (check_mcode d d1)
1086 (List.fold_left
1087 (function prev ->
1088 function
1089 | Ast0.WhenNot wc ->
1090 conjunct_bindings prev
1091 (add_multi_dot_binding d
1092 (Ast0.DotsStmtTag wc))
1093 | Ast0.WhenAlways wc ->
1094 conjunct_bindings prev
1095 (add_multi_dot_binding d (Ast0.StmtTag wc))
1096 | Ast0.WhenNotTrue wc ->
1097 conjunct_bindings prev
1098 (add_multi_dot_binding d
1099 (Ast0.IsoWhenTTag wc))
1100 | Ast0.WhenNotFalse wc ->
1101 conjunct_bindings prev
1102 (add_multi_dot_binding d
1103 (Ast0.IsoWhenFTag wc))
1104 | Ast0.WhenModifier(x) ->
1105 conjunct_bindings prev
1106 (add_multi_dot_binding d
1107 (Ast0.IsoWhenTag x)))
1108 (return true) wc)
1109 else
1110 (Printf.printf
1111 "warning: not applying iso because of whencode";
1112 return false))
1113 | (Ast0.Dots(_,_::_),_) | (Ast0.Circles(_,_::_),_)
1114 | (Ast0.Stars(_,_::_),_) ->
1115 failwith "whencode not allowed in a pattern3"
1116 | (Ast0.OptStm(rea),Ast0.OptStm(reb))
1117 | (Ast0.UniqueStm(rea),Ast0.UniqueStm(reb)) ->
1118 match_statement rea reb
1119 | (_,Ast0.OptStm(reb))
1120 | (_,Ast0.UniqueStm(reb)) -> match_statement pattern reb
1121 | _ -> return false
1122 else return_false (ContextRequired (Ast0.StmtTag s))
1123
1124 (* first should provide a subset of the information in the second *)
1125 and match_fninfo patterninfo cinfo =
1126 let patterninfo = List.sort compare patterninfo in
1127 let cinfo = List.sort compare cinfo in
1128 let rec loop = function
1129 (Ast0.FStorage(sta)::resta,Ast0.FStorage(stb)::restb) ->
1130 if mcode_equal sta stb
1131 then conjunct_bindings (check_mcode sta stb) (loop (resta,restb))
1132 else return false
1133 | (Ast0.FType(tya)::resta,Ast0.FType(tyb)::restb) ->
1134 conjunct_bindings (match_typeC tya tyb) (loop (resta,restb))
1135 | (Ast0.FInline(ia)::resta,Ast0.FInline(ib)::restb) ->
1136 if mcode_equal ia ib
1137 then conjunct_bindings (check_mcode ia ib) (loop (resta,restb))
1138 else return false
1139 | (Ast0.FAttr(ia)::resta,Ast0.FAttr(ib)::restb) ->
1140 if mcode_equal ia ib
1141 then conjunct_bindings (check_mcode ia ib) (loop (resta,restb))
1142 else return false
1143 | (x::resta,((y::_) as restb)) ->
1144 (match compare x y with
1145 -1 -> return false
1146 | 1 -> loop (resta,restb)
1147 | _ -> failwith "not possible")
1148 | _ -> return false in
1149 loop (patterninfo,cinfo)
1150
1151 and match_case_line pattern c =
1152 if not(checks_needed) or not(context_required) or is_context c
1153 then
1154 match (Ast0.unwrap pattern,Ast0.unwrap c) with
1155 (Ast0.Default(d1,c1,codea),Ast0.Default(d,c,codeb)) ->
1156 conjunct_many_bindings
1157 [check_mcode d1 d; check_mcode c1 c;
1158 match_dots match_statement is_slist_matcher do_slist_match
1159 codea codeb]
1160 | (Ast0.Case(ca1,expa,c1,codea),Ast0.Case(ca,expb,c,codeb)) ->
1161 conjunct_many_bindings
1162 [check_mcode ca1 ca; check_mcode c1 c; match_expr expa expb;
1163 match_dots match_statement is_slist_matcher do_slist_match
1164 codea codeb]
1165 | (Ast0.OptCase(ca),Ast0.OptCase(cb)) -> match_case_line ca cb
1166 | (_,Ast0.OptCase(cb)) -> match_case_line pattern cb
1167 | _ -> return false
1168 else return_false (ContextRequired (Ast0.CaseLineTag c)) in
1169
1170 let match_statement_dots x y =
1171 match_dots match_statement is_slist_matcher do_slist_match x y in
1172
1173 (match_expr, match_decl, match_statement, match_typeC,
1174 match_statement_dots)
1175
1176 let match_expr dochecks context_required whencode_allowed =
1177 let (fn,_,_,_,_) = match_maker dochecks context_required whencode_allowed in
1178 fn
1179
1180 let match_decl dochecks context_required whencode_allowed =
1181 let (_,fn,_,_,_) = match_maker dochecks context_required whencode_allowed in
1182 fn
1183
1184 let match_statement dochecks context_required whencode_allowed =
1185 let (_,_,fn,_,_) = match_maker dochecks context_required whencode_allowed in
1186 fn
1187
1188 let match_typeC dochecks context_required whencode_allowed =
1189 let (_,_,_,fn,_) = match_maker dochecks context_required whencode_allowed in
1190 fn
1191
1192 let match_statement_dots dochecks context_required whencode_allowed =
1193 let (_,_,_,_,fn) = match_maker dochecks context_required whencode_allowed in
1194 fn
1195
1196 (* --------------------------------------------------------------------- *)
1197 (* make an entire tree MINUS *)
1198
1199 let make_minus =
1200 let mcode (term,arity,info,mcodekind,pos) =
1201 let new_mcodekind =
1202 match mcodekind with
1203 Ast0.CONTEXT(mc) ->
1204 (match !mc with
1205 (Ast.NOTHING,_,_) -> Ast0.MINUS(ref([],Ast0.default_token_info))
1206 | _ -> failwith "make_minus: unexpected befaft")
1207 | Ast0.MINUS(mc) -> mcodekind (* in the part copied from the src term *)
1208 | _ -> failwith "make_minus mcode: unexpected mcodekind" in
1209 (term,arity,info,new_mcodekind,pos) in
1210
1211 let update_mc mcodekind e =
1212 match !mcodekind with
1213 Ast0.CONTEXT(mc) ->
1214 (match !mc with
1215 (Ast.NOTHING,_,_) ->
1216 mcodekind := Ast0.MINUS(ref([],Ast0.default_token_info))
1217 | _ -> failwith "make_minus: unexpected befaft")
1218 | Ast0.MINUS(_mc) -> () (* in the part copied from the src term *)
1219 | Ast0.PLUS -> failwith "make_minus donothing: unexpected plus mcodekind"
1220 | _ -> failwith "make_minus donothing: unexpected mcodekind" in
1221
1222 let donothing r k e =
1223 let mcodekind = Ast0.get_mcodekind_ref e in
1224 let e = k e in update_mc mcodekind e; e in
1225
1226 (* special case for whencode, because it isn't processed by contextneg,
1227 since it doesn't appear in the + code *)
1228 (* cases for dots and nests *)
1229 let expression r k e =
1230 let mcodekind = Ast0.get_mcodekind_ref e in
1231 match Ast0.unwrap e with
1232 Ast0.Edots(d,whencode) ->
1233 (*don't recurse because whencode hasn't been processed by context_neg*)
1234 update_mc mcodekind e; Ast0.rewrap e (Ast0.Edots(mcode d,whencode))
1235 | Ast0.Ecircles(d,whencode) ->
1236 (*don't recurse because whencode hasn't been processed by context_neg*)
1237 update_mc mcodekind e; Ast0.rewrap e (Ast0.Ecircles(mcode d,whencode))
1238 | Ast0.Estars(d,whencode) ->
1239 (*don't recurse because whencode hasn't been processed by context_neg*)
1240 update_mc mcodekind e; Ast0.rewrap e (Ast0.Estars(mcode d,whencode))
1241 | Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) ->
1242 update_mc mcodekind e;
1243 Ast0.rewrap e
1244 (Ast0.NestExpr(mcode starter,
1245 r.VT0.rebuilder_rec_expression_dots expr_dots,
1246 mcode ender,whencode,multi))
1247 | _ -> donothing r k e in
1248
1249 let declaration r k e =
1250 let mcodekind = Ast0.get_mcodekind_ref e in
1251 match Ast0.unwrap e with
1252 Ast0.Ddots(d,whencode) ->
1253 (*don't recurse because whencode hasn't been processed by context_neg*)
1254 update_mc mcodekind e; Ast0.rewrap e (Ast0.Ddots(mcode d,whencode))
1255 | _ -> donothing r k e in
1256
1257 let statement r k e =
1258 let mcodekind = Ast0.get_mcodekind_ref e in
1259 match Ast0.unwrap e with
1260 Ast0.Dots(d,whencode) ->
1261 (*don't recurse because whencode hasn't been processed by context_neg*)
1262 update_mc mcodekind e; Ast0.rewrap e (Ast0.Dots(mcode d,whencode))
1263 | Ast0.Circles(d,whencode) ->
1264 update_mc mcodekind e; Ast0.rewrap e (Ast0.Circles(mcode d,whencode))
1265 | Ast0.Stars(d,whencode) ->
1266 update_mc mcodekind e; Ast0.rewrap e (Ast0.Stars(mcode d,whencode))
1267 | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
1268 update_mc mcodekind e;
1269 Ast0.rewrap e
1270 (Ast0.Nest
1271 (mcode starter,r.VT0.rebuilder_rec_statement_dots stmt_dots,
1272 mcode ender,whencode,multi))
1273 | _ -> donothing r k e in
1274
1275 let initialiser r k e =
1276 let mcodekind = Ast0.get_mcodekind_ref e in
1277 match Ast0.unwrap e with
1278 Ast0.Idots(d,whencode) ->
1279 (*don't recurse because whencode hasn't been processed by context_neg*)
1280 update_mc mcodekind e; Ast0.rewrap e (Ast0.Idots(mcode d,whencode))
1281 | _ -> donothing r k e in
1282
1283 let dots r k e =
1284 let info = Ast0.get_info e in
1285 let mcodekind = Ast0.get_mcodekind_ref e in
1286 match Ast0.unwrap e with
1287 Ast0.DOTS([]) ->
1288 (* if context is - this should be - as well. There are no tokens
1289 here though, so the bottom-up minusifier in context_neg leaves it
1290 as mixed (or context for sgrep2). It would be better to fix
1291 context_neg, but that would
1292 require a special case for each term with a dots subterm. *)
1293 (match !mcodekind with
1294 Ast0.MIXED(mc) | Ast0.CONTEXT(mc) ->
1295 (match !mc with
1296 (Ast.NOTHING,_,_) ->
1297 mcodekind := Ast0.MINUS(ref([],Ast0.default_token_info));
1298 e
1299 | _ -> failwith "make_minus: unexpected befaft")
1300 (* code already processed by an enclosing iso *)
1301 | Ast0.MINUS(mc) -> e
1302 | _ ->
1303 failwith
1304 (Printf.sprintf
1305 "%d: make_minus donothingxxx: unexpected mcodekind: %s"
1306 info.Ast0.pos_info.Ast0.line_start (Dumper.dump e)))
1307 | _ -> donothing r k e in
1308
1309 V0.flat_rebuilder
1310 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1311 dots dots dots dots dots dots
1312 donothing expression donothing initialiser donothing declaration
1313 statement donothing donothing
1314
1315 (* --------------------------------------------------------------------- *)
1316 (* rebuild mcode cells in an instantiated alt *)
1317
1318 (* mcodes will be side effected later with plus code, so we have to copy
1319 them on instantiating an isomorphism. One could wonder whether it would
1320 be better not to use side-effects, but they are convenient for insert_plus
1321 where is it useful to manipulate a list of the mcodes but side-effect a
1322 tree *)
1323 (* hmm... Insert_plus is called before Iso_pattern... *)
1324 let rebuild_mcode start_line =
1325 let copy_mcodekind = function
1326 Ast0.CONTEXT(mc) -> Ast0.CONTEXT(ref (!mc))
1327 | Ast0.MINUS(mc) -> Ast0.MINUS(ref (!mc))
1328 | Ast0.MIXED(mc) -> Ast0.MIXED(ref (!mc))
1329 | Ast0.PLUS ->
1330 (* this function is used elsewhere where we need to rebuild the
1331 indices, and so we allow PLUS code as well *)
1332 Ast0.PLUS in
1333
1334 let mcode (term,arity,info,mcodekind,pos) =
1335 let info =
1336 match start_line with
1337 Some x ->
1338 let new_pos_info =
1339 {info.Ast0.pos_info with
1340 Ast0.line_start = x;
1341 Ast0.line_end = x; } in
1342 {info with Ast0.pos_info = new_pos_info}
1343 | None -> info in
1344 (term,arity,info,copy_mcodekind mcodekind,pos) in
1345
1346 let copy_one x =
1347 let old_info = Ast0.get_info x in
1348 let info =
1349 match start_line with
1350 Some x ->
1351 let new_pos_info =
1352 {old_info.Ast0.pos_info with
1353 Ast0.line_start = x;
1354 Ast0.line_end = x; } in
1355 {old_info with Ast0.pos_info = new_pos_info}
1356 | None -> old_info in
1357 {x with Ast0.info = info; Ast0.index = ref(Ast0.get_index x);
1358 Ast0.mcodekind = ref (copy_mcodekind (Ast0.get_mcodekind x))} in
1359
1360 let donothing r k e = copy_one (k e) in
1361
1362 (* case for control operators (if, etc) *)
1363 let statement r k e =
1364 let s = k e in
1365 let res =
1366 copy_one
1367 (Ast0.rewrap s
1368 (match Ast0.unwrap s with
1369 Ast0.Decl((info,mc),decl) ->
1370 Ast0.Decl((info,copy_mcodekind mc),decl)
1371 | Ast0.IfThen(iff,lp,tst,rp,branch,(info,mc)) ->
1372 Ast0.IfThen(iff,lp,tst,rp,branch,(info,copy_mcodekind mc))
1373 | Ast0.IfThenElse(iff,lp,tst,rp,branch1,els,branch2,(info,mc)) ->
1374 Ast0.IfThenElse(iff,lp,tst,rp,branch1,els,branch2,
1375 (info,copy_mcodekind mc))
1376 | Ast0.While(whl,lp,exp,rp,body,(info,mc)) ->
1377 Ast0.While(whl,lp,exp,rp,body,(info,copy_mcodekind mc))
1378 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,mc)) ->
1379 Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,
1380 (info,copy_mcodekind mc))
1381 | Ast0.Iterator(nm,lp,args,rp,body,(info,mc)) ->
1382 Ast0.Iterator(nm,lp,args,rp,body,(info,copy_mcodekind mc))
1383 | Ast0.FunDecl
1384 ((info,mc),fninfo,name,lp,params,rp,lbrace,body,rbrace) ->
1385 Ast0.FunDecl
1386 ((info,copy_mcodekind mc),
1387 fninfo,name,lp,params,rp,lbrace,body,rbrace)
1388 | s -> s)) in
1389 Ast0.set_dots_bef_aft res
1390 (match Ast0.get_dots_bef_aft res with
1391 Ast0.NoDots -> Ast0.NoDots
1392 | Ast0.AddingBetweenDots s ->
1393 Ast0.AddingBetweenDots(r.VT0.rebuilder_rec_statement s)
1394 | Ast0.DroppingBetweenDots s ->
1395 Ast0.DroppingBetweenDots(r.VT0.rebuilder_rec_statement s)) in
1396
1397 V0.flat_rebuilder
1398 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1399 donothing donothing donothing donothing donothing donothing
1400 donothing donothing donothing donothing donothing
1401 donothing statement donothing donothing
1402
1403 (* --------------------------------------------------------------------- *)
1404 (* The problem of whencode. If an isomorphism contains dots in multiple
1405 rules, then the code that is matched cannot contain whencode, because we
1406 won't know which dots it goes with. Should worry about nests, but they
1407 aren't allowed in isomorphisms for the moment. *)
1408
1409 let count_edots =
1410 let option_default = 0 in
1411 let bind x y = x + y in
1412 let exprfn r k e =
1413 match Ast0.unwrap e with
1414 Ast0.Edots(_,_) | Ast0.Ecircles(_,_) | Ast0.Estars(_,_) -> 1
1415 | _ -> 0 in
1416
1417 V0.combiner bind option_default
1418 {V0.combiner_functions with VT0.combiner_exprfn = exprfn}
1419
1420 let count_idots =
1421 let option_default = 0 in
1422 let bind x y = x + y in
1423 let initfn r k e =
1424 match Ast0.unwrap e with Ast0.Idots(_,_) -> 1 | _ -> 0 in
1425
1426 V0.combiner bind option_default
1427 {V0.combiner_functions with VT0.combiner_initfn = initfn}
1428
1429 let count_dots =
1430 let option_default = 0 in
1431 let bind x y = x + y in
1432 let stmtfn r k e =
1433 match Ast0.unwrap e with
1434 Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) -> 1
1435 | _ -> 0 in
1436
1437 V0.combiner bind option_default
1438 {V0.combiner_functions with VT0.combiner_stmtfn = stmtfn}
1439
1440 (* --------------------------------------------------------------------- *)
1441
1442 let lookup name bindings mv_bindings =
1443 try Common.Left (List.assoc (term name) bindings)
1444 with
1445 Not_found ->
1446 (* failure is not possible anymore *)
1447 Common.Right (List.assoc (term name) mv_bindings)
1448
1449 (* mv_bindings is for the fresh metavariables that are introduced by the
1450 isomorphism *)
1451 let instantiate bindings mv_bindings =
1452 let mcode x =
1453 match Ast0.get_pos x with
1454 Ast0.MetaPos(name,_,_) ->
1455 (try
1456 match lookup name bindings mv_bindings with
1457 Common.Left(Ast0.MetaPosTag(id)) -> Ast0.set_pos id x
1458 | _ -> failwith "not possible"
1459 with Not_found -> Ast0.set_pos Ast0.NoMetaPos x)
1460 | _ -> x in
1461 let donothing r k e = k e in
1462
1463 (* cases where metavariables can occur *)
1464 let identfn r k e =
1465 let e = k e in
1466 match Ast0.unwrap e with
1467 Ast0.MetaId(name,constraints,pure) ->
1468 (rebuild_mcode None).VT0.rebuilder_rec_ident
1469 (match lookup name bindings mv_bindings with
1470 Common.Left(Ast0.IdentTag(id)) -> id
1471 | Common.Left(_) -> failwith "not possible 1"
1472 | Common.Right(new_mv) ->
1473 Ast0.rewrap e
1474 (Ast0.MetaId
1475 (Ast0.set_mcode_data new_mv name,constraints,pure)))
1476 | Ast0.MetaFunc(name,_,pure) -> failwith "metafunc not supported"
1477 | Ast0.MetaLocalFunc(name,_,pure) -> failwith "metalocalfunc not supported"
1478 | _ -> e in
1479
1480 (* case for list metavariables *)
1481 let rec elist r same_dots = function
1482 [] -> []
1483 | [x] ->
1484 (match Ast0.unwrap x with
1485 Ast0.MetaExprList(name,lenname,pure) ->
1486 failwith "meta_expr_list in iso not supported"
1487 (*match lookup name bindings mv_bindings with
1488 Common.Left(Ast0.DotsExprTag(exp)) ->
1489 (match same_dots exp with
1490 Some l -> l
1491 | None -> failwith "dots put in incompatible context")
1492 | Common.Left(Ast0.ExprTag(exp)) -> [exp]
1493 | Common.Left(_) -> failwith "not possible 1"
1494 | Common.Right(new_mv) ->
1495 failwith "MetaExprList in SP not supported"*)
1496 | _ -> [r.VT0.rebuilder_rec_expression x])
1497 | x::xs -> (r.VT0.rebuilder_rec_expression x)::(elist r same_dots xs) in
1498
1499 let rec plist r same_dots = function
1500 [] -> []
1501 | [x] ->
1502 (match Ast0.unwrap x with
1503 Ast0.MetaParamList(name,lenname,pure) ->
1504 failwith "meta_param_list in iso not supported"
1505 (*match lookup name bindings mv_bindings with
1506 Common.Left(Ast0.DotsParamTag(param)) ->
1507 (match same_dots param with
1508 Some l -> l
1509 | None -> failwith "dots put in incompatible context")
1510 | Common.Left(Ast0.ParamTag(param)) -> [param]
1511 | Common.Left(_) -> failwith "not possible 1"
1512 | Common.Right(new_mv) ->
1513 failwith "MetaExprList in SP not supported"*)
1514 | _ -> [r.VT0.rebuilder_rec_parameter x])
1515 | x::xs -> (r.VT0.rebuilder_rec_parameter x)::(plist r same_dots xs) in
1516
1517 let rec slist r same_dots = function
1518 [] -> []
1519 | [x] ->
1520 (match Ast0.unwrap x with
1521 Ast0.MetaStmtList(name,pure) ->
1522 (match lookup name bindings mv_bindings with
1523 Common.Left(Ast0.DotsStmtTag(stm)) ->
1524 (match same_dots stm with
1525 Some l -> l
1526 | None -> failwith "dots put in incompatible context")
1527 | Common.Left(Ast0.StmtTag(stm)) -> [stm]
1528 | Common.Left(_) -> failwith "not possible 1"
1529 | Common.Right(new_mv) ->
1530 failwith "MetaExprList in SP not supported")
1531 | _ -> [r.VT0.rebuilder_rec_statement x])
1532 | x::xs -> (r.VT0.rebuilder_rec_statement x)::(slist r same_dots xs) in
1533
1534 let same_dots d =
1535 match Ast0.unwrap d with Ast0.DOTS(l) -> Some l |_ -> None in
1536 let same_circles d =
1537 match Ast0.unwrap d with Ast0.CIRCLES(l) -> Some l |_ -> None in
1538 let same_stars d =
1539 match Ast0.unwrap d with Ast0.STARS(l) -> Some l |_ -> None in
1540
1541 let dots list_fn r k d =
1542 Ast0.rewrap d
1543 (match Ast0.unwrap d with
1544 Ast0.DOTS(l) -> Ast0.DOTS(list_fn r same_dots l)
1545 | Ast0.CIRCLES(l) -> Ast0.CIRCLES(list_fn r same_circles l)
1546 | Ast0.STARS(l) -> Ast0.STARS(list_fn r same_stars l)) in
1547
1548 let exprfn r k old_e = (* need to keep the original code for ! optim *)
1549 let e = k old_e in
1550 let e1 =
1551 match Ast0.unwrap e with
1552 Ast0.MetaExpr(name,constraints,x,form,pure) ->
1553 (rebuild_mcode None).VT0.rebuilder_rec_expression
1554 (match lookup name bindings mv_bindings with
1555 Common.Left(Ast0.ExprTag(exp)) -> exp
1556 | Common.Left(_) -> failwith "not possible 1"
1557 | Common.Right(new_mv) ->
1558 let new_types =
1559 match x with
1560 None -> None
1561 | Some types ->
1562 let rec renamer = function
1563 Type_cocci.MetaType(name,keep,inherited) ->
1564 (match
1565 lookup (name,(),(),(),None) bindings mv_bindings
1566 with
1567 Common.Left(Ast0.TypeCTag(t)) ->
1568 Ast0.ast0_type_to_type t
1569 | Common.Left(_) ->
1570 failwith "iso pattern: unexpected type"
1571 | Common.Right(new_mv) ->
1572 Type_cocci.MetaType(new_mv,keep,inherited))
1573 | Type_cocci.ConstVol(cv,ty) ->
1574 Type_cocci.ConstVol(cv,renamer ty)
1575 | Type_cocci.Pointer(ty) ->
1576 Type_cocci.Pointer(renamer ty)
1577 | Type_cocci.FunctionPointer(ty) ->
1578 Type_cocci.FunctionPointer(renamer ty)
1579 | Type_cocci.Array(ty) ->
1580 Type_cocci.Array(renamer ty)
1581 | t -> t in
1582 Some(List.map renamer types) in
1583 Ast0.rewrap e
1584 (Ast0.MetaExpr
1585 (Ast0.set_mcode_data new_mv name,constraints,
1586 new_types,form,pure)))
1587 | Ast0.MetaErr(namea,_,pure) -> failwith "metaerr not supported"
1588 | Ast0.MetaExprList(namea,lenname,pure) ->
1589 failwith "metaexprlist not supported"
1590 | Ast0.Unary(exp,unop) ->
1591 (match Ast0.unwrap_mcode unop with
1592 Ast.Not ->
1593 let was_meta =
1594 (* k e doesn't change the outer structure of the term,
1595 only the metavars *)
1596 match Ast0.unwrap old_e with
1597 Ast0.Unary(exp,_) ->
1598 (match Ast0.unwrap exp with
1599 Ast0.MetaExpr(name,constraints,x,form,pure) -> true
1600 | _ -> false)
1601 | _ -> failwith "not possible" in
1602 let nomodif e =
1603 let mc = Ast0.get_mcodekind exp in
1604 match mc with
1605 Ast0.MINUS(x) ->
1606 (match !x with
1607 ([],_) -> true
1608 | _ -> false)
1609 | Ast0.CONTEXT(x) | Ast0.MIXED(x) ->
1610 (match !x with
1611 (Ast.NOTHING,_,_) -> true
1612 | _ -> false)
1613 | _ -> failwith "plus not possible" in
1614 if was_meta && nomodif exp && nomodif e
1615 then
1616 let idcont x = x in
1617 let rec negate e (*for rewrapping*) res (*code to process*) k =
1618 (* k accumulates parens, to keep negation outside if no
1619 propagation is possible *)
1620 match Ast0.unwrap res with
1621 Ast0.Unary(e1,op) when Ast0.unwrap_mcode op = Ast.Not ->
1622 k (Ast0.rewrap e (Ast0.unwrap e1))
1623 | Ast0.Edots(_,_) -> k (Ast0.rewrap e (Ast0.unwrap res))
1624 | Ast0.Paren(lp,e,rp) ->
1625 negate e e
1626 (function x ->
1627 k (Ast0.rewrap res (Ast0.Paren(lp,x,rp))))
1628 | Ast0.Binary(e1,op,e2) ->
1629 let reb nop = Ast0.rewrap_mcode op (Ast.Logical(nop)) in
1630 let k1 x = k (Ast0.rewrap e x) in
1631 (match Ast0.unwrap_mcode op with
1632 Ast.Logical(Ast.Inf) ->
1633 k1 (Ast0.Binary(e1,reb Ast.SupEq,e2))
1634 | Ast.Logical(Ast.Sup) ->
1635 k1 (Ast0.Binary(e1,reb Ast.InfEq,e2))
1636 | Ast.Logical(Ast.InfEq) ->
1637 k1 (Ast0.Binary(e1,reb Ast.Sup,e2))
1638 | Ast.Logical(Ast.SupEq) ->
1639 k1 (Ast0.Binary(e1,reb Ast.Inf,e2))
1640 | Ast.Logical(Ast.Eq) ->
1641 k1 (Ast0.Binary(e1,reb Ast.NotEq,e2))
1642 | Ast.Logical(Ast.NotEq) ->
1643 k1 (Ast0.Binary(e1,reb Ast.Eq,e2))
1644 | Ast.Logical(Ast.AndLog) ->
1645 k1 (Ast0.Binary(negate e1 e1 idcont,reb Ast.OrLog,
1646 negate e2 e2 idcont))
1647 | Ast.Logical(Ast.OrLog) ->
1648 k1 (Ast0.Binary(negate e1 e1 idcont,reb Ast.AndLog,
1649 negate e2 e2 idcont))
1650 | _ ->
1651 Ast0.rewrap e
1652 (Ast0.Unary(k res,Ast0.rewrap_mcode op Ast.Not)))
1653 | Ast0.DisjExpr(lp,exps,mids,rp) ->
1654 (* use res because it is the transformed argument *)
1655 let exps = List.map (function e -> negate e e k) exps in
1656 Ast0.rewrap res (Ast0.DisjExpr(lp,exps,mids,rp))
1657 | _ ->
1658 (*use e, because this might be the toplevel expression*)
1659 Ast0.rewrap e
1660 (Ast0.Unary(k res,Ast0.rewrap_mcode unop Ast.Not)) in
1661 negate e exp idcont
1662 else e
1663 | _ -> e)
1664 | Ast0.Edots(d,_) ->
1665 (try
1666 (match List.assoc (dot_term d) bindings with
1667 Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Edots(d,Some exp))
1668 | _ -> failwith "unexpected binding")
1669 with Not_found -> e)
1670 | Ast0.Ecircles(d,_) ->
1671 (try
1672 (match List.assoc (dot_term d) bindings with
1673 Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Ecircles(d,Some exp))
1674 | _ -> failwith "unexpected binding")
1675 with Not_found -> e)
1676 | Ast0.Estars(d,_) ->
1677 (try
1678 (match List.assoc (dot_term d) bindings with
1679 Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Estars(d,Some exp))
1680 | _ -> failwith "unexpected binding")
1681 with Not_found -> e)
1682 | _ -> e in
1683 if Ast0.get_test_exp old_e then Ast0.set_test_exp e1 else e1 in
1684
1685 let tyfn r k e =
1686 let e = k e in
1687 match Ast0.unwrap e with
1688 Ast0.MetaType(name,pure) ->
1689 (rebuild_mcode None).VT0.rebuilder_rec_typeC
1690 (match lookup name bindings mv_bindings with
1691 Common.Left(Ast0.TypeCTag(ty)) -> ty
1692 | Common.Left(_) -> failwith "not possible 1"
1693 | Common.Right(new_mv) ->
1694 Ast0.rewrap e
1695 (Ast0.MetaType(Ast0.set_mcode_data new_mv name,pure)))
1696 | _ -> e in
1697
1698 let initfn r k e =
1699 let e = k e in
1700 match Ast0.unwrap e with
1701 Ast0.MetaInit(name,pure) ->
1702 (rebuild_mcode None).VT0.rebuilder_rec_initialiser
1703 (match lookup name bindings mv_bindings with
1704 Common.Left(Ast0.InitTag(ty)) -> ty
1705 | Common.Left(_) -> failwith "not possible 1"
1706 | Common.Right(new_mv) ->
1707 Ast0.rewrap e
1708 (Ast0.MetaInit(Ast0.set_mcode_data new_mv name,pure)))
1709 | _ -> e in
1710
1711 let declfn r k e =
1712 let e = k e in
1713 match Ast0.unwrap e with
1714 Ast0.Ddots(d,_) ->
1715 (try
1716 (match List.assoc (dot_term d) bindings with
1717 Ast0.DeclTag(exp) -> Ast0.rewrap e (Ast0.Ddots(d,Some exp))
1718 | _ -> failwith "unexpected binding")
1719 with Not_found -> e)
1720 | _ -> e in
1721
1722 let paramfn r k e =
1723 let e = k e in
1724 match Ast0.unwrap e with
1725 Ast0.MetaParam(name,pure) ->
1726 (rebuild_mcode None).VT0.rebuilder_rec_parameter
1727 (match lookup name bindings mv_bindings with
1728 Common.Left(Ast0.ParamTag(param)) -> param
1729 | Common.Left(_) -> failwith "not possible 1"
1730 | Common.Right(new_mv) ->
1731 Ast0.rewrap e
1732 (Ast0.MetaParam(Ast0.set_mcode_data new_mv name, pure)))
1733 | Ast0.MetaParamList(name,lenname,pure) ->
1734 failwith "metaparamlist not supported"
1735 | _ -> e in
1736
1737 let whenfn (_,v) =
1738 match v with
1739 Ast0.DotsStmtTag(stms) -> Ast0.WhenNot stms
1740 | Ast0.StmtTag(stm) -> Ast0.WhenAlways stm
1741 | Ast0.IsoWhenTTag(stm) -> Ast0.WhenNotTrue stm
1742 | Ast0.IsoWhenFTag(stm) -> Ast0.WhenNotFalse stm
1743 | Ast0.IsoWhenTag(x) -> Ast0.WhenModifier(x)
1744 | _ -> failwith "unexpected binding" in
1745
1746 let stmtfn r k e =
1747 let e = k e in
1748 match Ast0.unwrap e with
1749 Ast0.MetaStmt(name,pure) ->
1750 (rebuild_mcode None).VT0.rebuilder_rec_statement
1751 (match lookup name bindings mv_bindings with
1752 Common.Left(Ast0.StmtTag(stm)) -> stm
1753 | Common.Left(_) -> failwith "not possible 1"
1754 | Common.Right(new_mv) ->
1755 Ast0.rewrap e
1756 (Ast0.MetaStmt(Ast0.set_mcode_data new_mv name,pure)))
1757 | Ast0.MetaStmtList(name,pure) -> failwith "metastmtlist not supported"
1758 | Ast0.Dots(d,_) ->
1759 Ast0.rewrap e
1760 (Ast0.Dots
1761 (d,
1762 List.map whenfn
1763 (List.filter (function (x,v) -> x = (dot_term d)) bindings)))
1764 | Ast0.Circles(d,_) ->
1765 Ast0.rewrap e
1766 (Ast0.Circles
1767 (d,
1768 List.map whenfn
1769 (List.filter (function (x,v) -> x = (dot_term d)) bindings)))
1770 | Ast0.Stars(d,_) ->
1771 Ast0.rewrap e
1772 (Ast0.Stars
1773 (d,
1774 List.map whenfn
1775 (List.filter (function (x,v) -> x = (dot_term d)) bindings)))
1776 | _ -> e in
1777
1778 V0.flat_rebuilder
1779 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1780 (dots elist) donothing (dots plist) (dots slist) donothing donothing
1781 identfn exprfn tyfn initfn paramfn declfn stmtfn donothing donothing
1782
1783 (* --------------------------------------------------------------------- *)
1784
1785 let is_minus e =
1786 match Ast0.get_mcodekind e with Ast0.MINUS(cell) -> true | _ -> false
1787
1788 let context_required e = not(is_minus e) && not !Flag.sgrep_mode2
1789
1790 let disj_fail bindings e =
1791 match bindings with
1792 Some x -> Printf.fprintf stderr "no disj available at this type"; e
1793 | None -> e
1794
1795 (* isomorphism code is by default CONTEXT *)
1796 let merge_plus model_mcode e_mcode =
1797 match model_mcode with
1798 Ast0.MINUS(mc) ->
1799 (* add the replacement information at the root *)
1800 (match e_mcode with
1801 Ast0.MINUS(emc) ->
1802 emc :=
1803 (match (!mc,!emc) with
1804 (([],_),(x,t)) | ((x,_),([],t)) -> (x,t)
1805 | _ -> failwith "how can we combine minuses?")
1806 | _ -> failwith "not possible 6")
1807 | Ast0.CONTEXT(mc) ->
1808 (match e_mcode with
1809 Ast0.CONTEXT(emc) ->
1810 (* keep the logical line info as in the model *)
1811 let (mba,tb,ta) = !mc in
1812 let (eba,_,_) = !emc in
1813 (* merging may be required when a term is replaced by a subterm *)
1814 let merged =
1815 match (mba,eba) with
1816 (x,Ast.NOTHING) | (Ast.NOTHING,x) -> x
1817 | (Ast.BEFORE(b1),Ast.BEFORE(b2)) -> Ast.BEFORE(b1@b2)
1818 | (Ast.BEFORE(b),Ast.AFTER(a)) -> Ast.BEFOREAFTER(b,a)
1819 | (Ast.BEFORE(b1),Ast.BEFOREAFTER(b2,a)) ->
1820 Ast.BEFOREAFTER(b1@b2,a)
1821 | (Ast.AFTER(a),Ast.BEFORE(b)) -> Ast.BEFOREAFTER(b,a)
1822 | (Ast.AFTER(a1),Ast.AFTER(a2)) ->Ast.AFTER(a2@a1)
1823 | (Ast.AFTER(a1),Ast.BEFOREAFTER(b,a2)) -> Ast.BEFOREAFTER(b,a2@a1)
1824 | (Ast.BEFOREAFTER(b1,a),Ast.BEFORE(b2)) ->
1825 Ast.BEFOREAFTER(b1@b2,a)
1826 | (Ast.BEFOREAFTER(b,a1),Ast.AFTER(a2)) ->
1827 Ast.BEFOREAFTER(b,a2@a1)
1828 | (Ast.BEFOREAFTER(b1,a1),Ast.BEFOREAFTER(b2,a2)) ->
1829 Ast.BEFOREAFTER(b1@b2,a2@a1) in
1830 emc := (merged,tb,ta)
1831 | Ast0.MINUS(emc) ->
1832 let (anything_bef_aft,_,_) = !mc in
1833 let (anythings,t) = !emc in
1834 emc :=
1835 (match anything_bef_aft with
1836 Ast.BEFORE(b) -> (b@anythings,t)
1837 | Ast.AFTER(a) -> (anythings@a,t)
1838 | Ast.BEFOREAFTER(b,a) -> (b@anythings@a,t)
1839 | Ast.NOTHING -> (anythings,t))
1840 | _ -> failwith "not possible 7")
1841 | Ast0.MIXED(_) -> failwith "not possible 8"
1842 | Ast0.PLUS -> failwith "not possible 9"
1843
1844 let copy_plus printer minusify model e =
1845 if !Flag.sgrep_mode2
1846 then e (* no plus code, can cause a "not possible" error, so just avoid it *)
1847 else
1848 let e =
1849 match Ast0.get_mcodekind model with
1850 Ast0.MINUS(mc) -> minusify e
1851 | Ast0.CONTEXT(mc) -> e
1852 | _ -> failwith "not possible: copy_plus\n" in
1853 merge_plus (Ast0.get_mcodekind model) (Ast0.get_mcodekind e);
1854 e
1855
1856 let copy_minus printer minusify model e =
1857 match Ast0.get_mcodekind model with
1858 Ast0.MINUS(mc) -> minusify e
1859 | Ast0.CONTEXT(mc) -> e
1860 | Ast0.MIXED(_) ->
1861 if !Flag.sgrep_mode2
1862 then e
1863 else failwith "not possible 8"
1864 | Ast0.PLUS -> failwith "not possible 9"
1865
1866 let whencode_allowed prev_ecount prev_icount prev_dcount
1867 ecount icount dcount rest =
1868 (* actually, if ecount or dcount is 0, the flag doesn't matter, because it
1869 won't be tested *)
1870 let other_ecount = (* number of edots *)
1871 List.fold_left (function rest -> function (_,ec,ic,dc) -> ec + rest)
1872 prev_ecount rest in
1873 let other_icount = (* number of dots *)
1874 List.fold_left (function rest -> function (_,ec,ic,dc) -> ic + rest)
1875 prev_icount rest in
1876 let other_dcount = (* number of dots *)
1877 List.fold_left (function rest -> function (_,ec,ic,dc) -> dc + rest)
1878 prev_dcount rest in
1879 (ecount = 0 or other_ecount = 0, icount = 0 or other_icount = 0,
1880 dcount = 0 or other_dcount = 0)
1881
1882 (* copy the befores and afters to the instantiated code *)
1883 let extra_copy_stmt_plus model e =
1884 (if not !Flag.sgrep_mode2 (* sgrep has no plus code, so nothing to do *)
1885 then
1886 (match Ast0.unwrap model with
1887 Ast0.FunDecl((info,bef),_,_,_,_,_,_,_,_)
1888 | Ast0.Decl((info,bef),_) ->
1889 (match Ast0.unwrap e with
1890 Ast0.FunDecl((info,bef1),_,_,_,_,_,_,_,_)
1891 | Ast0.Decl((info,bef1),_) ->
1892 merge_plus bef bef1
1893 | _ -> merge_plus bef (Ast0.get_mcodekind e))
1894 | Ast0.IfThen(_,_,_,_,_,(info,aft))
1895 | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft))
1896 | Ast0.While(_,_,_,_,_,(info,aft))
1897 | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft))
1898 | Ast0.Iterator(_,_,_,_,_,(info,aft)) ->
1899 (match Ast0.unwrap e with
1900 Ast0.IfThen(_,_,_,_,_,(info,aft1))
1901 | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft1))
1902 | Ast0.While(_,_,_,_,_,(info,aft1))
1903 | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft1))
1904 | Ast0.Iterator(_,_,_,_,_,(info,aft1)) ->
1905 merge_plus aft aft1
1906 | _ -> merge_plus aft (Ast0.get_mcodekind e))
1907 | _ -> ()));
1908 e
1909
1910 let extra_copy_other_plus model e = e
1911
1912 (* --------------------------------------------------------------------- *)
1913
1914 let mv_count = ref 0
1915 let new_mv (_,s) =
1916 let ct = !mv_count in
1917 mv_count := !mv_count + 1;
1918 "_"^s^"_"^(string_of_int ct)
1919
1920 let get_name = function
1921 Ast.MetaIdDecl(ar,nm) ->
1922 (nm,function nm -> Ast.MetaIdDecl(ar,nm))
1923 | Ast.MetaFreshIdDecl(nm,seed) ->
1924 (nm,function nm -> Ast.MetaFreshIdDecl(nm,seed))
1925 | Ast.MetaTypeDecl(ar,nm) ->
1926 (nm,function nm -> Ast.MetaTypeDecl(ar,nm))
1927 | Ast.MetaInitDecl(ar,nm) ->
1928 (nm,function nm -> Ast.MetaInitDecl(ar,nm))
1929 | Ast.MetaListlenDecl(nm) ->
1930 failwith "should not be rebuilt"
1931 | Ast.MetaParamDecl(ar,nm) ->
1932 (nm,function nm -> Ast.MetaParamDecl(ar,nm))
1933 | Ast.MetaParamListDecl(ar,nm,nm1) ->
1934 (nm,function nm -> Ast.MetaParamListDecl(ar,nm,nm1))
1935 | Ast.MetaConstDecl(ar,nm,ty) ->
1936 (nm,function nm -> Ast.MetaConstDecl(ar,nm,ty))
1937 | Ast.MetaErrDecl(ar,nm) ->
1938 (nm,function nm -> Ast.MetaErrDecl(ar,nm))
1939 | Ast.MetaExpDecl(ar,nm,ty) ->
1940 (nm,function nm -> Ast.MetaExpDecl(ar,nm,ty))
1941 | Ast.MetaIdExpDecl(ar,nm,ty) ->
1942 (nm,function nm -> Ast.MetaIdExpDecl(ar,nm,ty))
1943 | Ast.MetaLocalIdExpDecl(ar,nm,ty) ->
1944 (nm,function nm -> Ast.MetaLocalIdExpDecl(ar,nm,ty))
1945 | Ast.MetaExpListDecl(ar,nm,nm1) ->
1946 (nm,function nm -> Ast.MetaExpListDecl(ar,nm,nm1))
1947 | Ast.MetaStmDecl(ar,nm) ->
1948 (nm,function nm -> Ast.MetaStmDecl(ar,nm))
1949 | Ast.MetaStmListDecl(ar,nm) ->
1950 (nm,function nm -> Ast.MetaStmListDecl(ar,nm))
1951 | Ast.MetaFuncDecl(ar,nm) ->
1952 (nm,function nm -> Ast.MetaFuncDecl(ar,nm))
1953 | Ast.MetaLocalFuncDecl(ar,nm) ->
1954 (nm,function nm -> Ast.MetaLocalFuncDecl(ar,nm))
1955 | Ast.MetaPosDecl(ar,nm) ->
1956 (nm,function nm -> Ast.MetaPosDecl(ar,nm))
1957 | Ast.MetaDeclarerDecl(ar,nm) ->
1958 (nm,function nm -> Ast.MetaDeclarerDecl(ar,nm))
1959 | Ast.MetaIteratorDecl(ar,nm) ->
1960 (nm,function nm -> Ast.MetaIteratorDecl(ar,nm))
1961
1962 let make_new_metavars metavars bindings =
1963 let new_metavars =
1964 List.filter
1965 (function mv ->
1966 let (s,_) = get_name mv in
1967 try let _ = List.assoc s bindings in false with Not_found -> true)
1968 metavars in
1969 List.split
1970 (List.map
1971 (function mv ->
1972 let (s,rebuild) = get_name mv in
1973 let new_s = (!current_rule,new_mv s) in
1974 (rebuild new_s, (s,new_s)))
1975 new_metavars)
1976
1977 (* --------------------------------------------------------------------- *)
1978
1979 let do_nothing x = x
1980
1981 let mkdisj matcher metavars alts e instantiater mkiso disj_maker minusify
1982 rebuild_mcodes name printer extra_plus update_others =
1983 let call_instantiate bindings mv_bindings alts =
1984 List.concat
1985 (List.map
1986 (function (a,_,_,_) ->
1987 nub
1988 (* no need to create duplicates when the bindings have no effect *)
1989 (List.map
1990 (function bindings ->
1991 Ast0.set_iso
1992 (copy_plus printer minusify e
1993 (extra_plus e
1994 (instantiater bindings mv_bindings
1995 (rebuild_mcodes a))))
1996 ((name,mkiso a)::(Ast0.get_iso e))) (* keep count, not U *)
1997 bindings))
1998 alts) in
1999 let rec inner_loop all_alts prev_ecount prev_icount prev_dcount = function
2000 [] -> Common.Left (prev_ecount, prev_icount, prev_dcount)
2001 | ((pattern,ecount,icount,dcount)::rest) ->
2002 let wc =
2003 whencode_allowed prev_ecount prev_icount prev_dcount
2004 ecount dcount icount rest in
2005 (match matcher true (context_required e) wc pattern e init_env with
2006 Fail(reason) ->
2007 if reason = NonMatch || not !Flag_parsing_cocci.show_iso_failures
2008 then ()
2009 else
2010 (match matcher false false wc pattern e init_env with
2011 OK _ ->
2012 interpret_reason name (Ast0.get_line e) reason
2013 (function () -> printer e)
2014 | _ -> ());
2015 inner_loop all_alts (prev_ecount + ecount) (prev_icount + icount)
2016 (prev_dcount + dcount) rest
2017 | OK (bindings : (((string * string) * 'a) list list)) ->
2018 let all_alts =
2019 (* apply update_others to all patterns other than the matched
2020 one. This is used to desigate the others as test
2021 expressions in the TestExpression case *)
2022 (List.map
2023 (function (x,e,i,d) as all ->
2024 if x = pattern
2025 then all
2026 else (update_others x,e,i,d))
2027 (List.hd all_alts)) ::
2028 (List.map
2029 (List.map (function (x,e,i,d) -> (update_others x,e,i,d)))
2030 (List.tl all_alts)) in
2031 (match List.concat all_alts with
2032 [x] -> Common.Left (prev_ecount, prev_icount, prev_dcount)
2033 | all_alts ->
2034 let (new_metavars,mv_bindings) =
2035 make_new_metavars metavars (nub(List.concat bindings)) in
2036 Common.Right
2037 (new_metavars,
2038 call_instantiate bindings mv_bindings all_alts))) in
2039 let rec outer_loop prev_ecount prev_icount prev_dcount = function
2040 [] | [[_]] (*only one alternative*) -> (0,[],e) (* nothing matched *)
2041 | (alts::rest) as all_alts ->
2042 match inner_loop all_alts prev_ecount prev_icount prev_dcount alts with
2043 Common.Left(prev_ecount, prev_icount, prev_dcount) ->
2044 outer_loop prev_ecount prev_icount prev_dcount rest
2045 | Common.Right (new_metavars,res) ->
2046 (1,new_metavars,
2047 copy_minus printer minusify e (disj_maker res)) in
2048 let (count,metavars,e) = outer_loop 0 0 0 alts in
2049 (count, metavars, e)
2050
2051 (* no one should ever look at the information stored in these mcodes *)
2052 let disj_starter lst =
2053 let old_info = Ast0.get_info(List.hd lst) in
2054 let new_pos_info =
2055 { old_info.Ast0.pos_info with
2056 Ast0.line_end = old_info.Ast0.pos_info.Ast0.line_start;
2057 Ast0.logical_end = old_info.Ast0.pos_info.Ast0.logical_start; } in
2058 let info =
2059 { Ast0.pos_info = new_pos_info;
2060 Ast0.attachable_start = false; Ast0.attachable_end = false;
2061 Ast0.mcode_start = []; Ast0.mcode_end = [];
2062 Ast0.strings_before = []; Ast0.strings_after = [] } in
2063 Ast0.make_mcode_info "(" info
2064
2065 let disj_ender lst =
2066 let old_info = Ast0.get_info(List.hd lst) in
2067 let new_pos_info =
2068 { old_info.Ast0.pos_info with
2069 Ast0.line_start = old_info.Ast0.pos_info.Ast0.line_end;
2070 Ast0.logical_start = old_info.Ast0.pos_info.Ast0.logical_end; } in
2071 let info =
2072 { Ast0.pos_info = new_pos_info;
2073 Ast0.attachable_start = false; Ast0.attachable_end = false;
2074 Ast0.mcode_start = []; Ast0.mcode_end = [];
2075 Ast0.strings_before = []; Ast0.strings_after = [] } in
2076 Ast0.make_mcode_info ")" info
2077
2078 let disj_mid _ = Ast0.make_mcode "|"
2079
2080 let make_disj_type tl =
2081 let mids =
2082 match tl with
2083 [] -> failwith "bad disjunction"
2084 | x::xs -> List.map disj_mid xs in
2085 Ast0.context_wrap (Ast0.DisjType(disj_starter tl,tl,mids,disj_ender tl))
2086 let make_disj_stmt_list tl =
2087 let mids =
2088 match tl with
2089 [] -> failwith "bad disjunction"
2090 | x::xs -> List.map disj_mid xs in
2091 Ast0.context_wrap (Ast0.Disj(disj_starter tl,tl,mids,disj_ender tl))
2092 let make_disj_expr model el =
2093 let mids =
2094 match el with
2095 [] -> failwith "bad disjunction"
2096 | x::xs -> List.map disj_mid xs in
2097 let update_arg x =
2098 if Ast0.get_arg_exp model then Ast0.set_arg_exp x else x in
2099 let update_test x =
2100 let x = if Ast0.get_test_pos model then Ast0.set_test_pos x else x in
2101 if Ast0.get_test_exp model then Ast0.set_test_exp x else x in
2102 let el = List.map update_arg (List.map update_test el) in
2103 Ast0.context_wrap (Ast0.DisjExpr(disj_starter el,el,mids,disj_ender el))
2104 let make_disj_decl dl =
2105 let mids =
2106 match dl with
2107 [] -> failwith "bad disjunction"
2108 | x::xs -> List.map disj_mid xs in
2109 Ast0.context_wrap (Ast0.DisjDecl(disj_starter dl,dl,mids,disj_ender dl))
2110 let make_disj_stmt sl =
2111 let dotify x = Ast0.context_wrap (Ast0.DOTS[x]) in
2112 let mids =
2113 match sl with
2114 [] -> failwith "bad disjunction"
2115 | x::xs -> List.map disj_mid xs in
2116 Ast0.context_wrap
2117 (Ast0.Disj(disj_starter sl,List.map dotify sl,mids,disj_ender sl))
2118
2119 let transform_type (metavars,alts,name) e =
2120 match alts with
2121 (Ast0.TypeCTag(_)::_)::_ ->
2122 (* start line is given to any leaves in the iso code *)
2123 let start_line =
2124 Some ((Ast0.get_info e).Ast0.pos_info.Ast0.line_start) in
2125 let alts =
2126 List.map
2127 (List.map
2128 (function
2129 Ast0.TypeCTag(p) ->
2130 (p,count_edots.VT0.combiner_rec_typeC p,
2131 count_idots.VT0.combiner_rec_typeC p,
2132 count_dots.VT0.combiner_rec_typeC p)
2133 | _ -> failwith "invalid alt"))
2134 alts in
2135 mkdisj match_typeC metavars alts e
2136 (function b -> function mv_b ->
2137 (instantiate b mv_b).VT0.rebuilder_rec_typeC)
2138 (function t -> Ast0.TypeCTag t)
2139 make_disj_type make_minus.VT0.rebuilder_rec_typeC
2140 (rebuild_mcode start_line).VT0.rebuilder_rec_typeC
2141 name Unparse_ast0.typeC extra_copy_other_plus do_nothing
2142 | _ -> (0,[],e)
2143
2144
2145 let transform_expr (metavars,alts,name) e =
2146 let process update_others =
2147 (* start line is given to any leaves in the iso code *)
2148 let start_line =
2149 Some ((Ast0.get_info e).Ast0.pos_info.Ast0.line_start) in
2150 let alts =
2151 List.map
2152 (List.map
2153 (function
2154 Ast0.ExprTag(p) | Ast0.ArgExprTag(p) | Ast0.TestExprTag(p) ->
2155 (p,count_edots.VT0.combiner_rec_expression p,
2156 count_idots.VT0.combiner_rec_expression p,
2157 count_dots.VT0.combiner_rec_expression p)
2158 | _ -> failwith "invalid alt"))
2159 alts in
2160 mkdisj match_expr metavars alts e
2161 (function b -> function mv_b ->
2162 (instantiate b mv_b).VT0.rebuilder_rec_expression)
2163 (function e -> Ast0.ExprTag e)
2164 (make_disj_expr e)
2165 make_minus.VT0.rebuilder_rec_expression
2166 (rebuild_mcode start_line).VT0.rebuilder_rec_expression
2167 name Unparse_ast0.expression extra_copy_other_plus update_others in
2168 match alts with
2169 (Ast0.ExprTag(_)::_)::_ -> process do_nothing
2170 | (Ast0.ArgExprTag(_)::_)::_ when Ast0.get_arg_exp e -> process do_nothing
2171 | (Ast0.TestExprTag(_)::_)::_ when Ast0.get_test_pos e ->
2172 process Ast0.set_test_exp
2173 | _ -> (0,[],e)
2174
2175 let transform_decl (metavars,alts,name) e =
2176 match alts with
2177 (Ast0.DeclTag(_)::_)::_ ->
2178 (* start line is given to any leaves in the iso code *)
2179 let start_line =
2180 Some (Ast0.get_info e).Ast0.pos_info.Ast0.line_start in
2181 let alts =
2182 List.map
2183 (List.map
2184 (function
2185 Ast0.DeclTag(p) ->
2186 (p,count_edots.VT0.combiner_rec_declaration p,
2187 count_idots.VT0.combiner_rec_declaration p,
2188 count_dots.VT0.combiner_rec_declaration p)
2189 | _ -> failwith "invalid alt"))
2190 alts in
2191 mkdisj match_decl metavars alts e
2192 (function b -> function mv_b ->
2193 (instantiate b mv_b).VT0.rebuilder_rec_declaration)
2194 (function d -> Ast0.DeclTag d)
2195 make_disj_decl
2196 make_minus.VT0.rebuilder_rec_declaration
2197 (rebuild_mcode start_line).VT0.rebuilder_rec_declaration
2198 name Unparse_ast0.declaration extra_copy_other_plus do_nothing
2199 | _ -> (0,[],e)
2200
2201 let transform_stmt (metavars,alts,name) e =
2202 match alts with
2203 (Ast0.StmtTag(_)::_)::_ ->
2204 (* start line is given to any leaves in the iso code *)
2205 let start_line =
2206 Some (Ast0.get_info e).Ast0.pos_info.Ast0.line_start in
2207 let alts =
2208 List.map
2209 (List.map
2210 (function
2211 Ast0.StmtTag(p) ->
2212 (p,count_edots.VT0.combiner_rec_statement p,
2213 count_idots.VT0.combiner_rec_statement p,
2214 count_dots.VT0.combiner_rec_statement p)
2215 | _ -> failwith "invalid alt"))
2216 alts in
2217 mkdisj match_statement metavars alts e
2218 (function b -> function mv_b ->
2219 (instantiate b mv_b).VT0.rebuilder_rec_statement)
2220 (function s -> Ast0.StmtTag s)
2221 make_disj_stmt make_minus.VT0.rebuilder_rec_statement
2222 (rebuild_mcode start_line).VT0.rebuilder_rec_statement
2223 name (Unparse_ast0.statement "") extra_copy_stmt_plus do_nothing
2224 | _ -> (0,[],e)
2225
2226 (* sort of a hack, because there is no disj at top level *)
2227 let transform_top (metavars,alts,name) e =
2228 match Ast0.unwrap e with
2229 Ast0.DECL(declstm) ->
2230 (try
2231 let strip alts =
2232 List.map
2233 (List.map
2234 (function
2235 Ast0.DotsStmtTag(d) ->
2236 (match Ast0.unwrap d with
2237 Ast0.DOTS([s]) -> Ast0.StmtTag(s)
2238 | _ -> raise (Failure ""))
2239 | _ -> raise (Failure "")))
2240 alts in
2241 let (count,mv,s) = transform_stmt (metavars,strip alts,name) declstm in
2242 (count,mv,Ast0.rewrap e (Ast0.DECL(s)))
2243 with Failure _ -> (0,[],e))
2244 | Ast0.CODE(stmts) ->
2245 let (count,mv,res) =
2246 match alts with
2247 (Ast0.DotsStmtTag(_)::_)::_ ->
2248 (* start line is given to any leaves in the iso code *)
2249 let start_line =
2250 Some ((Ast0.get_info e).Ast0.pos_info.Ast0.line_start) in
2251 let alts =
2252 List.map
2253 (List.map
2254 (function
2255 Ast0.DotsStmtTag(p) ->
2256 (p,count_edots.VT0.combiner_rec_statement_dots p,
2257 count_idots.VT0.combiner_rec_statement_dots p,
2258 count_dots.VT0.combiner_rec_statement_dots p)
2259 | _ -> failwith "invalid alt"))
2260 alts in
2261 mkdisj match_statement_dots metavars alts stmts
2262 (function b -> function mv_b ->
2263 (instantiate b mv_b).VT0.rebuilder_rec_statement_dots)
2264 (function s -> Ast0.DotsStmtTag s)
2265 (function x ->
2266 Ast0.rewrap e (Ast0.DOTS([make_disj_stmt_list x])))
2267 (function x ->
2268 make_minus.VT0.rebuilder_rec_statement_dots x)
2269 (rebuild_mcode start_line).VT0.rebuilder_rec_statement_dots
2270 name Unparse_ast0.statement_dots extra_copy_other_plus do_nothing
2271 | _ -> (0,[],stmts) in
2272 (count,mv,Ast0.rewrap e (Ast0.CODE res))
2273 | _ -> (0,[],e)
2274
2275 (* --------------------------------------------------------------------- *)
2276
2277 let transform (alts : isomorphism) t =
2278 (* the following ugliness is because rebuilder only returns a new term *)
2279 let extra_meta_decls = ref ([] : Ast_cocci.metavar list) in
2280 let in_limit n = function
2281 None -> true
2282 | Some n1 ->
2283 n < n1 or
2284 ((if !Flag_parsing_cocci.show_iso_failures
2285 then Common.pr2_once "execeeded iso threshold, see -iso_limit option");
2286 false) in
2287 let bind x y = x + y in
2288 let option_default = 0 in
2289 let exprfn r k e =
2290 let (e_count,e) = k e in
2291 if in_limit e_count !Flag_parsing_cocci.iso_limit
2292 then
2293 let (count,extra_meta,exp) = transform_expr alts e in
2294 extra_meta_decls := extra_meta @ !extra_meta_decls;
2295 (bind count e_count,exp)
2296 else (e_count,e) in
2297
2298 let declfn r k e =
2299 let (e_count,e) = k e in
2300 if in_limit e_count !Flag_parsing_cocci.iso_limit
2301 then
2302 let (count,extra_meta,dec) = transform_decl alts e in
2303 extra_meta_decls := extra_meta @ !extra_meta_decls;
2304 (bind count e_count,dec)
2305 else (e_count,e) in
2306
2307 let stmtfn r k e =
2308 let (e_count,e) = k e in
2309 if in_limit e_count !Flag_parsing_cocci.iso_limit
2310 then
2311 let (count,extra_meta,stm) = transform_stmt alts e in
2312 extra_meta_decls := extra_meta @ !extra_meta_decls;
2313 (bind count e_count,stm)
2314 else (e_count,e) in
2315
2316 let typefn r k e =
2317 let (continue,e_count,e) =
2318 match Ast0.unwrap e with
2319 Ast0.Signed(signb,tyb) ->
2320 (* Hack! How else to prevent iso from applying under an
2321 unsigned??? *)
2322 (true,0,e)
2323 | _ ->
2324 let (e_count,e) = k e in
2325 if in_limit e_count !Flag_parsing_cocci.iso_limit
2326 then (true,e_count,e)
2327 else (false,e_count,e) in
2328 if continue
2329 then
2330 let (count,extra_meta,ty) = transform_type alts e in
2331 extra_meta_decls := extra_meta @ !extra_meta_decls;
2332 (bind count e_count,ty)
2333 else (e_count,e) in
2334
2335 let topfn r k e =
2336 let (e_count,e) = k e in
2337 if in_limit e_count !Flag_parsing_cocci.iso_limit
2338 then
2339 let (count,extra_meta,ty) = transform_top alts e in
2340 extra_meta_decls := extra_meta @ !extra_meta_decls;
2341 (bind count e_count,ty)
2342 else (e_count,e) in
2343
2344 let res =
2345 V0.combiner_rebuilder bind option_default
2346 {V0.combiner_rebuilder_functions with
2347 VT0.combiner_rebuilder_exprfn = exprfn;
2348 VT0.combiner_rebuilder_tyfn = typefn;
2349 VT0.combiner_rebuilder_declfn = declfn;
2350 VT0.combiner_rebuilder_stmtfn = stmtfn;
2351 VT0.combiner_rebuilder_topfn = topfn} in
2352 let (_,res) = res.VT0.top_level t in
2353 (!extra_meta_decls,res)
2354
2355 (* --------------------------------------------------------------------- *)
2356
2357 (* should be done by functorizing the parser to use wrap or context_wrap *)
2358 let rewrap =
2359 let mcode (x,a,i,mc,pos) = (x,a,i,Ast0.context_befaft(),pos) in
2360 let donothing r k e = Ast0.context_wrap(Ast0.unwrap(k e)) in
2361 V0.flat_rebuilder
2362 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
2363 donothing donothing donothing donothing donothing donothing
2364 donothing donothing donothing donothing donothing donothing donothing
2365 donothing donothing
2366
2367 let rewrap_anything = function
2368 Ast0.DotsExprTag(d) ->
2369 Ast0.DotsExprTag(rewrap.VT0.rebuilder_rec_expression_dots d)
2370 | Ast0.DotsInitTag(d) ->
2371 Ast0.DotsInitTag(rewrap.VT0.rebuilder_rec_initialiser_list d)
2372 | Ast0.DotsParamTag(d) ->
2373 Ast0.DotsParamTag(rewrap.VT0.rebuilder_rec_parameter_list d)
2374 | Ast0.DotsStmtTag(d) ->
2375 Ast0.DotsStmtTag(rewrap.VT0.rebuilder_rec_statement_dots d)
2376 | Ast0.DotsDeclTag(d) ->
2377 Ast0.DotsDeclTag(rewrap.VT0.rebuilder_rec_declaration_dots d)
2378 | Ast0.DotsCaseTag(d) ->
2379 Ast0.DotsCaseTag(rewrap.VT0.rebuilder_rec_case_line_dots d)
2380 | Ast0.IdentTag(d) -> Ast0.IdentTag(rewrap.VT0.rebuilder_rec_ident d)
2381 | Ast0.ExprTag(d) -> Ast0.ExprTag(rewrap.VT0.rebuilder_rec_expression d)
2382 | Ast0.ArgExprTag(d) ->
2383 Ast0.ArgExprTag(rewrap.VT0.rebuilder_rec_expression d)
2384 | Ast0.TestExprTag(d) ->
2385 Ast0.TestExprTag(rewrap.VT0.rebuilder_rec_expression d)
2386 | Ast0.TypeCTag(d) -> Ast0.TypeCTag(rewrap.VT0.rebuilder_rec_typeC d)
2387 | Ast0.InitTag(d) -> Ast0.InitTag(rewrap.VT0.rebuilder_rec_initialiser d)
2388 | Ast0.ParamTag(d) -> Ast0.ParamTag(rewrap.VT0.rebuilder_rec_parameter d)
2389 | Ast0.DeclTag(d) -> Ast0.DeclTag(rewrap.VT0.rebuilder_rec_declaration d)
2390 | Ast0.StmtTag(d) -> Ast0.StmtTag(rewrap.VT0.rebuilder_rec_statement d)
2391 | Ast0.CaseLineTag(d) ->
2392 Ast0.CaseLineTag(rewrap.VT0.rebuilder_rec_case_line d)
2393 | Ast0.TopTag(d) -> Ast0.TopTag(rewrap.VT0.rebuilder_rec_top_level d)
2394 | Ast0.IsoWhenTag(_) | Ast0.IsoWhenTTag(_) | Ast0.IsoWhenFTag(_) ->
2395 failwith "only for isos within iso phase"
2396 | Ast0.MetaPosTag(p) -> Ast0.MetaPosTag(p)
2397
2398 (* --------------------------------------------------------------------- *)
2399
2400 let apply_isos isos rule rule_name =
2401 if isos = []
2402 then ([],rule)
2403 else
2404 begin
2405 current_rule := rule_name;
2406 let isos =
2407 List.map
2408 (function (metavars,iso,name) ->
2409 (metavars,List.map (List.map rewrap_anything) iso,name))
2410 isos in
2411 let (extra_meta,rule) =
2412 List.split
2413 (List.map
2414 (function t ->
2415 List.fold_left
2416 (function (extra_meta,t) -> function iso ->
2417 let (new_extra_meta,t) = transform iso t in
2418 (new_extra_meta@extra_meta,t))
2419 ([],t) isos)
2420 rule) in
2421 (List.concat extra_meta, Compute_lines.compute_lines rule)
2422 end