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.
25 module Ast0
= Ast0_cocci
26 module Ast
= Ast_cocci
27 module V0
= Visitor_ast0
28 module VT0
= Visitor_ast0_types
30 type id
= Id
of string | Meta
of Ast.meta_name
32 let rec get_name name
=
33 match Ast0.unwrap name
with
34 Ast0.Id
(nm
) -> [Id
(Ast0.unwrap_mcode nm
)]
35 | Ast0.MetaId
(nm
,_
,_
,_
) | Ast0.MetaFunc
(nm
,_
,_
)
36 | Ast0.MetaLocalFunc
(nm
,_
,_
) -> [Meta
(Ast0.unwrap_mcode nm
)]
37 | Ast0.DisjId
(_
,id_list
,_
,_
) -> List.concat
(List.map
get_name id_list
)
38 | Ast0.OptIdent
(id
) | Ast0.UniqueIdent
(id
) ->
41 (* --------------------------------------------------------------------- *)
42 (* collect all of the functions *)
44 let brace_to_semi (_
,arity
,info
,mcodekind
,pos
,adj
) =
46 (* drop column information, so that with -smpl_spacing the semicolon
47 will come out right after the close parenthesis *)
48 {info with Ast0.pos_info
= {info.Ast0.pos_info
with Ast0.column
= -1}} in
49 (";",Ast0.NONE
,info,mcodekind
,pos
,adj
)
51 let collect_function (stm
: Ast0.statement
) =
52 match Ast0.unwrap stm
with
53 Ast0.FunDecl
(_
,fninfo
,name
,lp
,params
,rp
,lbrace
,body
,rbrace
) ->
56 List.filter
(function Ast0.FStorage
(_
) -> true | _
-> false)
57 fninfo
with [Ast0.FStorage
(s
)] -> Some s
| _
-> None
in
60 List.filter
(function Ast0.FType
(_
) -> true | _
-> false)
61 fninfo
with [Ast0.FType
(t
)] -> Some t
| _
-> None
in
66 (Ast0.Decl
((Ast0.default_info
(),Ast0.context_befaft
()),
71 (Ast0.FunctionType
(ty,lp
,params
,rp
)),
72 name
,brace_to_semi lbrace
))))))
76 let collect_functions stmt_dots
=
77 List.concat
(List.map
collect_function (Ast0.undots stmt_dots
))
79 let get_all_functions rule
=
81 match Ast0.unwrap rule
with
82 Ast0.DECL
(stmt
) -> collect_function stmt
83 | Ast0.CODE
(rule_elem_dots
) -> collect_functions rule_elem_dots
86 (function (nm
,def
,vl
) ->
88 (def
,(Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement vl
)))
91 (* --------------------------------------------------------------------- *)
92 (* try to match up the functions *)
94 (* pass through the - and + functions in lockstep, until one runs out.
95 Then process the remaining minuses, if any. If we can find another
96 function of the same name for either the current - or + function, take that
97 one. Otherwise, align the two current ones. *)
99 let rec align all_minus all_plus
=
100 let rec loop = function
102 | ((mname
,(mdef
,mproto
))::minus
,[]) ->
104 let (_
,pproto
) = List.assoc mname all_plus
in
105 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
,[]))
106 with Not_found
-> (mname
,mdef
,mproto
,None
)::(loop (minus
, [])))
107 | ((mname
,(mdef
,mproto
))::minus
,(pname
,(pdef
,pproto
))::plus
) ->
109 then (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, []))
112 let (_
,pproto_for_minus
) = List.assoc mname all_plus
in
114 let _ = List.assoc mname all_plus
in
115 (* protos that match both *)
116 (mname
,mdef
,mproto
,Some pproto_for_minus
)::(loop (minus
, plus
))
118 (* proto that matches only minus *)
119 (mname
,mdef
,mproto
,Some pproto_for_minus
)::
120 (loop (minus
, ((pname
,(pdef
,pproto
))::plus
))))
123 let _ = List.assoc mname all_plus
in
124 (* proto only for plus *)
125 (mname
,mdef
,mproto
,None
)::(loop (minus
, plus
))
127 (* protos for no one *)
128 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, plus
)))) in
129 List.filter changed_proto
(loop (all_minus
, all_plus
))
131 (* --------------------------------------------------------------------- *)
134 let donothing r k e
=
135 {(Ast0.wrap
(Ast0.unwrap
(k e
))) with
136 Ast0.mcodekind
= ref (Ast0.PLUS
Ast.ONE
)} in
137 let mcode (mc
,_,_,_,_,_) =
138 (mc
,Ast0.NONE
,Ast0.default_info
(),Ast0.PLUS
Ast.ONE
,
141 (* need a case for everything that has an unvisited component and can be in
142 a function prototype *)
147 (match Ast0.unwrap e
with
148 Ast0.MetaId
(nm
,constraints
,seed
,pure
) ->
149 Ast0.MetaId
(nm
,constraints
,seed
,Ast0.Pure
)
150 | Ast0.MetaFunc
(nm
,constraints
,pure
) ->
151 Ast0.MetaFunc
(nm
,constraints
,Ast0.Pure
)
152 | Ast0.MetaLocalFunc
(nm
,constraints
,pure
) ->
153 Ast0.MetaLocalFunc
(nm
,constraints
,Ast0.Pure
)
159 (match Ast0.unwrap e
with
160 Ast0.MetaType
(nm
,pure
) -> Ast0.MetaType
(nm
,Ast0.Pure
)
166 (match Ast0.unwrap e
with
167 Ast0.MetaParam
(nm
,pure
) ->
168 Ast0.MetaParam
(nm
,Ast0.Pure
)
169 | Ast0.MetaParamList
(nm
,lenname
,pure
) ->
170 Ast0.MetaParamList
(nm
,lenname
,Ast0.Pure
)
174 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
175 donothing donothing donothing donothing donothing donothing
176 ident donothing typeC donothing param donothing donothing
179 and changed_proto
= function
180 (mname
,mdef
,mproto
,None
) -> true
181 | (mname
,mdef
,mproto
,Some pproto
) ->
182 not
((strip
.VT0.rebuilder_rec_statement mproto
) =
183 (strip
.VT0.rebuilder_rec_statement pproto
))
185 (* --------------------------------------------------------------------- *)
188 let rec drop_param_name p
=
190 (match Ast0.unwrap p
with
191 Ast0.Param
(p
,_) -> Ast0.Param
(p
,None
)
192 | Ast0.OptParam
(p
) -> Ast0.OptParam
(drop_param_name p
)
193 | Ast0.UniqueParam
(p
) -> Ast0.UniqueParam
(p
)
197 let dec = (Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement
dec in
198 match Ast0.unwrap
dec with
199 Ast0.Decl
(info,uninit
) ->
200 (match Ast0.unwrap uninit
with
201 Ast0.UnInit
(stg,typ
,name
,sem
) ->
202 (match Ast0.unwrap typ
with
203 Ast0.FunctionType
(ty,lp
,params
,rp
) ->
205 match Ast0.unwrap
params with
207 Ast0.rewrap
params (Ast0.DOTS
(List.map
drop_param_name l
))
210 (Ast0.CIRCLES
(List.map
drop_param_name l
))
211 | Ast0.STARS
(l
) -> failwith
"unexpected stars" in
219 (Ast0.FunctionType
(ty,lp
,params,rp
)),
221 | _ -> failwith
"function prototypes: unexpected type")
222 | _ -> failwith
"unexpected declaration")
223 | _ -> failwith
"unexpected term"
230 name^
"__"^
(string_of_int
n)
232 let rec rename_param old_name all
param =
233 match Ast0.unwrap
param with
234 Ast0.Param
(ty,Some id
) when all
->
235 (match Ast0.unwrap id
with
237 (((_,name
),arity
,info,mcodekind
,pos
,adj
),constraints
,seed
,pure
) ->
238 let nm = ("__no_name__",new_name name
) in
242 ((nm,arity
,info,mcodekind
,pos
,adj
),constraints
,seed
,
244 ([Ast.MetaIdDecl
(Ast.NONE
,nm)],
245 Ast0.rewrap
param (Ast0.Param
(ty,Some
new_id)))
248 let nm = (old_name
,new_name "__P") in
249 let nml = (old_name
,new_name "__n") in
252 (Ast0.MetaParamList
(Ast0.rewrap_mcode d
nm,
253 Ast0.MetaListLen
(Ast0.rewrap_mcode d
nml),
255 ([Ast.MetaParamListDecl
(Ast.NONE
,nm,Ast.MetaLen
nml);
256 Ast.MetaListlenDecl
(nml)],
258 | Ast0.OptParam
(p
) ->
259 let (metavars
,p
) = rename_param old_name all p
in
260 (metavars
,Ast0.rewrap
param (Ast0.OptParam
(p
)))
261 | Ast0.UniqueParam
(p
) ->
262 let (metavars
,p
) = rename_param old_name all p
in
263 (metavars
,Ast0.rewrap
param (Ast0.UniqueParam
(p
)))
266 (* try to convert names in the - parameter list to new metavariables, to
267 account for spelling mistakes on the part of the programmer *)
268 let fresh_names old_name mdef
dec =
269 let res = ([],[],dec,mdef
) in
270 match Ast0.unwrap
dec with
271 Ast0.Decl
(info,uninit
) ->
272 (match Ast0.unwrap uninit
with
273 Ast0.UnInit
(stg,typ
,name
,sem
) ->
274 (match Ast0.unwrap typ
with
275 Ast0.FunctionType
(ty,lp
,params,rp
) ->
276 let (metavars
,newdec
) =
279 (List.map
(rename_param old_name
true)
280 (Ast0.undots
params)) in
281 (List.concat metavars
,
290 (ty,lp
,Ast0.rewrap
params (Ast0.DOTS
(l
)),
293 let (def_metavars
,newdef
) =
294 match Ast0.unwrap mdef
with
295 Ast0.FunDecl
(x
,fninfo
,name
,lp
,params,rp
,lb
,body
,rb
) ->
296 let (def_metavars
,def_l
) =
298 (List.map
(rename_param old_name
false)
299 (Ast0.undots
params)) in
300 (List.concat def_metavars
,
302 (Ast0.FunDecl
(x
,fninfo
,name
,lp
,
303 Ast0.rewrap
params (Ast0.DOTS
(def_l
)),
305 | _ -> failwith
"unexpected function definition" in
306 (metavars
,def_metavars
,newdec
,newdef
)
311 (* since there is no + counterpart, the function must be completely deleted *)
313 match Ast0.unwrap
dec with
314 Ast0.Decl
(info,uninit
) ->
315 (match Ast0.unwrap uninit
with
316 Ast0.UnInit
(stg,typ
,name
,sem
) ->
317 (match Ast0.unwrap typ
with
318 Ast0.FunctionType
(ty,lp
,params,rp
) ->
329 (let info = Ast0.get_info
params in
331 (* use the mcodekind of an atomic minused
333 Ast0.get_mcode_mcodekind lp
in
335 ("...",Ast0.NONE
,info,mcodekind,
339 (Ast0.Pdots
(pdots))])),
346 let merge mproto pproto
=
348 Compute_lines.compute_lines
true
349 [Ast0.copywrap
mproto (Ast0.DECL
mproto)] in
351 Compute_lines.compute_lines
true
352 [Ast0.copywrap
pproto (Ast0.DECL
pproto)] in
353 let (m
,p
) = List.split
(Context_neg.context_neg
mproto pproto) in
354 Insert_plus.insert_plus m p
true (* no isos for protos *);
355 (* convert to ast so that the + code will fall down to the tokens
356 and off the artificially added Ast0.DECL *)
357 let mproto = Ast0toast.ast0toast_toplevel
(List.hd
mproto) in
358 (* clean up the wrapping added above *)
359 match Ast.unwrap
mproto with
360 Ast.DECL
mproto -> mproto
361 | _ -> failwith
"not possible"
363 let make_rule rule_name
= function
364 (mname
,mdef
,mproto,Some
pproto) ->
365 let (metavars
,mdef_metavars
,mproto,mdef
) =
366 fresh_names rule_name mdef
mproto in
367 let no_name_mproto = drop_names mproto in
368 let no_name_pproto = drop_names pproto in
369 (metavars
,mdef_metavars
,
370 [merge mproto pproto; merge no_name_mproto no_name_pproto],mdef
)
371 | (mname
,mdef
,mproto,None
) ->
372 ([],[],[Ast0toast.statement
(no_names mproto)],mdef
)
374 (* --------------------------------------------------------------------- *)
376 let reinsert mdefs minus
=
380 match Ast0.unwrap x
with
381 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
383 | _ -> failwith
"bad mdef")
387 match Ast0.unwrap x
with
389 (match Ast0.unwrap stmt
with
390 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
391 (try Ast0.rewrap x
(Ast0.DECL
(List.assoc name
table))
394 | Ast0.CODE
(rule_elem_dots
) ->
395 (* let's hope there are no functions in here... *)
400 (* --------------------------------------------------------------------- *)
403 let rec split4 = function
406 let (ax
,bx
,cx
,dx
) = split4 rest
in (a
::ax
,b
::bx
,c
::cx
,d
::dx
)
408 let process rule_name rule_metavars dropped_isos minus plus ruletype
=
409 let minus_functions = List.concat
(List.map
get_all_functions minus
) in
410 match minus_functions with
411 [] -> ((rule_metavars
,minus
),None
)
414 List.concat
(List.map
get_all_functions plus
) in
415 let protos = align minus_functions plus_functions in
416 let (metavars
,mdef_metavars
,rules
,mdefs
) =
417 split4(List.map
(make_rule rule_name
) protos) in
418 let metavars = List.concat
metavars in
419 let mdef_metavars = (List.concat
mdef_metavars) @ rule_metavars
in
420 let rules = List.concat
rules in
421 let minus = reinsert mdefs
minus in
423 [] -> ((rule_metavars
,minus),None
)
425 (* probably not possible, since there is always the version with
426 variables and the version without *)
427 ((mdef_metavars,minus),
431 ("proto for "^rule_name
,
432 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
433 [Ast.rewrap x
(Ast.DECL x
)],
437 List.map
(function x
-> Ast.rewrap x
(Ast.DOTS
[x
])) rules in
440 ("proto for "^rule_name
,
441 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
442 [Ast.rewrap x
(Ast.DECL
(Ast.rewrap x
(Ast.Disj
drules)))],
444 ((mdef_metavars,minus),Some
(metavars,res))