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.
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.
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.
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/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
26 * Copyright 2010, INRIA, University of Copenhagen
27 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
28 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
29 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
30 * This file is part of Coccinelle.
32 * Coccinelle is free software: you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation, according to version 2 of the License.
36 * Coccinelle is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
41 * You should have received a copy of the GNU General Public License
42 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
49 module Ast0
= Ast0_cocci
50 module Ast
= Ast_cocci
51 module V0
= Visitor_ast0
52 module VT0
= Visitor_ast0_types
54 type id
= Id
of string | Meta
of Ast.meta_name
56 let rec get_name name
=
57 match Ast0.unwrap name
with
58 Ast0.Id
(nm
) -> Id
(Ast0.unwrap_mcode nm
)
59 | Ast0.MetaId
(nm
,_
,_
) | Ast0.MetaFunc
(nm
,_
,_
)
60 | Ast0.MetaLocalFunc
(nm
,_
,_
) -> Meta
(Ast0.unwrap_mcode nm
)
61 | Ast0.OptIdent
(id
) | Ast0.UniqueIdent
(id
) ->
64 (* --------------------------------------------------------------------- *)
65 (* collect all of the functions *)
67 let brace_to_semi (_
,arity
,info
,mcodekind
,pos
,adj
) =
69 (* drop column information, so that with -smpl_spacing the semicolon
70 will come out right after the close parenthesis *)
71 {info with Ast0.pos_info
= {info.Ast0.pos_info
with Ast0.column
= -1}} in
72 (";",Ast0.NONE
,info,mcodekind
,pos
,adj
)
74 let collect_function (stm
: Ast0.statement
) =
75 match Ast0.unwrap stm
with
76 Ast0.FunDecl
(_
,fninfo
,name
,lp
,params
,rp
,lbrace
,body
,rbrace
) ->
79 List.filter
(function Ast0.FStorage
(_
) -> true | _
-> false)
80 fninfo
with [Ast0.FStorage
(s
)] -> Some s
| _
-> None
in
83 List.filter
(function Ast0.FType
(_
) -> true | _
-> false)
84 fninfo
with [Ast0.FType
(t
)] -> Some t
| _
-> None
in
87 (Ast0.Decl
((Ast0.default_info
(),Ast0.context_befaft
()),
92 (Ast0.FunctionType
(ty,lp
,params
,rp
)),
93 name
,brace_to_semi lbrace
)))))]
96 let collect_functions stmt_dots
=
97 List.concat
(List.map
collect_function (Ast0.undots stmt_dots
))
99 let get_all_functions rule
=
101 match Ast0.unwrap rule
with
102 Ast0.DECL
(stmt
) -> collect_function stmt
103 | Ast0.CODE
(rule_elem_dots
) -> collect_functions rule_elem_dots
106 (function (nm
,def
,vl
) ->
108 (def
,(Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement vl
)))
111 (* --------------------------------------------------------------------- *)
112 (* try to match up the functions *)
114 (* pass through the - and + functions in lockstep, until one runs out.
115 Then process the remaining minuses, if any. If we can find another
116 function of the same name for either the current - or + function, take that
117 one. Otherwise, align the two current ones. *)
119 let rec align all_minus all_plus
=
120 let rec loop = function
122 | ((mname
,(mdef
,mproto
))::minus
,[]) ->
124 let (_
,pproto
) = List.assoc mname all_plus
in
125 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
,[]))
126 with Not_found
-> (mname
,mdef
,mproto
,None
)::(loop (minus
, [])))
127 | ((mname
,(mdef
,mproto
))::minus
,(pname
,(pdef
,pproto
))::plus
) ->
129 then (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, []))
132 let (_
,pproto_for_minus
) = List.assoc mname all_plus
in
134 let _ = List.assoc mname all_plus
in
135 (* protos that match both *)
136 (mname
,mdef
,mproto
,Some pproto_for_minus
)::(loop (minus
, plus
))
138 (* proto that matches only minus *)
139 (mname
,mdef
,mproto
,Some pproto_for_minus
)::
140 (loop (minus
, ((pname
,(pdef
,pproto
))::plus
))))
143 let _ = List.assoc mname all_plus
in
144 (* proto only for plus *)
145 (mname
,mdef
,mproto
,None
)::(loop (minus
, plus
))
147 (* protos for no one *)
148 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, plus
)))) in
149 List.filter changed_proto
(loop (all_minus
, all_plus
))
151 (* --------------------------------------------------------------------- *)
154 let donothing r k e
=
155 {(Ast0.wrap
(Ast0.unwrap
(k e
))) with
156 Ast0.mcodekind
= ref (Ast0.PLUS
Ast.ONE
)} in
157 let mcode (mc
,_,_,_,_,_) =
158 (mc
,Ast0.NONE
,Ast0.default_info
(),Ast0.PLUS
Ast.ONE
,
159 ref Ast0.NoMetaPos
,-1) in
161 (* need a case for everything that has an unvisited component and can be in
162 a function prototype *)
167 (match Ast0.unwrap e
with
168 Ast0.MetaId
(nm
,constraints
,pure
) ->
169 Ast0.MetaId
(nm
,constraints
,Ast0.Pure
)
170 | Ast0.MetaFunc
(nm
,constraints
,pure
) ->
171 Ast0.MetaFunc
(nm
,constraints
,Ast0.Pure
)
172 | Ast0.MetaLocalFunc
(nm
,constraints
,pure
) ->
173 Ast0.MetaLocalFunc
(nm
,constraints
,Ast0.Pure
)
179 (match Ast0.unwrap e
with
180 Ast0.MetaType
(nm
,pure
) -> Ast0.MetaType
(nm
,Ast0.Pure
)
186 (match Ast0.unwrap e
with
187 Ast0.MetaParam
(nm
,pure
) ->
188 Ast0.MetaParam
(nm
,Ast0.Pure
)
189 | Ast0.MetaParamList
(nm
,lenname
,pure
) ->
190 Ast0.MetaParamList
(nm
,lenname
,Ast0.Pure
)
194 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
195 donothing donothing donothing donothing donothing donothing
196 ident donothing typeC donothing param donothing donothing
199 and changed_proto
= function
200 (mname
,mdef
,mproto
,None
) -> true
201 | (mname
,mdef
,mproto
,Some pproto
) ->
202 not
((strip
.VT0.rebuilder_rec_statement mproto
) =
203 (strip
.VT0.rebuilder_rec_statement pproto
))
205 (* --------------------------------------------------------------------- *)
208 let rec drop_param_name p
=
210 (match Ast0.unwrap p
with
211 Ast0.Param
(p
,_) -> Ast0.Param
(p
,None
)
212 | Ast0.OptParam
(p
) -> Ast0.OptParam
(drop_param_name p
)
213 | Ast0.UniqueParam
(p
) -> Ast0.UniqueParam
(p
)
217 let dec = (Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement
dec in
218 match Ast0.unwrap
dec with
219 Ast0.Decl
(info,uninit
) ->
220 (match Ast0.unwrap uninit
with
221 Ast0.UnInit
(stg,typ
,name
,sem
) ->
222 (match Ast0.unwrap typ
with
223 Ast0.FunctionType
(ty,lp
,params
,rp
) ->
225 match Ast0.unwrap
params with
227 Ast0.rewrap
params (Ast0.DOTS
(List.map
drop_param_name l
))
230 (Ast0.CIRCLES
(List.map
drop_param_name l
))
231 | Ast0.STARS
(l
) -> failwith
"unexpected stars" in
239 (Ast0.FunctionType
(ty,lp
,params,rp
)),
241 | _ -> failwith
"function prototypes: unexpected type")
242 | _ -> failwith
"unexpected declaration")
243 | _ -> failwith
"unexpected term"
250 name^
"__"^
(string_of_int
n)
252 let rec rename_param old_name all
param =
253 match Ast0.unwrap
param with
254 Ast0.Param
(ty,Some id
) when all
->
255 (match Ast0.unwrap id
with
257 (((_,name
),arity
,info,mcodekind
,pos
,adj
),constraints
,pure
) ->
258 let nm = ("__no_name__",new_name name
) in
262 ((nm,arity
,info,mcodekind
,pos
,adj
),constraints
,
264 ([Ast.MetaIdDecl
(Ast.NONE
,nm)],
265 Ast0.rewrap
param (Ast0.Param
(ty,Some
new_id)))
268 let nm = (old_name
,new_name "__P") in
269 let nml = (old_name
,new_name "__n") in
272 (Ast0.MetaParamList
(Ast0.rewrap_mcode d
nm,
273 Ast0.MetaListLen
(Ast0.rewrap_mcode d
nml),
275 ([Ast.MetaParamListDecl
(Ast.NONE
,nm,Ast.MetaLen
nml);
276 Ast.MetaListlenDecl
(nml)],
278 | Ast0.OptParam
(p
) ->
279 let (metavars
,p
) = rename_param old_name all p
in
280 (metavars
,Ast0.rewrap
param (Ast0.OptParam
(p
)))
281 | Ast0.UniqueParam
(p
) ->
282 let (metavars
,p
) = rename_param old_name all p
in
283 (metavars
,Ast0.rewrap
param (Ast0.UniqueParam
(p
)))
286 (* try to convert names in the - parameter list to new metavariables, to
287 account for spelling mistakes on the part of the programmer *)
288 let fresh_names old_name mdef
dec =
289 let res = ([],[],dec,mdef
) in
290 match Ast0.unwrap
dec with
291 Ast0.Decl
(info,uninit
) ->
292 (match Ast0.unwrap uninit
with
293 Ast0.UnInit
(stg,typ
,name
,sem
) ->
294 (match Ast0.unwrap typ
with
295 Ast0.FunctionType
(ty,lp
,params,rp
) ->
296 let (metavars
,newdec
) =
299 (List.map
(rename_param old_name
true)
300 (Ast0.undots
params)) in
301 (List.concat metavars
,
310 (ty,lp
,Ast0.rewrap
params (Ast0.DOTS
(l
)),
313 let (def_metavars
,newdef
) =
314 match Ast0.unwrap mdef
with
315 Ast0.FunDecl
(x
,fninfo
,name
,lp
,params,rp
,lb
,body
,rb
) ->
316 let (def_metavars
,def_l
) =
318 (List.map
(rename_param old_name
false)
319 (Ast0.undots
params)) in
320 (List.concat def_metavars
,
322 (Ast0.FunDecl
(x
,fninfo
,name
,lp
,
323 Ast0.rewrap
params (Ast0.DOTS
(def_l
)),
325 | _ -> failwith
"unexpected function definition" in
326 (metavars
,def_metavars
,newdec
,newdef
)
331 (* since there is no + counterpart, the function must be completely deleted *)
333 match Ast0.unwrap
dec with
334 Ast0.Decl
(info,uninit
) ->
335 (match Ast0.unwrap uninit
with
336 Ast0.UnInit
(stg,typ
,name
,sem
) ->
337 (match Ast0.unwrap typ
with
338 Ast0.FunctionType
(ty,lp
,params,rp
) ->
349 (let info = Ast0.get_info
params in
351 (* use the mcodekind of an atomic minused
353 Ast0.get_mcode_mcodekind lp
in
355 ("...",Ast0.NONE
,info,mcodekind,
356 ref Ast0.NoMetaPos
,-1) in
359 (Ast0.Pdots
(pdots))])),
366 let merge mproto pproto
=
368 Compute_lines.compute_lines
true
369 [Ast0.copywrap
mproto (Ast0.DECL
mproto)] in
371 Compute_lines.compute_lines
true
372 [Ast0.copywrap
pproto (Ast0.DECL
pproto)] in
373 let (m
,p
) = List.split
(Context_neg.context_neg
mproto pproto) in
374 Insert_plus.insert_plus m p
true (* no isos for protos *);
375 (* convert to ast so that the + code will fall down to the tokens
376 and off the artificially added Ast0.DECL *)
377 let mproto = Ast0toast.ast0toast_toplevel
(List.hd
mproto) in
378 (* clean up the wrapping added above *)
379 match Ast.unwrap
mproto with
380 Ast.DECL
mproto -> mproto
381 | _ -> failwith
"not possible"
383 let make_rule rule_name
= function
384 (mname
,mdef
,mproto,Some
pproto) ->
385 let (metavars
,mdef_metavars
,mproto,mdef
) =
386 fresh_names rule_name mdef
mproto in
387 let no_name_mproto = drop_names mproto in
388 let no_name_pproto = drop_names pproto in
389 (metavars
,mdef_metavars
,
390 [merge mproto pproto; merge no_name_mproto no_name_pproto],mdef
)
391 | (mname
,mdef
,mproto,None
) ->
392 ([],[],[Ast0toast.statement
(no_names mproto)],mdef
)
394 (* --------------------------------------------------------------------- *)
396 let reinsert mdefs minus
=
400 match Ast0.unwrap x
with
401 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
403 | _ -> failwith
"bad mdef")
407 match Ast0.unwrap x
with
409 (match Ast0.unwrap stmt
with
410 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
411 (try Ast0.rewrap x
(Ast0.DECL
(List.assoc name
table))
414 | Ast0.CODE
(rule_elem_dots
) ->
415 (* let's hope there are no functions in here... *)
420 (* --------------------------------------------------------------------- *)
423 let rec split4 = function
426 let (ax
,bx
,cx
,dx
) = split4 rest
in (a
::ax
,b
::bx
,c
::cx
,d
::dx
)
428 let process rule_name rule_metavars dropped_isos minus plus ruletype
=
429 let minus_functions = List.concat
(List.map
get_all_functions minus
) in
430 match minus_functions with
431 [] -> ((rule_metavars
,minus
),None
)
434 List.concat
(List.map
get_all_functions plus
) in
435 let protos = align minus_functions plus_functions in
436 let (metavars
,mdef_metavars
,rules
,mdefs
) =
437 split4(List.map
(make_rule rule_name
) protos) in
438 let metavars = List.concat
metavars in
439 let mdef_metavars = (List.concat
mdef_metavars) @ rule_metavars
in
440 let rules = List.concat
rules in
441 let minus = reinsert mdefs
minus in
443 [] -> ((rule_metavars
,minus),None
)
445 (* probably not possible, since there is always the version with
446 variables and the version without *)
447 ((mdef_metavars,minus),
451 ("proto for "^rule_name
,
452 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
453 [Ast.rewrap x
(Ast.DECL x
)],
457 List.map
(function x
-> Ast.rewrap x
(Ast.DOTS
[x
])) rules in
460 ("proto for "^rule_name
,
461 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
462 [Ast.rewrap x
(Ast.DECL
(Ast.rewrap x
(Ast.Disj
drules)))],
464 ((mdef_metavars,minus),Some
(metavars,res))