Release coccinelle-0.2.3rc1
[bpt/coccinelle.git] / engine / pattern_c.ml
CommitLineData
9f8e26f4 1(*
ae4735db 2 * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
9f8e26f4
C
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
5636bb2c
C
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
951c7801
C
45(* Yoann Padioleau
46 *
47 * Copyright (C) 2006, 2007 Ecole des Mines de Nantes
48 *
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.
ae4735db 52 *
951c7801
C
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.
ae4735db 57 *
951c7801
C
58 * This file was part of Coccinelle.
59 *)
34e49164
C
60open Common
61
485bce71 62module Flag_engine = Flag_matcher
34e49164 63(*****************************************************************************)
ae4735db 64(* The functor argument *)
34e49164
C
65(*****************************************************************************)
66
67(* info passed recursively in monad in addition to binding *)
ae4735db 68type xinfo = {
34e49164
C
69 optional_storage_iso : bool;
70 optional_qualifier_iso : bool;
71 value_format_iso : bool;
72}
73
74module XMATCH = struct
75
76 (* ------------------------------------------------------------------------*)
ae4735db 77 (* Combinators history *)
34e49164
C
78 (* ------------------------------------------------------------------------*)
79 (*
ae4735db 80 * version0:
34e49164
C
81 * type ('a, 'b) matcher = 'a -> 'b -> bool
82 *
83 * version1: same but with a global variable holding the current binding
84 * BUT bug
85 * - can have multiple possibilities
86 * - globals sux
ae4735db 87 * - sometimes have to undo, cos if start match, then it binds,
34e49164 88 * and if later it does not match, then must undo the first binds.
ae4735db 89 * ex: when match parameters, can try to match, but then we found far
34e49164
C
90 * later that the last argument of a function does not match
91 * => have to uando the binding !!!
ae4735db 92 * (can handle that too with a global, by saving the
34e49164
C
93 * global, ... but sux)
94 * => better not use global
ae4735db
C
95 *
96 * version2:
34e49164
C
97 * type ('a, 'b) matcher = binding -> 'a -> 'b -> binding list
98 *
99 * Empty list mean failure (let matchfailure = []).
ae4735db 100 * To be able to have pretty code, have to use partial application
34e49164
C
101 * powa, and so the type is in fact
102 *
103 * version3:
104 * type ('a, 'b) matcher = 'a -> 'b -> binding -> binding list
105 *
106 * Then by defining the correct combinators, can have quite pretty code (that
107 * looks like the clean code of version0).
ae4735db 108 *
34e49164 109 * opti: return a lazy list of possible matchs ?
ae4735db 110 *
34e49164
C
111 * version4: type tin = Lib_engine.metavars_binding
112 *)
113
114 (* ------------------------------------------------------------------------*)
ae4735db 115 (* Standard type and operators *)
34e49164
C
116 (* ------------------------------------------------------------------------*)
117
ae4735db 118 type tin = {
34e49164
C
119 extra: xinfo;
120 binding: Lib_engine.metavars_binding;
1be43e12 121 binding0: Lib_engine.metavars_binding; (* inherited bindings *)
34e49164
C
122 }
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 *)
ae4735db 125 type 'x tout = ('x * Lib_engine.metavars_binding) list
34e49164
C
126
127 type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout
128
129 (* was >&&> *)
130 let (>>=) m1 m2 = fun tin ->
131 let xs = m1 tin in
ae4735db 132 let xxs = xs +> List.map (fun ((a,b), binding) ->
1be43e12 133 m2 a b {tin with binding = binding}
34e49164
C
134 ) in
135 List.flatten xxs
136
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.
ae4735db 140 *
34e49164
C
141 * update: still useful now that julia better handle Exp directly via
142 * ctl tricks using positions ?
143 *)
ae4735db 144 let (>|+|>) m1 m2 = fun tin ->
34e49164
C
145(* CHOICE
146 let xs = m1 tin in
147 if null xs
148 then m2 tin
149 else xs
150*)
151 let res1 = m1 tin in
152 let res2 = m2 tin in
153 let list_bindings_already = List.map snd res1 in
ae4735db
C
154 res1 ++
155 (res2 +> List.filter (fun (x, binding) ->
156 not
157 (list_bindings_already +> List.exists (fun already ->
34e49164
C
158 Lib_engine.equal_binding binding already))
159 ))
160
ae4735db
C
161
162
163
34e49164
C
164 let (>||>) m1 m2 = fun tin ->
165(* CHOICE
166 let xs = m1 tin in
167 if null xs
168 then m2 tin
169 else xs
170*)
171 (* opti? use set instead of list *)
9f8e26f4
C
172 let l1 = m1 tin in
173 let l2 = m2 tin in
174 if l2 = [] then l1 else l1 ++ l2 (*a small benefit; avoid a trivial @*)
34e49164
C
175
176
ae4735db 177 let return res = fun tin ->
34e49164
C
178 [res, tin.binding]
179
ae4735db 180 let fail = fun tin ->
34e49164
C
181 []
182
ae4735db 183 let (>&&>) f m = fun tin ->
34e49164
C
184 if f tin
185 then m tin
186 else fail tin
187
188
485bce71 189 let mode = Cocci_vs_c.PatternMode
34e49164
C
190
191 (* ------------------------------------------------------------------------*)
ae4735db 192 (* Exp *)
34e49164 193 (* ------------------------------------------------------------------------*)
ae4735db 194 let cocciExp = fun expf expa node -> fun tin ->
34e49164
C
195
196 let globals = ref [] in
ae4735db 197 let bigf = {
34e49164 198 (* julia's style *)
ae4735db 199 Visitor_c.default_visitor_c with
34e49164
C
200 Visitor_c.kexpr = (fun (k, bigf) expb ->
201 match expf expa expb tin with
202 | [] -> (* failed *) k expb
ae4735db
C
203 | xs ->
204 globals := xs @ !globals;
34e49164
C
205 if not !Flag_engine.disallow_nested_exps then k expb (* CHOICE *)
206 );
207 (* pad's style.
208 * push2 expr globals; k expr
209 * ...
ae4735db 210 * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e)
34e49164 211 * (return false)
ae4735db 212 *
34e49164
C
213 *)
214 }
215 in
216 Visitor_c.vk_node bigf node;
ae4735db 217 !globals +> List.map (fun ((a, _exp), binding) ->
34e49164
C
218 (a, node), binding
219 )
220
221 (* same as cocciExp, but for expressions in an expression, not expressions
222 in a node *)
ae4735db 223 let cocciExpExp = fun expf expa expb -> fun tin ->
34e49164
C
224
225 let globals = ref [] in
ae4735db 226 let bigf = {
34e49164 227 (* julia's style *)
ae4735db 228 Visitor_c.default_visitor_c with
34e49164
C
229 Visitor_c.kexpr = (fun (k, bigf) expb ->
230 match expf expa expb tin with
231 | [] -> (* failed *) k expb
ae4735db
C
232 | xs ->
233 globals := xs @ !globals;
34e49164
C
234 if not !Flag_engine.disallow_nested_exps then k expb (* CHOICE *)
235 );
236 (* pad's style.
237 * push2 expr globals; k expr
238 * ...
ae4735db 239 * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e)
34e49164 240 * (return false)
ae4735db 241 *
34e49164
C
242 *)
243 }
244 in
245 Visitor_c.vk_expr bigf expb;
ae4735db 246 !globals +> List.map (fun ((a, _exp), binding) ->
34e49164
C
247 (a, expb), binding
248 )
249
ae4735db 250 let cocciTy = fun expf expa node -> fun tin ->
34e49164
C
251
252 let globals = ref [] in
ae4735db
C
253 let bigf = {
254 Visitor_c.default_visitor_c with
255 Visitor_c.ktype = (fun (k, bigf) expb ->
34e49164
C
256 match expf expa expb tin with
257 | [] -> (* failed *) k expb
258 | xs -> globals := xs @ !globals);
259
ae4735db 260 }
34e49164
C
261 in
262 Visitor_c.vk_node bigf node;
ae4735db 263 !globals +> List.map (fun ((a, _exp), binding) ->
34e49164
C
264 (a, node), binding
265 )
266
ae4735db 267 let cocciInit = fun expf expa node -> fun tin ->
1be43e12
C
268
269 let globals = ref [] in
ae4735db
C
270 let bigf = {
271 Visitor_c.default_visitor_c with
272 Visitor_c.kini = (fun (k, bigf) expb ->
1be43e12
C
273 match expf expa expb tin with
274 | [] -> (* failed *) k expb
275 | xs -> globals := xs @ !globals);
276
ae4735db 277 }
1be43e12
C
278 in
279 Visitor_c.vk_node bigf node;
ae4735db 280 !globals +> List.map (fun ((a, _exp), binding) ->
1be43e12
C
281 (a, node), binding
282 )
283
34e49164
C
284
285 (* ------------------------------------------------------------------------*)
ae4735db 286 (* Distribute mcode *)
34e49164
C
287 (* ------------------------------------------------------------------------*)
288 let tag_mck_pos mck posmck =
ae4735db 289 match mck with
951c7801 290 | Ast_cocci.PLUS c -> Ast_cocci.PLUS c
ae4735db 291 | Ast_cocci.CONTEXT (pos, xs) ->
b1b2de81 292 assert (pos =*= Ast_cocci.NoPos || pos =*= Ast_cocci.DontCarePos);
34e49164 293 Ast_cocci.CONTEXT (posmck, xs)
ae4735db 294 | Ast_cocci.MINUS (pos, inst, adj, xs) ->
b1b2de81 295 assert (pos =*= Ast_cocci.NoPos || pos =*= Ast_cocci.DontCarePos);
708f4980 296 Ast_cocci.MINUS (posmck, inst, adj, xs)
34e49164 297
ae4735db
C
298
299 let tag_mck_pos_mcode (x,info,mck,pos) posmck stuff = fun tin ->
34e49164 300 [((x, info, tag_mck_pos mck posmck, pos),stuff), tin.binding]
ae4735db 301
34e49164
C
302
303 let distrf (ii_of_x_f) =
ae4735db 304 fun mcode x -> fun tin ->
34e49164
C
305 let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x)
306 in
ae4735db 307 let posmck = Ast_cocci.FixPos (min, max) (* subtil: and not max, min !!*)
34e49164
C
308 in
309 tag_mck_pos_mcode mcode posmck x tin
310
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)
321
322
323 (* ------------------------------------------------------------------------*)
951c7801 324 (* Constraints on metavariable values *)
34e49164 325 (* ------------------------------------------------------------------------*)
951c7801
C
326 let check_idconstraint matcher c id = fun f tin ->
327 if matcher c id then
328 (* success *)
329 f () tin
330 else
331 (* failure *)
332 fail tin
333
334 let check_constraints_ne matcher constraints exp = fun f tin ->
34e49164
C
335 let rec loop = function
336 [] -> f () tin (* success *)
337 | c::cs ->
338 match matcher c exp tin with
339 [] (* failure *) -> loop cs
340 | _ (* success *) -> fail tin in
341 loop constraints
342
343 let check_pos_constraints constraints pvalu f tin =
951c7801 344 check_constraints_ne
34e49164
C
345 (fun c exp tin ->
346 let success = [[]] in
347 let failure = [] in
1be43e12
C
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
34e49164 351 Some valu' ->
978fd7e5 352 if Cocci_vs_c.equal_inh_metavarval exp valu'
34e49164
C
353 then success else failure
354 | None ->
355 (* if the variable is not there, it puts no constraints *)
356 (* not sure this is still useful *)
357 failure))
358 constraints pvalu f tin
359
360 (* ------------------------------------------------------------------------*)
ae4735db 361 (* Environment *)
34e49164
C
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
ae4735db 365 *
34e49164
C
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.
369 *)
370 let check_add_metavars_binding strip _keep inherited = fun (k, valu) tin ->
1be43e12
C
371 if inherited
372 then
373 match Common.optionise (fun () -> tin.binding0 +> List.assoc k) with
374 | Some (valu') ->
978fd7e5 375 if Cocci_vs_c.equal_inh_metavarval valu valu'
1be43e12
C
376 then Some tin.binding
377 else None
378 | None -> None
379 else
380 match Common.optionise (fun () -> tin.binding +> List.assoc k) with
381 | Some (valu') ->
485bce71 382 if Cocci_vs_c.equal_metavarval valu valu'
1be43e12
C
383 then Some tin.binding
384 else None
ae4735db 385
1be43e12 386 | None ->
5636bb2c
C
387 let success valu' =
388 Some (tin.binding +> Common.insert_assoc (k, valu')) in
389 (match valu with
390 Ast_c.MetaIdVal (a,c) ->
391 (* c is a negated constraint *)
392 let rec loop = function
393 [] -> success(Ast_c.MetaIdVal(a,[]))
394 | c::cs ->
395 let tmp =
396 Common.optionise
397 (fun () -> tin.binding0 +> List.assoc c) in
398 (match tmp with
399 Some (Ast_c.MetaIdVal(v,_)) ->
400 if a =$= 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
405 loop c
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 *)
416 let stripped =
417 if strip
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,[]))
423 | c::cs ->
424 let tmp =
425 Common.optionise
426 (fun () -> tin.binding0 +> List.assoc c) in
427 (match tmp with
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
434 doesn't exist *)
435 | None -> None) in
436 loop c
437 | Ast_c.MetaExprListVal a ->
438 success
439 (Ast_c.MetaExprListVal
440 (if strip
441 then Lib_parsing_c.al_arguments a
442 else Lib_parsing_c.semi_al_arguments a))
443
444 | Ast_c.MetaStmtVal a ->
445 success
446 (Ast_c.MetaStmtVal
447 (if strip
448 then Lib_parsing_c.al_statement a
449 else Lib_parsing_c.semi_al_statement a))
450 | Ast_c.MetaTypeVal a ->
451 success
452 (Ast_c.MetaTypeVal
453 (if strip
454 then Lib_parsing_c.al_type a
455 else Lib_parsing_c.semi_al_type a))
456
457 | Ast_c.MetaInitVal a ->
458 success
459 (Ast_c.MetaInitVal
460 (if strip
461 then Lib_parsing_c.al_init a
462 else Lib_parsing_c.semi_al_init a))
463
464 | Ast_c.MetaListlenVal a -> success(Ast_c.MetaListlenVal a)
465
466 | Ast_c.MetaParamVal a ->
467 success
468 (Ast_c.MetaParamVal
469 (if strip
470 then Lib_parsing_c.al_param a
471 else Lib_parsing_c.semi_al_param a))
472 | Ast_c.MetaParamListVal a ->
473 success
474 (Ast_c.MetaParamListVal
475 (if strip
476 then Lib_parsing_c.al_params a
477 else Lib_parsing_c.semi_al_params a))
478
479 | Ast_c.MetaPosVal (pos1,pos2) ->
480 success(Ast_c.MetaPosVal (pos1,pos2))
481 | Ast_c.MetaPosValList l -> success (Ast_c.MetaPosValList l))
34e49164
C
482
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
486 | Some binding ->
1be43e12 487 let new_tin = {tin with binding = binding} in
34e49164
C
488 (match Ast_cocci.get_pos_var k with
489 Ast_cocci.MetaPos(name,constraints,per,keep,inherited) ->
490 let pvalu =
485bce71
C
491 let (file,current_element,min,max) = get_max_min() in
492 Ast_c.MetaPosValList[(file,current_element,min,max)] in
34e49164
C
493 (* check constraints. success means that there is a match with
494 one of the constraints, which will ultimately result in
495 failure. *)
496 check_pos_constraints constraints pvalu
497 (function () ->
498 (* constraints are satisfied, now see if we are compatible
499 with existing bindings *)
500 function new_tin ->
501 let x = Ast_cocci.unwrap_mcode name in
502 (match
503 check_add_metavars_binding false keep inherited (x, pvalu)
504 new_tin with
505 | Some binding ->
1be43e12 506 f () {new_tin with binding = binding}
34e49164
C
507 | None -> fail tin))
508 new_tin
509 | Ast_cocci.NoMetaPos -> f () new_tin)
510 | None -> fail tin
511
512 (* ------------------------------------------------------------------------*)
ae4735db 513 (* Environment, allbounds *)
34e49164
C
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. *)
522
523 let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin ->
ae4735db 524 l +> List.for_all (fun inhvar ->
1be43e12 525 match Common.optionise (fun () -> tin.binding0 +> List.assoc inhvar) with
34e49164
C
526 | Some _ -> true
527 | None -> false
528 )
529
ae4735db 530 let optional_storage_flag f = fun tin ->
34e49164
C
531 f (tin.extra.optional_storage_iso) tin
532
ae4735db 533 let optional_qualifier_flag f = fun tin ->
34e49164
C
534 f (tin.extra.optional_qualifier_iso) tin
535
ae4735db 536 let value_format_flag f = fun tin ->
34e49164
C
537 f (tin.extra.value_format_iso) tin
538
539
540 (* ------------------------------------------------------------------------*)
ae4735db 541 (* Tokens *)
34e49164
C
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
552 (function () ->
553 (* constraints are satisfied, now see if we are compatible
554 with existing bindings *)
555 function new_tin ->
556 let x = Ast_cocci.unwrap_mcode name in
557 (match
558 check_add_metavars_binding false keep inherited (x, pvalu) tin
559 with
1be43e12 560 Some binding -> finish {tin with binding = binding}
34e49164
C
561 | None -> fail tin))
562 tin
563 | _ -> finish tin
564
ae4735db 565 let tokenf_mck mck ib = fun tin ->
34e49164
C
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]
ae4735db 569
34e49164
C
570end
571
572(*****************************************************************************)
ae4735db 573(* Entry point *)
34e49164 574(*****************************************************************************)
485bce71 575module MATCH = Cocci_vs_c.COCCI_VS_C (XMATCH)
34e49164
C
576
577
ae4735db 578let match_re_node2 dropped_isos a b binding0 =
34e49164 579
ae4735db 580 let tin = {
34e49164
C
581 XMATCH.extra = {
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);
585 };
1be43e12
C
586 XMATCH.binding = [];
587 XMATCH.binding0 = binding0;
34e49164
C
588 } in
589
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)
593
594
ae4735db
C
595let match_re_node a b c d =
596 Common.profile_code "Pattern3.match_re_node"
34e49164 597 (fun () -> match_re_node2 a b c d)