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