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