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