2 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
4 * This file is part of Coccinelle.
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
24 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
25 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
26 * This file is part of Coccinelle.
28 * Coccinelle is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, according to version 2 of the License.
32 * Coccinelle is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public License
38 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
40 * The authors reserve the right to distribute this or future versions of
41 * Coccinelle under other licenses.
47 * Copyright (C) 2006, 2007 Ecole des Mines de Nantes
49 * This program is free software; you can redistribute it and/or
50 * modify it under the terms of the GNU General Public License (GPL)
51 * version 2 as published by the Free Software Foundation.
53 * This program is distributed in the hope that it will be useful,
54 * but WITHOUT ANY WARRANTY; without even the implied warranty of
55 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56 * file license.txt for more details.
58 * This file was part of Coccinelle.
62 module Flag_engine
= Flag_matcher
63 (*****************************************************************************)
64 (* The functor argument *)
65 (*****************************************************************************)
67 (* info passed recursively in monad in addition to binding *)
69 optional_storage_iso
: bool;
70 optional_qualifier_iso
: bool;
71 value_format_iso
: bool;
74 module XMATCH
= struct
76 (* ------------------------------------------------------------------------*)
77 (* Combinators history *)
78 (* ------------------------------------------------------------------------*)
81 * type ('a, 'b) matcher = 'a -> 'b -> bool
83 * version1: same but with a global variable holding the current binding
85 * - can have multiple possibilities
87 * - sometimes have to undo, cos if start match, then it binds,
88 * and if later it does not match, then must undo the first binds.
89 * ex: when match parameters, can try to match, but then we found far
90 * later that the last argument of a function does not match
91 * => have to uando the binding !!!
92 * (can handle that too with a global, by saving the
93 * global, ... but sux)
94 * => better not use global
97 * type ('a, 'b) matcher = binding -> 'a -> 'b -> binding list
99 * Empty list mean failure (let matchfailure = []).
100 * To be able to have pretty code, have to use partial application
101 * powa, and so the type is in fact
104 * type ('a, 'b) matcher = 'a -> 'b -> binding -> binding list
106 * Then by defining the correct combinators, can have quite pretty code (that
107 * looks like the clean code of version0).
109 * opti: return a lazy list of possible matchs ?
111 * version4: type tin = Lib_engine.metavars_binding
114 (* ------------------------------------------------------------------------*)
115 (* Standard type and operators *)
116 (* ------------------------------------------------------------------------*)
120 binding
: Lib_engine.metavars_binding
;
121 binding0
: Lib_engine.metavars_binding
; (* inherited bindings *)
123 (* 'x is a ('a * 'b) but in fact dont care about 'b, we just tag the SP *)
124 (* opti? use set instead of list *)
125 type 'x tout
= ('x
* Lib_engine.metavars_binding
) list
127 type ('a
, 'b
) matcher
= 'a
-> 'b
-> tin
-> ('a
* 'b
) tout
130 let (>>=) m1 m2
= fun tin
->
132 let xxs = xs +> List.map
(fun ((a
,b
), binding
) ->
133 m2 a b
{tin
with binding
= binding
}
137 (* Je compare les bindings retournés par les differentes branches.
138 * Si la deuxieme branche amene a des bindings qui sont deja presents
139 * dans la premiere branche, alors je ne les accepte pas.
141 * update: still useful now that julia better handle Exp directly via
142 * ctl tricks using positions ?
144 let (>|+|>) m1 m2
= fun tin
->
153 let list_bindings_already = List.map snd
res1 in
155 (res2 +> List.filter
(fun (x
, binding
) ->
157 (list_bindings_already +> List.exists
(fun already
->
158 Lib_engine.equal_binding binding already
))
164 let (>||>) m1 m2
= fun tin
->
171 (* opti? use set instead of list *)
174 if l2 = [] then l1 else l1 ++ l2 (*a small benefit; avoid a trivial @*)
177 let return res
= fun tin
->
180 let fail = fun tin
->
183 let (>&&>) f m
= fun tin
->
189 let mode = Cocci_vs_c.PatternMode
191 (* ------------------------------------------------------------------------*)
193 (* ------------------------------------------------------------------------*)
194 let cocciExp = fun expf expa node
-> fun tin
->
196 let globals = ref [] in
199 Visitor_c.default_visitor_c
with
200 Visitor_c.kexpr
= (fun (k
, bigf) expb
->
201 match expf expa expb tin
with
202 | [] -> (* failed *) k expb
204 globals := xs @ !globals;
205 if not
!Flag_engine.disallow_nested_exps
then k expb
(* CHOICE *)
208 * push2 expr globals; k expr
210 * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e)
216 Visitor_c.vk_node
bigf node
;
217 !globals +> List.map
(fun ((a
, _exp
), binding
) ->
221 (* same as cocciExp, but for expressions in an expression, not expressions
223 let cocciExpExp = fun expf expa expb
-> fun tin
->
225 let globals = ref [] in
228 Visitor_c.default_visitor_c
with
229 Visitor_c.kexpr
= (fun (k
, bigf) expb
->
230 match expf expa expb tin
with
231 | [] -> (* failed *) k expb
233 globals := xs @ !globals;
234 if not
!Flag_engine.disallow_nested_exps
then k expb
(* CHOICE *)
237 * push2 expr globals; k expr
239 * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e)
245 Visitor_c.vk_expr
bigf expb
;
246 !globals +> List.map
(fun ((a
, _exp
), binding
) ->
250 let cocciTy = fun expf expa node
-> fun tin
->
252 let globals = ref [] in
254 Visitor_c.default_visitor_c
with
255 Visitor_c.ktype
= (fun (k
, bigf) expb
->
256 match expf expa expb tin
with
257 | [] -> (* failed *) k expb
258 | xs -> globals := xs @ !globals);
262 Visitor_c.vk_node
bigf node
;
263 !globals +> List.map
(fun ((a
, _exp
), binding
) ->
267 let cocciInit = fun expf expa node
-> fun tin
->
269 let globals = ref [] in
271 Visitor_c.default_visitor_c
with
272 Visitor_c.kini
= (fun (k
, bigf) expb
->
273 match expf expa expb tin
with
274 | [] -> (* failed *) k expb
275 | xs -> globals := xs @ !globals);
279 Visitor_c.vk_node
bigf node
;
280 !globals +> List.map
(fun ((a
, _exp
), binding
) ->
285 (* ------------------------------------------------------------------------*)
286 (* Distribute mcode *)
287 (* ------------------------------------------------------------------------*)
288 let tag_mck_pos mck posmck
=
290 | Ast_cocci.PLUS c
-> Ast_cocci.PLUS c
291 | Ast_cocci.CONTEXT
(pos
, xs) ->
292 assert (pos
=*= Ast_cocci.NoPos
|| pos
=*= Ast_cocci.DontCarePos
);
293 Ast_cocci.CONTEXT
(posmck
, xs)
294 | Ast_cocci.MINUS
(pos
, inst
, adj
, xs) ->
295 assert (pos
=*= Ast_cocci.NoPos
|| pos
=*= Ast_cocci.DontCarePos
);
296 Ast_cocci.MINUS
(posmck
, inst
, adj
, xs)
299 let tag_mck_pos_mcode (x
,info
,mck
,pos
) posmck stuff
= fun tin
->
300 [((x
, info
, tag_mck_pos mck posmck
, pos
),stuff
), tin
.binding
]
303 let distrf (ii_of_x_f
) =
304 fun mcode x
-> fun tin
->
305 let (max
, min
) = Lib_parsing_c.max_min_by_pos
(ii_of_x_f x
)
307 let posmck = Ast_cocci.FixPos
(min
, max
) (* subtil: and not max, min !!*)
309 tag_mck_pos_mcode mcode
posmck x tin
311 let distrf_e = distrf (Lib_parsing_c.ii_of_expr
)
312 let distrf_args = distrf (Lib_parsing_c.ii_of_args
)
313 let distrf_type = distrf (Lib_parsing_c.ii_of_type
)
314 let distrf_param = distrf (Lib_parsing_c.ii_of_param
)
315 let distrf_params = distrf (Lib_parsing_c.ii_of_params
)
316 let distrf_ini = distrf (Lib_parsing_c.ii_of_ini
)
317 let distrf_node = distrf (Lib_parsing_c.ii_of_node
)
318 let distrf_struct_fields = distrf (Lib_parsing_c.ii_of_struct_fields
)
319 let distrf_cst = distrf (Lib_parsing_c.ii_of_cst
)
320 let distrf_define_params = distrf (Lib_parsing_c.ii_of_define_params
)
323 (* ------------------------------------------------------------------------*)
324 (* Constraints on metavariable values *)
325 (* ------------------------------------------------------------------------*)
326 let check_idconstraint matcher c id
= fun f tin
->
334 let check_constraints_ne matcher constraints exp
= fun f tin
->
335 let rec loop = function
336 [] -> f
() tin
(* success *)
338 match matcher c exp tin
with
339 [] (* failure *) -> loop cs
340 | _
(* success *) -> fail tin
in
343 let check_pos_constraints constraints pvalu f tin
=
346 let success = [[]] in
348 (* relies on the fact that constraints on pos variables must refer to
349 inherited variables *)
350 (match Common.optionise
(fun () -> tin
.binding0
+> List.assoc c
) with
352 if Cocci_vs_c.equal_inh_metavarval exp valu'
353 then success else failure
355 (* if the variable is not there, it puts no constraints *)
356 (* not sure this is still useful *)
358 constraints pvalu f tin
360 (* ------------------------------------------------------------------------*)
362 (* ------------------------------------------------------------------------*)
363 (* pre: if have declared a new metavar that hide another one, then
364 * must be passed with a binding that deleted this metavar
366 * Here we dont use the keep argument of julia. cf f(X,X), J'ai
367 * besoin de garder le X en interne, meme si julia s'en fout elle du
368 * X et qu'elle a mis X a DontSaved.
370 let check_add_metavars_binding strip _keep inherited
= fun (k
, valu
) tin
->
373 match Common.optionise
(fun () -> tin
.binding0
+> List.assoc k
) with
375 if Cocci_vs_c.equal_inh_metavarval valu valu'
376 then Some tin
.binding
380 match Common.optionise
(fun () -> tin
.binding
+> List.assoc k
) with
382 if Cocci_vs_c.equal_metavarval valu valu'
383 then Some tin
.binding
388 Some
(tin
.binding
+> Common.insert_assoc
(k
, valu'
)) in
390 Ast_c.MetaIdVal
(a
,c
) ->
391 (* c is a negated constraint *)
392 let rec loop = function
393 [] -> success(Ast_c.MetaIdVal
(a
,[]))
397 (fun () -> tin
.binding0
+> List.assoc c
) in
399 Some
(Ast_c.MetaIdVal
(v
,_
)) ->
401 then None
(* failure *)
402 else success(Ast_c.MetaIdVal
(a
,[]))
403 | Some _
-> failwith
"Not possible"
404 | None
-> success(Ast_c.MetaIdVal
(a
,[]))) in
406 | Ast_c.MetaFuncVal a
->
407 success(Ast_c.MetaFuncVal a
)
408 | Ast_c.MetaLocalFuncVal a
->
409 success(Ast_c.MetaLocalFuncVal a
) (*more?*)
410 | Ast_c.MetaExprVal
(a
,c
) ->
411 (* c in the value is only to prepare for the future in which
412 we figure out how to have subterm constraints on unbound
413 variables. Now an environment will only contain expression
414 values with empty constraints, as all constraints are
415 resolved at binding time *)
418 then Lib_parsing_c.al_expr a
419 else Lib_parsing_c.semi_al_expr a
in
420 let inh_stripped = Lib_parsing_c.al_inh_expr a
in
421 let rec loop = function
422 [] -> success(Ast_c.MetaExprVal
(stripped,[]))
426 (fun () -> tin
.binding0
+> List.assoc c
) in
428 Some
(Ast_c.MetaExprVal
(v
,_
)) ->
429 if C_vs_c.subexpression_of_expression
inh_stripped v
430 then loop cs
(* forget satisfied constraints *)
431 else None
(* failure *)
432 | Some _
-> failwith
"not possible"
433 (* fail if this should be a subterm of something that
437 | Ast_c.MetaExprListVal a
->
439 (Ast_c.MetaExprListVal
441 then Lib_parsing_c.al_arguments a
442 else Lib_parsing_c.semi_al_arguments a
))
444 | Ast_c.MetaStmtVal a
->
448 then Lib_parsing_c.al_statement a
449 else Lib_parsing_c.semi_al_statement a
))
450 | Ast_c.MetaTypeVal a
->
454 then Lib_parsing_c.al_type a
455 else Lib_parsing_c.semi_al_type a
))
457 | Ast_c.MetaInitVal a
->
461 then Lib_parsing_c.al_init a
462 else Lib_parsing_c.semi_al_init a
))
464 | Ast_c.MetaListlenVal a
-> success(Ast_c.MetaListlenVal a
)
466 | Ast_c.MetaParamVal a
->
470 then Lib_parsing_c.al_param a
471 else Lib_parsing_c.semi_al_param a
))
472 | Ast_c.MetaParamListVal a
->
474 (Ast_c.MetaParamListVal
476 then Lib_parsing_c.al_params a
477 else Lib_parsing_c.semi_al_params a
))
479 | Ast_c.MetaPosVal
(pos1
,pos2
) ->
480 success(Ast_c.MetaPosVal
(pos1
,pos2
))
481 | Ast_c.MetaPosValList l
-> success (Ast_c.MetaPosValList l
))
483 let envf keep inherited
= fun (k
, valu
, get_max_min
) f tin
->
484 let x = Ast_cocci.unwrap_mcode k
in
485 match check_add_metavars_binding true keep inherited
(x, valu
) tin
with
487 let new_tin = {tin
with binding
= binding
} in
488 (match Ast_cocci.get_pos_var k
with
489 Ast_cocci.MetaPos
(name
,constraints
,per
,keep
,inherited
) ->
491 let (file
,current_element
,min
,max
) = get_max_min
() in
492 Ast_c.MetaPosValList
[(file
,current_element
,min
,max
)] in
493 (* check constraints. success means that there is a match with
494 one of the constraints, which will ultimately result in
496 check_pos_constraints constraints
pvalu
498 (* constraints are satisfied, now see if we are compatible
499 with existing bindings *)
501 let x = Ast_cocci.unwrap_mcode name
in
503 check_add_metavars_binding false keep inherited
(x, pvalu)
506 f
() {new_tin with binding
= binding
}
509 | Ast_cocci.NoMetaPos
-> f
() new_tin)
512 (* ------------------------------------------------------------------------*)
513 (* Environment, allbounds *)
514 (* ------------------------------------------------------------------------*)
515 (* all referenced inherited variables have to be bound. This would
516 * be naturally checked for the minus or context ones in the
517 * matching process, but have to check the plus ones as well. The
518 * result of get_inherited contains all of these, but the potential
519 * redundant checking for the minus and context ones is probably not
520 * a big deal. If it's a problem, could fix free_vars to distinguish
521 * between + variables and the other ones. *)
523 let (all_bound
: Ast_cocci.meta_name list
-> tin
-> bool) = fun l tin
->
524 l
+> List.for_all
(fun inhvar
->
525 match Common.optionise
(fun () -> tin
.binding0
+> List.assoc inhvar
) with
530 let optional_storage_flag f
= fun tin
->
531 f
(tin
.extra
.optional_storage_iso
) tin
533 let optional_qualifier_flag f
= fun tin
->
534 f
(tin
.extra
.optional_qualifier_iso
) tin
536 let value_format_flag f
= fun tin
->
537 f
(tin
.extra
.value_format_iso
) tin
540 (* ------------------------------------------------------------------------*)
542 (* ------------------------------------------------------------------------*)
543 let tokenf ia ib
= fun tin
->
544 let pos = Ast_c.info_to_fixpos ib
in
545 let posmck = Ast_cocci.FixPos
(pos, pos) in
546 let finish tin
= tag_mck_pos_mcode ia
posmck ib tin
in
547 match Ast_cocci.get_pos_var ia
with
548 Ast_cocci.MetaPos
(name
,constraints
,per
,keep
,inherited
) ->
549 let mpos = Lib_parsing_c.lin_col_by_pos
[ib
] in
550 let pvalu = Ast_c.MetaPosValList
[mpos] in
551 check_pos_constraints constraints
pvalu
553 (* constraints are satisfied, now see if we are compatible
554 with existing bindings *)
556 let x = Ast_cocci.unwrap_mcode name
in
558 check_add_metavars_binding false keep inherited
(x, pvalu) tin
560 Some binding
-> finish {tin
with binding
= binding
}
565 let tokenf_mck mck ib
= fun tin
->
566 let pos = Ast_c.info_to_fixpos ib
in
567 let posmck = Ast_cocci.FixPos
(pos, pos) in
568 [(tag_mck_pos mck
posmck, ib
), tin
.binding
]
572 (*****************************************************************************)
574 (*****************************************************************************)
575 module MATCH
= Cocci_vs_c.COCCI_VS_C
(XMATCH
)
578 let match_re_node2 dropped_isos a b binding0
=
582 optional_storage_iso
= not
(List.mem
"optional_storage" dropped_isos
);
583 optional_qualifier_iso
= not
(List.mem
"optional_qualifier" dropped_isos
);
584 value_format_iso
= not
(List.mem
"value_format" dropped_isos
);
587 XMATCH.binding0
= binding0
;
590 MATCH.rule_elem_node a b
tin
591 (* take only the tagged-SP, the 'a' *)
592 +> List.map
(fun ((a
,_b
), binding
) -> a
, binding
)
595 let match_re_node a b c d
=
596 Common.profile_code
"Pattern3.match_re_node"
597 (fun () -> match_re_node2 a b c d
)