2 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
4 * This file is part of Coccinelle.
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
23 module Ast0
= Ast0_cocci
24 module Ast
= Ast_cocci
25 module V0
= Visitor_ast0
26 module VT0
= Visitor_ast0_types
28 type id
= Id
of string | Meta
of (string * string)
30 let rec get_name name
=
31 match Ast0.unwrap name
with
32 Ast0.Id
(nm
) -> Id
(Ast0.unwrap_mcode nm
)
33 | Ast0.MetaId
(nm
,_
,_
) | Ast0.MetaFunc
(nm
,_
,_
)
34 | Ast0.MetaLocalFunc
(nm
,_
,_
) -> Meta
(Ast0.unwrap_mcode nm
)
35 | Ast0.OptIdent
(id
) | Ast0.UniqueIdent
(id
) ->
38 (* --------------------------------------------------------------------- *)
39 (* collect all of the functions *)
41 let brace_to_semi (_
,arity
,info
,mcodekind
,pos
) =
42 (";",Ast0.NONE
,info
,mcodekind
,pos
)
44 let collect_function (stm
: Ast0.statement
) =
45 match Ast0.unwrap stm
with
46 Ast0.FunDecl
(_
,fninfo
,name
,lp
,params
,rp
,lbrace
,body
,rbrace
) ->
49 List.filter
(function Ast0.FStorage
(_
) -> true | _
-> false)
50 fninfo
with [Ast0.FStorage
(s
)] -> Some s
| _
-> None
in
53 List.filter
(function Ast0.FType
(_
) -> true | _
-> false)
54 fninfo
with [Ast0.FType
(t
)] -> Some t
| _
-> None
in
57 (Ast0.Decl
((Ast0.default_info
(),Ast0.context_befaft
()),
62 (Ast0.FunctionType
(ty,lp
,params
,rp
)),
63 name
,brace_to_semi lbrace
)))))]
66 let collect_functions stmt_dots
=
67 List.concat
(List.map
collect_function (Ast0.undots stmt_dots
))
69 let get_all_functions rule
=
71 match Ast0.unwrap rule
with
72 Ast0.DECL
(stmt
) -> collect_function stmt
73 | Ast0.CODE
(rule_elem_dots
) -> collect_functions rule_elem_dots
76 (function (nm
,def
,vl
) ->
78 (def
,(Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement vl
)))
81 (* --------------------------------------------------------------------- *)
82 (* try to match up the functions *)
84 (* pass through the - and + functions in lockstep, until one runs out.
85 Then process the remaining minuses, if any. If we can find another
86 function of the same name for either the current - or + function, take that
87 one. Otherwise, align the two current ones. *)
89 let rec align all_minus all_plus
=
90 let rec loop = function
92 | ((mname
,(mdef
,mproto
))::minus
,[]) ->
94 let (_
,pproto
) = List.assoc mname all_plus
in
95 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
,[]))
96 with Not_found
-> (mname
,mdef
,mproto
,None
)::(loop (minus
, [])))
97 | ((mname
,(mdef
,mproto
))::minus
,(pname
,(pdef
,pproto
))::plus
) ->
99 then (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, []))
102 let (_
,pproto_for_minus
) = List.assoc mname all_plus
in
104 let _ = List.assoc mname all_plus
in
105 (* protos that match both *)
106 (mname
,mdef
,mproto
,Some pproto_for_minus
)::(loop (minus
, plus
))
108 (* proto that matches only minus *)
109 (mname
,mdef
,mproto
,Some pproto_for_minus
)::
110 (loop (minus
, ((pname
,(pdef
,pproto
))::plus
))))
113 let _ = List.assoc mname all_plus
in
114 (* proto only for plus *)
115 (mname
,mdef
,mproto
,None
)::(loop (minus
, plus
))
117 (* protos for no one *)
118 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, plus
)))) in
119 List.filter changed_proto
(loop (all_minus
, all_plus
))
121 (* --------------------------------------------------------------------- *)
124 let donothing r k e
=
125 {(Ast0.wrap
(Ast0.unwrap
(k e
))) with Ast0.mcodekind
= ref Ast0.PLUS
} in
126 let mcode (mc
,_,_,_,_) =
127 (mc
,Ast0.NONE
,Ast0.default_info
(),Ast0.PLUS
,ref Ast0.NoMetaPos
) in
129 (* need a case for everything that has an unvisited component and can be in
130 a function prototype *)
135 (match Ast0.unwrap e
with
136 Ast0.MetaId
(nm
,constraints
,pure
) ->
137 Ast0.MetaId
(nm
,constraints
,Ast0.Pure
)
138 | Ast0.MetaFunc
(nm
,constraints
,pure
) ->
139 Ast0.MetaFunc
(nm
,constraints
,Ast0.Pure
)
140 | Ast0.MetaLocalFunc
(nm
,constraints
,pure
) ->
141 Ast0.MetaLocalFunc
(nm
,constraints
,Ast0.Pure
)
147 (match Ast0.unwrap e
with
148 Ast0.MetaType
(nm
,pure
) -> Ast0.MetaType
(nm
,Ast0.Pure
)
154 (match Ast0.unwrap e
with
155 Ast0.MetaParam
(nm
,pure
) ->
156 Ast0.MetaParam
(nm
,Ast0.Pure
)
157 | Ast0.MetaParamList
(nm
,lenname
,pure
) ->
158 Ast0.MetaParamList
(nm
,lenname
,Ast0.Pure
)
162 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
163 donothing donothing donothing donothing donothing donothing
164 ident donothing typeC donothing param donothing donothing
167 and changed_proto
= function
168 (mname
,mdef
,mproto
,None
) -> true
169 | (mname
,mdef
,mproto
,Some pproto
) ->
170 not
((strip
.VT0.rebuilder_rec_statement mproto
) =
171 (strip
.VT0.rebuilder_rec_statement pproto
))
173 (* --------------------------------------------------------------------- *)
176 let rec drop_param_name p
=
178 (match Ast0.unwrap p
with
179 Ast0.Param
(p
,_) -> Ast0.Param
(p
,None
)
180 | Ast0.OptParam
(p
) -> Ast0.OptParam
(drop_param_name p
)
181 | Ast0.UniqueParam
(p
) -> Ast0.UniqueParam
(p
)
185 let dec = (Iso_pattern.rebuild_mcode None
).VT0.rebuilder_rec_statement
dec in
186 match Ast0.unwrap
dec with
187 Ast0.Decl
(info
,uninit
) ->
188 (match Ast0.unwrap uninit
with
189 Ast0.UnInit
(stg,typ
,name
,sem
) ->
190 (match Ast0.unwrap typ
with
191 Ast0.FunctionType
(ty,lp
,params
,rp
) ->
193 match Ast0.unwrap
params with
195 Ast0.rewrap
params (Ast0.DOTS
(List.map
drop_param_name l
))
198 (Ast0.CIRCLES
(List.map
drop_param_name l
))
199 | Ast0.STARS
(l
) -> failwith
"unexpected stars" in
207 (Ast0.FunctionType
(ty,lp
,params,rp
)),
209 | _ -> failwith
"function prototypes: unexpected type")
210 | _ -> failwith
"unexpected declaration")
211 | _ -> failwith
"unexpected term"
218 name^
"__"^
(string_of_int
n)
220 let rec rename_param old_name all
param =
221 match Ast0.unwrap
param with
222 Ast0.Param
(ty,Some id
) when all
->
223 (match Ast0.unwrap id
with
224 Ast0.MetaId
(((_,name
),arity
,info
,mcodekind
,pos
),constraints
,pure
) ->
225 let nm = ("__no_name__",new_name name
) in
229 ((nm,arity
,info
,mcodekind
,pos
),constraints
,Ast0.Pure
)) in
230 ([Ast.MetaIdDecl
(Ast.NONE
,nm)],
231 Ast0.rewrap
param (Ast0.Param
(ty,Some
new_id)))
234 let nm = (old_name
,new_name "__P") in
235 let nml = (old_name
,new_name "__n") in
238 (Ast0.MetaParamList
(Ast0.rewrap_mcode d
nm,
239 Some
(Ast0.rewrap_mcode d
nml),
241 ([Ast.MetaParamListDecl
(Ast.NONE
,nm,Some
nml);Ast.MetaListlenDecl
(nml)],
243 | Ast0.OptParam
(p
) ->
244 let (metavars
,p
) = rename_param old_name all p
in
245 (metavars
,Ast0.rewrap
param (Ast0.OptParam
(p
)))
246 | Ast0.UniqueParam
(p
) ->
247 let (metavars
,p
) = rename_param old_name all p
in
248 (metavars
,Ast0.rewrap
param (Ast0.UniqueParam
(p
)))
251 (* try to convert names in the - parameter list to new metavariables, to
252 account for spelling mistakes on the part of the programmer *)
253 let fresh_names old_name mdef
dec =
254 let res = ([],[],dec,mdef
) in
255 match Ast0.unwrap
dec with
256 Ast0.Decl
(info
,uninit
) ->
257 (match Ast0.unwrap uninit
with
258 Ast0.UnInit
(stg,typ
,name
,sem
) ->
259 (match Ast0.unwrap typ
with
260 Ast0.FunctionType
(ty,lp
,params,rp
) ->
261 let (metavars
,newdec
) =
264 (List.map
(rename_param old_name
true)
265 (Ast0.undots
params)) in
266 (List.concat metavars
,
275 (ty,lp
,Ast0.rewrap
params (Ast0.DOTS
(l
)),
278 let (def_metavars
,newdef
) =
279 match Ast0.unwrap mdef
with
280 Ast0.FunDecl
(x
,fninfo
,name
,lp
,params,rp
,lb
,body
,rb
) ->
281 let (def_metavars
,def_l
) =
283 (List.map
(rename_param old_name
false)
284 (Ast0.undots
params)) in
285 (List.concat def_metavars
,
287 (Ast0.FunDecl
(x
,fninfo
,name
,lp
,
288 Ast0.rewrap
params (Ast0.DOTS
(def_l
)),
290 | _ -> failwith
"unexpected function definition" in
291 (metavars
,def_metavars
,newdec
,newdef
)
296 (* since there is no + counterpart, the function must be completely deleted *)
298 match Ast0.unwrap
dec with
299 Ast0.Decl
(info
,uninit
) ->
300 (match Ast0.unwrap uninit
with
301 Ast0.UnInit
(stg,typ
,name
,sem
) ->
302 (match Ast0.unwrap typ
with
303 Ast0.FunctionType
(ty,lp
,params,rp
) ->
314 (let info = Ast0.get_info
params in
316 (* use the mcodekind of an atomic minused
318 Ast0.get_mcode_mcodekind lp
in
320 ("...",Ast0.NONE
,info,mcodekind,
321 ref Ast0.NoMetaPos
) in
324 (Ast0.Pdots
(pdots))])),
331 let merge mproto pproto
=
333 Compute_lines.compute_lines
[Ast0.copywrap
mproto (Ast0.DECL
mproto)] in
335 Compute_lines.compute_lines
[Ast0.copywrap
pproto (Ast0.DECL
pproto)] in
336 let (m
,p
) = List.split
(Context_neg.context_neg
mproto pproto) in
337 Insert_plus.insert_plus m p
true (* no isos for protos *);
338 (* convert to ast so that the + code will fall down to the tokens
339 and off the artificially added Ast0.DECL *)
340 let mproto = Ast0toast.ast0toast_toplevel
(List.hd
mproto) in
341 (* clean up the wrapping added above *)
342 match Ast.unwrap
mproto with
343 Ast.DECL
mproto -> mproto
344 | _ -> failwith
"not possible"
346 let make_rule rule_name
= function
347 (mname
,mdef
,mproto,Some
pproto) ->
348 let (metavars
,mdef_metavars
,mproto,mdef
) =
349 fresh_names rule_name mdef
mproto in
350 let no_name_mproto = drop_names mproto in
351 let no_name_pproto = drop_names pproto in
352 (metavars
,mdef_metavars
,
353 [merge mproto pproto; merge no_name_mproto no_name_pproto],mdef
)
354 | (mname
,mdef
,mproto,None
) ->
355 ([],[],[Ast0toast.statement
(no_names mproto)],mdef
)
357 (* --------------------------------------------------------------------- *)
359 let reinsert mdefs minus
=
363 match Ast0.unwrap x
with
364 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
366 | _ -> failwith
"bad mdef")
370 match Ast0.unwrap x
with
372 (match Ast0.unwrap stmt
with
373 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
374 (try Ast0.rewrap x
(Ast0.DECL
(List.assoc name
table))
377 | Ast0.CODE
(rule_elem_dots
) ->
378 (* let's hope there are no functions in here... *)
383 (* --------------------------------------------------------------------- *)
386 let rec split4 = function
389 let (ax
,bx
,cx
,dx
) = split4 rest
in (a
::ax
,b
::bx
,c
::cx
,d
::dx
)
391 let process rule_name rule_metavars dropped_isos minus plus ruletype
=
392 let minus_functions = List.concat
(List.map
get_all_functions minus
) in
393 match minus_functions with
394 [] -> ((rule_metavars
,minus
),None
)
397 List.concat
(List.map
get_all_functions plus
) in
398 let protos = align minus_functions plus_functions in
399 let (metavars
,mdef_metavars
,rules
,mdefs
) =
400 split4(List.map
(make_rule rule_name
) protos) in
401 let metavars = List.concat
metavars in
402 let mdef_metavars = (List.concat
mdef_metavars) @ rule_metavars
in
403 let rules = List.concat
rules in
404 let minus = reinsert mdefs
minus in
406 [] -> ((rule_metavars
,minus),None
)
408 (* probably not possible, since there is always the version with
409 variables and the version without *)
410 ((mdef_metavars,minus),
414 ("proto for "^rule_name
,
415 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
416 [Ast.rewrap x
(Ast.DECL x
)],
420 List.map
(function x
-> Ast.rewrap x
(Ast.DOTS
[x
])) rules in
423 ("proto for "^rule_name
,
424 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
425 [Ast.rewrap x
(Ast.DECL
(Ast.rewrap x
(Ast.Disj
drules)))],
427 ((mdef_metavars,minus),Some
(metavars,res))