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.
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.
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.
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/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
25 (* Arities matter for the minus slice, but not for the plus slice. *)
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. *)
30 module Ast0
= Ast0_cocci
31 module Ast
= Ast_cocci
32 module V0
= Visitor_ast0
33 module VT0
= Visitor_ast0_types
35 let unitary = Type_cocci.Unitary
43 (* --------------------------------------------------------------------- *)
44 (* Move plus tokens from the MINUS and CONTEXT structured nodes to the
45 corresponding leftmost and rightmost mcodes *)
49 let option_default = () in
51 let do_nothing r k e
=
53 let einfo = Ast0.get_info e
in
54 match (Ast0.get_mcodekind e
) with
55 Ast0.MINUS
(replacements
) ->
56 (match !replacements
with
59 let minus_try = function
63 Ast0.MINUS
(mreplacements
) -> true | _
-> false)
68 Ast0.MINUS
(mreplacements
) ->
69 mreplacements
:= replacements
75 if not
(minus_try(einfo.Ast0.attachable_start
,
76 einfo.Ast0.mcode_start
)
78 minus_try(einfo.Ast0.attachable_end
,
79 einfo.Ast0.mcode_end
))
81 failwith
"minus tree should not have bad code on both sides")
82 | Ast0.CONTEXT
(befaft
)
83 | Ast0.MIXED
(befaft
) ->
84 let concat starter startinfo ender endinfo
=
86 match (starter
,ender
) with
90 if startinfo
.Ast0.tline_end
= endinfo
.Ast0.tline_start
91 then (* put them in the same inner list *)
92 let last = List.hd
(List.rev starter
) in
93 let butlast = List.rev
(List.tl
(List.rev starter
)) in
94 butlast @ (last@(List.hd ender
)) :: (List.tl ender
)
95 else starter
@ ender
in
97 {endinfo
with Ast0.tline_start
= startinfo
.Ast0.tline_start
}) in
98 let attach_bef bef beforeinfo befit
= function
102 Ast0.MINUS
(mreplacements
) ->
103 let (mrepl
,tokeninfo
) = !mreplacements
in
104 mreplacements
:= concat bef beforeinfo mrepl tokeninfo
105 | Ast0.CONTEXT
(mbefaft
) ->
107 (Ast.BEFORE
(mbef
,it
),mbeforeinfo
,a
) ->
108 let (newbef
,newinfo
) =
109 concat bef beforeinfo mbef mbeforeinfo
in
110 let it = Ast.lub_count befit
it in
111 mbefaft
:= (Ast.BEFORE
(newbef
,it),newinfo
,a
)
112 | (Ast.AFTER
(maft
,it),_
,a
) ->
113 let it = Ast.lub_count befit
it in
115 (Ast.BEFOREAFTER
(bef
,maft
,it),beforeinfo
,a
)
116 | (Ast.BEFOREAFTER
(mbef
,maft
,it),mbeforeinfo
,a
) ->
117 let (newbef
,newinfo
) =
118 concat bef beforeinfo mbef mbeforeinfo
in
119 let it = Ast.lub_count befit
it in
121 (Ast.BEFOREAFTER
(newbef
,maft
,it),newinfo
,a
)
122 | (Ast.NOTHING
,_
,a
) ->
124 (Ast.BEFORE
(bef
,befit
),beforeinfo
,a
))
125 | _
-> failwith
"unexpected annotation")
128 Printf.printf
"before %s\n" (Dumper.dump bef
);
130 "context tree should not have bad code before" in
131 let attach_aft aft afterinfo aftit
= function
135 Ast0.MINUS
(mreplacements
) ->
136 let (mrepl
,tokeninfo
) = !mreplacements
in
137 mreplacements
:= concat mrepl tokeninfo aft afterinfo
138 | Ast0.CONTEXT
(mbefaft
) ->
140 (Ast.BEFORE
(mbef
,it),b
,_
) ->
141 let it = Ast.lub_count aftit
it in
143 (Ast.BEFOREAFTER
(mbef
,aft
,it),b
,afterinfo
)
144 | (Ast.AFTER
(maft
,it),b
,mafterinfo
) ->
145 let (newaft
,newinfo
) =
146 concat maft mafterinfo aft afterinfo
in
147 let it = Ast.lub_count aftit
it in
148 mbefaft
:= (Ast.AFTER
(newaft
,it),b
,newinfo
)
149 | (Ast.BEFOREAFTER
(mbef
,maft
,it),b
,mafterinfo
) ->
150 let (newaft
,newinfo
) =
151 concat maft mafterinfo aft afterinfo
in
152 let it = Ast.lub_count aftit
it in
154 (Ast.BEFOREAFTER
(mbef
,newaft
,it),b
,newinfo
)
155 | (Ast.NOTHING
,b
,_
) ->
156 mbefaft
:= (Ast.AFTER
(aft
,aftit
),b
,afterinfo
))
157 | _
-> failwith
"unexpected annotation")
161 "context tree should not have bad code after" in
163 (Ast.BEFORE
(bef
,it),beforeinfo
,_
) ->
164 attach_bef bef beforeinfo
it
165 (einfo.Ast0.attachable_start
,einfo.Ast0.mcode_start
)
166 | (Ast.AFTER
(aft
,it),_
,afterinfo
) ->
167 attach_aft aft afterinfo
it
168 (einfo.Ast0.attachable_end
,einfo.Ast0.mcode_end
)
169 | (Ast.BEFOREAFTER
(bef
,aft
,it),beforeinfo
,afterinfo
) ->
170 attach_bef bef beforeinfo
it
171 (einfo.Ast0.attachable_start
,einfo.Ast0.mcode_start
);
172 attach_aft aft afterinfo
it
173 (einfo.Ast0.attachable_end
,einfo.Ast0.mcode_end
)
174 | (Ast.NOTHING
,_
,_
) -> ())
175 | Ast0.PLUS _
-> () in
176 V0.flat_combiner
bind option_default
177 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
179 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
180 do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
181 do_nothing do_nothing do_nothing
183 (* --------------------------------------------------------------------- *)
184 (* For function declarations. Can't use the mcode at the root, because that
185 might be mixed when the function contains ()s, where agglomeration of -s is
189 let donothing r k e
= k e
in
190 let bind x y
= x
&& y
in
191 let option_default = true in
192 let mcode (_
,_
,_
,mc
,_
,_
) =
194 Ast0.MINUS
(r
) -> let (plusses
,_
) = !r
in plusses
= []
197 (* special case for disj *)
199 match Ast0.unwrap e
with
200 Ast0.DisjId
(starter
,id_list
,mids
,ender
) ->
201 List.for_all r
.VT0.combiner_rec_ident id_list
204 let expression r k e
=
205 match Ast0.unwrap e
with
206 Ast0.DisjExpr
(starter
,expr_list
,mids
,ender
) ->
207 List.for_all r
.VT0.combiner_rec_expression expr_list
210 let declaration r k e
=
211 match Ast0.unwrap e
with
212 Ast0.DisjDecl
(starter
,decls
,mids
,ender
) ->
213 List.for_all r
.VT0.combiner_rec_declaration decls
217 match Ast0.unwrap e
with
218 Ast0.DisjType
(starter
,decls
,mids
,ender
) ->
219 List.for_all r
.VT0.combiner_rec_typeC decls
222 let statement r k e
=
223 match Ast0.unwrap e
with
224 Ast0.Disj
(starter
,statement_dots_list
,mids
,ender
) ->
225 List.for_all r
.VT0.combiner_rec_statement_dots statement_dots_list
228 let case_line r k e
=
229 match Ast0.unwrap e
with
230 Ast0.DisjCase
(starter
,case_lines
,mids
,ender
) ->
231 List.for_all r
.VT0.combiner_rec_case_line case_lines
234 V0.flat_combiner
bind option_default
235 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
237 donothing donothing donothing donothing donothing donothing
238 ident expression typeC donothing donothing declaration
239 statement case_line donothing
241 (* --------------------------------------------------------------------- *)
242 (* --------------------------------------------------------------------- *)
244 let get_option fn
= function
246 | Some x
-> Some
(fn x
)
248 (* --------------------------------------------------------------------- *)
249 (* --------------------------------------------------------------------- *)
252 let convert_info info
=
255 (function (s
,info
) -> (s
,info
.Ast0.line_start
,info
.Ast0.column
))
257 { Ast.line
= info
.Ast0.pos_info
.Ast0.line_start
;
258 Ast.column
= info
.Ast0.pos_info
.Ast0.column
;
259 Ast.strbef
= strings_to_s info
.Ast0.strings_before
;
260 Ast.straft
= strings_to_s info
.Ast0.strings_after
;}
262 let convert_mcodekind adj
= function
263 Ast0.MINUS
(replacements
) ->
264 let (replacements
,_
) = !replacements
in
265 Ast.MINUS
(Ast.NoPos
,[],adj
,replacements
)
266 | Ast0.PLUS count
-> Ast.PLUS count
267 | Ast0.CONTEXT
(befaft
) ->
268 let (befaft
,_
,_
) = !befaft
in Ast.CONTEXT
(Ast.NoPos
,befaft
)
269 | Ast0.MIXED
(_
) -> failwith
"not possible for mcode"
271 let pos_mcode(term
,_
,info
,mcodekind
,pos
,adj
) =
272 (* avoids a recursion problem *)
273 (term
,convert_info info
,convert_mcodekind adj mcodekind
,Ast.NoMetaPos
)
275 let mcode (term
,_
,info
,mcodekind
,pos
,adj
) =
278 Ast0.MetaPos
(pos,constraints
,per
) ->
279 Ast.MetaPos
(pos_mcode pos,constraints
,per
,unitary,false)
280 | _
-> Ast.NoMetaPos
in
281 (term
,convert_info info
,convert_mcodekind adj mcodekind
,pos)
283 (* --------------------------------------------------------------------- *)
285 let wrap ast line isos
=
286 {(Ast.make_term ast
) with Ast.node_line
= line
;
289 let rewrap ast0 isos ast
=
290 wrap ast
((Ast0.get_info ast0
).Ast0.pos_info
.Ast0.line_start
) isos
294 (* no isos on tokens *)
295 let tokenwrap (_
,info
,_
,_
) s ast
= wrap ast info
.Ast.line
no_isos
296 let iso_tokenwrap (_
,info
,_
,_
) s ast iso
= wrap ast info
.Ast.line iso
300 (match Ast0.unwrap d
with
301 Ast0.DOTS
(x
) -> Ast.DOTS
(List.map fn x
)
302 | Ast0.CIRCLES
(x
) -> Ast.CIRCLES
(List.map fn x
)
303 | Ast0.STARS
(x
) -> Ast.STARS
(List.map fn x
))
305 (* commas in dotted lists, here due to polymorphism restrictions *)
307 let add_comma is_comma make_comma itemlist
=
308 match Ast0.unwrap itemlist
with
310 (match List.rev x
with
317 match Ast0.get_mcodekind e
with
318 Ast0.MINUS
(_
) -> (Ast0.make_minus_mcode
",")
319 | _
-> (Ast0.make_mcode
",") in
322 (List.rev
(Ast0.rewrap e
(make_comma
comma) :: (e
::es
)))))
323 | _
-> failwith
"not possible"
327 (function x
-> match Ast0.unwrap x
with Ast0.EComma _
-> true | _
-> false)
328 (function x
-> Ast0.EComma x
)
332 (function x
-> match Ast0.unwrap x
with Ast0.IComma _
-> true | _
-> false)
333 (function x
-> Ast0.IComma x
)
335 (* --------------------------------------------------------------------- *)
338 let rec do_isos l
= List.map
(function (nm
,x
) -> (nm
,anything x
)) l
341 rewrap i
(do_isos (Ast0.get_iso i
))
342 (match Ast0.unwrap i
with
343 Ast0.Id
(name
) -> Ast.Id
(mcode name
)
344 | Ast0.DisjId
(_
,id_list
,_
,_
) ->
345 Ast.DisjId
(List.map
ident id_list
)
346 | Ast0.MetaId
(name
,constraints
,_
) ->
347 Ast.MetaId
(mcode name
,constraints
,unitary,false)
348 | Ast0.MetaFunc
(name
,constraints
,_
) ->
349 Ast.MetaFunc
(mcode name
,constraints
,unitary,false)
350 | Ast0.MetaLocalFunc
(name
,constraints
,_
) ->
351 Ast.MetaLocalFunc
(mcode name
,constraints
,unitary,false)
352 | Ast0.OptIdent
(id
) -> Ast.OptIdent
(ident id
)
353 | Ast0.UniqueIdent
(id
) -> Ast.UniqueIdent
(ident id
))
355 (* --------------------------------------------------------------------- *)
360 rewrap e
(do_isos (Ast0.get_iso e
))
361 (match Ast0.unwrap e
with
362 Ast0.Ident
(id
) -> Ast.Ident
(ident id
)
363 | Ast0.Constant
(const
) ->
364 Ast.Constant
(mcode const
)
365 | Ast0.FunCall
(fn
,lp
,args
,rp
) ->
366 let fn = expression fn in
368 let args = dots expression args in
370 Ast.FunCall
(fn,lp,args,rp)
371 | Ast0.Assignment
(left
,op
,right
,simple
) ->
372 Ast.Assignment
(expression left
,mcode op
,expression right
,simple
)
373 | Ast0.CondExpr
(exp1
,why
,exp2
,colon
,exp3
) ->
374 let exp1 = expression exp1 in
375 let why = mcode why in
376 let exp2 = get_option expression exp2 in
377 let colon = mcode colon in
378 let exp3 = expression exp3 in
379 Ast.CondExpr
(exp1,why,exp2,colon,exp3)
380 | Ast0.Postfix
(exp
,op
) ->
381 Ast.Postfix
(expression exp
,mcode op
)
382 | Ast0.Infix
(exp
,op
) ->
383 Ast.Infix
(expression exp
,mcode op
)
384 | Ast0.Unary
(exp
,op
) ->
385 Ast.Unary
(expression exp
,mcode op
)
386 | Ast0.Binary
(left
,op
,right
) ->
387 Ast.Binary
(expression left
,mcode op
,expression right
)
388 | Ast0.Nested
(left
,op
,right
) ->
389 Ast.Nested
(expression left
,mcode op
,expression right
)
390 | Ast0.Paren
(lp,exp
,rp) ->
391 Ast.Paren
(mcode lp,expression exp
,mcode rp)
392 | Ast0.ArrayAccess
(exp1,lb
,exp2,rb
) ->
393 Ast.ArrayAccess
(expression exp1,mcode lb
,expression exp2,mcode rb
)
394 | Ast0.RecordAccess
(exp
,pt
,field
) ->
395 Ast.RecordAccess
(expression exp
,mcode pt
,ident field
)
396 | Ast0.RecordPtAccess
(exp
,ar
,field
) ->
397 Ast.RecordPtAccess
(expression exp
,mcode ar
,ident field
)
398 | Ast0.Cast
(lp,ty
,rp,exp
) ->
399 Ast.Cast
(mcode lp,typeC ty
,mcode rp,expression exp
)
400 | Ast0.SizeOfExpr
(szf
,exp
) ->
401 Ast.SizeOfExpr
(mcode szf
,expression exp
)
402 | Ast0.SizeOfType
(szf
,lp,ty
,rp) ->
403 Ast.SizeOfType
(mcode szf
, mcode lp,typeC ty
,mcode rp)
404 | Ast0.TypeExp
(ty
) -> Ast.TypeExp
(typeC ty
)
405 | Ast0.MetaErr
(name
,cstrts
,_
) ->
406 Ast.MetaErr
(mcode name
,constraints cstrts
,unitary,false)
407 | Ast0.MetaExpr
(name
,cstrts
,ty
,form
,_
) ->
408 Ast.MetaExpr
(mcode name
,constraints cstrts
,unitary,ty
,form
,false)
409 | Ast0.MetaExprList
(name
,lenname
,_
) ->
410 Ast.MetaExprList
(mcode name
,do_lenname lenname
,unitary,false)
411 | Ast0.EComma
(cm
) -> Ast.EComma
(mcode cm
)
412 | Ast0.DisjExpr
(_
,exps
,_
,_
) ->
413 Ast.DisjExpr
(List.map
expression exps
)
414 | Ast0.NestExpr
(starter
,exp_dots
,ender
,whencode
,multi
) ->
415 let starter = mcode starter in
416 let whencode = get_option expression whencode in
417 let ender = mcode ender in
418 Ast.NestExpr
(starter,dots expression exp_dots
,ender,whencode,multi
)
419 | Ast0.Edots
(dots,whencode) ->
420 let dots = mcode dots in
421 let whencode = get_option expression whencode in
422 Ast.Edots
(dots,whencode)
423 | Ast0.Ecircles
(dots,whencode) ->
424 let dots = mcode dots in
425 let whencode = get_option expression whencode in
426 Ast.Ecircles
(dots,whencode)
427 | Ast0.Estars
(dots,whencode) ->
428 let dots = mcode dots in
429 let whencode = get_option expression whencode in
430 Ast.Estars
(dots,whencode)
431 | Ast0.OptExp
(exp
) -> Ast.OptExp
(expression exp
)
432 | Ast0.UniqueExp
(exp
) -> Ast.UniqueExp
(expression exp
)) in
433 if Ast0.get_test_exp e
then Ast.set_test_exp
e1 else e1
435 and expression_dots ed
= dots expression ed
439 Ast0.NoConstraint
-> Ast.NoConstraint
440 | Ast0.NotIdCstrt idctrt
-> Ast.NotIdCstrt idctrt
441 | Ast0.NotExpCstrt exps
-> Ast.NotExpCstrt
(List.map
expression exps
)
442 | Ast0.SubExpCstrt ids
-> Ast.SubExpCstrt ids
444 and do_lenname
= function
445 Ast0.MetaListLen
(nm
) -> Ast.MetaListLen
(mcode nm
,unitary,false)
446 | Ast0.CstListLen n
-> Ast.CstListLen n
447 | Ast0.AnyListLen
-> Ast.AnyListLen
449 (* --------------------------------------------------------------------- *)
452 and rewrap_iso t t1
= rewrap t
(do_isos (Ast0.get_iso t
)) t1
455 rewrap t
(do_isos (Ast0.get_iso t
))
456 (match Ast0.unwrap t
with
457 Ast0.ConstVol
(cv
,ty
) ->
458 let rec collect_disjs t
=
459 match Ast0.unwrap t
with
460 Ast0.DisjType
(_
,types
,_
,_
) ->
461 if Ast0.get_iso t
= []
462 then List.concat (List.map
collect_disjs types
)
463 else failwith
"unexpected iso on a disjtype"
469 (Some
(mcode cv
),rewrap_iso ty
(base_typeC ty
)))
470 (collect_disjs ty
) in
471 (* one could worry that isos are lost because we flatten the
472 disjunctions. but there should not be isos on the disjunctions
476 | types
-> Ast.DisjType
(List.map
(rewrap t
no_isos) types
))
477 | Ast0.BaseType
(_
) | Ast0.Signed
(_
,_
) | Ast0.Pointer
(_
,_
)
478 | Ast0.FunctionPointer
(_
,_
,_
,_
,_
,_
,_
) | Ast0.FunctionType
(_
,_
,_
,_
)
479 | Ast0.Array
(_
,_
,_
,_
) | Ast0.EnumName
(_
,_
) | Ast0.StructUnionName
(_
,_
)
480 | Ast0.StructUnionDef
(_
,_
,_
,_
) | Ast0.EnumDef
(_
,_
,_
,_
)
481 | Ast0.TypeName
(_
) | Ast0.MetaType
(_
,_
) ->
482 Ast.Type
(None
,rewrap t
no_isos (base_typeC t
))
483 | Ast0.DisjType
(_
,types
,_
,_
) -> Ast.DisjType
(List.map
typeC types
)
484 | Ast0.OptType
(ty
) -> Ast.OptType
(typeC ty
)
485 | Ast0.UniqueType
(ty
) -> Ast.UniqueType
(typeC ty
))
488 match Ast0.unwrap t
with
489 Ast0.BaseType
(ty
,strings
) -> Ast.BaseType
(ty
,List.map
mcode strings
)
490 | Ast0.Signed
(sgn
,ty
) ->
491 Ast.SignedT
(mcode sgn
,
492 get_option (function x
-> rewrap_iso x
(base_typeC x
)) ty
)
493 | Ast0.Pointer
(ty
,star
) -> Ast.Pointer
(typeC ty
,mcode star
)
494 | Ast0.FunctionPointer
(ty
,lp1
,star
,rp1
,lp2
,params
,rp2
) ->
496 (typeC ty
,mcode lp1
,mcode star
,mcode rp1
,
497 mcode lp2
,parameter_list params
,mcode rp2
)
498 | Ast0.FunctionType
(ret
,lp,params
,rp) ->
499 let allminus = check_allminus.VT0.combiner_rec_typeC t
in
501 (allminus,get_option typeC ret
,mcode lp,
502 parameter_list params
,mcode rp)
503 | Ast0.Array
(ty
,lb
,size
,rb
) ->
504 Ast.Array
(typeC ty
,mcode lb
,get_option expression size
,mcode rb
)
505 | Ast0.EnumName
(kind
,name
) ->
506 Ast.EnumName
(mcode kind
,get_option ident name
)
507 | Ast0.EnumDef
(ty
,lb
,ids
,rb
) ->
508 let ids = add_exp_comma ids in
509 Ast.EnumDef
(typeC ty
,mcode lb
,dots expression ids,mcode rb
)
510 | Ast0.StructUnionName
(kind
,name
) ->
511 Ast.StructUnionName
(mcode kind
,get_option ident name
)
512 | Ast0.StructUnionDef
(ty
,lb
,decls
,rb
) ->
513 Ast.StructUnionDef
(typeC ty
,mcode lb
,
514 dots declaration decls
,
516 | Ast0.TypeName
(name
) -> Ast.TypeName
(mcode name
)
517 | Ast0.MetaType
(name
,_
) ->
518 Ast.MetaType
(mcode name
,unitary,false)
519 | _
-> failwith
"ast0toast: unexpected type"
521 (* --------------------------------------------------------------------- *)
522 (* Variable declaration *)
523 (* Even if the Cocci program specifies a list of declarations, they are
524 split out into multiple declarations of a single variable each. *)
527 rewrap d
(do_isos (Ast0.get_iso d
))
528 (match Ast0.unwrap d
with
529 Ast0.MetaDecl
(name
,_
) -> Ast.MetaDecl
(mcode name
,unitary,false)
530 | Ast0.MetaField
(name
,_
) -> Ast.MetaField
(mcode name
,unitary,false)
531 | Ast0.MetaFieldList
(name
,lenname
,_
) ->
532 Ast.MetaFieldList
(mcode name
,do_lenname lenname
,unitary,false)
533 | Ast0.Init
(stg
,ty
,id
,eq
,ini
,sem
) ->
534 let stg = get_option mcode stg in
538 let ini = initialiser
ini in
539 let sem = mcode sem in
540 Ast.Init
(stg,ty,id,eq,ini,sem)
541 | Ast0.UnInit
(stg,ty,id,sem) ->
542 (match Ast0.unwrap
ty with
543 Ast0.FunctionType
(tyx
,lp1
,params
,rp1
) ->
544 let allminus = check_allminus.VT0.combiner_rec_declaration d
in
545 Ast.UnInit
(get_option mcode stg,
546 rewrap ty (do_isos (Ast0.get_iso
ty))
551 (allminus,get_option typeC tyx
,mcode lp1
,
552 parameter_list params
,mcode rp1
)))),
554 | _
-> Ast.UnInit
(get_option mcode stg,typeC ty,ident id,mcode sem))
555 | Ast0.MacroDecl
(name
,lp,args,rp,sem) ->
556 let name = ident name in
558 let args = dots expression args in
560 let sem = mcode sem in
561 Ast.MacroDecl
(name,lp,args,rp,sem)
562 | Ast0.TyDecl
(ty,sem) -> Ast.TyDecl
(typeC ty,mcode sem)
563 | Ast0.Typedef
(stg,ty,id,sem) ->
565 (match Ast.unwrap
id with
566 Ast.Type
(None
,id) -> (* only MetaType or Id *)
567 Ast.Typedef
(mcode stg,typeC ty,id,mcode sem)
568 | _
-> failwith
"bad typedef")
569 | Ast0.DisjDecl
(_
,decls
,_
,_
) -> Ast.DisjDecl
(List.map
declaration decls
)
570 | Ast0.Ddots
(dots,whencode) ->
571 let dots = mcode dots in
572 let whencode = get_option declaration whencode in
573 Ast.Ddots
(dots,whencode)
574 | Ast0.OptDecl
(decl
) -> Ast.OptDecl
(declaration decl
)
575 | Ast0.UniqueDecl
(decl
) -> Ast.UniqueDecl
(declaration decl
))
577 and declaration_dots l
= dots declaration l
579 (* --------------------------------------------------------------------- *)
582 and strip_idots initlist
=
584 match Ast0.get_mcode_mcodekind mc
with
587 match Ast0.unwrap initlist
with
590 match List.rev
l with
593 (match (Ast0.unwrap x
,Ast0.unwrap y
) with
594 (Ast0.IComma _
,Ast0.Idots _
) ->
595 (* drop comma that was added by add_comma *)
598 let (whencode,init
,dotinfo
) =
599 let rec loop = function
602 (match Ast0.unwrap x
with
603 Ast0.Idots
(dots,Some
whencode) ->
604 let (restwhen
,restinit
,dotinfo
) = loop rest
in
605 (whencode :: restwhen
, restinit
,
606 (isminus dots)::dotinfo
)
607 | Ast0.Idots
(dots,None
) ->
608 let (restwhen
,restinit
,dotinfo
) = loop rest
in
609 (restwhen
, restinit
, (isminus dots)::dotinfo
)
611 let (restwhen
,restinit
,dotinfo
) = loop rest
in
612 (restwhen
,x
::restinit
,dotinfo
)) in
615 if List.for_all
(function x
-> not x
) dotinfo
616 then false (* false if no dots *)
618 if List.for_all
(function x
-> x
) dotinfo
620 else failwith
"inconsistent annotations on initialiser list dots" in
621 (whencode, init
, allminus)
622 | Ast0.CIRCLES
(x
) | Ast0.STARS
(x
) -> failwith
"not possible for an initlist"
626 (match Ast0.unwrap i
with
627 Ast0.MetaInit
(name,_
) -> Ast.MetaInit
(mcode name,unitary,false)
628 | Ast0.InitExpr
(exp
) -> Ast.InitExpr
(expression exp
)
629 | Ast0.InitList
(lb
,initlist
,rb
,true) ->
630 let initlist = add_init_comma
initlist in
631 Ast.ArInitList
(mcode lb
,dots initialiser
initlist,mcode rb
)
632 | Ast0.InitList
(lb
,initlist,rb
,false) ->
633 let initlist = add_init_comma
initlist in
634 let (whencode,initlist,allminus) = strip_idots
initlist in
636 (allminus,mcode lb
,List.map initialiser
initlist,mcode rb
,
637 List.map initialiser
whencode)
638 | Ast0.InitGccExt
(designators
,eq,ini) ->
639 Ast.InitGccExt
(List.map designator designators
,mcode eq,
641 | Ast0.InitGccName
(name,eq,ini) ->
642 Ast.InitGccName
(ident name,mcode eq,initialiser
ini)
643 | Ast0.IComma
(comma) -> Ast.IComma
(mcode comma)
644 | Ast0.Idots
(dots,whencode) ->
645 let dots = mcode dots in
646 let whencode = get_option initialiser
whencode in
647 Ast.Idots
(dots,whencode)
648 | Ast0.OptIni
(ini) -> Ast.OptIni
(initialiser
ini)
649 | Ast0.UniqueIni
(ini) -> Ast.UniqueIni
(initialiser
ini))
651 and designator
= function
652 Ast0.DesignatorField
(dot
,id) -> Ast.DesignatorField
(mcode dot
,ident id)
653 | Ast0.DesignatorIndex
(lb
,exp
,rb
) ->
654 Ast.DesignatorIndex
(mcode lb
, expression exp
, mcode rb
)
655 | Ast0.DesignatorRange
(lb
,min
,dots,max
,rb
) ->
656 Ast.DesignatorRange
(mcode lb
,expression min
,mcode dots,expression max
,
659 (* --------------------------------------------------------------------- *)
662 and parameterTypeDef p
=
664 (match Ast0.unwrap p
with
665 Ast0.VoidParam
(ty) -> Ast.VoidParam
(typeC ty)
666 | Ast0.Param
(ty,id) -> Ast.Param
(typeC ty,get_option ident id)
667 | Ast0.MetaParam
(name,_
) ->
668 Ast.MetaParam
(mcode name,unitary,false)
669 | Ast0.MetaParamList
(name,lenname
,_
) ->
670 Ast.MetaParamList
(mcode name,do_lenname lenname
,unitary,false)
671 | Ast0.PComma
(cm
) -> Ast.PComma
(mcode cm
)
672 | Ast0.Pdots
(dots) -> Ast.Pdots
(mcode dots)
673 | Ast0.Pcircles
(dots) -> Ast.Pcircles
(mcode dots)
674 | Ast0.OptParam
(param
) -> Ast.OptParam
(parameterTypeDef param
)
675 | Ast0.UniqueParam
(param
) -> Ast.UniqueParam
(parameterTypeDef param
))
677 and parameter_list
l = dots parameterTypeDef
l
679 (* --------------------------------------------------------------------- *)
683 let rec statement seqible s
=
684 let rewrap_stmt ast0 ast
=
686 match Ast0.get_dots_bef_aft s
with
687 Ast0.NoDots
-> Ast.NoDots
688 | Ast0.DroppingBetweenDots s
->
689 Ast.DroppingBetweenDots
(statement seqible s
,get_ctr())
690 | Ast0.AddingBetweenDots s
->
691 Ast.AddingBetweenDots
(statement seqible s
,get_ctr()) in
692 Ast.set_dots_bef_aft
befaft (rewrap ast0
no_isos ast
) in
693 let rewrap_rule_elem ast0 ast
=
694 rewrap ast0
(do_isos (Ast0.get_iso ast0
)) ast
in
696 (match Ast0.unwrap s
with
697 Ast0.Decl
((_
,bef
),decl
) ->
698 Ast.Atomic
(rewrap_rule_elem s
699 (Ast.Decl
(convert_mcodekind (-1) bef
,
700 check_allminus.VT0.combiner_rec_statement s
,
702 | Ast0.Seq
(lbrace
,body
,rbrace
) ->
703 let lbrace = mcode lbrace in
704 let body = dots (statement seqible
) body in
705 let rbrace = mcode rbrace in
706 Ast.Seq
(iso_tokenwrap lbrace s
(Ast.SeqStart
(lbrace))
707 (do_isos (Ast0.get_iso s
)),
709 tokenwrap rbrace s
(Ast.SeqEnd
(rbrace)))
710 | Ast0.ExprStatement
(exp
,sem) ->
711 Ast.Atomic
(rewrap_rule_elem s
712 (Ast.ExprStatement
(expression exp
,mcode sem)))
713 | Ast0.IfThen
(iff
,lp,exp
,rp,branch
,(_
,aft
)) ->
716 (Ast.IfHeader
(mcode iff
,mcode lp,expression exp
,mcode rp)),
717 statement Ast.NotSequencible branch
,
718 ([],[],[],convert_mcodekind (-1) aft
))
719 | Ast0.IfThenElse
(iff
,lp,exp
,rp,branch1
,els
,branch2
,(_
,aft
)) ->
720 let els = mcode els in
723 (Ast.IfHeader
(mcode iff
,mcode lp,expression exp
,mcode rp)),
724 statement Ast.NotSequencible branch1
,
725 tokenwrap els s
(Ast.Else
(els)),
726 statement Ast.NotSequencible branch2
,
727 ([],[],[],convert_mcodekind (-1) aft
))
728 | Ast0.While
(wh
,lp,exp
,rp,body,(_
,aft
)) ->
729 Ast.While
(rewrap_rule_elem s
731 (mcode wh
,mcode lp,expression exp
,mcode rp)),
732 statement Ast.NotSequencible
body,
733 ([],[],[],convert_mcodekind (-1) aft
))
734 | Ast0.Do
(d
,body,wh
,lp,exp
,rp,sem) ->
736 Ast.Do
(rewrap_rule_elem s
(Ast.DoHeader
(mcode d
)),
737 statement Ast.NotSequencible
body,
739 (Ast.WhileTail
(wh,mcode lp,expression exp
,mcode rp,
741 | Ast0.For
(fr
,lp,exp1,sem1
,exp2,sem2
,exp3,rp,body,(_
,aft
)) ->
744 let exp1 = get_option expression exp1 in
745 let sem1 = mcode sem1 in
746 let exp2 = get_option expression exp2 in
747 let sem2= mcode sem2 in
748 let exp3 = get_option expression exp3 in
750 let body = statement Ast.NotSequencible
body in
751 Ast.For
(rewrap_rule_elem s
752 (Ast.ForHeader
(fr,lp,exp1,sem1,exp2,sem2,exp3,rp)),
753 body,([],[],[],convert_mcodekind (-1) aft
))
754 | Ast0.Iterator
(nm
,lp,args,rp,body,(_
,aft
)) ->
755 Ast.Iterator
(rewrap_rule_elem s
758 dots expression args,
760 statement Ast.NotSequencible
body,
761 ([],[],[],convert_mcodekind (-1) aft
))
762 | Ast0.Switch
(switch
,lp,exp
,rp,lb
,decls
,cases
,rb
) ->
763 let switch = mcode switch in
765 let exp = expression exp in
768 let decls = dots (statement seqible
) decls in
769 let cases = List.map
case_line (Ast0.undots
cases) in
771 Ast.Switch
(rewrap_rule_elem s
(Ast.SwitchHeader
(switch,lp,exp,rp)),
772 tokenwrap lb s
(Ast.SeqStart
(lb)),
774 tokenwrap rb s
(Ast.SeqEnd
(rb)))
775 | Ast0.Break
(br
,sem) ->
776 Ast.Atomic
(rewrap_rule_elem s
(Ast.Break
(mcode br
,mcode sem)))
777 | Ast0.Continue
(cont
,sem) ->
778 Ast.Atomic
(rewrap_rule_elem s
(Ast.Continue
(mcode cont
,mcode sem)))
779 | Ast0.Label
(l,dd
) ->
780 Ast.Atomic
(rewrap_rule_elem s
(Ast.Label
(ident l,mcode dd
)))
781 | Ast0.Goto
(goto
,l,sem) ->
783 (rewrap_rule_elem s
(Ast.Goto
(mcode goto
,ident l,mcode sem)))
784 | Ast0.Return
(ret
,sem) ->
785 Ast.Atomic
(rewrap_rule_elem s
(Ast.Return
(mcode ret
,mcode sem)))
786 | Ast0.ReturnExpr
(ret
,exp,sem) ->
789 (Ast.ReturnExpr
(mcode ret
,expression exp,mcode sem)))
790 | Ast0.MetaStmt
(name,_
) ->
791 Ast.Atomic
(rewrap_rule_elem s
792 (Ast.MetaStmt
(mcode name,unitary,seqible
,false)))
793 | Ast0.MetaStmtList
(name,_
) ->
794 Ast.Atomic
(rewrap_rule_elem s
795 (Ast.MetaStmtList
(mcode name,unitary,false)))
796 | Ast0.TopExp
(exp) ->
797 Ast.Atomic
(rewrap_rule_elem s
(Ast.TopExp
(expression exp)))
799 Ast.Atomic
(rewrap_rule_elem s
(Ast.Exp
(expression exp)))
800 | Ast0.TopInit
(init
) ->
801 Ast.Atomic
(rewrap_rule_elem s
(Ast.TopInit
(initialiser init
)))
803 Ast.Atomic
(rewrap_rule_elem s
(Ast.Ty
(typeC ty)))
804 | Ast0.Disj
(_
,rule_elem_dots_list
,_
,_
) ->
805 Ast.Disj
(List.map
(function x
-> statement_dots seqible x
)
807 | Ast0.Nest
(starter,rule_elem_dots
,ender,whn
,multi
) ->
809 (mcode starter,statement_dots
Ast.Sequencible rule_elem_dots
,
812 (whencode (statement_dots
Ast.Sequencible
)
813 (statement Ast.NotSequencible
))
816 | Ast0.Dots
(d
,whn
) ->
820 (whencode (statement_dots
Ast.Sequencible
)
821 (statement Ast.NotSequencible
))
823 Ast.Dots
(d,whn,[],[])
824 | Ast0.Circles
(d,whn) ->
828 (whencode (statement_dots
Ast.Sequencible
)
829 (statement Ast.NotSequencible
))
831 Ast.Circles
(d,whn,[],[])
832 | Ast0.Stars
(d,whn) ->
836 (whencode (statement_dots
Ast.Sequencible
)
837 (statement Ast.NotSequencible
))
839 Ast.Stars
(d,whn,[],[])
840 | Ast0.FunDecl
((_
,bef
),fi
,name,lp,params
,rp,lbrace,body,rbrace) ->
841 let fi = List.map fninfo
fi in
842 let name = ident name in
844 let params = parameter_list
params in
846 let lbrace = mcode lbrace in
847 let body = dots (statement seqible
) body in
848 let rbrace = mcode rbrace in
849 let allminus = check_allminus.VT0.combiner_rec_statement s
in
850 Ast.FunDecl
(rewrap_rule_elem s
851 (Ast.FunHeader
(convert_mcodekind (-1) bef
,
852 allminus,fi,name,lp,params,rp)),
853 tokenwrap lbrace s
(Ast.SeqStart
(lbrace)),
855 tokenwrap rbrace s
(Ast.SeqEnd
(rbrace)))
856 | Ast0.Include
(inc
,str
) ->
857 Ast.Atomic
(rewrap_rule_elem s
(Ast.Include
(mcode inc
,mcode str
)))
858 | Ast0.Undef
(def
,id) ->
859 Ast.Atomic
(rewrap_rule_elem s
(Ast.Undef
(mcode def
,ident id)))
860 | Ast0.Define
(def
,id,params,body) ->
864 (mcode def
,ident id, define_parameters
params)),
865 statement_dots
Ast.NotSequencible
(*not sure*) body)
866 | Ast0.OptStm
(stm
) -> Ast.OptStm
(statement seqible stm
)
867 | Ast0.UniqueStm
(stm
) -> Ast.UniqueStm
(statement seqible stm
))
869 and define_parameters p
=
871 (match Ast0.unwrap p
with
872 Ast0.NoParams
-> Ast.NoParams
873 | Ast0.DParams
(lp,params,rp) ->
874 Ast.DParams
(mcode lp,
875 dots define_param
params,
880 (match Ast0.unwrap p
with
881 Ast0.DParam
(id) -> Ast.DParam
(ident id)
882 | Ast0.DPComma
(comma) -> Ast.DPComma
(mcode comma)
883 | Ast0.DPdots
(d) -> Ast.DPdots
(mcode d)
884 | Ast0.DPcircles
(c) -> Ast.DPcircles
(mcode c)
885 | Ast0.OptDParam
(dp
) -> Ast.OptDParam
(define_param dp
)
886 | Ast0.UniqueDParam
(dp
) -> Ast.UniqueDParam
(define_param dp
))
888 and whencode notfn alwaysfn
= function
889 Ast0.WhenNot a
-> Ast.WhenNot
(notfn a
)
890 | Ast0.WhenAlways a
-> Ast.WhenAlways
(alwaysfn a
)
891 | Ast0.WhenModifier
(x
) -> Ast.WhenModifier
(x
)
893 let rewrap_rule_elem ast0 ast
=
894 rewrap ast0
(do_isos (Ast0.get_iso ast0
)) ast
in
896 Ast0.WhenNotTrue
(e
) ->
897 Ast.WhenNotTrue
(rewrap_rule_elem e
(Ast.Exp
(expression e
)))
898 | Ast0.WhenNotFalse
(e
) ->
899 Ast.WhenNotFalse
(rewrap_rule_elem e
(Ast.Exp
(expression e
)))
900 | _
-> failwith
"not possible"
902 and process_list seqible isos
= function
905 let first = statement seqible x
in
907 if !Flag.track_iso_usage
908 then Ast.set_isos
first (isos
@(Ast.get_isos
first))
910 (match Ast0.unwrap x
with
911 Ast0.Dots
(_
,_
) | Ast0.Nest
(_
) ->
912 first::(process_list
(Ast.SequencibleAfterDots
[]) no_isos rest
)
914 first::(process_list
Ast.Sequencible
no_isos rest
))
916 and statement_dots seqible
d =
917 let isos = do_isos (Ast0.get_iso
d) in
919 (match Ast0.unwrap
d with
920 Ast0.DOTS
(x
) -> Ast.DOTS
(process_list seqible
isos x
)
921 | Ast0.CIRCLES
(x
) -> Ast.CIRCLES
(process_list seqible
isos x
)
922 | Ast0.STARS
(x
) -> Ast.STARS
(process_list seqible
isos x
))
924 (* the following is no longer used.
925 the goal was to let one put a statement at the very beginning of a function
926 pattern and have it skip over the declarations in the C code.
927 that feature was removed a long time ago, however, in favor of
928 ... when != S, which also causes whatever comes after it to match the
929 first real statement.
930 the separation of declarations from the rest of the body means that the
931 quantifier of any variable shared between them comes out too high, posing
932 problems when there is ... decl ... stmt, as the quantifier of any shared
933 variable will be around the whole thing, making variables not free enough
934 in the first ..., and thus not implementing the expected shortest path
935 condition. example: f() { ... int A; ... foo(A); }.
936 the quantifier for A should start just before int A, not at the top of the
938 and separate_decls seqible d =
939 let rec collect_decls = function
942 (match Ast0.unwrap x with
944 let (decls,other) = collect_decls xs in
946 | Ast0.Dots(_,_) | Ast0.Nest(_,_,_,_,_) ->
947 let (decls,other) = collect_decls xs in
950 | _ -> (x :: decls,other))
951 | Ast0.Disj(starter,stmt_dots_list,mids,ender) ->
952 let disjs = List.map collect_dot_decls stmt_dots_list in
953 let all_decls = List.for_all (function (_,s) -> s=[]) disjs in
956 let (decls,other) = collect_decls xs in
961 and collect_dot_decls d =
962 match Ast0.unwrap d with
963 Ast0.DOTS(x) -> collect_decls x
964 | Ast0.CIRCLES(x) -> collect_decls x
965 | Ast0.STARS(x) -> collect_decls x in
968 let (decls,other) = collect_decls l in
969 (rewrap d no_isos (fn (List.map (statement seqible) decls)),
971 (fn (process_list seqible (do_isos (Ast0.get_iso d)) other))) in
972 match Ast0.unwrap d with
973 Ast0.DOTS(x) -> process x d (function x -> Ast.DOTS x)
974 | Ast0.CIRCLES(x) -> process x d (function x -> Ast.CIRCLES x)
975 | Ast0.STARS(x) -> process x d (function x -> Ast.STARS x) *) in
977 statement Ast.Sequencible s
979 and fninfo
= function
980 Ast0.FStorage
(stg) -> Ast.FStorage
(mcode stg)
981 | Ast0.FType
(ty) -> Ast.FType
(typeC ty)
982 | Ast0.FInline
(inline
) -> Ast.FInline
(mcode inline
)
983 | Ast0.FAttr
(attr
) -> Ast.FAttr
(mcode attr
)
985 and option_to_list
= function
991 (match Ast0.unwrap
c with
992 Ast0.Default
(def
,colon,code
) ->
993 let def = mcode def in
994 let colon = mcode colon in
995 let code = dots statement code in
996 Ast.CaseLine
(rewrap c no_isos (Ast.Default
(def,colon)),code)
997 | Ast0.Case
(case
,exp,colon,code) ->
998 let case = mcode case in
999 let exp = expression exp in
1000 let colon = mcode colon in
1001 let code = dots statement code in
1002 Ast.CaseLine
(rewrap c no_isos (Ast.Case
(case,exp,colon)),code)
1003 | Ast0.DisjCase
(_
,case_lines
,_
,_
) ->
1004 failwith
"not supported"
1005 (*Ast.CaseLine(Ast.DisjRuleElem(List.map case_line case_lines))*)
1007 | Ast0.OptCase
(case) -> Ast.OptCase
(case_line case))
1009 and statement_dots
l = dots statement l
1011 (* --------------------------------------------------------------------- *)
1013 (* what is possible is only what is at the top level in an iso *)
1014 and anything
= function
1015 Ast0.DotsExprTag
(d) -> Ast.ExprDotsTag
(expression_dots
d)
1016 | Ast0.DotsParamTag
(d) -> Ast.ParamDotsTag
(parameter_list
d)
1017 | Ast0.DotsInitTag
(d) -> failwith
"not possible"
1018 | Ast0.DotsStmtTag
(d) -> Ast.StmtDotsTag
(statement_dots
d)
1019 | Ast0.DotsDeclTag
(d) -> Ast.DeclDotsTag
(declaration_dots
d)
1020 | Ast0.DotsCaseTag
(d) -> failwith
"not possible"
1021 | Ast0.IdentTag
(d) -> Ast.IdentTag
(ident d)
1022 | Ast0.ExprTag
(d) -> Ast.ExpressionTag
(expression d)
1023 | Ast0.ArgExprTag
(d) | Ast0.TestExprTag
(d) ->
1024 failwith
"only in isos, not converted to ast"
1025 | Ast0.TypeCTag
(d) -> Ast.FullTypeTag
(typeC d)
1026 | Ast0.ParamTag
(d) -> Ast.ParamTag
(parameterTypeDef
d)
1027 | Ast0.InitTag
(d) -> Ast.InitTag
(initialiser
d)
1028 | Ast0.DeclTag
(d) -> Ast.DeclarationTag
(declaration d)
1029 | Ast0.StmtTag
(d) -> Ast.StatementTag
(statement d)
1030 | Ast0.CaseLineTag
(d) -> Ast.CaseLineTag
(case_line d)
1031 | Ast0.TopTag
(d) -> Ast.Code
(top_level
d)
1032 | Ast0.IsoWhenTag
(_
) -> failwith
"not possible"
1033 | Ast0.IsoWhenTTag
(_
) -> failwith
"not possible"
1034 | Ast0.IsoWhenFTag
(_
) -> failwith
"not possible"
1035 | Ast0.MetaPosTag _
-> failwith
"not possible"
1037 (* --------------------------------------------------------------------- *)
1038 (* Function declaration *)
1039 (* top level isos are probably lost to tracking *)
1043 (match Ast0.unwrap t
with
1044 Ast0.FILEINFO
(old_file
,new_file
) ->
1045 Ast.FILEINFO
(mcode old_file
,mcode new_file
)
1046 | Ast0.DECL
(stmt
) -> Ast.DECL
(statement stmt
)
1047 | Ast0.CODE
(rule_elem_dots
) ->
1048 Ast.CODE
(statement_dots rule_elem_dots
)
1049 | Ast0.ERRORWORDS
(exps
) -> Ast.ERRORWORDS
(List.map
expression exps
)
1050 | Ast0.OTHER
(_
) -> failwith
"eliminated by top_level")
1052 (* --------------------------------------------------------------------- *)
1053 (* Entry point for minus code *)
1055 (* Inline_mcodes is very important - sends + code attached to the - code
1056 down to the mcodes. The functions above can only be used when there is no
1057 attached + code, eg in + code itself. *)
1058 let ast0toast_toplevel x
=
1059 inline_mcodes.VT0.combiner_rec_top_level x
;
1062 let ast0toast name deps dropped exists x is_exp ruletype
=
1063 List.iter
inline_mcodes.VT0.combiner_rec_top_level x
;
1065 (name,(deps
,dropped
,exists
),List.map top_level x
,is_exp
,ruletype
)