permit multiline comments and strings in macros
[bpt/coccinelle.git] / parsing_c / lib_parsing_c.ml
CommitLineData
0708f913 1(* Yoann Padioleau
ae4735db
C
2 *
3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
0708f913 4 * Copyright (C) 2007, 2008, 2009 Ecole des Mines de Nantes
34e49164
C
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License (GPL)
8 * version 2 as published by the Free Software Foundation.
ae4735db 9 *
34e49164
C
10 * This program 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 * file license.txt for more details.
14 *)
15open Common
16
708f4980
C
17(*****************************************************************************)
18(* Wrappers *)
19(*****************************************************************************)
20let pr2, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing
21
34e49164
C
22(*****************************************************************************)
23(* Abstract line *)
24(*****************************************************************************)
25
26(* todo?: al_expr doit enlever les infos de type ? et doit remettre en
ae4735db 27 * emptyAnnot ?
978fd7e5
C
28
29No! Keeping the type information is important to ensuring that variables
30of different type and declared in different places do not seem to match
31each other. On the other hand, we don't want to keep around the
32information about whether the expression is a test expression, because a
33term that is a test expression should match one that is not. The test
34information is only useful for matching to the CTL.
35
34e49164
C
36 *)
37
38(* drop all info information *)
39
ae4735db 40let strip_info_visitor _ =
978fd7e5
C
41 let drop_test ty =
42 let (ty,_) = !ty in
43 ref (ty,Ast_c.NotTest) in
44
34e49164
C
45 { Visitor_c.default_visitor_c_s with
46 Visitor_c.kinfo_s =
47 (* traversal should be deterministic... *)
ae4735db 48 (let ctr = ref 0 in
34e49164 49 (function (k,_) ->
b1b2de81 50 function i -> ctr := !ctr + 1; Ast_c.al_info_cpp !ctr i));
34e49164 51
ae4735db 52 Visitor_c.kexpr_s = (fun (k,_) e ->
708f4980 53 let (e', ty), ii' = k e in
978fd7e5 54 (e', drop_test ty), ii' (* keep type - jll *)
34e49164
C
55 );
56
57(*
ae4735db 58 Visitor_c.ktype_s = (fun (k,_) ft ->
34e49164
C
59 let ft' = k ft in
60 match Ast_c.unwrap_typeC ft' with
ae4735db 61 | Ast_c.TypeName (s,_typ) ->
34e49164
C
62 Ast_c.TypeName (s, Ast_c.noTypedefDef()) +> Ast_c.rewrap_typeC ft'
63 | _ -> ft'
64
65 );
66*)
ae4735db 67
34e49164
C
68 }
69
70let al_expr x = Visitor_c.vk_expr_s (strip_info_visitor()) x
413ffc02
C
71let al_declaration x = Visitor_c.vk_decl_s (strip_info_visitor()) x
72let al_field x = Visitor_c.vk_struct_field_s (strip_info_visitor()) x
34e49164
C
73let al_statement x = Visitor_c.vk_statement_s (strip_info_visitor()) x
74let al_type x = Visitor_c.vk_type_s (strip_info_visitor()) x
113803cf 75let al_init x = Visitor_c.vk_ini_s (strip_info_visitor()) x
8f657093 76let al_inits x = Visitor_c.vk_inis_s (strip_info_visitor()) x
34e49164
C
77let al_param x = Visitor_c.vk_param_s (strip_info_visitor()) x
78let al_params x = Visitor_c.vk_params_s (strip_info_visitor()) x
79let al_arguments x = Visitor_c.vk_arguments_s (strip_info_visitor()) x
91eba41f 80let al_fields x = Visitor_c.vk_struct_fields_s (strip_info_visitor()) x
c491d8ee 81let al_name x = Visitor_c.vk_name_s (strip_info_visitor()) x
91eba41f
C
82
83let al_node x = Visitor_c.vk_node_s (strip_info_visitor()) x
34e49164
C
84
85let al_program x = List.map (Visitor_c.vk_toplevel_s (strip_info_visitor())) x
91eba41f
C
86let al_ii x = Visitor_c.vk_ii_s (strip_info_visitor()) x
87
88
89
90
978fd7e5
C
91let strip_inh_info_visitor _ = (* for inherited metavariables *)
92 let drop_test_lv ty =
93 let (ty,_) = !ty in
94 let ty =
95 match ty with
96 None -> None
97 | Some (ty,_) -> Some (ty,Ast_c.NotLocalVar) in
98 ref (ty,Ast_c.NotTest) in
99
100 { Visitor_c.default_visitor_c_s with
101 Visitor_c.kinfo_s =
102 (* traversal should be deterministic... *)
ae4735db 103 (let ctr = ref 0 in
978fd7e5
C
104 (function (k,_) ->
105 function i -> ctr := !ctr + 1; Ast_c.al_info_cpp !ctr i));
106
ae4735db 107 Visitor_c.kexpr_s = (fun (k,_) e ->
978fd7e5
C
108 let (e', ty), ii' = k e in
109 (e', drop_test_lv ty), ii' (* keep type - jll *)
110 );
111
112(*
ae4735db 113 Visitor_c.ktype_s = (fun (k,_) ft ->
978fd7e5
C
114 let ft' = k ft in
115 match Ast_c.unwrap_typeC ft' with
ae4735db 116 | Ast_c.TypeName (s,_typ) ->
978fd7e5
C
117 Ast_c.TypeName (s, Ast_c.noTypedefDef()) +> Ast_c.rewrap_typeC ft'
118 | _ -> ft'
119
120 );
121*)
ae4735db 122
978fd7e5
C
123 }
124
125let al_inh_expr x = Visitor_c.vk_expr_s (strip_inh_info_visitor()) x
413ffc02 126let al_inh_declaration x = Visitor_c.vk_decl_s (strip_inh_info_visitor()) x
190f1acf
C
127let al_inh_field x = Visitor_c.vk_struct_field_s (strip_inh_info_visitor()) x
128let al_inh_field_list x =
129 Visitor_c.vk_struct_fields_s (strip_inh_info_visitor()) x
978fd7e5
C
130let al_inh_statement x = Visitor_c.vk_statement_s (strip_inh_info_visitor()) x
131let al_inh_type x = Visitor_c.vk_type_s (strip_inh_info_visitor()) x
132let al_inh_init x = Visitor_c.vk_ini_s (strip_inh_info_visitor()) x
8f657093 133let al_inh_inits x = Visitor_c.vk_inis_s (strip_inh_info_visitor()) x
978fd7e5
C
134let al_inh_arguments x = Visitor_c.vk_arguments_s (strip_inh_info_visitor()) x
135
91eba41f 136
34e49164
C
137
138let semi_strip_info_visitor = (* keep position information *)
978fd7e5
C
139 let drop_test ty =
140 let (ty,_) = !ty in
141 ref (ty,Ast_c.NotTest) in
142
34e49164 143 { Visitor_c.default_visitor_c_s with
b1b2de81 144 Visitor_c.kinfo_s = (fun (k,_) i -> Ast_c.semi_al_info_cpp i);
34e49164 145
ae4735db 146 Visitor_c.kexpr_s = (fun (k,_) e ->
34e49164 147 let (e', ty),ii' = k e in
978fd7e5 148 (e', drop_test ty), ii' (* keep type - jll *)
34e49164 149 );
ae4735db 150
34e49164
C
151 }
152
ae4735db 153let semi_al_expr = Visitor_c.vk_expr_s semi_strip_info_visitor
413ffc02
C
154let semi_al_declaration = Visitor_c.vk_decl_s semi_strip_info_visitor
155let semi_al_field = Visitor_c.vk_struct_field_s semi_strip_info_visitor
190f1acf 156let semi_al_fields = Visitor_c.vk_struct_fields_s semi_strip_info_visitor
34e49164
C
157let semi_al_statement = Visitor_c.vk_statement_s semi_strip_info_visitor
158let semi_al_type = Visitor_c.vk_type_s semi_strip_info_visitor
113803cf 159let semi_al_init = Visitor_c.vk_ini_s semi_strip_info_visitor
8f657093 160let semi_al_inits = Visitor_c.vk_inis_s semi_strip_info_visitor
34e49164
C
161let semi_al_param = Visitor_c.vk_param_s semi_strip_info_visitor
162let semi_al_params = Visitor_c.vk_params_s semi_strip_info_visitor
163let semi_al_arguments = Visitor_c.vk_arguments_s semi_strip_info_visitor
164
b1b2de81
C
165let semi_al_program =
166 List.map (Visitor_c.vk_toplevel_s semi_strip_info_visitor)
34e49164 167
91eba41f
C
168
169
170
0708f913 171(* really strip, do not keep position nor anything specificities, true
002099fc 172 * abstracted form. This is used outside coccinelle in Yacfe and aComment *)
ae4735db 173let real_strip_info_visitor _ =
91eba41f
C
174 { Visitor_c.default_visitor_c_s with
175 Visitor_c.kinfo_s = (fun (k,_) i ->
b1b2de81 176 Ast_c.real_al_info_cpp i
91eba41f
C
177 );
178
ae4735db 179 Visitor_c.kexpr_s = (fun (k,_) e ->
91eba41f
C
180 let (e', ty),ii' = k e in
181 (e', Ast_c.noType()), ii'
182 );
183
184(*
ae4735db 185 Visitor_c.ktype_s = (fun (k,_) ft ->
91eba41f
C
186 let ft' = k ft in
187 match Ast_c.unwrap_typeC ft' with
ae4735db 188 | Ast_c.TypeName (s,_typ) ->
91eba41f
C
189 Ast_c.TypeName (s, Ast_c.noTypedefDef()) +> Ast_c.rewrap_typeC ft'
190 | _ -> ft'
191
192 );
193*)
ae4735db 194
91eba41f
C
195 }
196
197let real_al_expr x = Visitor_c.vk_expr_s (real_strip_info_visitor()) x
993936c0 198let real_al_arguments x = Visitor_c.vk_arguments_s (real_strip_info_visitor()) x
91eba41f
C
199let real_al_node x = Visitor_c.vk_node_s (real_strip_info_visitor()) x
200let real_al_type x = Visitor_c.vk_type_s (real_strip_info_visitor()) x
993936c0
C
201let real_al_decl x = Visitor_c.vk_decl_s (real_strip_info_visitor()) x
202let real_al_init x = Visitor_c.vk_ini_s (real_strip_info_visitor()) x
203let real_al_inits x = Visitor_c.vk_inis_s (real_strip_info_visitor()) x
190f1acf
C
204let real_al_statement x = Visitor_c.vk_statement_s (real_strip_info_visitor()) x
205let real_al_def x = Visitor_c.vk_toplevel_s (real_strip_info_visitor()) x
91eba41f 206
34e49164
C
207(*****************************************************************************)
208(* Extract infos *)
209(*****************************************************************************)
210
ae4735db 211let extract_info_visitor recursor x =
34e49164 212 let globals = ref [] in
ae4735db 213 let visitor =
34e49164
C
214 {
215 Visitor_c.default_visitor_c with
216 Visitor_c.kinfo = (fun (k, _) i -> Common.push2 i globals)
217 } in
218 begin
219 recursor visitor x;
220 !globals
221 end
222
223let ii_of_decl = extract_info_visitor Visitor_c.vk_decl
413ffc02 224let ii_of_field = extract_info_visitor Visitor_c.vk_struct_field
34e49164
C
225let ii_of_node = extract_info_visitor Visitor_c.vk_node
226let ii_of_expr = extract_info_visitor Visitor_c.vk_expr
227let ii_of_stmt = extract_info_visitor Visitor_c.vk_statement
228let ii_of_args = extract_info_visitor Visitor_c.vk_args_splitted
229let ii_of_type = extract_info_visitor Visitor_c.vk_type
230let ii_of_ini = extract_info_visitor Visitor_c.vk_ini
c491d8ee 231let ii_of_inis = extract_info_visitor Visitor_c.vk_inis_splitted
34e49164
C
232let ii_of_param = extract_info_visitor Visitor_c.vk_param
233let ii_of_params = extract_info_visitor Visitor_c.vk_params_splitted
c491d8ee 234let ii_of_enum_fields = extract_info_visitor Visitor_c.vk_enum_fields_splitted
34e49164 235let ii_of_struct_fields = extract_info_visitor Visitor_c.vk_struct_fields
485bce71
C
236(*let ii_of_struct_field = extract_info_visitor Visitor_c.vk_struct_field*)
237let ii_of_struct_fieldkinds = extract_info_visitor Visitor_c.vk_struct_fieldkinds
34e49164 238let ii_of_cst = extract_info_visitor Visitor_c.vk_cst
ae4735db 239let ii_of_define_params =
34e49164 240 extract_info_visitor Visitor_c.vk_define_params_splitted
485bce71 241let ii_of_toplevel = extract_info_visitor Visitor_c.vk_toplevel
34e49164 242
91eba41f
C
243(*****************************************************************************)
244(* Max min, range *)
485bce71 245(*****************************************************************************)
ae4735db 246let max_min_ii_by_pos xs =
34e49164
C
247 match xs with
248 | [] -> failwith "empty list, max_min_ii_by_pos"
249 | [x] -> (x, x)
ae4735db 250 | x::xs ->
b1b2de81 251 let pos_leq p1 p2 = (Ast_c.compare_pos p1 p2) =|= (-1) in
ae4735db 252 xs +> List.fold_left (fun (maxii,minii) e ->
34e49164
C
253 let maxii' = if pos_leq maxii e then e else maxii in
254 let minii' = if pos_leq e minii then e else minii in
255 maxii', minii'
256 ) (x,x)
257
258let info_to_fixpos ii =
259 match Ast_c.pinfo_of_info ii with
260 Ast_c.OriginTok pi -> Ast_cocci.Real pi.Common.charpos
261 | Ast_c.ExpandedTok (_,(pi,offset)) ->
262 Ast_cocci.Virt (pi.Common.charpos,offset)
263 | Ast_c.FakeTok (_,(pi,offset)) ->
264 Ast_cocci.Virt (pi.Common.charpos,offset)
265 | Ast_c.AbstractLineTok pi -> failwith "unexpected abstract"
ae4735db
C
266
267let max_min_by_pos xs =
34e49164
C
268 let (i1, i2) = max_min_ii_by_pos xs in
269 (info_to_fixpos i1, info_to_fixpos i2)
270
ae4735db 271let lin_col_by_pos xs =
34e49164 272 (* put min before max; no idea why they are backwards above *)
951c7801
C
273 let non_fake = List.filter (function ii -> not (Ast_c.is_fake ii)) xs in
274 let (i2, i1) = max_min_ii_by_pos non_fake in
34e49164
C
275 let posf x = Ast_c.col_of_info x in
276 let mposf x = Ast_c.col_of_info x + String.length (Ast_c.str_of_info x) in
485bce71 277 (Ast_c.file_of_info i1,!Flag.current_element,
34e49164
C
278 (Ast_c.line_of_info i1, posf i1), (Ast_c.line_of_info i2, mposf i2))
279
280
91eba41f
C
281
282
283
ae4735db 284let min_pinfo_of_node node =
91eba41f
C
285 let ii = ii_of_node node in
286 let (maxii, minii) = max_min_ii_by_pos ii in
287 Ast_c.parse_info_of_info minii
288
289
ae4735db
C
290let (range_of_origin_ii: Ast_c.info list -> (int * int) option) =
291 fun ii ->
91eba41f 292 let ii = List.filter Ast_c.is_origintok ii in
ae4735db 293 try
91eba41f
C
294 let (max, min) = max_min_ii_by_pos ii in
295 assert(Ast_c.is_origintok max);
296 assert(Ast_c.is_origintok min);
297 let strmax = Ast_c.str_of_info max in
ae4735db 298 Some
91eba41f 299 (Ast_c.pos_of_info min, Ast_c.pos_of_info max + String.length strmax)
ae4735db 300 with _ ->
91eba41f 301 None
0708f913
C
302
303
304(*****************************************************************************)
305(* Ast getters *)
306(*****************************************************************************)
307
ae4735db 308let names_of_parameters_in_def def =
0708f913 309 match def.Ast_c.f_old_c_style with
ae4735db 310 | Some _ ->
0708f913
C
311 pr2_once "names_of_parameters_in_def: f_old_c_style not handled";
312 []
ae4735db 313 | None ->
0708f913
C
314 let ftyp = def.Ast_c.f_type in
315 let (ret, (params, bwrap)) = ftyp in
ae4735db 316 params +> Common.map_filter (fun (param,ii) ->
0708f913
C
317 Ast_c.name_of_parameter param
318 )
319
ae4735db
C
320let names_of_parameters_in_macro xs =
321 xs +> List.map (fun (xx, ii) ->
0708f913
C
322 let (s, ii2) = xx in
323 s
324 )
708f4980
C
325
326
327
328(* only used in ast_to_flow, so move it ? *)
ae4735db
C
329let rec stmt_elems_of_sequencable xs =
330 xs +> Common.map (fun x ->
708f4980
C
331 match x with
332 | Ast_c.StmtElem e -> [e]
333 | Ast_c.CppDirectiveStmt _
ae4735db
C
334 | Ast_c.IfdefStmt _
335 ->
708f4980
C
336 pr2_once ("stmt_elems_of_sequencable: filter a directive");
337 []
ae4735db 338 | Ast_c.IfdefStmt2 (_ifdef, xxs) ->
708f4980 339 pr2 ("stmt_elems_of_sequencable: IfdefStm2 TODO?");
ae4735db 340 xxs +> List.map (fun xs ->
708f4980
C
341 let xs' = stmt_elems_of_sequencable xs in
342 xs'
343 ) +> List.flatten
344 ) +> List.flatten
ae4735db
C
345
346
708f4980 347