Release coccinelle-0.1.5
[bpt/coccinelle.git] / parsing_c / unparse_hrule.ml
CommitLineData
faf9a90c
C
1module Ast = Ast_cocci
2module V = Visitor_ast
34e49164 3
faf9a90c
C
4let error x s =
5 failwith
6 (Printf.sprintf "unparse_hrule: line: %d, %s" (Ast.get_line x) s)
34e49164 7
faf9a90c 8let names = ref ([] : (string * int ref) list)
34e49164
C
9
10(* ----------------------------------------------------------------------- *)
11(* Create rule to check for header include *)
12
13let print_header_rule pr srcfile =
14 match Str.split (Str.regexp "/") srcfile with
15 [x] ->
16 pr "@header@\n@@\n\n#include \""; pr x; pr "\"\n\n"; true
17 | l ->
18 let rec loop = function
19 [] -> false
20 | [x] ->
21 pr "@header@\n@@\n\n#include \""; pr x; pr "\"\n\n"; true
22 | "include"::(x::xs) ->
23 pr "@header@\n@@\n\n#include <";
24 let x =
25 if Str.string_match (Str.regexp "asm-") x 0 then "asm" else x in
26 pr (String.concat "/" (x::xs));
27 pr ">\n\n"; true
28 | x::xs -> loop xs in
29 loop l
30
faf9a90c
C
31(* ----------------------------------------------------------------------- *)
32(* Print check that we are not in the defining function *)
33
34let print_check_rule pr function_name header_req =
35 (if header_req
36 then pr "@same depends on header@\n"
37 else pr "@same@\n");
38 pr "position p;\n";
39 pr "@@\n\n";
40 pr function_name; pr "@p(...) { ... }\n\n"
41
42(* ----------------------------------------------------------------------- *)
43(* get paramaters of the matched function *)
44
45let rec env_lookup fn = function
46 [] -> failwith "no binding"
47 | (nm,vl)::rest when fn nm -> vl
48 | _::rest -> env_lookup fn rest
49
50let get_paramst env =
51 let argname = ref ("","") in
52 let fn ((_,nm) as name) =
53 if nm = "ARGS"
54 then (argname := name; true)
55 else false in
56 match env_lookup fn env with
57 Ast_c.MetaParamListVal(paramst) -> (paramst,!argname)
58 | _ -> failwith "not possible"
59
60let get_function_name rule env =
61 let donothing r k e = k e in
62 let option_default = [] in
63 let bind = Common.union_set in
64 let do_any_list_list r any_list_list =
65 List.fold_left
66 (List.fold_left
67 (function prev -> function cur ->
68 bind (r.V.combiner_anything cur) prev))
69 [] any_list_list in
70 let mcode r mc =
71 match Ast.get_mcodekind mc with
72 Ast.MINUS(_,any_list_list) -> do_any_list_list r any_list_list
73 | Ast.CONTEXT(_,any_befaft) ->
74 (match any_befaft with
75 Ast.BEFORE(any_list_list) | Ast.AFTER(any_list_list) ->
76 do_any_list_list r any_list_list
77 | Ast.BEFOREAFTER(ba,aa) ->
78 bind (do_any_list_list r ba) (do_any_list_list r aa)
79 | Ast.NOTHING -> [])
80 | Ast.PLUS -> [] in
81 let expression r k e =
82 bind (k e)
83 (match Ast.unwrap e with
84 Ast.FunCall(fn,lp,args,rp) ->
85 (match Ast.undots args with
86 [e] ->
87 (match Ast.unwrap e with
88 Ast.MetaExprList(nm,_,_,_) ->
89 (match Ast.unwrap_mcode nm with
90 (_,"ARGS") when Ast.get_mcodekind nm = Ast.PLUS ->
91 (match Ast.unwrap fn with
92 Ast.Ident(id) ->
93 (match Ast.unwrap id with
94 Ast.MetaId(nm,_,_,_)
95 | Ast.MetaFunc(nm,_,_,_)
96 | Ast.MetaLocalFunc(nm,_,_,_) ->
97 [Ast.unwrap_mcode nm]
98 | _ -> [])
99 | _ -> [])
100 | _ -> [])
101 | _ -> [])
102 | _ -> [])
103 | _ -> []) in
104 let names =
105 (V.combiner bind option_default
106 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
107 donothing donothing donothing donothing
108 donothing expression donothing donothing donothing donothing donothing
109 donothing donothing donothing donothing donothing).V.combiner_top_level
110 rule in
111 match names with
112 [name] ->
113 (match env_lookup (function nm -> nm = name) env with
114 Ast_c.MetaIdVal(s) | Ast_c.MetaFuncVal(s)
115 | Ast_c.MetaLocalFuncVal(s) -> s
116 | _ -> error rule "not possible")
117 | _ -> error rule "inconsistent rule generation"
118
34e49164
C
119(* ----------------------------------------------------------------------- *)
120(* Print metavariable declarations *)
121
faf9a90c 122let rec print_typedef pr typedefs = function
34e49164
C
123 (Ast_c.TypeName(s,_),_) ->
124 if not (List.mem s !typedefs)
125 then (typedefs := s::!typedefs; pr "typedef "; pr s; pr ";\n")
faf9a90c 126 | (Ast_c.Pointer(_,ty),_) -> print_typedef pr typedefs ty
34e49164
C
127 | _ -> ()
128
faf9a90c
C
129let rewrap_str s ii =
130 {ii with Ast_c.pinfo =
131 (match ii.Ast_c.pinfo with
132 Ast_c.OriginTok pi ->
133 Ast_c.OriginTok { pi with Common.str = s;}
134 | Ast_c.ExpandedTok (pi,vpi) ->
135 Ast_c.ExpandedTok ({ pi with Common.str = s;},vpi)
136 | Ast_c.FakeTok (_,vpi) -> Ast_c.FakeTok (s,vpi)
137 | Ast_c.AbstractLineTok pi ->
138 Ast_c.AbstractLineTok { pi with Common.str = s;})}
139
34e49164
C
140let print_metavar pr typedefs = function
141 ((_,Some param,(_,(Ast_c.Pointer(_,(Ast_c.BaseType(Ast_c.Void),_)),_))),_)
142 ->
faf9a90c 143 pr "expression _"; pr param
34e49164 144 | (((_,Some param,(_,ty)),il) : Ast_c.parameterType) ->
faf9a90c
C
145 let il =
146 match List.rev il with
147 name::rest -> (rewrap_str ("_"^param) name) :: rest
148 | _ -> failwith "no name" in
149 print_typedef pr typedefs ty;
34e49164
C
150 Pretty_print_c.pp_param_gen
151 (function x ->
152 let str = Ast_c.str_of_info x in
153 if not (List.mem str ["const";"volatile"])
faf9a90c 154 then pr str)
34e49164
C
155 (function _ -> pr " ")
156 ((false,Some param,
157 (({Ast_c.const = false; Ast_c.volatile = false},[]),ty)),
158 il)
159 | _ -> failwith "function must have named parameters"
160
faf9a90c
C
161let make_exp = function
162 (((_,Some name,ty),param_ii),comma_ii) ->
163 let no_info = (None,Ast_c.NotTest) in
164 let nm = "_"^name in
165 let exp =
166 ((Ast_c.Ident nm,ref no_info),
167 [rewrap_str nm (List.hd(List.rev param_ii))]) in
168 (name,(Common.Left exp,comma_ii))
169 | _ -> failwith "bad parameter"
170
171let print_extra_typedefs pr typedefs env =
172 let bigf =
173 { Visitor_c.default_visitor_c with
174 Visitor_c.ktype = (fun (k, bigf) ty ->
175 match ty with
176 (_,((Ast_c.TypeName(_,_),_) as ty)) -> print_typedef pr typedefs ty
177 | _ -> k ty) } in
178 List.iter
179 (function (_,vl) ->
180 match vl with
181 Ast_c.MetaIdVal(_) | Ast_c.MetaFuncVal(_)
182 | Ast_c.MetaLocalFuncVal(_) -> ()
183 | Ast_c.MetaExprVal(exp) -> Visitor_c.vk_expr bigf exp
184 | Ast_c.MetaExprListVal(args) -> Visitor_c.vk_argument_list bigf args
185 | Ast_c.MetaParamVal(param) -> Visitor_c.vk_param bigf param
186 | Ast_c.MetaParamListVal(params) -> Visitor_c.vk_param_list bigf params
187
188 | Ast_c.MetaTypeVal(ty) -> Visitor_c.vk_type bigf ty
113803cf 189 | Ast_c.MetaInitVal(ty) -> Visitor_c.vk_ini bigf ty
faf9a90c
C
190 | Ast_c.MetaStmtVal(stm) -> Visitor_c.vk_statement bigf stm
191 | Ast_c.MetaPosVal _ | Ast_c.MetaPosValList _
192 | Ast_c.MetaListlenVal _ -> ())
193 env
194
195let rename argids env =
196 let argenv = List.map (function arg -> (arg,"_"^arg)) argids in
197 let lookup x = try List.assoc x argenv with Not_found -> x in
198 let bigf =
199 { Visitor_c.default_visitor_c_s with
200 Visitor_c.kexpr_s = (fun (k,bigf) e ->
201 match e with
202 ((Ast_c.Ident s, info), [ii]) ->
203 let new_name = lookup s in
204 ((Ast_c.Ident new_name, info), [rewrap_str new_name ii])
205 | _ -> k e) } in
206 List.map
207 (function (x,vl) ->
208 (x,
209 match vl with
210 Ast_c.MetaIdVal(_) | Ast_c.MetaFuncVal(_)
211 | Ast_c.MetaLocalFuncVal(_) -> vl
212 | Ast_c.MetaExprVal(exp) ->
213 Ast_c.MetaExprVal(Visitor_c.vk_expr_s bigf exp)
214 | Ast_c.MetaExprListVal(args) ->
215 Ast_c.MetaExprListVal(Visitor_c.vk_arguments_s bigf args)
216 | Ast_c.MetaParamVal(param) ->
217 Ast_c.MetaParamVal(Visitor_c.vk_param_s bigf param)
218 | Ast_c.MetaParamListVal(params) ->
219 Ast_c.MetaParamListVal(Visitor_c.vk_params_s bigf params)
220
221 | Ast_c.MetaTypeVal(ty) ->
222 Ast_c.MetaTypeVal(Visitor_c.vk_type_s bigf ty)
113803cf
C
223 | Ast_c.MetaInitVal(ini) ->
224 Ast_c.MetaInitVal(Visitor_c.vk_ini_s bigf ini)
faf9a90c
C
225 | Ast_c.MetaStmtVal(stm) ->
226 Ast_c.MetaStmtVal(Visitor_c.vk_statement_s bigf stm)
227 | Ast_c.MetaPosVal _ | Ast_c.MetaPosValList _
228 | Ast_c.MetaListlenVal _ -> vl))
229 env
230
231let print_types pr = function
232 None -> ()
233 | Some [ty] -> pr (Type_cocci.type2c ty)
234 | Some types ->
235 pr "{";
236 Common.print_between (function _ -> pr ", ")
237 (function ty -> pr (Type_cocci.type2c ty)) types;
238 pr "}"
239
240let pp_meta_decl pr decl =
241 let no_arity = function Ast.NONE -> () | _ -> failwith "no arity allowed" in
242 let pp_name (_,n) = pr n in
243 match decl with
244 Ast.MetaIdDecl(ar, name) ->
245 no_arity ar; pr "identifier "; pp_name name; pr ";\n"
246 | Ast.MetaFreshIdDecl(ar, name) ->
247 no_arity ar; pr "fresh identifier "; pp_name name; pr ";\n"
248 | Ast.MetaTypeDecl(ar, name) ->
249 no_arity ar; pr "type "; pp_name name; pr ";\n"
113803cf
C
250 | Ast.MetaInitDecl(ar, name) ->
251 no_arity ar; pr "initialiser "; pp_name name; pr ";\n"
faf9a90c
C
252 | Ast.MetaListlenDecl(name) -> ()
253 | Ast.MetaParamDecl(ar, name) ->
254 no_arity ar; pr "parameter "; pp_name name; pr ";\n"
255 | Ast.MetaParamListDecl(ar, name, None) ->
256 no_arity ar; pr "parameter list "; pp_name name; pr ";\n"
257 | Ast.MetaParamListDecl(ar, name, Some len) ->
258 no_arity ar; pr "parameter list "; pp_name name;
259 pr "["; pp_name len; pr "]"; pr ";\n"
260 | Ast.MetaConstDecl(ar, name, types) ->
261 no_arity ar; pr "constant "; print_types pr types;
262 pp_name name; pr ";\n"
263 | Ast.MetaErrDecl(ar, name) ->
264 no_arity ar; pr "error "; pp_name name; pr ";\n"
265 | Ast.MetaExpDecl(ar, name, None) ->
266 no_arity ar; pr "expression "; pp_name name; pr ";\n"
267 | Ast.MetaExpDecl(ar, name, types) ->
268 no_arity ar; print_types pr types; pp_name name; pr ";\n"
269 | Ast.MetaIdExpDecl(ar, name, types) ->
270 no_arity ar; pr "idexpression ";
271 print_types pr types; pp_name name; pr ";\n"
272 | Ast.MetaLocalIdExpDecl(ar, name, types) ->
273 no_arity ar; pr "local idexpression ";
274 print_types pr types; pp_name name; pr ";\n"
275 | Ast.MetaExpListDecl(ar, name, None) ->
276 no_arity ar; pr "parameter list "; pp_name name; pr ";\n"
277 | Ast.MetaExpListDecl(ar, name, Some len) ->
278 no_arity ar; pr "parameter list ";
279 pp_name name; pr "["; pp_name len; pr "]"; pr ";\n"
280 | Ast.MetaStmDecl(ar, name) ->
281 no_arity ar; pr "statement "; pp_name name; pr ";\n"
282 | Ast.MetaStmListDecl(ar, name) ->
283 no_arity ar; pr "statement list "; pp_name name; pr ";\n"
284 | Ast.MetaFuncDecl(ar, name) ->
285 no_arity ar; pr "function "; pp_name name; pr ";\n"
286 | Ast.MetaLocalFuncDecl(ar, name) ->
287 no_arity ar; pr "local function "; pp_name name; pr ";\n"
288 | Ast.MetaPosDecl(ar, name) ->
289 no_arity ar; pr "position "; pp_name name; pr ";\n"
290 | Ast.MetaDeclarerDecl(ar, name) ->
291 no_arity ar; pr "declarer "; pp_name name; pr ";\n"
292 | Ast.MetaIteratorDecl(ar, name) ->
293 no_arity ar; pr "iterator "; pp_name name; pr ";\n"
294
295let print_metavariables pr local_metas paramst env header_req =
34e49164
C
296 (if header_req
297 then pr "@depends on header@\n"
298 else pr "@@\n");
faf9a90c
C
299 pr "position _p!=same.p;\n";
300 pr "identifier _f;\n";
34e49164 301 let typedefs = ref ([] : string list) in
faf9a90c
C
302 let rec loop = function
303 [] | [(((_,_,(_,(Ast_c.BaseType(Ast_c.Void),_))),_),_)] -> []
304 | ((first,_) as f)::rest ->
305 print_metavar pr typedefs first; pr ";\n";
306 (make_exp f) :: loop rest in
307 let args = loop paramst in
308 print_extra_typedefs pr typedefs env;
309 List.iter (pp_meta_decl pr) local_metas;
310 pr "@@\n\n";
311 args
34e49164
C
312
313(* ----------------------------------------------------------------------- *)
faf9a90c
C
314(* print_start/end *)
315
316let print_start pr =
317 pr "_f@_p(...) { <+...\n"
34e49164 318
faf9a90c
C
319let print_end pr =
320 pr "\n...+> }\n"
34e49164
C
321
322(* ----------------------------------------------------------------------- *)
323(* Print call to the defined function *)
324
325let print_param_name pr = function
326 ((_,Some param,_),_) -> pr param
327 | _ -> failwith "function must have named parameters"
328
485bce71
C
329let pp_def_gen pr defn isexp =
330 let {Ast_c.f_name = s; f_type = (_, (paramst, (b, iib))); } = defn in
34e49164
C
331 pr s; pr "(";
332 (if b then failwith "not handling variable argument functions");
333 (match paramst with
334 [] | [(((_,_,(_,(Ast_c.BaseType(Ast_c.Void),_))),_),_)] -> ()
335 | (first,_)::rest ->
336 print_param_name pr first;
337 List.iter (function (x,_) -> pr ", "; print_param_name pr x) rest);
338 pr ")"; if not isexp then pr ";"
339
340(* ----------------------------------------------------------------------- *)
341(* Entry point *)
342
faf9a90c
C
343let pp_rule local_metas ast env srcfile =
344 let (paramst,args_name) = get_paramst env in
345 (* get rule information *)
346 let (rule,printable) =
347 match ast with
348 Ast.CocciRule(_,_,[body],_,_) -> (* could extend to use attributes *)
349 (body,
350 match Ast.unwrap body with
351 Ast.DECL(s) -> [[Ast.StatementTag s]]
352 | Ast.CODE(ss) -> [[Ast.StmtDotsTag ss]]
353 | _ -> error body "bad rule body")
354 | _ -> failwith "bad rule" in
355 (* create the output file *)
356 let outdir =
357 match !Flag.make_hrule with
358 Some outdir -> outdir
359 | None -> error rule "not possible" in
360 let function_name = get_function_name rule env in
361 let outfile = outdir ^ "/" ^ function_name in
362 let outfile =
363 try
364 let cell = List.assoc outfile !names in
365 let ct = !cell in
366 cell := ct + 1;
367 outfile ^ (string_of_int ct)
368 with Not_found ->
369 let cell = ref 1 in names := (outfile,cell) :: !names; outfile in
370 let outfile = outfile ^ ".cocci" in
371 Common.with_open_outfile outfile (fun (pr,chan) ->
372 let header_req = print_header_rule pr srcfile in
373 print_check_rule pr function_name header_req;
374 let args = print_metavariables pr local_metas paramst env header_req in
375 let (argids,args) = List.split args in
376 let env = rename argids env in
377 let env = (args_name,Ast_c.MetaExprListVal args)::env in
378 print_start pr;
379 (* for printing C tokens *)
380 let pr_c info =
381 match Ast_c.pinfo_of_info info with
382 Ast_c.AbstractLineTok _ -> pr (Ast_c.str_of_info info)
383 | Ast_c.FakeTok (s,_) -> pr s
384 | _ ->
385 Printf.printf "line: %s\n" (Common.dump info);
386 error rule "not an abstract line" in
387 Unparse_cocci.pp_list_list_any
388 (env, pr, pr_c, (function _ -> pr " "),
389 (function _ -> ()), (function _ -> ()))
390 true printable Unparse_cocci.InPlace;
391 print_end pr;
392 pr "\n")