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