Release coccinelle-0.2.3rc2
[bpt/coccinelle.git] / parsing_cocci / ast0toast.ml
1 (*
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.
7 *
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.
11 *
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.
16 *
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/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
25 (* Arities matter for the minus slice, but not for the plus slice. *)
26
27 (* + only allowed on code in a nest (in_nest = true). ? only allowed on
28 rule_elems, and on subterms if the context is ? also. *)
29
30 module Ast0 = Ast0_cocci
31 module Ast = Ast_cocci
32 module V0 = Visitor_ast0
33 module VT0 = Visitor_ast0_types
34 module V = Visitor_ast
35
36 let unitary = Type_cocci.Unitary
37
38 let ctr = ref 0
39 let get_ctr _ =
40 let c = !ctr in
41 ctr := !ctr + 1;
42 c
43
44 (* --------------------------------------------------------------------- *)
45 (* Move plus tokens from the MINUS and CONTEXT structured nodes to the
46 corresponding leftmost and rightmost mcodes *)
47
48 let inline_mcodes =
49 let bind x y = () in
50 let option_default = () in
51 let mcode _ = () in
52 let do_nothing r k e =
53 k e;
54 let einfo = Ast0.get_info e in
55 match (Ast0.get_mcodekind e) with
56 Ast0.MINUS(replacements) ->
57 (match !replacements with
58 ([],_) -> ()
59 | replacements ->
60 let minus_try = function
61 (true,mc) ->
62 if List.for_all
63 (function
64 Ast0.MINUS(mreplacements) -> true | _ -> false)
65 mc
66 then
67 (List.iter
68 (function
69 Ast0.MINUS(mreplacements) ->
70 mreplacements := replacements
71 | _ -> ())
72 mc;
73 true)
74 else false
75 | _ -> false in
76 if not (minus_try(einfo.Ast0.attachable_start,
77 einfo.Ast0.mcode_start)
78 or
79 minus_try(einfo.Ast0.attachable_end,
80 einfo.Ast0.mcode_end))
81 then
82 failwith "minus tree should not have bad code on both sides")
83 | Ast0.CONTEXT(befaft)
84 | Ast0.MIXED(befaft) ->
85 let concat starter startinfo ender endinfo =
86 let lst =
87 match (starter,ender) with
88 ([],_) -> ender
89 | (_,[]) -> starter
90 | _ ->
91 if startinfo.Ast0.tline_end = endinfo.Ast0.tline_start
92 then (* put them in the same inner list *)
93 let last = List.hd (List.rev starter) in
94 let butlast = List.rev(List.tl(List.rev starter)) in
95 butlast @ (last@(List.hd ender)) :: (List.tl ender)
96 else starter @ ender in
97 (lst,
98 {endinfo with Ast0.tline_start = startinfo.Ast0.tline_start}) in
99 let attach_bef bef beforeinfo befit = function
100 (true,mcl) ->
101 List.iter
102 (function
103 Ast0.MINUS(mreplacements) ->
104 let (mrepl,tokeninfo) = !mreplacements in
105 mreplacements := concat bef beforeinfo mrepl tokeninfo
106 | Ast0.CONTEXT(mbefaft) ->
107 (match !mbefaft with
108 (Ast.BEFORE(mbef,it),mbeforeinfo,a) ->
109 let (newbef,newinfo) =
110 concat bef beforeinfo mbef mbeforeinfo in
111 let it = Ast.lub_count befit it in
112 mbefaft := (Ast.BEFORE(newbef,it),newinfo,a)
113 | (Ast.AFTER(maft,it),_,a) ->
114 let it = Ast.lub_count befit it in
115 mbefaft :=
116 (Ast.BEFOREAFTER(bef,maft,it),beforeinfo,a)
117 | (Ast.BEFOREAFTER(mbef,maft,it),mbeforeinfo,a) ->
118 let (newbef,newinfo) =
119 concat bef beforeinfo mbef mbeforeinfo in
120 let it = Ast.lub_count befit it in
121 mbefaft :=
122 (Ast.BEFOREAFTER(newbef,maft,it),newinfo,a)
123 | (Ast.NOTHING,_,a) ->
124 mbefaft :=
125 (Ast.BEFORE(bef,befit),beforeinfo,a))
126 | _ -> failwith "unexpected annotation")
127 mcl
128 | _ ->
129 Printf.printf "before %s\n" (Dumper.dump bef);
130 failwith
131 "context tree should not have bad code before" in
132 let attach_aft aft afterinfo aftit = function
133 (true,mcl) ->
134 List.iter
135 (function
136 Ast0.MINUS(mreplacements) ->
137 let (mrepl,tokeninfo) = !mreplacements in
138 mreplacements := concat mrepl tokeninfo aft afterinfo
139 | Ast0.CONTEXT(mbefaft) ->
140 (match !mbefaft with
141 (Ast.BEFORE(mbef,it),b,_) ->
142 let it = Ast.lub_count aftit it in
143 mbefaft :=
144 (Ast.BEFOREAFTER(mbef,aft,it),b,afterinfo)
145 | (Ast.AFTER(maft,it),b,mafterinfo) ->
146 let (newaft,newinfo) =
147 concat maft mafterinfo aft afterinfo in
148 let it = Ast.lub_count aftit it in
149 mbefaft := (Ast.AFTER(newaft,it),b,newinfo)
150 | (Ast.BEFOREAFTER(mbef,maft,it),b,mafterinfo) ->
151 let (newaft,newinfo) =
152 concat maft mafterinfo aft afterinfo in
153 let it = Ast.lub_count aftit it in
154 mbefaft :=
155 (Ast.BEFOREAFTER(mbef,newaft,it),b,newinfo)
156 | (Ast.NOTHING,b,_) ->
157 mbefaft := (Ast.AFTER(aft,aftit),b,afterinfo))
158 | _ -> failwith "unexpected annotation")
159 mcl
160 | _ ->
161 failwith
162 "context tree should not have bad code after" in
163 (match !befaft with
164 (Ast.BEFORE(bef,it),beforeinfo,_) ->
165 attach_bef bef beforeinfo it
166 (einfo.Ast0.attachable_start,einfo.Ast0.mcode_start)
167 | (Ast.AFTER(aft,it),_,afterinfo) ->
168 attach_aft aft afterinfo it
169 (einfo.Ast0.attachable_end,einfo.Ast0.mcode_end)
170 | (Ast.BEFOREAFTER(bef,aft,it),beforeinfo,afterinfo) ->
171 attach_bef bef beforeinfo it
172 (einfo.Ast0.attachable_start,einfo.Ast0.mcode_start);
173 attach_aft aft afterinfo it
174 (einfo.Ast0.attachable_end,einfo.Ast0.mcode_end)
175 | (Ast.NOTHING,_,_) -> ())
176 | Ast0.PLUS _ -> () in
177 V0.flat_combiner bind option_default
178 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
179 mcode mcode
180 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
181 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
182 do_nothing do_nothing do_nothing
183
184 (* --------------------------------------------------------------------- *)
185 (* For function declarations. Can't use the mcode at the root, because that
186 might be mixed when the function contains ()s, where agglomeration of -s is
187 not possible. *)
188
189 let check_allminus =
190 let donothing r k e = k e in
191 let bind x y = x && y in
192 let option_default = true in
193 let mcode (_,_,_,mc,_,_) =
194 match mc with
195 Ast0.MINUS(r) -> let (plusses,_) = !r in plusses = []
196 | _ -> false in
197
198 (* special case for disj *)
199 let expression r k e =
200 match Ast0.unwrap e with
201 Ast0.DisjExpr(starter,expr_list,mids,ender) ->
202 List.for_all r.VT0.combiner_rec_expression expr_list
203 | _ -> k e in
204
205 let declaration r k e =
206 match Ast0.unwrap e with
207 Ast0.DisjDecl(starter,decls,mids,ender) ->
208 List.for_all r.VT0.combiner_rec_declaration decls
209 | _ -> k e in
210
211 let typeC r k e =
212 match Ast0.unwrap e with
213 Ast0.DisjType(starter,decls,mids,ender) ->
214 List.for_all r.VT0.combiner_rec_typeC decls
215 | _ -> k e in
216
217 let statement r k e =
218 match Ast0.unwrap e with
219 Ast0.Disj(starter,statement_dots_list,mids,ender) ->
220 List.for_all r.VT0.combiner_rec_statement_dots statement_dots_list
221 | _ -> k e in
222
223 let case_line r k e =
224 match Ast0.unwrap e with
225 Ast0.DisjCase(starter,case_lines,mids,ender) ->
226 List.for_all r.VT0.combiner_rec_case_line case_lines
227 | _ -> k e in
228
229 V0.flat_combiner bind option_default
230 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
231 mcode mcode
232 donothing donothing donothing donothing donothing donothing
233 donothing expression typeC donothing donothing declaration
234 statement case_line donothing
235
236 (* --------------------------------------------------------------------- *)
237 (* --------------------------------------------------------------------- *)
238
239 let get_option fn = function
240 None -> None
241 | Some x -> Some (fn x)
242
243 (* --------------------------------------------------------------------- *)
244 (* --------------------------------------------------------------------- *)
245 (* Mcode *)
246
247 let convert_info info =
248 let strings_to_s l =
249 List.map
250 (function (s,info) -> (s,info.Ast0.line_start,info.Ast0.column))
251 l in
252 { Ast.line = info.Ast0.pos_info.Ast0.line_start;
253 Ast.column = info.Ast0.pos_info.Ast0.column;
254 Ast.strbef = strings_to_s info.Ast0.strings_before;
255 Ast.straft = strings_to_s info.Ast0.strings_after;}
256
257 let convert_mcodekind adj = function
258 Ast0.MINUS(replacements) ->
259 let (replacements,_) = !replacements in
260 Ast.MINUS(Ast.NoPos,[],adj,replacements)
261 | Ast0.PLUS count -> Ast.PLUS count
262 | Ast0.CONTEXT(befaft) ->
263 let (befaft,_,_) = !befaft in Ast.CONTEXT(Ast.NoPos,befaft)
264 | Ast0.MIXED(_) -> failwith "not possible for mcode"
265
266 let pos_mcode(term,_,info,mcodekind,pos,adj) =
267 (* avoids a recursion problem *)
268 (term,convert_info info,convert_mcodekind adj mcodekind,Ast.NoMetaPos)
269
270 let mcode (term,_,info,mcodekind,pos,adj) =
271 let pos =
272 match !pos with
273 Ast0.MetaPos(pos,constraints,per) ->
274 Ast.MetaPos(pos_mcode pos,constraints,per,unitary,false)
275 | _ -> Ast.NoMetaPos in
276 (term,convert_info info,convert_mcodekind adj mcodekind,pos)
277
278 (* --------------------------------------------------------------------- *)
279 (* Dots *)
280 let wrap ast line isos =
281 {(Ast.make_term ast) with Ast.node_line = line;
282 Ast.iso_info = isos}
283
284 let rewrap ast0 isos ast =
285 wrap ast ((Ast0.get_info ast0).Ast0.pos_info.Ast0.line_start) isos
286
287 let no_isos = []
288
289 (* no isos on tokens *)
290 let tokenwrap (_,info,_,_) s ast = wrap ast info.Ast.line no_isos
291 let iso_tokenwrap (_,info,_,_) s ast iso = wrap ast info.Ast.line iso
292
293 let dots fn d =
294 rewrap d no_isos
295 (match Ast0.unwrap d with
296 Ast0.DOTS(x) -> Ast.DOTS(List.map fn x)
297 | Ast0.CIRCLES(x) -> Ast.CIRCLES(List.map fn x)
298 | Ast0.STARS(x) -> Ast.STARS(List.map fn x))
299
300 (* --------------------------------------------------------------------- *)
301 (* Identifier *)
302
303 let rec do_isos l = List.map (function (nm,x) -> (nm,anything x)) l
304
305 and ident i =
306 rewrap i (do_isos (Ast0.get_iso i))
307 (match Ast0.unwrap i with
308 Ast0.Id(name) -> Ast.Id(mcode name)
309 | Ast0.MetaId(name,constraints,_) ->
310 Ast.MetaId(mcode name,constraints,unitary,false)
311 | Ast0.MetaFunc(name,constraints,_) ->
312 Ast.MetaFunc(mcode name,constraints,unitary,false)
313 | Ast0.MetaLocalFunc(name,constraints,_) ->
314 Ast.MetaLocalFunc(mcode name,constraints,unitary,false)
315 | Ast0.OptIdent(id) -> Ast.OptIdent(ident id)
316 | Ast0.UniqueIdent(id) -> Ast.UniqueIdent(ident id))
317
318 (* --------------------------------------------------------------------- *)
319 (* Expression *)
320
321 and expression e =
322 let e1 =
323 rewrap e (do_isos (Ast0.get_iso e))
324 (match Ast0.unwrap e with
325 Ast0.Ident(id) -> Ast.Ident(ident id)
326 | Ast0.Constant(const) ->
327 Ast.Constant(mcode const)
328 | Ast0.FunCall(fn,lp,args,rp) ->
329 let fn = expression fn in
330 let lp = mcode lp in
331 let args = dots expression args in
332 let rp = mcode rp in
333 Ast.FunCall(fn,lp,args,rp)
334 | Ast0.Assignment(left,op,right,simple) ->
335 Ast.Assignment(expression left,mcode op,expression right,simple)
336 | Ast0.CondExpr(exp1,why,exp2,colon,exp3) ->
337 let exp1 = expression exp1 in
338 let why = mcode why in
339 let exp2 = get_option expression exp2 in
340 let colon = mcode colon in
341 let exp3 = expression exp3 in
342 Ast.CondExpr(exp1,why,exp2,colon,exp3)
343 | Ast0.Postfix(exp,op) ->
344 Ast.Postfix(expression exp,mcode op)
345 | Ast0.Infix(exp,op) ->
346 Ast.Infix(expression exp,mcode op)
347 | Ast0.Unary(exp,op) ->
348 Ast.Unary(expression exp,mcode op)
349 | Ast0.Binary(left,op,right) ->
350 Ast.Binary(expression left,mcode op,expression right)
351 | Ast0.Nested(left,op,right) ->
352 Ast.Nested(expression left,mcode op,expression right)
353 | Ast0.Paren(lp,exp,rp) ->
354 Ast.Paren(mcode lp,expression exp,mcode rp)
355 | Ast0.ArrayAccess(exp1,lb,exp2,rb) ->
356 Ast.ArrayAccess(expression exp1,mcode lb,expression exp2,mcode rb)
357 | Ast0.RecordAccess(exp,pt,field) ->
358 Ast.RecordAccess(expression exp,mcode pt,ident field)
359 | Ast0.RecordPtAccess(exp,ar,field) ->
360 Ast.RecordPtAccess(expression exp,mcode ar,ident field)
361 | Ast0.Cast(lp,ty,rp,exp) ->
362 Ast.Cast(mcode lp,typeC ty,mcode rp,expression exp)
363 | Ast0.SizeOfExpr(szf,exp) ->
364 Ast.SizeOfExpr(mcode szf,expression exp)
365 | Ast0.SizeOfType(szf,lp,ty,rp) ->
366 Ast.SizeOfType(mcode szf, mcode lp,typeC ty,mcode rp)
367 | Ast0.TypeExp(ty) -> Ast.TypeExp(typeC ty)
368 | Ast0.MetaErr(name,cstrts,_) ->
369 Ast.MetaErr(mcode name,constraints cstrts,unitary,false)
370 | Ast0.MetaExpr(name,cstrts,ty,form,_) ->
371 Ast.MetaExpr(mcode name,constraints cstrts,unitary,ty,form,false)
372 | Ast0.MetaExprList(name,Some lenname,_) ->
373 Ast.MetaExprList(mcode name,Some (mcode lenname,unitary,false),
374 unitary,false)
375 | Ast0.MetaExprList(name,None,_) ->
376 Ast.MetaExprList(mcode name,None,unitary,false)
377 | Ast0.EComma(cm) -> Ast.EComma(mcode cm)
378 | Ast0.DisjExpr(_,exps,_,_) ->
379 Ast.DisjExpr(List.map expression exps)
380 | Ast0.NestExpr(starter,exp_dots,ender,whencode,multi) ->
381 let starter = mcode starter in
382 let whencode = get_option expression whencode in
383 let ender = mcode ender in
384 Ast.NestExpr(starter,dots expression exp_dots,ender,whencode,multi)
385 | Ast0.Edots(dots,whencode) ->
386 let dots = mcode dots in
387 let whencode = get_option expression whencode in
388 Ast.Edots(dots,whencode)
389 | Ast0.Ecircles(dots,whencode) ->
390 let dots = mcode dots in
391 let whencode = get_option expression whencode in
392 Ast.Ecircles(dots,whencode)
393 | Ast0.Estars(dots,whencode) ->
394 let dots = mcode dots in
395 let whencode = get_option expression whencode in
396 Ast.Estars(dots,whencode)
397 | Ast0.OptExp(exp) -> Ast.OptExp(expression exp)
398 | Ast0.UniqueExp(exp) -> Ast.UniqueExp(expression exp)) in
399 if Ast0.get_test_exp e then Ast.set_test_exp e1 else e1
400
401 and expression_dots ed = dots expression ed
402
403 and constraints c =
404 match c with
405 Ast0.NoConstraint -> Ast.NoConstraint
406 | Ast0.NotIdCstrt idctrt -> Ast.NotIdCstrt idctrt
407 | Ast0.NotExpCstrt exps -> Ast.NotExpCstrt (List.map expression exps)
408 | Ast0.SubExpCstrt ids -> Ast.SubExpCstrt ids
409
410 (* --------------------------------------------------------------------- *)
411 (* Types *)
412
413 and rewrap_iso t t1 = rewrap t (do_isos (Ast0.get_iso t)) t1
414
415 and typeC t =
416 rewrap t (do_isos (Ast0.get_iso t))
417 (match Ast0.unwrap t with
418 Ast0.ConstVol(cv,ty) ->
419 let rec collect_disjs t =
420 match Ast0.unwrap t with
421 Ast0.DisjType(_,types,_,_) ->
422 if Ast0.get_iso t = []
423 then List.concat (List.map collect_disjs types)
424 else failwith "unexpected iso on a disjtype"
425 | _ -> [t] in
426 let res =
427 List.map
428 (function ty ->
429 Ast.Type
430 (Some (mcode cv),rewrap_iso ty (base_typeC ty)))
431 (collect_disjs ty) in
432 (* one could worry that isos are lost because we flatten the
433 disjunctions. but there should not be isos on the disjunctions
434 themselves. *)
435 (match res with
436 [ty] -> ty
437 | types -> Ast.DisjType(List.map (rewrap t no_isos) types))
438 | Ast0.BaseType(_) | Ast0.Signed(_,_) | Ast0.Pointer(_,_)
439 | Ast0.FunctionPointer(_,_,_,_,_,_,_) | Ast0.FunctionType(_,_,_,_)
440 | Ast0.Array(_,_,_,_) | Ast0.EnumName(_,_) | Ast0.StructUnionName(_,_)
441 | Ast0.StructUnionDef(_,_,_,_) | Ast0.TypeName(_) | Ast0.MetaType(_,_) ->
442 Ast.Type(None,rewrap t no_isos (base_typeC t))
443 | Ast0.DisjType(_,types,_,_) -> Ast.DisjType(List.map typeC types)
444 | Ast0.OptType(ty) -> Ast.OptType(typeC ty)
445 | Ast0.UniqueType(ty) -> Ast.UniqueType(typeC ty))
446
447 and base_typeC t =
448 match Ast0.unwrap t with
449 Ast0.BaseType(ty,strings) -> Ast.BaseType(ty,List.map mcode strings)
450 | Ast0.Signed(sgn,ty) ->
451 Ast.SignedT(mcode sgn,
452 get_option (function x -> rewrap_iso x (base_typeC x)) ty)
453 | Ast0.Pointer(ty,star) -> Ast.Pointer(typeC ty,mcode star)
454 | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) ->
455 Ast.FunctionPointer
456 (typeC ty,mcode lp1,mcode star,mcode rp1,
457 mcode lp2,parameter_list params,mcode rp2)
458 | Ast0.FunctionType(ret,lp,params,rp) ->
459 let allminus = check_allminus.VT0.combiner_rec_typeC t in
460 Ast.FunctionType
461 (allminus,get_option typeC ret,mcode lp,
462 parameter_list params,mcode rp)
463 | Ast0.Array(ty,lb,size,rb) ->
464 Ast.Array(typeC ty,mcode lb,get_option expression size,mcode rb)
465 | Ast0.EnumName(kind,name) ->
466 Ast.EnumName(mcode kind,ident name)
467 | Ast0.StructUnionName(kind,name) ->
468 Ast.StructUnionName(mcode kind,get_option ident name)
469 | Ast0.StructUnionDef(ty,lb,decls,rb) ->
470 Ast.StructUnionDef(typeC ty,mcode lb,
471 dots declaration decls,
472 mcode rb)
473 | Ast0.TypeName(name) -> Ast.TypeName(mcode name)
474 | Ast0.MetaType(name,_) ->
475 Ast.MetaType(mcode name,unitary,false)
476 | _ -> failwith "ast0toast: unexpected type"
477
478 (* --------------------------------------------------------------------- *)
479 (* Variable declaration *)
480 (* Even if the Cocci program specifies a list of declarations, they are
481 split out into multiple declarations of a single variable each. *)
482
483 and declaration d =
484 rewrap d (do_isos (Ast0.get_iso d))
485 (match Ast0.unwrap d with
486 Ast0.Init(stg,ty,id,eq,ini,sem) ->
487 let stg = get_option mcode stg in
488 let ty = typeC ty in
489 let id = ident id in
490 let eq = mcode eq in
491 let ini = initialiser ini in
492 let sem = mcode sem in
493 Ast.Init(stg,ty,id,eq,ini,sem)
494 | Ast0.UnInit(stg,ty,id,sem) ->
495 (match Ast0.unwrap ty with
496 Ast0.FunctionType(tyx,lp1,params,rp1) ->
497 let allminus = check_allminus.VT0.combiner_rec_declaration d in
498 Ast.UnInit(get_option mcode stg,
499 rewrap ty (do_isos (Ast0.get_iso ty))
500 (Ast.Type
501 (None,
502 rewrap ty no_isos
503 (Ast.FunctionType
504 (allminus,get_option typeC tyx,mcode lp1,
505 parameter_list params,mcode rp1)))),
506 ident id,mcode sem)
507 | _ -> Ast.UnInit(get_option mcode stg,typeC ty,ident id,mcode sem))
508 | Ast0.MacroDecl(name,lp,args,rp,sem) ->
509 let name = ident name in
510 let lp = mcode lp in
511 let args = dots expression args in
512 let rp = mcode rp in
513 let sem = mcode sem in
514 Ast.MacroDecl(name,lp,args,rp,sem)
515 | Ast0.TyDecl(ty,sem) -> Ast.TyDecl(typeC ty,mcode sem)
516 | Ast0.Typedef(stg,ty,id,sem) ->
517 let id = typeC id in
518 (match Ast.unwrap id with
519 Ast.Type(None,id) -> (* only MetaType or Id *)
520 Ast.Typedef(mcode stg,typeC ty,id,mcode sem)
521 | _ -> failwith "bad typedef")
522 | Ast0.DisjDecl(_,decls,_,_) -> Ast.DisjDecl(List.map declaration decls)
523 | Ast0.Ddots(dots,whencode) ->
524 let dots = mcode dots in
525 let whencode = get_option declaration whencode in
526 Ast.Ddots(dots,whencode)
527 | Ast0.OptDecl(decl) -> Ast.OptDecl(declaration decl)
528 | Ast0.UniqueDecl(decl) -> Ast.UniqueDecl(declaration decl))
529
530 and declaration_dots l = dots declaration l
531
532 (* --------------------------------------------------------------------- *)
533 (* Initialiser *)
534
535 and strip_idots initlist =
536 let isminus mc =
537 match Ast0.get_mcode_mcodekind mc with
538 Ast0.MINUS _ -> true
539 | _ -> false in
540 match Ast0.unwrap initlist with
541 Ast0.DOTS(x) ->
542 let (whencode,init,dotinfo) =
543 List.fold_left
544 (function (prevwhen,previnit,dotinfo) ->
545 function cur ->
546 match Ast0.unwrap cur with
547 Ast0.Idots(dots,Some whencode) ->
548 (whencode :: prevwhen, previnit,
549 (isminus dots)::dotinfo)
550 | Ast0.Idots(dots,None) ->
551 (prevwhen, previnit, (isminus dots)::dotinfo)
552 | _ -> (prevwhen, cur :: previnit, dotinfo))
553 ([],[],[]) x in
554 let allminus =
555 if List.for_all (function x -> not x) dotinfo
556 then false (* false if no dots *)
557 else
558 if List.for_all (function x -> x) dotinfo
559 then true
560 else failwith "inconsistent annotations on initialiser list dots" in
561 (List.rev whencode, List.rev init, allminus)
562 | Ast0.CIRCLES(x) | Ast0.STARS(x) -> failwith "not possible for an initlist"
563
564 and initialiser i =
565 rewrap i no_isos
566 (match Ast0.unwrap i with
567 Ast0.MetaInit(name,_) -> Ast.MetaInit(mcode name,unitary,false)
568 | Ast0.InitExpr(exp) -> Ast.InitExpr(expression exp)
569 | Ast0.InitList(lb,initlist,rb) ->
570 let (whencode,initlist,allminus) = strip_idots initlist in
571 Ast.InitList(allminus,mcode lb,List.map initialiser initlist,mcode rb,
572 List.map initialiser whencode)
573 | Ast0.InitGccExt(designators,eq,ini) ->
574 Ast.InitGccExt(List.map designator designators,mcode eq,
575 initialiser ini)
576 | Ast0.InitGccName(name,eq,ini) ->
577 Ast.InitGccName(ident name,mcode eq,initialiser ini)
578 | Ast0.IComma(comma) -> Ast.IComma(mcode comma)
579 | Ast0.Idots(_,_) -> failwith "Idots should have been removed"
580 | Ast0.OptIni(ini) -> Ast.OptIni(initialiser ini)
581 | Ast0.UniqueIni(ini) -> Ast.UniqueIni(initialiser ini))
582
583 and designator = function
584 Ast0.DesignatorField(dot,id) -> Ast.DesignatorField(mcode dot,ident id)
585 | Ast0.DesignatorIndex(lb,exp,rb) ->
586 Ast.DesignatorIndex(mcode lb, expression exp, mcode rb)
587 | Ast0.DesignatorRange(lb,min,dots,max,rb) ->
588 Ast.DesignatorRange(mcode lb,expression min,mcode dots,expression max,
589 mcode rb)
590
591 (* --------------------------------------------------------------------- *)
592 (* Parameter *)
593
594 and parameterTypeDef p =
595 rewrap p no_isos
596 (match Ast0.unwrap p with
597 Ast0.VoidParam(ty) -> Ast.VoidParam(typeC ty)
598 | Ast0.Param(ty,id) -> Ast.Param(typeC ty,get_option ident id)
599 | Ast0.MetaParam(name,_) ->
600 Ast.MetaParam(mcode name,unitary,false)
601 | Ast0.MetaParamList(name,Some lenname,_) ->
602 Ast.MetaParamList(mcode name,Some(mcode lenname,unitary,false),
603 unitary,false)
604 | Ast0.MetaParamList(name,None,_) ->
605 Ast.MetaParamList(mcode name,None,unitary,false)
606 | Ast0.PComma(cm) -> Ast.PComma(mcode cm)
607 | Ast0.Pdots(dots) -> Ast.Pdots(mcode dots)
608 | Ast0.Pcircles(dots) -> Ast.Pcircles(mcode dots)
609 | Ast0.OptParam(param) -> Ast.OptParam(parameterTypeDef param)
610 | Ast0.UniqueParam(param) -> Ast.UniqueParam(parameterTypeDef param))
611
612 and parameter_list l = dots parameterTypeDef l
613
614 (* --------------------------------------------------------------------- *)
615 (* Top-level code *)
616
617 and statement s =
618 let rec statement seqible s =
619 let rewrap_stmt ast0 ast =
620 let befaft =
621 match Ast0.get_dots_bef_aft s with
622 Ast0.NoDots -> Ast.NoDots
623 | Ast0.DroppingBetweenDots s ->
624 Ast.DroppingBetweenDots (statement seqible s,get_ctr())
625 | Ast0.AddingBetweenDots s ->
626 Ast.AddingBetweenDots (statement seqible s,get_ctr()) in
627 Ast.set_dots_bef_aft befaft (rewrap ast0 no_isos ast) in
628 let rewrap_rule_elem ast0 ast =
629 rewrap ast0 (do_isos (Ast0.get_iso ast0)) ast in
630 rewrap_stmt s
631 (match Ast0.unwrap s with
632 Ast0.Decl((_,bef),decl) ->
633 Ast.Atomic(rewrap_rule_elem s
634 (Ast.Decl(convert_mcodekind (-1) bef,
635 check_allminus.VT0.combiner_rec_statement s,
636 declaration decl)))
637 | Ast0.Seq(lbrace,body,rbrace) ->
638 let lbrace = mcode lbrace in
639 let body = dots (statement seqible) body in
640 let rbrace = mcode rbrace in
641 Ast.Seq(iso_tokenwrap lbrace s (Ast.SeqStart(lbrace))
642 (do_isos (Ast0.get_iso s)),
643 body,
644 tokenwrap rbrace s (Ast.SeqEnd(rbrace)))
645 | Ast0.ExprStatement(exp,sem) ->
646 Ast.Atomic(rewrap_rule_elem s
647 (Ast.ExprStatement(expression exp,mcode sem)))
648 | Ast0.IfThen(iff,lp,exp,rp,branch,(_,aft)) ->
649 Ast.IfThen
650 (rewrap_rule_elem s
651 (Ast.IfHeader(mcode iff,mcode lp,expression exp,mcode rp)),
652 statement Ast.NotSequencible branch,
653 ([],[],[],convert_mcodekind (-1) aft))
654 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(_,aft)) ->
655 let els = mcode els in
656 Ast.IfThenElse
657 (rewrap_rule_elem s
658 (Ast.IfHeader(mcode iff,mcode lp,expression exp,mcode rp)),
659 statement Ast.NotSequencible branch1,
660 tokenwrap els s (Ast.Else(els)),
661 statement Ast.NotSequencible branch2,
662 ([],[],[],convert_mcodekind (-1) aft))
663 | Ast0.While(wh,lp,exp,rp,body,(_,aft)) ->
664 Ast.While(rewrap_rule_elem s
665 (Ast.WhileHeader
666 (mcode wh,mcode lp,expression exp,mcode rp)),
667 statement Ast.NotSequencible body,
668 ([],[],[],convert_mcodekind (-1) aft))
669 | Ast0.Do(d,body,wh,lp,exp,rp,sem) ->
670 let wh = mcode wh in
671 Ast.Do(rewrap_rule_elem s (Ast.DoHeader(mcode d)),
672 statement Ast.NotSequencible body,
673 tokenwrap wh s
674 (Ast.WhileTail(wh,mcode lp,expression exp,mcode rp,
675 mcode sem)))
676 | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,(_,aft)) ->
677 let fr = mcode fr in
678 let lp = mcode lp in
679 let exp1 = get_option expression exp1 in
680 let sem1 = mcode sem1 in
681 let exp2 = get_option expression exp2 in
682 let sem2= mcode sem2 in
683 let exp3 = get_option expression exp3 in
684 let rp = mcode rp in
685 let body = statement Ast.NotSequencible body in
686 Ast.For(rewrap_rule_elem s
687 (Ast.ForHeader(fr,lp,exp1,sem1,exp2,sem2,exp3,rp)),
688 body,([],[],[],convert_mcodekind (-1) aft))
689 | Ast0.Iterator(nm,lp,args,rp,body,(_,aft)) ->
690 Ast.Iterator(rewrap_rule_elem s
691 (Ast.IteratorHeader
692 (ident nm,mcode lp,
693 dots expression args,
694 mcode rp)),
695 statement Ast.NotSequencible body,
696 ([],[],[],convert_mcodekind (-1) aft))
697 | Ast0.Switch(switch,lp,exp,rp,lb,decls,cases,rb) ->
698 let switch = mcode switch in
699 let lp = mcode lp in
700 let exp = expression exp in
701 let rp = mcode rp in
702 let lb = mcode lb in
703 let decls = dots (statement seqible) decls in
704 let cases = List.map case_line (Ast0.undots cases) in
705 let rb = mcode rb in
706 Ast.Switch(rewrap_rule_elem s (Ast.SwitchHeader(switch,lp,exp,rp)),
707 tokenwrap lb s (Ast.SeqStart(lb)),
708 decls,cases,
709 tokenwrap rb s (Ast.SeqEnd(rb)))
710 | Ast0.Break(br,sem) ->
711 Ast.Atomic(rewrap_rule_elem s (Ast.Break(mcode br,mcode sem)))
712 | Ast0.Continue(cont,sem) ->
713 Ast.Atomic(rewrap_rule_elem s (Ast.Continue(mcode cont,mcode sem)))
714 | Ast0.Label(l,dd) ->
715 Ast.Atomic(rewrap_rule_elem s (Ast.Label(ident l,mcode dd)))
716 | Ast0.Goto(goto,l,sem) ->
717 Ast.Atomic
718 (rewrap_rule_elem s (Ast.Goto(mcode goto,ident l,mcode sem)))
719 | Ast0.Return(ret,sem) ->
720 Ast.Atomic(rewrap_rule_elem s (Ast.Return(mcode ret,mcode sem)))
721 | Ast0.ReturnExpr(ret,exp,sem) ->
722 Ast.Atomic
723 (rewrap_rule_elem s
724 (Ast.ReturnExpr(mcode ret,expression exp,mcode sem)))
725 | Ast0.MetaStmt(name,_) ->
726 Ast.Atomic(rewrap_rule_elem s
727 (Ast.MetaStmt(mcode name,unitary,seqible,false)))
728 | Ast0.MetaStmtList(name,_) ->
729 Ast.Atomic(rewrap_rule_elem s
730 (Ast.MetaStmtList(mcode name,unitary,false)))
731 | Ast0.TopExp(exp) ->
732 Ast.Atomic(rewrap_rule_elem s (Ast.TopExp(expression exp)))
733 | Ast0.Exp(exp) ->
734 Ast.Atomic(rewrap_rule_elem s (Ast.Exp(expression exp)))
735 | Ast0.TopInit(init) ->
736 Ast.Atomic(rewrap_rule_elem s (Ast.TopInit(initialiser init)))
737 | Ast0.Ty(ty) ->
738 Ast.Atomic(rewrap_rule_elem s (Ast.Ty(typeC ty)))
739 | Ast0.Disj(_,rule_elem_dots_list,_,_) ->
740 Ast.Disj(List.map (function x -> statement_dots seqible x)
741 rule_elem_dots_list)
742 | Ast0.Nest(starter,rule_elem_dots,ender,whn,multi) ->
743 Ast.Nest
744 (mcode starter,statement_dots Ast.Sequencible rule_elem_dots,
745 mcode ender,
746 List.map
747 (whencode (statement_dots Ast.Sequencible)
748 (statement Ast.NotSequencible))
749 whn,
750 multi,[],[])
751 | Ast0.Dots(d,whn) ->
752 let d = mcode d in
753 let whn =
754 List.map
755 (whencode (statement_dots Ast.Sequencible)
756 (statement Ast.NotSequencible))
757 whn in
758 Ast.Dots(d,whn,[],[])
759 | Ast0.Circles(d,whn) ->
760 let d = mcode d in
761 let whn =
762 List.map
763 (whencode (statement_dots Ast.Sequencible)
764 (statement Ast.NotSequencible))
765 whn in
766 Ast.Circles(d,whn,[],[])
767 | Ast0.Stars(d,whn) ->
768 let d = mcode d in
769 let whn =
770 List.map
771 (whencode (statement_dots Ast.Sequencible)
772 (statement Ast.NotSequencible))
773 whn in
774 Ast.Stars(d,whn,[],[])
775 | Ast0.FunDecl((_,bef),fi,name,lp,params,rp,lbrace,body,rbrace) ->
776 let fi = List.map fninfo fi in
777 let name = ident name in
778 let lp = mcode lp in
779 let params = parameter_list params in
780 let rp = mcode rp in
781 let lbrace = mcode lbrace in
782 let body = dots (statement seqible) body in
783 let rbrace = mcode rbrace in
784 let allminus = check_allminus.VT0.combiner_rec_statement s in
785 Ast.FunDecl(rewrap_rule_elem s
786 (Ast.FunHeader(convert_mcodekind (-1) bef,
787 allminus,fi,name,lp,params,rp)),
788 tokenwrap lbrace s (Ast.SeqStart(lbrace)),
789 body,
790 tokenwrap rbrace s (Ast.SeqEnd(rbrace)))
791 | Ast0.Include(inc,str) ->
792 Ast.Atomic(rewrap_rule_elem s (Ast.Include(mcode inc,mcode str)))
793 | Ast0.Define(def,id,params,body) ->
794 Ast.Define
795 (rewrap_rule_elem s
796 (Ast.DefineHeader
797 (mcode def,ident id, define_parameters params)),
798 statement_dots Ast.NotSequencible (*not sure*) body)
799 | Ast0.OptStm(stm) -> Ast.OptStm(statement seqible stm)
800 | Ast0.UniqueStm(stm) -> Ast.UniqueStm(statement seqible stm))
801
802 and define_parameters p =
803 rewrap p no_isos
804 (match Ast0.unwrap p with
805 Ast0.NoParams -> Ast.NoParams
806 | Ast0.DParams(lp,params,rp) ->
807 Ast.DParams(mcode lp,
808 dots define_param params,
809 mcode rp))
810
811 and define_param p =
812 rewrap p no_isos
813 (match Ast0.unwrap p with
814 Ast0.DParam(id) -> Ast.DParam(ident id)
815 | Ast0.DPComma(comma) -> Ast.DPComma(mcode comma)
816 | Ast0.DPdots(d) -> Ast.DPdots(mcode d)
817 | Ast0.DPcircles(c) -> Ast.DPcircles(mcode c)
818 | Ast0.OptDParam(dp) -> Ast.OptDParam(define_param dp)
819 | Ast0.UniqueDParam(dp) -> Ast.UniqueDParam(define_param dp))
820
821 and whencode notfn alwaysfn = function
822 Ast0.WhenNot a -> Ast.WhenNot (notfn a)
823 | Ast0.WhenAlways a -> Ast.WhenAlways (alwaysfn a)
824 | Ast0.WhenModifier(x) -> Ast.WhenModifier(x)
825 | x ->
826 let rewrap_rule_elem ast0 ast =
827 rewrap ast0 (do_isos (Ast0.get_iso ast0)) ast in
828 match x with
829 Ast0.WhenNotTrue(e) ->
830 Ast.WhenNotTrue(rewrap_rule_elem e (Ast.Exp(expression e)))
831 | Ast0.WhenNotFalse(e) ->
832 Ast.WhenNotFalse(rewrap_rule_elem e (Ast.Exp(expression e)))
833 | _ -> failwith "not possible"
834
835 and process_list seqible isos = function
836 [] -> []
837 | x::rest ->
838 let first = statement seqible x in
839 let first =
840 if !Flag.track_iso_usage
841 then Ast.set_isos first (isos@(Ast.get_isos first))
842 else first in
843 (match Ast0.unwrap x with
844 Ast0.Dots(_,_) | Ast0.Nest(_) ->
845 first::(process_list (Ast.SequencibleAfterDots []) no_isos rest)
846 | _ ->
847 first::(process_list Ast.Sequencible no_isos rest))
848
849 and statement_dots seqible d =
850 let isos = do_isos (Ast0.get_iso d) in
851 rewrap d no_isos
852 (match Ast0.unwrap d with
853 Ast0.DOTS(x) -> Ast.DOTS(process_list seqible isos x)
854 | Ast0.CIRCLES(x) -> Ast.CIRCLES(process_list seqible isos x)
855 | Ast0.STARS(x) -> Ast.STARS(process_list seqible isos x))
856
857 (* the following is no longer used.
858 the goal was to let one put a statement at the very beginning of a function
859 pattern and have it skip over the declarations in the C code.
860 that feature was removed a long time ago, however, in favor of
861 ... when != S, which also causes whatever comes after it to match the
862 first real statement.
863 the separation of declarations from the rest of the body means that the
864 quantifier of any variable shared between them comes out too high, posing
865 problems when there is ... decl ... stmt, as the quantifier of any shared
866 variable will be around the whole thing, making variables not free enough
867 in the first ..., and thus not implementing the expected shortest path
868 condition. example: f() { ... int A; ... foo(A); }.
869 the quantifier for A should start just before int A, not at the top of the
870 function.
871 and separate_decls seqible d =
872 let rec collect_decls = function
873 [] -> ([],[])
874 | (x::xs) as l ->
875 (match Ast0.unwrap x with
876 Ast0.Decl(_) ->
877 let (decls,other) = collect_decls xs in
878 (x :: decls,other)
879 | Ast0.Dots(_,_) | Ast0.Nest(_,_,_,_,_) ->
880 let (decls,other) = collect_decls xs in
881 (match decls with
882 [] -> ([],x::other)
883 | _ -> (x :: decls,other))
884 | Ast0.Disj(starter,stmt_dots_list,mids,ender) ->
885 let disjs = List.map collect_dot_decls stmt_dots_list in
886 let all_decls = List.for_all (function (_,s) -> s=[]) disjs in
887 if all_decls
888 then
889 let (decls,other) = collect_decls xs in
890 (x :: decls,other)
891 else ([],l)
892 | _ -> ([],l))
893
894 and collect_dot_decls d =
895 match Ast0.unwrap d with
896 Ast0.DOTS(x) -> collect_decls x
897 | Ast0.CIRCLES(x) -> collect_decls x
898 | Ast0.STARS(x) -> collect_decls x in
899
900 let process l d fn =
901 let (decls,other) = collect_decls l in
902 (rewrap d no_isos (fn (List.map (statement seqible) decls)),
903 rewrap d no_isos
904 (fn (process_list seqible (do_isos (Ast0.get_iso d)) other))) in
905 match Ast0.unwrap d with
906 Ast0.DOTS(x) -> process x d (function x -> Ast.DOTS x)
907 | Ast0.CIRCLES(x) -> process x d (function x -> Ast.CIRCLES x)
908 | Ast0.STARS(x) -> process x d (function x -> Ast.STARS x) *) in
909
910 statement Ast.Sequencible s
911
912 and fninfo = function
913 Ast0.FStorage(stg) -> Ast.FStorage(mcode stg)
914 | Ast0.FType(ty) -> Ast.FType(typeC ty)
915 | Ast0.FInline(inline) -> Ast.FInline(mcode inline)
916 | Ast0.FAttr(attr) -> Ast.FAttr(mcode attr)
917
918 and option_to_list = function
919 Some x -> [x]
920 | None -> []
921
922 and case_line c =
923 rewrap c no_isos
924 (match Ast0.unwrap c with
925 Ast0.Default(def,colon,code) ->
926 let def = mcode def in
927 let colon = mcode colon in
928 let code = dots statement code in
929 Ast.CaseLine(rewrap c no_isos (Ast.Default(def,colon)),code)
930 | Ast0.Case(case,exp,colon,code) ->
931 let case = mcode case in
932 let exp = expression exp in
933 let colon = mcode colon in
934 let code = dots statement code in
935 Ast.CaseLine(rewrap c no_isos (Ast.Case(case,exp,colon)),code)
936 | Ast0.DisjCase(_,case_lines,_,_) ->
937 failwith "not supported"
938 (*Ast.CaseLine(Ast.DisjRuleElem(List.map case_line case_lines))*)
939
940 | Ast0.OptCase(case) -> Ast.OptCase(case_line case))
941
942 and statement_dots l = dots statement l
943
944 (* --------------------------------------------------------------------- *)
945
946 (* what is possible is only what is at the top level in an iso *)
947 and anything = function
948 Ast0.DotsExprTag(d) -> Ast.ExprDotsTag(expression_dots d)
949 | Ast0.DotsParamTag(d) -> Ast.ParamDotsTag(parameter_list d)
950 | Ast0.DotsInitTag(d) -> failwith "not possible"
951 | Ast0.DotsStmtTag(d) -> Ast.StmtDotsTag(statement_dots d)
952 | Ast0.DotsDeclTag(d) -> Ast.DeclDotsTag(declaration_dots d)
953 | Ast0.DotsCaseTag(d) -> failwith "not possible"
954 | Ast0.IdentTag(d) -> Ast.IdentTag(ident d)
955 | Ast0.ExprTag(d) -> Ast.ExpressionTag(expression d)
956 | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) ->
957 failwith "only in isos, not converted to ast"
958 | Ast0.TypeCTag(d) -> Ast.FullTypeTag(typeC d)
959 | Ast0.ParamTag(d) -> Ast.ParamTag(parameterTypeDef d)
960 | Ast0.InitTag(d) -> Ast.InitTag(initialiser d)
961 | Ast0.DeclTag(d) -> Ast.DeclarationTag(declaration d)
962 | Ast0.StmtTag(d) -> Ast.StatementTag(statement d)
963 | Ast0.CaseLineTag(d) -> Ast.CaseLineTag(case_line d)
964 | Ast0.TopTag(d) -> Ast.Code(top_level d)
965 | Ast0.IsoWhenTag(_) -> failwith "not possible"
966 | Ast0.IsoWhenTTag(_) -> failwith "not possible"
967 | Ast0.IsoWhenFTag(_) -> failwith "not possible"
968 | Ast0.MetaPosTag _ -> failwith "not possible"
969
970 (* --------------------------------------------------------------------- *)
971 (* Function declaration *)
972 (* top level isos are probably lost to tracking *)
973
974 and top_level t =
975 rewrap t no_isos
976 (match Ast0.unwrap t with
977 Ast0.FILEINFO(old_file,new_file) ->
978 Ast.FILEINFO(mcode old_file,mcode new_file)
979 | Ast0.DECL(stmt) -> Ast.DECL(statement stmt)
980 | Ast0.CODE(rule_elem_dots) ->
981 Ast.CODE(statement_dots rule_elem_dots)
982 | Ast0.ERRORWORDS(exps) -> Ast.ERRORWORDS(List.map expression exps)
983 | Ast0.OTHER(_) -> failwith "eliminated by top_level")
984
985 (* --------------------------------------------------------------------- *)
986 (* Entry point for minus code *)
987
988 (* Inline_mcodes is very important - sends + code attached to the - code
989 down to the mcodes. The functions above can only be used when there is no
990 attached + code, eg in + code itself. *)
991 let ast0toast_toplevel x =
992 inline_mcodes.VT0.combiner_rec_top_level x;
993 top_level x
994
995 let ast0toast name deps dropped exists x is_exp ruletype =
996 List.iter inline_mcodes.VT0.combiner_rec_top_level x;
997 Ast.CocciRule
998 (name,(deps,dropped,exists),List.map top_level x,is_exp,ruletype)