Commit | Line | Data |
---|---|---|
485bce71 C |
1 | (* Copyright (C) 2006, 2007 Yoann Padioleau |
2 | * | |
3 | * This program is free software; you can redistribute it and/or | |
4 | * modify it under the terms of the GNU General Public License (GPL) | |
5 | * version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * file license.txt for more details. | |
11 | * | |
12 | * This file was part of Coccinelle. | |
13 | *) | |
34e49164 C |
14 | open Common |
15 | ||
16 | module F = Control_flow_c | |
17 | ||
485bce71 | 18 | module Flag = Flag_matcher |
34e49164 C |
19 | (*****************************************************************************) |
20 | (* The functor argument *) | |
21 | (*****************************************************************************) | |
22 | ||
23 | (* info passed recursively in monad in addition to binding *) | |
24 | type xinfo = { | |
25 | optional_storage_iso : bool; | |
26 | optional_qualifier_iso : bool; | |
27 | value_format_iso : bool; | |
28 | current_rule_name : string; (* used for errors *) | |
29 | } | |
30 | ||
31 | module XTRANS = struct | |
32 | ||
33 | (* ------------------------------------------------------------------------*) | |
34 | (* Combinators history *) | |
35 | (* ------------------------------------------------------------------------*) | |
36 | (* | |
37 | * version0: | |
38 | * type ('a, 'b) transformer = | |
39 | * 'a -> 'b -> Lib_engine.metavars_binding -> 'b | |
40 | * exception NoMatch | |
41 | * | |
42 | * version1: | |
43 | * type ('a, 'b) transformer = | |
44 | * 'a -> 'b -> Lib_engine.metavars_binding -> 'b option | |
45 | * use an exception monad | |
46 | * | |
47 | * version2: | |
48 | * type tin = Lib_engine.metavars_binding | |
49 | *) | |
50 | ||
51 | (* ------------------------------------------------------------------------*) | |
52 | (* Standard type and operators *) | |
53 | (* ------------------------------------------------------------------------*) | |
54 | ||
55 | type tin = { | |
56 | extra: xinfo; | |
57 | binding: Lib_engine.metavars_binding; | |
1be43e12 | 58 | binding0: Lib_engine.metavars_binding; (* inherited variable *) |
34e49164 C |
59 | } |
60 | type 'x tout = 'x option | |
61 | ||
62 | type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout | |
63 | ||
64 | let (>>=) m f = fun tin -> | |
65 | match m tin with | |
66 | | None -> None | |
67 | | Some (a,b) -> f a b tin | |
68 | ||
69 | let return = fun x -> fun tin -> | |
70 | Some x | |
71 | ||
72 | (* can have fail in transform now that the process is deterministic ? *) | |
73 | let fail = fun tin -> | |
74 | None | |
75 | ||
76 | let (>||>) m1 m2 = fun tin -> | |
77 | match m1 tin with | |
78 | | None -> m2 tin | |
79 | | Some x -> Some x (* stop as soon as have found something *) | |
80 | ||
81 | let (>|+|>) m1 m2 = m1 >||> m2 | |
82 | ||
83 | let (>&&>) f m = fun tin -> | |
84 | if f tin then m tin else fail tin | |
85 | ||
86 | let optional_storage_flag f = fun tin -> | |
87 | f (tin.extra.optional_storage_iso) tin | |
88 | ||
89 | let optional_qualifier_flag f = fun tin -> | |
90 | f (tin.extra.optional_qualifier_iso) tin | |
91 | ||
92 | let value_format_flag f = fun tin -> | |
93 | f (tin.extra.value_format_iso) tin | |
94 | ||
485bce71 | 95 | let mode = Cocci_vs_c.TransformMode |
34e49164 C |
96 | |
97 | (* ------------------------------------------------------------------------*) | |
98 | (* Exp *) | |
99 | (* ------------------------------------------------------------------------*) | |
100 | let cocciExp = fun expf expa node -> fun tin -> | |
101 | ||
102 | let bigf = { | |
103 | Visitor_c.default_visitor_c_s with | |
104 | Visitor_c.kexpr_s = (fun (k, bigf) expb -> | |
105 | match expf expa expb tin with | |
106 | | None -> (* failed *) k expb | |
107 | | Some (x, expb) -> expb); | |
108 | } | |
109 | in | |
110 | Some (expa, Visitor_c.vk_node_s bigf node) | |
111 | ||
112 | ||
113 | (* same as cocciExp, but for expressions in an expression, not expressions | |
114 | in a node *) | |
115 | let cocciExpExp = fun expf expa expb -> fun tin -> | |
116 | ||
117 | let bigf = { | |
118 | Visitor_c.default_visitor_c_s with | |
119 | Visitor_c.kexpr_s = (fun (k, bigf) expb -> | |
120 | match expf expa expb tin with | |
121 | | None -> (* failed *) k expb | |
122 | | Some (x, expb) -> expb); | |
123 | } | |
124 | in | |
125 | Some (expa, Visitor_c.vk_expr_s bigf expb) | |
126 | ||
127 | ||
128 | let cocciTy = fun expf expa node -> fun tin -> | |
129 | ||
130 | let bigf = { | |
131 | Visitor_c.default_visitor_c_s with | |
132 | Visitor_c.ktype_s = (fun (k, bigf) expb -> | |
133 | match expf expa expb tin with | |
134 | | None -> (* failed *) k expb | |
135 | | Some (x, expb) -> expb); | |
136 | } | |
137 | in | |
138 | Some (expa, Visitor_c.vk_node_s bigf node) | |
139 | ||
1be43e12 C |
140 | let cocciInit = fun expf expa node -> fun tin -> |
141 | ||
142 | let bigf = { | |
143 | Visitor_c.default_visitor_c_s with | |
144 | Visitor_c.kini_s = (fun (k, bigf) expb -> | |
145 | match expf expa expb tin with | |
146 | | None -> (* failed *) k expb | |
147 | | Some (x, expb) -> expb); | |
148 | } | |
149 | in | |
150 | Some (expa, Visitor_c.vk_node_s bigf node) | |
151 | ||
34e49164 C |
152 | |
153 | (* ------------------------------------------------------------------------*) | |
154 | (* Tokens *) | |
155 | (* ------------------------------------------------------------------------*) | |
156 | let check_pos info mck pos = | |
157 | match mck with | |
158 | | Ast_cocci.PLUS -> raise Impossible | |
159 | | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) | |
160 | | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_) -> | |
161 | pos <= i2 && pos >= i1 | |
162 | | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) | |
163 | | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_) -> | |
164 | true | |
165 | | _ -> | |
166 | match info with | |
167 | Some info -> | |
168 | failwith | |
169 | (Printf.sprintf | |
170 | "wierd: dont have position info for the mcodekind in line %d column %d" | |
171 | info.Ast_cocci.line info.Ast_cocci.column) | |
172 | | None -> | |
173 | failwith "wierd: dont have position info for the mcodekind" | |
174 | ||
175 | ||
176 | let tag_with_mck mck ib = fun tin -> | |
177 | ||
178 | let cocciinforef = ib.Ast_c.cocci_tag in | |
179 | let (oldmcode, oldenv) = !cocciinforef in | |
180 | ||
181 | let mck = | |
485bce71 | 182 | (* coccionly: |
34e49164 C |
183 | if !Flag_parsing_cocci.sgrep_mode |
184 | then Sgrep.process_sgrep ib mck | |
485bce71 C |
185 | else |
186 | *) | |
187 | mck | |
34e49164 C |
188 | in |
189 | (match mck, Ast_c.pinfo_of_info ib with | |
190 | | _, Ast_c.AbstractLineTok _ -> raise Impossible | |
191 | | Ast_cocci.MINUS(_), Ast_c.ExpandedTok _ -> | |
192 | failwith ("try to delete an expanded token: " ^ (Ast_c.str_of_info ib)) | |
193 | | _ -> () | |
194 | ); | |
195 | ||
196 | match (oldmcode,mck) with | |
197 | | (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING), _) | |
198 | | (_, Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING)) | |
199 | -> | |
200 | cocciinforef := (mck, tin.binding); | |
201 | ib | |
202 | ||
203 | | _ -> | |
204 | if (oldmcode, oldenv) = (mck, tin.binding) | |
205 | then begin | |
206 | if !Flag.show_misc | |
207 | then pr2 "already tagged but with same mcode, so safe"; | |
208 | ib | |
209 | end | |
210 | else | |
485bce71 | 211 | (* coccionly: |
34e49164 C |
212 | if !Flag.sgrep_mode2 |
213 | then ib (* safe *) | |
214 | else | |
485bce71 C |
215 | *) |
216 | begin | |
217 | (* coccionly: | |
34e49164 C |
218 | Format.set_formatter_out_channel stderr; |
219 | Common.pr2 "SP mcode "; | |
220 | Pretty_print_cocci.print_mcodekind oldmcode; | |
221 | Format.print_newline(); | |
222 | Common.pr2 "C code mcode "; | |
223 | Pretty_print_cocci.print_mcodekind mck; | |
224 | Format.print_newline(); | |
225 | Format.print_flush(); | |
485bce71 | 226 | *) |
34e49164 C |
227 | failwith |
228 | (Common.sprintf "%s: already tagged token:\n%s" | |
229 | tin.extra.current_rule_name | |
230 | (Common.error_message (Ast_c.file_of_info ib) | |
231 | (Ast_c.str_of_info ib, Ast_c.opos_of_info ib))) | |
232 | end | |
233 | ||
234 | let tokenf ia ib = fun tin -> | |
235 | let (_,i,mck,_) = ia in | |
236 | let pos = Ast_c.info_to_fixpos ib in | |
237 | if check_pos (Some i) mck pos | |
238 | then return (ia, tag_with_mck mck ib tin) tin | |
239 | else fail tin | |
240 | ||
241 | let tokenf_mck mck ib = fun tin -> | |
242 | let pos = Ast_c.info_to_fixpos ib in | |
243 | if check_pos None mck pos | |
244 | then return (mck, tag_with_mck mck ib tin) tin | |
245 | else fail tin | |
246 | ||
247 | ||
248 | (* ------------------------------------------------------------------------*) | |
249 | (* Distribute mcode *) | |
250 | (* ------------------------------------------------------------------------*) | |
251 | ||
252 | (* When in the SP we attach something to a metavariable, or delete it, as in | |
253 | * - S | |
254 | * + foo(); | |
255 | * we have to minusize all the token that compose S in the C code, and | |
256 | * attach the 'foo();' to the right token, the one at the very right. | |
257 | *) | |
258 | ||
259 | type 'a distributer = | |
260 | (Ast_c.info -> Ast_c.info) * (* what to do on left *) | |
261 | (Ast_c.info -> Ast_c.info) * (* what to do on middle *) | |
262 | (Ast_c.info -> Ast_c.info) * (* what to do on right *) | |
263 | (Ast_c.info -> Ast_c.info) -> (* what to do on both *) | |
264 | 'a -> 'a | |
265 | ||
266 | let distribute_mck mcodekind distributef expr tin = | |
267 | match mcodekind with | |
268 | | Ast_cocci.MINUS (pos,any_xxs) -> | |
269 | distributef ( | |
270 | (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,any_xxs)) ib tin), | |
271 | (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,[])) ib tin), | |
272 | (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,[])) ib tin), | |
273 | (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,any_xxs)) ib tin) | |
274 | ) expr | |
275 | | Ast_cocci.CONTEXT (pos,any_befaft) -> | |
276 | (match any_befaft with | |
277 | | Ast_cocci.NOTHING -> expr | |
278 | ||
279 | | Ast_cocci.BEFORE xxs -> | |
280 | distributef ( | |
281 | (fun ib -> tag_with_mck | |
282 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin), | |
283 | (fun x -> x), | |
284 | (fun x -> x), | |
285 | (fun ib -> tag_with_mck | |
286 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin) | |
287 | ) expr | |
288 | | Ast_cocci.AFTER xxs -> | |
289 | distributef ( | |
290 | (fun x -> x), | |
291 | (fun x -> x), | |
292 | (fun ib -> tag_with_mck | |
293 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER xxs)) ib tin), | |
294 | (fun ib -> tag_with_mck | |
295 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER xxs)) ib tin) | |
296 | ) expr | |
297 | ||
298 | | Ast_cocci.BEFOREAFTER (xxs, yys) -> | |
299 | distributef ( | |
300 | (fun ib -> tag_with_mck | |
301 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin), | |
302 | (fun x -> x), | |
303 | (fun ib -> tag_with_mck | |
304 | (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER yys)) ib tin), | |
305 | (fun ib -> tag_with_mck | |
306 | (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFOREAFTER (xxs,yys))) | |
307 | ib tin) | |
308 | ) expr | |
309 | ||
310 | ) | |
311 | | Ast_cocci.PLUS -> raise Impossible | |
312 | ||
313 | ||
314 | (* use new strategy, collect ii, sort, recollect and tag *) | |
315 | ||
316 | let mk_bigf (maxpos, minpos) (lop,mop,rop,bop) = | |
317 | let bigf = { | |
318 | Visitor_c.default_visitor_c_s with | |
319 | Visitor_c.kinfo_s = (fun (k,bigf) i -> | |
320 | let pos = Ast_c.info_to_fixpos i in | |
321 | match () with | |
322 | | _ when Ast_cocci.equal_pos pos maxpos && | |
323 | Ast_cocci.equal_pos pos minpos -> bop i | |
324 | | _ when Ast_cocci.equal_pos pos maxpos -> rop i | |
325 | | _ when Ast_cocci.equal_pos pos minpos -> lop i | |
326 | | _ -> mop i | |
327 | ) | |
328 | } in | |
329 | bigf | |
330 | ||
331 | let distribute_mck_expr (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
332 | Visitor_c.vk_expr_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
333 | ||
334 | let distribute_mck_args (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
335 | Visitor_c.vk_args_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
336 | ||
337 | let distribute_mck_type (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
338 | Visitor_c.vk_type_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
339 | ||
340 | let distribute_mck_ini (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
341 | Visitor_c.vk_ini_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
342 | ||
343 | let distribute_mck_param (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> | |
344 | Visitor_c.vk_param_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x | |
345 | ||
346 | let distribute_mck_params (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> | |
347 | Visitor_c.vk_params_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
348 | x | |
349 | ||
350 | let distribute_mck_node (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> | |
351 | Visitor_c.vk_node_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
352 | x | |
353 | ||
354 | let distribute_mck_struct_fields (maxpos, minpos) = | |
355 | fun (lop,mop,rop,bop) ->fun x -> | |
356 | Visitor_c.vk_struct_fields_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
357 | x | |
358 | ||
359 | let distribute_mck_cst (maxpos, minpos) = | |
360 | fun (lop,mop,rop,bop) ->fun x -> | |
361 | Visitor_c.vk_cst_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
362 | x | |
363 | ||
364 | ||
365 | let distribute_mck_define_params (maxpos, minpos) = fun (lop,mop,rop,bop) -> | |
366 | fun x -> | |
367 | Visitor_c.vk_define_params_splitted_s | |
368 | (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) | |
369 | x | |
370 | ||
371 | let get_pos mck = | |
372 | match mck with | |
373 | | Ast_cocci.PLUS -> raise Impossible | |
374 | | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) | |
375 | | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_) -> | |
376 | Ast_cocci.FixPos (i1,i2) | |
377 | | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) | |
378 | | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_) -> | |
379 | Ast_cocci.DontCarePos | |
380 | | _ -> failwith "wierd: dont have position info for the mcodekind" | |
381 | ||
382 | let distrf (ii_of_x_f, distribute_mck_x_f) = | |
383 | fun ia x -> fun tin -> | |
384 | let mck = Ast_cocci.get_mcodekind ia in | |
385 | let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x) | |
386 | in | |
387 | if | |
388 | (* bug: check_pos mck max && check_pos mck min | |
389 | * | |
390 | * if do that then if have - f(...); and in C f(1,2); then we | |
391 | * would get a "already tagged" because the '...' would sucess in | |
392 | * transformaing both '1' and '1,2'. So being in the range is not | |
393 | * enough. We must be equal exactly to the range! | |
394 | *) | |
395 | (match get_pos mck with | |
396 | | Ast_cocci.DontCarePos -> true | |
397 | | Ast_cocci.FixPos (i1, i2) -> | |
398 | i1 = min && i2 = max | |
399 | | _ -> raise Impossible | |
400 | ) | |
401 | ||
402 | then | |
403 | return ( | |
404 | ia, | |
405 | distribute_mck mck (distribute_mck_x_f (max,min)) x tin | |
406 | ) tin | |
407 | else fail tin | |
408 | ||
409 | ||
410 | let distrf_e = distrf (Lib_parsing_c.ii_of_expr, distribute_mck_expr) | |
411 | let distrf_args = distrf (Lib_parsing_c.ii_of_args, distribute_mck_args) | |
412 | let distrf_type = distrf (Lib_parsing_c.ii_of_type, distribute_mck_type) | |
413 | let distrf_param = distrf (Lib_parsing_c.ii_of_param, distribute_mck_param) | |
414 | let distrf_params = distrf (Lib_parsing_c.ii_of_params,distribute_mck_params) | |
415 | let distrf_ini = distrf (Lib_parsing_c.ii_of_ini,distribute_mck_ini) | |
416 | let distrf_node = distrf (Lib_parsing_c.ii_of_node,distribute_mck_node) | |
417 | let distrf_struct_fields = | |
418 | distrf (Lib_parsing_c.ii_of_struct_fields, distribute_mck_struct_fields) | |
419 | let distrf_cst = | |
420 | distrf (Lib_parsing_c.ii_of_cst, distribute_mck_cst) | |
421 | let distrf_define_params = | |
422 | distrf (Lib_parsing_c.ii_of_define_params,distribute_mck_define_params) | |
423 | ||
424 | ||
425 | (* ------------------------------------------------------------------------*) | |
426 | (* Environment *) | |
427 | (* ------------------------------------------------------------------------*) | |
428 | let meta_name_to_str (s1, s2) = | |
429 | s1 ^ "." ^ s2 | |
430 | ||
431 | let envf keep _inherited = fun (s, value, _) f tin -> | |
432 | let s = Ast_cocci.unwrap_mcode s in | |
433 | let v = | |
434 | if keep = Type_cocci.Saved | |
435 | then ( | |
436 | try Some (List.assoc s tin.binding) | |
437 | with Not_found -> | |
438 | pr2(sprintf | |
439 | "Don't find value for metavariable %s in the environment" | |
440 | (meta_name_to_str s)); | |
441 | None) | |
442 | else | |
443 | (* not raise Impossible! *) | |
444 | Some (value) | |
445 | in | |
446 | match v with | |
447 | | None -> fail tin | |
448 | | Some (value') -> | |
449 | ||
450 | (* Ex: in cocci_vs_c someone wants to add a binding. Here in | |
451 | * transformation3 the value for this var may be already in the | |
452 | * env, because for instance its value were fixed in a previous | |
453 | * SmPL rule. So here we want to check that this is the same value. | |
454 | * If forget to do the check, what can happen ? Because of Exp | |
455 | * and other disjunctive feature of cocci_vs_c (>||>), we | |
456 | * may accept a match at a wrong position. Maybe later this | |
457 | * will be detected via the pos system on tokens, but maybe | |
458 | * not. So safer to keep the check. | |
459 | *) | |
460 | ||
461 | (*f () tin*) | |
485bce71 | 462 | if Cocci_vs_c.equal_metavarval value value' |
34e49164 C |
463 | then f () tin |
464 | else fail tin | |
465 | ||
466 | ||
467 | let check_constraints matcher constraints exp = fun f tin -> f () tin | |
468 | ||
469 | (* ------------------------------------------------------------------------*) | |
470 | (* Environment, allbounds *) | |
471 | (* ------------------------------------------------------------------------*) | |
472 | let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin -> | |
473 | true (* in transform we don't care ? *) | |
474 | ||
475 | end | |
476 | ||
477 | (*****************************************************************************) | |
478 | (* Entry point *) | |
479 | (*****************************************************************************) | |
485bce71 | 480 | module TRANS = Cocci_vs_c.COCCI_VS_C (XTRANS) |
34e49164 C |
481 | |
482 | ||
483 | let transform_re_node a b tin = | |
484 | match TRANS.rule_elem_node a b tin with | |
485 | | None -> raise Impossible | |
486 | | Some (_sp, b') -> b' | |
487 | ||
34e49164 | 488 | let (transform2: string (* rule name *) -> string list (* dropped_isos *) -> |
1be43e12 | 489 | Lib_engine.metavars_binding (* inherited bindings *) -> |
34e49164 | 490 | Lib_engine.transformation_info -> F.cflow -> F.cflow) = |
1be43e12 | 491 | fun rule_name dropped_isos binding0 xs cflow -> |
34e49164 C |
492 | |
493 | let extra = { | |
494 | optional_storage_iso = not(List.mem "optional_storage" dropped_isos); | |
495 | optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos); | |
496 | value_format_iso = not(List.mem "value_format" dropped_isos); | |
497 | current_rule_name = rule_name; | |
498 | } in | |
499 | ||
500 | (* find the node, transform, update the node, and iter for all elements *) | |
501 | ||
502 | xs +> List.fold_left (fun acc (nodei, binding, rule_elem) -> | |
503 | (* subtil: not cflow#nodes but acc#nodes *) | |
504 | let node = acc#nodes#assoc nodei in | |
505 | ||
506 | if !Flag.show_misc | |
507 | then pr2 "transform one node"; | |
508 | ||
509 | let tin = { | |
510 | XTRANS.extra = extra; | |
1be43e12 C |
511 | XTRANS.binding = binding0@binding; |
512 | XTRANS.binding0 = []; (* not used - everything constant for trans *) | |
34e49164 C |
513 | } in |
514 | ||
515 | let node' = transform_re_node rule_elem node tin in | |
516 | ||
517 | (* assert that have done something. But with metaruleElem sometimes | |
518 | dont modify fake nodes. So special case before on Fake nodes. *) | |
519 | (match F.unwrap node with | |
520 | | F.Enter | F.Exit | F.ErrorExit | |
521 | | F.EndStatement _ | F.CaseNode _ | |
522 | | F.Fake | |
523 | | F.TrueNode | F.FalseNode | F.AfterNode | F.FallThroughNode | |
524 | -> () | |
525 | | _ -> () (* assert (not (node =*= node')); *) | |
526 | ); | |
527 | ||
528 | (* useless, we dont go back from flow to ast now *) | |
529 | (* let node' = lastfix_comma_struct node' in *) | |
530 | ||
531 | acc#replace_node (nodei, node'); | |
532 | acc | |
533 | ) cflow | |
534 | ||
535 | ||
536 | ||
1be43e12 | 537 | let transform a b c d e = |
34e49164 | 538 | Common.profile_code "Transformation3.transform" |
1be43e12 | 539 | (fun () -> transform2 a b c d e) |