2 * Copyright 2005-2008, 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
27 type id
= Id
of string | Meta
of (string * string)
29 let rec get_name name
=
30 match Ast0.unwrap name
with
31 Ast0.Id
(nm
) -> Id
(Ast0.unwrap_mcode nm
)
32 | Ast0.MetaId
(nm
,_
,_
) | Ast0.MetaFunc
(nm
,_
,_
)
33 | Ast0.MetaLocalFunc
(nm
,_
,_
) -> Meta
(Ast0.unwrap_mcode nm
)
34 | Ast0.OptIdent
(id
) | Ast0.UniqueIdent
(id
) ->
37 (* --------------------------------------------------------------------- *)
38 (* collect all of the functions *)
40 let brace_to_semi (_
,arity
,info
,mcodekind
,pos
) =
41 (";",Ast0.NONE
,info
,mcodekind
,pos
)
43 let collect_function (stm
: Ast0.statement
) =
44 match Ast0.unwrap stm
with
45 Ast0.FunDecl
(_
,fninfo
,name
,lp
,params
,rp
,lbrace
,body
,rbrace
) ->
48 List.filter
(function Ast0.FStorage
(_
) -> true | _
-> false)
49 fninfo
with [Ast0.FStorage
(s
)] -> Some s
| _
-> None
in
52 List.filter
(function Ast0.FType
(_
) -> true | _
-> false)
53 fninfo
with [Ast0.FType
(t
)] -> Some t
| _
-> None
in
56 (Ast0.Decl
((Ast0.default_info
(),Ast0.context_befaft
()),
61 (Ast0.FunctionType
(ty,lp
,params
,rp
)),
62 name
,brace_to_semi lbrace
)))))]
65 let collect_functions stmt_dots
=
66 List.concat
(List.map
collect_function (Ast0.undots stmt_dots
))
68 let get_all_functions rule
=
70 match Ast0.unwrap rule
with
71 Ast0.DECL
(stmt
) -> collect_function stmt
72 | Ast0.CODE
(rule_elem_dots
) -> collect_functions rule_elem_dots
75 (function (nm
,def
,vl
) ->
76 (nm
,(def
,(Iso_pattern.rebuild_mcode None
).V0.rebuilder_statement vl
)))
79 (* --------------------------------------------------------------------- *)
80 (* try to match up the functions *)
82 (* pass through the - and + functions in lockstep, until one runs out.
83 Then process the remaining minuses, if any. If we can find another
84 function of the same name for either the current - or + function, take that
85 one. Otherwise, align the two current ones. *)
87 let rec align all_minus all_plus
=
88 let rec loop = function
90 | ((mname
,(mdef
,mproto
))::minus
,[]) ->
92 let (_
,pproto
) = List.assoc mname all_plus
in
93 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
,[]))
94 with Not_found
-> (mname
,mdef
,mproto
,None
)::(loop (minus
, [])))
95 | ((mname
,(mdef
,mproto
))::minus
,(pname
,(pdef
,pproto
))::plus
) ->
97 then (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, []))
100 let (_
,pproto_for_minus
) = List.assoc mname all_plus
in
102 let _ = List.assoc mname all_plus
in
103 (* protos that match both *)
104 (mname
,mdef
,mproto
,Some pproto_for_minus
)::(loop (minus
, plus
))
106 (* proto that matches only minus *)
107 (mname
,mdef
,mproto
,Some pproto_for_minus
)::
108 (loop (minus
, ((pname
,(pdef
,pproto
))::plus
))))
111 let _ = List.assoc mname all_plus
in
112 (* proto only for plus *)
113 (mname
,mdef
,mproto
,None
)::(loop (minus
, plus
))
115 (* protos for no one *)
116 (mname
,mdef
,mproto
,Some pproto
)::(loop (minus
, plus
)))) in
117 List.filter changed_proto
(loop (all_minus
, all_plus
))
119 (* --------------------------------------------------------------------- *)
122 let donothing r k e
=
123 {(Ast0.wrap
(Ast0.unwrap
(k e
))) with Ast0.mcodekind
= ref Ast0.PLUS
} in
124 let mcode (mc
,_,_,_,_) =
125 (mc
,Ast0.NONE
,Ast0.default_info
(),Ast0.PLUS
,ref Ast0.NoMetaPos
) in
127 (* need a case for everything that has an unvisited component and can be in
128 a function prototype *)
133 (match Ast0.unwrap e
with
134 Ast0.MetaId
(nm
,constraints
,pure
) ->
135 Ast0.MetaId
(nm
,constraints
,Ast0.Pure
)
136 | Ast0.MetaFunc
(nm
,constraints
,pure
) ->
137 Ast0.MetaFunc
(nm
,constraints
,Ast0.Pure
)
138 | Ast0.MetaLocalFunc
(nm
,constraints
,pure
) ->
139 Ast0.MetaLocalFunc
(nm
,constraints
,Ast0.Pure
)
145 (match Ast0.unwrap e
with
146 Ast0.MetaType
(nm
,pure
) -> Ast0.MetaType
(nm
,Ast0.Pure
)
152 (match Ast0.unwrap e
with
153 Ast0.MetaParam
(nm
,pure
) ->
154 Ast0.MetaParam
(nm
,Ast0.Pure
)
155 | Ast0.MetaParamList
(nm
,lenname
,pure
) ->
156 Ast0.MetaParamList
(nm
,lenname
,Ast0.Pure
)
160 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
162 donothing donothing donothing donothing donothing donothing
163 ident donothing typeC donothing param donothing donothing
166 and changed_proto
= function
167 (mname
,mdef
,mproto
,None
) -> true
168 | (mname
,mdef
,mproto
,Some pproto
) ->
169 not
((strip
.V0.rebuilder_statement mproto
) =
170 (strip
.V0.rebuilder_statement pproto
))
172 (* --------------------------------------------------------------------- *)
175 let rec drop_param_name p
=
177 (match Ast0.unwrap p
with
178 Ast0.Param
(p
,_) -> Ast0.Param
(p
,None
)
179 | Ast0.OptParam
(p
) -> Ast0.OptParam
(drop_param_name p
)
180 | Ast0.UniqueParam
(p
) -> Ast0.UniqueParam
(p
)
184 let dec = (Iso_pattern.rebuild_mcode None
).V0.rebuilder_statement
dec in
185 match Ast0.unwrap
dec with
186 Ast0.Decl
(info
,uninit
) ->
187 (match Ast0.unwrap uninit
with
188 Ast0.UnInit
(stg,typ
,name
,sem
) ->
189 (match Ast0.unwrap typ
with
190 Ast0.FunctionType
(ty,lp
,params
,rp
) ->
192 match Ast0.unwrap
params with
194 Ast0.rewrap
params (Ast0.DOTS
(List.map
drop_param_name l
))
197 (Ast0.CIRCLES
(List.map
drop_param_name l
))
198 | Ast0.STARS
(l
) -> failwith
"unexpected stars" in
206 (Ast0.FunctionType
(ty,lp
,params,rp
)),
208 | _ -> failwith
"function prototypes: unexpected type")
209 | _ -> failwith
"unexpected declaration")
210 | _ -> failwith
"unexpected term"
217 name^
"__"^
(string_of_int
n)
219 let rec rename_param old_name all
param =
220 match Ast0.unwrap
param with
221 Ast0.Param
(ty,Some id
) when all
->
222 (match Ast0.unwrap id
with
223 Ast0.MetaId
(((_,name
),arity
,info
,mcodekind
,pos
),constraints
,pure
) ->
224 let nm = ("__no_name__",new_name name
) in
228 ((nm,arity
,info
,mcodekind
,pos
),constraints
,Ast0.Pure
)) in
229 ([Ast.MetaIdDecl
(Ast.NONE
,nm)],
230 Ast0.rewrap
param (Ast0.Param
(ty,Some
new_id)))
233 let nm = (old_name
,new_name "__P") in
234 let nml = (old_name
,new_name "__n") in
237 (Ast0.MetaParamList
(Ast0.rewrap_mcode d
nm,
238 Some
(Ast0.rewrap_mcode d
nml),
240 ([Ast.MetaParamListDecl
(Ast.NONE
,nm,Some
nml);Ast.MetaListlenDecl
(nml)],
242 | Ast0.OptParam
(p
) ->
243 let (metavars
,p
) = rename_param old_name all p
in
244 (metavars
,Ast0.rewrap
param (Ast0.OptParam
(p
)))
245 | Ast0.UniqueParam
(p
) ->
246 let (metavars
,p
) = rename_param old_name all p
in
247 (metavars
,Ast0.rewrap
param (Ast0.UniqueParam
(p
)))
250 (* try to convert names in the - parameter list to new metavariables, to
251 account for spelling mistakes on the part of the programmer *)
252 let fresh_names old_name mdef
dec =
253 let res = ([],[],dec,mdef
) in
254 match Ast0.unwrap
dec with
255 Ast0.Decl
(info
,uninit
) ->
256 (match Ast0.unwrap uninit
with
257 Ast0.UnInit
(stg,typ
,name
,sem
) ->
258 (match Ast0.unwrap typ
with
259 Ast0.FunctionType
(ty,lp
,params,rp
) ->
260 let (metavars
,newdec
) =
263 (List.map
(rename_param old_name
true)
264 (Ast0.undots
params)) in
265 (List.concat metavars
,
274 (ty,lp
,Ast0.rewrap
params (Ast0.DOTS
(l
)),
277 let (def_metavars
,newdef
) =
278 match Ast0.unwrap mdef
with
279 Ast0.FunDecl
(x
,fninfo
,name
,lp
,params,rp
,lb
,body
,rb
) ->
280 let (def_metavars
,def_l
) =
282 (List.map
(rename_param old_name
false)
283 (Ast0.undots
params)) in
284 (List.concat def_metavars
,
286 (Ast0.FunDecl
(x
,fninfo
,name
,lp
,
287 Ast0.rewrap
params (Ast0.DOTS
(def_l
)),
289 | _ -> failwith
"unexpected function definition" in
290 (metavars
,def_metavars
,newdec
,newdef
)
295 (* since there is no + counterpart, the function must be completely deleted *)
297 match Ast0.unwrap
dec with
298 Ast0.Decl
(info
,uninit
) ->
299 (match Ast0.unwrap uninit
with
300 Ast0.UnInit
(stg,typ
,name
,sem
) ->
301 (match Ast0.unwrap typ
with
302 Ast0.FunctionType
(ty,lp
,params,rp
) ->
313 (let info = Ast0.get_info
params in
315 (* use the mcodekind of an atomic minused
317 Ast0.get_mcode_mcodekind lp
in
319 ("...",Ast0.NONE
,info,mcodekind,
320 ref Ast0.NoMetaPos
) in
323 (Ast0.Pdots
(pdots))])),
330 let merge mproto pproto
=
332 Compute_lines.compute_lines
[Ast0.copywrap
mproto (Ast0.DECL
mproto)] in
334 Compute_lines.compute_lines
[Ast0.copywrap
pproto (Ast0.DECL
pproto)] in
335 let (m
,p
) = List.split
(Context_neg.context_neg
mproto pproto) in
336 Insert_plus.insert_plus m p
;
337 (* convert to ast so that the + code will fall down to the tokens
338 and off the artificially added Ast0.DECL *)
339 let mproto = Ast0toast.ast0toast_toplevel
(List.hd
mproto) in
340 (* clean up the wrapping added above *)
341 match Ast.unwrap
mproto with
342 Ast.DECL
mproto -> mproto
343 | _ -> failwith
"not possible"
345 let make_rule rule_name
= function
346 (mname
,mdef
,mproto,Some
pproto) ->
347 let (metavars
,mdef_metavars
,mproto,mdef
) =
348 fresh_names rule_name mdef
mproto in
349 let no_name_mproto = drop_names mproto in
350 let no_name_pproto = drop_names pproto in
351 (metavars
,mdef_metavars
,
352 [merge mproto pproto; merge no_name_mproto no_name_pproto],mdef
)
353 | (mname
,mdef
,mproto,None
) ->
354 ([],[],[Ast0toast.statement
(no_names mproto)],mdef
)
356 (* --------------------------------------------------------------------- *)
358 let reinsert mdefs minus
=
362 match Ast0.unwrap x
with
363 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
365 | _ -> failwith
"bad mdef")
369 match Ast0.unwrap x
with
371 (match Ast0.unwrap stmt
with
372 Ast0.FunDecl
(_,fninfo
,name
,lp
,params,rp
,lbrace
,body
,rbrace
) ->
373 (try Ast0.rewrap x
(Ast0.DECL
(List.assoc name
table))
376 | Ast0.CODE
(rule_elem_dots
) ->
377 (* let's hope there are no functions in here... *)
382 (* --------------------------------------------------------------------- *)
385 let rec split4 = function
388 let (ax
,bx
,cx
,dx
) = split4 rest
in (a
::ax
,b
::bx
,c
::cx
,d
::dx
)
390 let process rule_name rule_metavars dropped_isos minus plus
=
391 let minus_functions = List.concat
(List.map
get_all_functions minus
) in
392 match minus_functions with
393 [] -> ((rule_metavars
,minus
),None
)
396 List.concat
(List.map
get_all_functions plus
) in
397 let protos = align minus_functions plus_functions in
398 let (metavars
,mdef_metavars
,rules
,mdefs
) =
399 split4(List.map
(make_rule rule_name
) protos) in
400 let metavars = List.concat
metavars in
401 let mdef_metavars = (List.concat
mdef_metavars) @ rule_metavars
in
402 let rules = List.concat
rules in
403 let minus = reinsert mdefs
minus in
405 [] -> ((rule_metavars
,minus),None
)
407 (* probably not possible, since there is always the version with
408 variables and the version without *)
409 ((mdef_metavars,minus),
413 ("proto for "^rule_name
,
414 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
415 [Ast.rewrap x
(Ast.DECL x
)],
419 List.map
(function x
-> Ast.rewrap x
(Ast.DOTS
[x
])) rules in
422 ("proto for "^rule_name
,
423 (Ast.Dep rule_name
,dropped_isos
,Ast.Forall
),
424 [Ast.rewrap x
(Ast.DECL
(Ast.rewrap x
(Ast.Disj
drules)))],
426 ((mdef_metavars,minus),Some
(metavars,res))