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