Commit | Line | Data |
---|---|---|
faf9a90c C |
1 | module Ast = Ast_cocci |
2 | module V = Visitor_ast | |
34e49164 | 3 | |
faf9a90c C |
4 | let error x s = |
5 | failwith | |
6 | (Printf.sprintf "unparse_hrule: line: %d, %s" (Ast.get_line x) s) | |
34e49164 | 7 | |
faf9a90c | 8 | let names = ref ([] : (string * int ref) list) |
34e49164 C |
9 | |
10 | (* ----------------------------------------------------------------------- *) | |
11 | (* Create rule to check for header include *) | |
12 | ||
13 | let 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 | ||
34 | let 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 | ||
45 | let rec env_lookup fn = function | |
46 | [] -> failwith "no binding" | |
47 | | (nm,vl)::rest when fn nm -> vl | |
48 | | _::rest -> env_lookup fn rest | |
49 | ||
50 | let 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 | ||
60 | let 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 | 122 | let 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 |
129 | let 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 |
140 | let 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 |
161 | let 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 | ||
171 | let 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 | ||
195 | let 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 | ||
231 | let 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 | ||
240 | let 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 | ||
295 | let 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 | ||
316 | let print_start pr = | |
317 | pr "_f@_p(...) { <+...\n" | |
34e49164 | 318 | |
faf9a90c C |
319 | let print_end pr = |
320 | pr "\n...+> }\n" | |
34e49164 C |
321 | |
322 | (* ----------------------------------------------------------------------- *) | |
323 | (* Print call to the defined function *) | |
324 | ||
325 | let print_param_name pr = function | |
326 | ((_,Some param,_),_) -> pr param | |
327 | | _ -> failwith "function must have named parameters" | |
328 | ||
485bce71 C |
329 | let 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 |
343 | let 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") |