Coccinelle release 1.0.0-rc13
[bpt/coccinelle.git] / python / yes_pycocci.ml
1 (*
2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
5 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
6 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
7 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
8 * This file is part of Coccinelle.
9 *
10 * Coccinelle is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, according to version 2 of the License.
13 *
14 * Coccinelle is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
24 *)
25
26
27 # 0 "./yes_pycocci.ml"
28 (*
29 * Copyright 2012, INRIA
30 * Julia Lawall, Gilles Muller
31 * Copyright 2010-2011, INRIA, University of Copenhagen
32 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
33 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
34 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
35 * This file is part of Coccinelle.
36 *
37 * Coccinelle is free software: you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation, according to version 2 of the License.
40 *
41 * Coccinelle is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
45 *
46 * You should have received a copy of the GNU General Public License
47 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
48 *
49 * The authors reserve the right to distribute this or future versions of
50 * Coccinelle under other licenses.
51 *)
52
53
54 # 0 "./yes_pycocci.ml"
55 open Ast_c
56 open Common
57 open Pycaml
58 open Pycocci_aux
59 module StringMap = Map.Make (String)
60
61 exception Pycocciexception
62
63 let python_support = true
64
65 (* ------------------------------------------------------------------- *)
66 (* The following definitions are from
67 http://patches.ubuntu.com/by-release/extracted/debian/c/coccinelle/0.1.5dbs-2/01-system-pycaml
68 as well as _pycocci_setargs *)
69
70 let _pycocci_none () =
71 let builtins = pyeval_getbuiltins () in
72 pyobject_getitem (builtins, pystring_fromstring "None")
73
74 let _pycocci_true () =
75 let builtins = pyeval_getbuiltins () in
76 pyobject_getitem (builtins, pystring_fromstring "True")
77
78 let _pycocci_false () =
79 let builtins = pyeval_getbuiltins () in
80 pyobject_getitem (builtins, pystring_fromstring "False")
81
82 let _pycocci_tuple6 (a,b,c,d,e,f) =
83 pytuple_fromarray ([|a; b; c; d; e; f|])
84
85 (* ------------------------------------------------------------------- *)
86
87 let check_return_value msg v =
88 if v =*= (pynull ()) then
89 (pyerr_print ();
90 Common.pr2 ("while " ^ msg ^ ":");
91 raise Pycocciexception)
92 else ()
93 let check_int_return_value msg v =
94 if v =|= -1 then
95 (pyerr_print ();
96 Common.pr2 ("while " ^ msg ^ ":");
97 raise Pycocciexception)
98 else ()
99
100 let initialised = ref false
101
102 let coccinelle_module = ref (_pycocci_none ())
103 let cocci_file_name = ref ""
104
105 (* dealing with python modules loaded *)
106 let module_map = ref (StringMap.add "__main__" (_pycocci_none ()) StringMap.empty)
107
108 let get_module module_name =
109 StringMap.find module_name (!module_map)
110
111 let is_module_loaded module_name =
112 try
113 let _ = get_module module_name in
114 true
115 with Not_found -> false
116
117 let load_module module_name =
118 if not (is_module_loaded module_name) then
119 (* let _ = Sys.command("python3 -c 'import " ^ module_name ^ "'") in *)
120 let m = pyimport_importmodule module_name in
121 check_return_value ("importing module " ^ module_name) m;
122 (module_map := (StringMap.add module_name m (!module_map));
123 m)
124 else get_module module_name
125 (* end python module handling part *)
126
127 (* python interaction *)
128 let split_fqn fqn =
129 let last_period = String.rindex fqn '.' in
130 let module_name = String.sub fqn 0 last_period in
131 let class_name = String.sub fqn (last_period + 1) (String.length fqn - last_period - 1) in
132 (module_name, class_name)
133
134 let pycocci_get_class_type fqn =
135 let (module_name, class_name) = split_fqn fqn in
136 let m = get_module module_name in
137 let attr = pyobject_getattrstring(m, class_name) in
138 check_return_value "obtaining a python class type" attr;
139 attr
140
141 let pycocci_instantiate_class fqn args =
142 let class_type = pycocci_get_class_type fqn in
143 let obj =
144 pyeval_callobjectwithkeywords(class_type, args, pynull()) in
145 check_return_value "instantiating a python class" obj;
146 obj
147
148 (* end python interaction *)
149
150 let inc_match = ref true
151 let exited = ref false
152
153 let include_match v =
154 let truth = pyobject_istrue (pytuple_getitem (v, 1)) in
155 check_int_return_value "testing include_match" truth;
156 inc_match := truth != 0;
157 _pycocci_none ()
158
159 let sp_exit _ =
160 exited := true;
161 _pycocci_none ()
162
163 let build_method (mname, camlfunc, args) pymodule classx classdict =
164 let cmx = pymethod_new(pywrap_closure camlfunc, args, classx) in
165 let v = pydict_setitemstring(classdict, mname, cmx) in
166 check_int_return_value ("building python method " ^ mname) v;
167 ()
168
169 let build_class cname parent methods pymodule =
170 let cd = pydict_new() in
171 check_return_value "creating a new python dictionary" cd;
172 let cx = pyclass_new(pytuple_fromsingle (pycocci_get_class_type parent), cd,
173 pystring_fromstring cname) in
174 check_return_value "creating a new python class" cx;
175 List.iter (function meth -> build_method meth pymodule cx cd) methods;
176 let v = pydict_setitemstring(pymodule_getdict pymodule, cname, cx) in
177 check_int_return_value ("adding python class " ^ cname) v;
178 (cd, cx)
179
180 let the_environment = ref []
181
182 let has_environment_binding name =
183 let a = pytuple_toarray name in
184 let (rule, name) = (Array.get a 1, Array.get a 2) in
185 let orule = pystring_asstring rule in
186 let oname = pystring_asstring name in
187 let e = List.exists (function (x,y) -> orule =*= x && oname =$= y)
188 !the_environment in
189 if e then _pycocci_true () else _pycocci_false ()
190
191 let pyoutputinstance = ref (_pycocci_none ())
192 let pyoutputdict = ref (_pycocci_none ())
193
194 let get_cocci_file args =
195 pystring_fromstring (!cocci_file_name)
196
197 (* initialisation routines *)
198 let _pycocci_setargs argv0 =
199 let argv =
200 pysequence_list (pytuple_fromsingle (pystring_fromstring argv0)) in
201 let sys_mod = load_module "sys" in
202 pyobject_setattrstring (sys_mod, "argv", argv)
203
204 let pycocci_init () =
205 (* initialize *)
206 if not !initialised then (
207 initialised := true;
208 (* use python_path_base as default (overridable) dir for coccilib *)
209 let python_path_base = Printf.sprintf "%s/coccinelle" (Unix.getenv "HOME") in
210 let python_path = try Unix.getenv "PYTHONPATH" ^ ":" ^ python_path_base
211 with Not_found -> python_path_base in
212 Unix.putenv "PYTHONPATH" python_path;
213 let _ = if not (py_isinitialized () != 0) then
214 (if !Flag.show_misc then Common.pr2 "Initializing python\n%!";
215 py_initialize()) in
216
217 (* set argv *)
218 let argv0 = Sys.executable_name in
219 let _ = _pycocci_setargs argv0 in
220
221 coccinelle_module := (pymodule_new "coccinelle");
222 module_map := StringMap.add "coccinelle" !coccinelle_module !module_map;
223 let _ = load_module "coccilib.elems" in
224 let _ = load_module "coccilib.output" in
225
226 let module_dictionary = pyimport_getmoduledict() in
227 coccinelle_module := pymodule_new "coccinelle";
228 let mx = !coccinelle_module in
229 let (cd, cx) = build_class "Cocci" (!Flag.pyoutput)
230 [("exit", sp_exit, (pynull()));
231 ("include_match", include_match, (pynull()));
232 ("has_env_binding", has_environment_binding, (pynull()))] mx in
233 pyoutputinstance := cx;
234 pyoutputdict := cd;
235 let v1 = pydict_setitemstring(module_dictionary, "coccinelle", mx) in
236 check_int_return_value "adding coccinelle python module" v1;
237 let mypystring = pystring_fromstring !cocci_file_name in
238 let v2 = pydict_setitemstring(cd, "cocci_file", mypystring) in
239 check_int_return_value "adding python field cocci_file" v2;
240 ()) else
241 ()
242
243 (*let _ = pycocci_init ()*)
244 (* end initialisation routines *)
245
246 let added_variables = ref []
247
248 let build_classes env =
249 let _ = pycocci_init () in
250 inc_match := true;
251 exited := false;
252 the_environment := env;
253 let mx = !coccinelle_module in
254 let dict = pymodule_getdict mx in
255 List.iter
256 (function
257 "include_match" | "has_env_binding" | "exit" -> ()
258 | name ->
259 let v = pydict_delitemstring(dict,name) in
260 check_int_return_value ("removing " ^ name ^ " from python coccinelle module") v)
261 !added_variables;
262 added_variables := [];
263 ()
264
265 let build_variable name value =
266 let mx = !coccinelle_module in
267 added_variables := name :: !added_variables;
268 check_int_return_value ("build python variable " ^ name)
269 (pydict_setitemstring(pymodule_getdict mx, name, value))
270
271 let get_variable name =
272 let mx = !coccinelle_module in
273 pystring_asstring
274 (pyobject_str(pydict_getitemstring(pymodule_getdict mx, name)))
275
276 let contains_binding e (_,(r,m),_) =
277 try
278 let _ = List.find (function ((re, rm), _) -> r =*= re && m =$= rm) e in
279 true
280 with Not_found -> false
281
282 let construct_variables mv e =
283 let find_binding (r,m) =
284 try
285 let elem = List.find (function ((re,rm),_) -> r =*= re && m =$= rm) e in
286 Some elem
287 with Not_found -> None
288 in
289
290 (* Only string in this representation, so no point
291 let instantiate_Expression(x) =
292 let str = pystring_fromstring (Pycocci_aux.exprrep x) in
293 pycocci_instantiate_class "coccilib.elems.Expression"
294 (pytuple_fromsingle (str))
295 in
296 *)
297
298 (* Only string in this representation, so no point
299 let instantiate_Identifier(x) =
300 let str = pystring_fromstring x in
301 pycocci_instantiate_class "coccilib.elems.Identifier"
302 (pytuple_fromsingle (str))
303 in
304 *)
305
306 let instantiate_term_list py printer lst =
307 let (str,elements) = printer lst in
308 let str = pystring_fromstring str in
309 let elements =
310 pytuple_fromarray
311 (Array.of_list (List.map pystring_fromstring elements)) in
312 let repr =
313 pycocci_instantiate_class "coccilib.elems.TermList"
314 (pytuple_fromarray (Array.of_list [str;elements])) in
315 let _ = build_variable py repr in () in
316
317 List.iter (function (py,(r,m),_) ->
318 match find_binding (r,m) with
319 None -> ()
320 (* | Some (_, Ast_c.MetaExprVal (expr,_)) ->
321 let expr_repr = instantiate_Expression(expr) in
322 let _ = build_variable py expr_repr in
323 () *)
324 (* | Some (_, Ast_c.MetaIdVal (id,_)) ->
325 let id_repr = instantiate_Identifier(id) in
326 let _ = build_variable py id_repr in
327 () *)
328 | Some (_, Ast_c.MetaExprListVal (exprlist)) ->
329 instantiate_term_list py Pycocci_aux.exprlistrep exprlist
330 | Some (_, Ast_c.MetaParamListVal (paramlist)) ->
331 instantiate_term_list py Pycocci_aux.paramlistrep paramlist
332 | Some (_, Ast_c.MetaInitListVal (initlist)) ->
333 instantiate_term_list py Pycocci_aux.initlistrep initlist
334 | Some (_, Ast_c.MetaFieldListVal (fieldlist)) ->
335 instantiate_term_list py Pycocci_aux.fieldlistrep fieldlist
336 | Some (_, Ast_c.MetaPosValList l) ->
337 let locs =
338 List.map
339 (function (fname,current_element,(line,col),(line_end,col_end)) ->
340 pycocci_instantiate_class "coccilib.elems.Location"
341 (_pycocci_tuple6
342 (pystring_fromstring fname,pystring_fromstring current_element,
343 pystring_fromstring (Printf.sprintf "%d" line),
344 pystring_fromstring (Printf.sprintf "%d" col),
345 pystring_fromstring (Printf.sprintf "%d" line_end),
346 pystring_fromstring (Printf.sprintf "%d" col_end)))) l in
347 let pylocs = pytuple_fromarray (Array.of_list locs) in
348 let _ = build_variable py pylocs in
349 ()
350 | Some (_,binding) ->
351 let _ =
352 build_variable py
353 (pystring_fromstring (Pycocci_aux.stringrep binding)) in
354 ()
355 ) mv;
356
357 ()
358
359 let construct_script_variables mv =
360 List.iter
361 (function (_,py) ->
362 let str =
363 pystring_fromstring
364 "initial value: consider using coccinelle.varname" in
365 let _ = build_variable py str in
366 ())
367 mv
368
369 let retrieve_script_variables mv =
370 List.map (function (_,py) -> get_variable py) mv
371
372 let set_coccifile cocci_file =
373 cocci_file_name := cocci_file;
374 ()
375
376 let pyrun_simplestring s =
377 let res = Pycaml.pyrun_simplestring s in
378 check_int_return_value ("running simple python string: " ^ s) res;
379 res
380
381 let py_isinitialized () =
382 Pycaml.py_isinitialized ()
383
384
385 let py_finalize () =
386 Pycaml.py_finalize ()