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