Release coccinelle-0.1.11rc1
[bpt/coccinelle.git] / parsing_c / unparse_cocci.ml
1 (* Copyright (C) 2006, 2007 Julia Lawall
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License (GPL)
5 * version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * file license.txt for more details.
11 *
12 * This file was part of Coccinelle.
13 *)
14 open Common
15
16 (*****************************************************************************)
17 (* mostly a copy paste of parsing_cocci/pretty_print_cocci.ml
18 * todo?: try to factorize ?
19 *)
20 (*****************************************************************************)
21
22 module Ast = Ast_cocci
23
24 let term s = Ast.unwrap_mcode s
25
26 (* or perhaps can have in plus, for instance a Disj, but those Disj must be
27 * handled by interactive tool (by proposing alternatives)
28 *)
29 exception CantBeInPlus
30
31 (*****************************************************************************)
32
33 type pos = Before | After | InPlace
34
35 let unknown = -1
36
37 let rec do_all
38 (env, pr, pr_celem, pr_cspace, pr_space, pr_arity, pr_barrier,
39 indent, unindent)
40 generating xxs before =
41
42 (* Just to be able to copy paste the code from pretty_print_cocci.ml. *)
43 let print_string s line lcol =
44 let rcol = if lcol = unknown then unknown else lcol + (String.length s) in
45 pr s line lcol rcol in
46 let print_text s = pr s unknown unknown unknown in
47 let close_box _ = () in
48 let force_newline _ = print_text "\n" in
49
50 let start_block () = force_newline(); indent() in
51 let end_block () = unindent(); force_newline () in
52 let print_string_box s = print_string s in
53
54 let print_option = Common.do_option in
55 let print_option_prespace fn = function
56 None -> ()
57 | Some x -> pr_space(); fn x in
58 let print_option_space fn = function
59 None -> ()
60 | Some x -> fn x; pr_space() in
61 let print_between = Common.print_between in
62
63 let outdent _ = () (* should go to leftmost col, does nothing now *) in
64
65 let pretty_print_c =
66 Pretty_print_c.mk_pretty_printers pr_celem pr_cspace
67 force_newline indent outdent unindent in
68
69 (* --------------------------------------------------------------------- *)
70 (* Only for make_hrule, print plus code, unbound metavariables *)
71
72 (* avoid polyvariance problems *)
73 let anything : (Ast.anything -> unit) ref = ref (function _ -> ()) in
74
75 let rec print_anything = function
76 [] -> ()
77 | stream ->
78 start_block();
79 print_between force_newline print_anything_list stream;
80 end_block()
81
82 and print_anything_list = function
83 [] -> ()
84 | [x] -> !anything x
85 | bef::((aft::_) as rest) ->
86 !anything bef;
87 let space =
88 (match bef with
89 Ast.Rule_elemTag(_) | Ast.AssignOpTag(_) | Ast.BinaryOpTag(_)
90 | Ast.ArithOpTag(_) | Ast.LogicalOpTag(_)
91 | Ast.Token("if",_) | Ast.Token("while",_) -> true | _ -> false) or
92 (match aft with
93 Ast.Rule_elemTag(_) | Ast.AssignOpTag(_) | Ast.BinaryOpTag(_)
94 | Ast.ArithOpTag(_) | Ast.LogicalOpTag(_) | Ast.Token("{",_) -> true
95 | _ -> false) in
96 if space then pr_space ();
97 print_anything_list rest in
98
99 let print_around printer term = function
100 Ast.NOTHING -> printer term
101 | Ast.BEFORE(bef,_) -> print_anything bef; printer term
102 | Ast.AFTER(aft,_) -> printer term; print_anything aft
103 | Ast.BEFOREAFTER(bef,aft,_) ->
104 print_anything bef; printer term; print_anything aft in
105
106 let print_string_befaft fn fn1 x info =
107 List.iter
108 (function (s,ln,col) -> fn1(); print_string s ln col; force_newline())
109 info.Ast.strbef;
110 fn x;
111 List.iter
112 (function (s,ln,col) -> force_newline(); fn1(); print_string s ln col)
113 info.Ast.straft in
114 let print_meta (r,x) = print_text x in
115
116 let print_pos = function
117 Ast.MetaPos(name,_,_,_,_) ->
118 let name = Ast.unwrap_mcode name in
119 print_text "@"; print_meta name
120 | _ -> () in
121
122 (* --------------------------------------------------------------------- *)
123
124 let mcode fn (s,info,mc,pos) =
125 let line = info.Ast.line in
126 let lcol = info.Ast.column in
127 match (generating,mc) with
128 (false,_) ->
129 (* printing for transformation *)
130 (* Here we don't care about the annotation on s. *)
131 let print_comments lb comments =
132 List.fold_left
133 (function line_before ->
134 function (str,line,col) ->
135 match line_before with
136 None -> print_string str line col; Some line
137 | Some lb when line =|= lb ->
138 print_string str line col; Some line
139 | _ -> force_newline(); print_string str line col; Some line)
140 lb comments in
141 let line_before = print_comments None info.Ast.strbef in
142 (match line_before with
143 None -> ()
144 | Some lb when lb =|= info.Ast.line -> ()
145 | _ -> force_newline());
146 fn s line lcol;
147 let _ = print_comments (Some info.Ast.line) info.Ast.straft in
148 (* newline after a pragma
149 should really store parsed versions of the strings, but make a cheap
150 effort here
151 print_comments takes care of interior newlines *)
152 (match List.rev info.Ast.straft with
153 (str,_,_)::_ when String.length str > 0 && String.get str 0 = '#' ->
154 force_newline()
155 | _ -> ());
156 ()
157 (* printing for rule generation *)
158 | (true, Ast.MINUS(_,_,_,plus_stream)) ->
159 force_newline();
160 print_text "- ";
161 fn s line lcol; print_pos pos;
162 print_anything plus_stream
163 | (true, Ast.CONTEXT(_,plus_streams)) ->
164 let fn s = force_newline(); fn s line lcol; print_pos pos in
165 print_around fn s plus_streams
166 | (true,Ast.PLUS Ast.ONE) ->
167 let fn s =
168 force_newline(); print_text "+ "; fn s line lcol; print_pos pos in
169 print_string_befaft fn (function _ -> print_text "+ ") s info
170 | (true,Ast.PLUS Ast.MANY) ->
171 let fn s =
172 force_newline(); print_text "++ "; fn s line lcol; print_pos pos in
173 print_string_befaft fn (function _ -> print_text "++ ") s info
174 in
175
176
177 (* --------------------------------------------------------------------- *)
178
179 let handle_metavar name fn =
180 let ((_,b) as s,info,mc,pos) = name in
181 let line = info.Ast.line in
182 let lcol = info.Ast.column in
183 match Common.optionise (fun () -> List.assoc s env) with
184 None ->
185 let name_string (_,s) = s in
186 if generating
187 then
188 mcode (function _ -> print_string (name_string s)) name
189 else
190 failwith
191 (Printf.sprintf "SP line %d: Not found a value in env for: %s"
192 line (name_string s))
193 | Some e ->
194 pr_barrier line lcol;
195 (if generating
196 then
197 (* call mcode to preserve the -+ annotation *)
198 mcode (fun _ _ _ -> fn e) name
199 else fn e);
200 let rcol = if lcol = unknown then unknown else lcol + (String.length b) in
201 pr_barrier line rcol
202 in
203 (* --------------------------------------------------------------------- *)
204 let dots between fn d =
205 match Ast.unwrap d with
206 Ast.DOTS(l) -> print_between between fn l
207 | Ast.CIRCLES(l) -> print_between between fn l
208 | Ast.STARS(l) -> print_between between fn l
209 in
210
211 let nest_dots multi fn f d =
212 let mo s = if multi then "<+"^s else "<"^s in
213 let mc s = if multi then s^"+>" else s^">" in
214 match Ast.unwrap d with
215 Ast.DOTS(l) ->
216 print_text (mo "..."); f(); start_block();
217 print_between force_newline fn l;
218 end_block(); print_text (mc "...")
219 | Ast.CIRCLES(l) ->
220 print_text (mo "ooo"); f(); start_block();
221 print_between force_newline fn l;
222 end_block(); print_text (mc "ooo")
223 | Ast.STARS(l) ->
224 print_text (mo "***"); f(); start_block();
225 print_between force_newline fn l;
226 end_block(); print_text (mc "***")
227 in
228
229 (* --------------------------------------------------------------------- *)
230 (* Identifier *)
231
232 let rec ident i =
233 match Ast.unwrap i with
234 Ast.Id(name) -> mcode print_string name
235 | Ast.MetaId(name,_,_,_) ->
236 handle_metavar name (function
237 | (Ast_c.MetaIdVal id) -> print_text id
238 | _ -> raise Impossible
239 )
240 | Ast.MetaFunc(name,_,_,_) ->
241 handle_metavar name (function
242 | (Ast_c.MetaFuncVal id) -> print_text id
243 | _ -> raise Impossible
244 )
245 | Ast.MetaLocalFunc(name,_,_,_) ->
246 handle_metavar name (function
247 | (Ast_c.MetaLocalFuncVal id) -> print_text id
248 | _ -> raise Impossible
249 )
250
251 | Ast.OptIdent(_) | Ast.UniqueIdent(_) ->
252 raise CantBeInPlus
253
254 in
255
256 (* --------------------------------------------------------------------- *)
257 (* Expression *)
258
259 let print_disj_list fn l =
260 print_text "\n(\n";
261 print_between (function _ -> print_text "\n|\n") fn l;
262 print_text "\n)\n" in
263
264 let rec expression e =
265 match Ast.unwrap e with
266 Ast.Ident(id) -> ident id
267 | Ast.Constant(const) -> mcode constant const
268 | Ast.FunCall(fn,lp,args,rp) ->
269 expression fn; mcode print_string_box lp;
270 let comma e =
271 expression e;
272 match Ast.unwrap e with
273 Ast.EComma(cm) -> pr_space()
274 | _ -> () in
275 dots (function _ -> ()) comma args;
276 close_box(); mcode print_string rp
277 | Ast.Assignment(left,op,right,_) ->
278 expression left; pr_space(); mcode assignOp op;
279 pr_space(); expression right
280 | Ast.CondExpr(exp1,why,exp2,colon,exp3) ->
281 expression exp1; pr_space(); mcode print_string why;
282 print_option (function e -> pr_space(); expression e) exp2;
283 pr_space(); mcode print_string colon; expression exp3
284 | Ast.Postfix(exp,op) -> expression exp; mcode fixOp op
285 | Ast.Infix(exp,op) -> mcode fixOp op; expression exp
286 | Ast.Unary(exp,op) -> mcode unaryOp op; expression exp
287 | Ast.Binary(left,op,right) ->
288 expression left; pr_space(); mcode binaryOp op; pr_space();
289 expression right
290 | Ast.Nested(left,op,right) -> failwith "nested only in minus code"
291 | Ast.Paren(lp,exp,rp) ->
292 mcode print_string_box lp; expression exp; close_box();
293 mcode print_string rp
294 | Ast.ArrayAccess(exp1,lb,exp2,rb) ->
295 expression exp1; mcode print_string_box lb; expression exp2; close_box();
296 mcode print_string rb
297 | Ast.RecordAccess(exp,pt,field) ->
298 expression exp; mcode print_string pt; ident field
299 | Ast.RecordPtAccess(exp,ar,field) ->
300 expression exp; mcode print_string ar; ident field
301 | Ast.Cast(lp,ty,rp,exp) ->
302 mcode print_string_box lp; fullType ty; close_box();
303 mcode print_string rp; expression exp
304 | Ast.SizeOfExpr(sizeof,exp) ->
305 mcode print_string sizeof; expression exp
306 | Ast.SizeOfType(sizeof,lp,ty,rp) ->
307 mcode print_string sizeof;
308 mcode print_string_box lp; fullType ty; close_box();
309 mcode print_string rp
310 | Ast.TypeExp(ty) -> fullType ty
311
312 | Ast.MetaErr(name,_,_,_) ->
313 failwith "metaErr not handled"
314
315 | Ast.MetaExpr (name,_,_,_typedontcare,_formdontcare,_) ->
316 handle_metavar name (function
317 | Ast_c.MetaExprVal exp ->
318 pretty_print_c.Pretty_print_c.expression exp
319 | _ -> raise Impossible
320 )
321
322 | Ast.MetaExprList (name,_,_,_) ->
323 handle_metavar name (function
324 | Ast_c.MetaExprListVal args ->
325 pretty_print_c.Pretty_print_c.arg_list args
326 | _ -> raise Impossible
327 )
328
329 | Ast.EComma(cm) -> mcode print_string cm
330
331 | Ast.DisjExpr(exp_list) ->
332 if generating
333 then print_disj_list expression exp_list
334 else raise CantBeInPlus
335 | Ast.NestExpr(expr_dots,Some whencode,multi) when generating ->
336 nest_dots multi expression
337 (function _ -> print_text " when != "; expression whencode)
338 expr_dots
339 | Ast.NestExpr(expr_dots,None,multi) when generating ->
340 nest_dots multi expression (function _ -> ()) expr_dots
341 | Ast.NestExpr(_) -> raise CantBeInPlus
342 | Ast.Edots(dots,Some whencode)
343 | Ast.Ecircles(dots,Some whencode)
344 | Ast.Estars(dots,Some whencode) ->
345 if generating
346 then
347 (mcode print_string dots;
348 print_text " when != ";
349 expression whencode)
350 else raise CantBeInPlus
351 | Ast.Edots(dots,None)
352 | Ast.Ecircles(dots,None)
353 | Ast.Estars(dots,None) ->
354 if generating
355 then mcode print_string dots
356 else raise CantBeInPlus
357
358 | Ast.OptExp(exp) | Ast.UniqueExp(exp) ->
359 raise CantBeInPlus
360
361 and unaryOp = function
362 Ast.GetRef -> print_string "&"
363 | Ast.DeRef -> print_string "*"
364 | Ast.UnPlus -> print_string "+"
365 | Ast.UnMinus -> print_string "-"
366 | Ast.Tilde -> print_string "~"
367 | Ast.Not -> print_string "!"
368
369 and assignOp = function
370 Ast.SimpleAssign -> print_string "="
371 | Ast.OpAssign(aop) ->
372 (function line -> function lcol ->
373 arithOp aop line lcol; print_string "=" line lcol)
374
375 and fixOp = function
376 Ast.Dec -> print_string "--"
377 | Ast.Inc -> print_string "++"
378
379 and binaryOp = function
380 Ast.Arith(aop) -> arithOp aop
381 | Ast.Logical(lop) -> logicalOp lop
382
383 and arithOp = function
384 Ast.Plus -> print_string "+"
385 | Ast.Minus -> print_string "-"
386 | Ast.Mul -> print_string "*"
387 | Ast.Div -> print_string "/"
388 | Ast.Mod -> print_string "%"
389 | Ast.DecLeft -> print_string "<<"
390 | Ast.DecRight -> print_string ">>"
391 | Ast.And -> print_string "&"
392 | Ast.Or -> print_string "|"
393 | Ast.Xor -> print_string "^"
394
395 and logicalOp = function
396 Ast.Inf -> print_string "<"
397 | Ast.Sup -> print_string ">"
398 | Ast.InfEq -> print_string "<="
399 | Ast.SupEq -> print_string ">="
400 | Ast.Eq -> print_string "=="
401 | Ast.NotEq -> print_string "!="
402 | Ast.AndLog -> print_string "&&"
403 | Ast.OrLog -> print_string "||"
404
405 and constant = function
406 Ast.String(s) -> print_string ("\""^s^"\"")
407 | Ast.Char(s) -> print_string ("\'"^s^"\'")
408 | Ast.Int(s) -> print_string s
409 | Ast.Float(s) -> print_string s
410
411 (* --------------------------------------------------------------------- *)
412 (* Types *)
413
414
415 and fullType ft =
416 match Ast.unwrap ft with
417 Ast.Type(cv,ty) -> print_option_space (mcode const_vol) cv; typeC ty
418 | Ast.DisjType _ -> failwith "can't be in plus"
419 | Ast.OptType(_) | Ast.UniqueType(_) ->
420 raise CantBeInPlus
421
422 and print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) fn =
423 fullType ty; mcode print_string lp1; mcode print_string star; fn();
424 mcode print_string rp1; mcode print_string lp1;
425 parameter_list params; mcode print_string rp2
426
427 and print_function_type (ty,lp1,params,rp1) fn =
428 print_option fullType ty; fn(); mcode print_string lp1;
429 parameter_list params; mcode print_string rp1
430
431 and typeC ty =
432 match Ast.unwrap ty with
433 Ast.BaseType(ty,strings) ->
434 print_between pr_space (mcode print_string) strings
435 | Ast.SignedT(sgn,ty) -> mcode sign sgn; print_option_prespace typeC ty
436 | Ast.Pointer(ty,star) -> fullType ty; ft_space ty; mcode print_string star
437 | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) ->
438 print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2)
439 (function _ -> ())
440 | Ast.FunctionType (am,ty,lp1,params,rp1) ->
441 print_function_type (ty,lp1,params,rp1) (function _ -> ())
442 | Ast.Array(ty,lb,size,rb) ->
443 fullType ty; mcode print_string lb; print_option expression size;
444 mcode print_string rb
445 | Ast.EnumName(kind,name) -> mcode print_string kind; pr_space();
446 ident name
447 | Ast.StructUnionName(kind,name) ->
448 mcode structUnion kind; print_option_prespace ident name
449 | Ast.StructUnionDef(ty,lb,decls,rb) ->
450 fullType ty; ft_space ty;
451 mcode print_string lb;
452 dots force_newline declaration decls;
453 mcode print_string rb
454 | Ast.TypeName(name)-> mcode print_string name
455 | Ast.MetaType(name,_,_) ->
456 handle_metavar name (function
457 Ast_c.MetaTypeVal exp ->
458 pretty_print_c.Pretty_print_c.ty exp
459 | _ -> raise Impossible)
460
461 and baseType = function
462 Ast.VoidType -> print_string "void"
463 | Ast.CharType -> print_string "char"
464 | Ast.ShortType -> print_string "short"
465 | Ast.IntType -> print_string "int"
466 | Ast.DoubleType -> print_string "double"
467 | Ast.FloatType -> print_string "float"
468 | Ast.LongType -> print_string "long"
469 | Ast.LongLongType -> print_string "long long"
470
471 and structUnion = function
472 Ast.Struct -> print_string "struct"
473 | Ast.Union -> print_string "union"
474
475 and sign = function
476 Ast.Signed -> print_string "signed"
477 | Ast.Unsigned -> print_string "unsigned"
478
479
480 and const_vol = function
481 Ast.Const -> print_string "const"
482 | Ast.Volatile -> print_string "volatile"
483
484 (* --------------------------------------------------------------------- *)
485 (* Function declaration *)
486
487 and storage = function
488 Ast.Static -> print_string "static"
489 | Ast.Auto -> print_string "auto"
490 | Ast.Register -> print_string "register"
491 | Ast.Extern -> print_string "extern"
492
493 (* --------------------------------------------------------------------- *)
494 (* Variable declaration *)
495
496 and print_named_type ty id =
497 match Ast.unwrap ty with
498 Ast.Type(None,ty1) ->
499 (match Ast.unwrap ty1 with
500 Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) ->
501 print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2)
502 (function _ -> pr_space(); ident id)
503 | Ast.FunctionType(am,ty,lp1,params,rp1) ->
504 print_function_type (ty,lp1,params,rp1)
505 (function _ -> pr_space(); ident id)
506 | Ast.Array(_,_,_,_) ->
507 let rec loop ty k =
508 match Ast.unwrap ty with
509 Ast.Array(ty,lb,size,rb) ->
510 (match Ast.unwrap ty with
511 Ast.Type(None,ty) ->
512 loop ty
513 (function _ ->
514 k ();
515 mcode print_string lb;
516 print_option expression size;
517 mcode print_string rb)
518 | _ -> failwith "complex array types not supported")
519 | _ -> typeC ty; ty_space ty; ident id; k () in
520 loop ty1 (function _ -> ())
521 (*| should have a case here for pointer to array or function type
522 that would put ( * ) around the variable. This makes one wonder
523 why we really need a special case for function pointer *)
524 | _ -> fullType ty; ft_space ty; ident id)
525 | _ -> fullType ty; ft_space ty; ident id
526
527 and ty_space ty =
528 match Ast.unwrap ty with
529 Ast.Pointer(_,_) -> ()
530 | _ -> pr_space()
531
532 and ft_space ty =
533 match Ast.unwrap ty with
534 Ast.Type(cv,ty) ->
535 (match Ast.unwrap ty with
536 Ast.Pointer(_,_) -> ()
537 | _ -> pr_space())
538 | _ -> pr_space()
539
540 and declaration d =
541 match Ast.unwrap d with
542 Ast.Init(stg,ty,id,eq,ini,sem) ->
543 print_option (mcode storage) stg;
544 print_option (function _ -> pr_space()) stg;
545 print_named_type ty id;
546 pr_space(); mcode print_string eq;
547 pr_space(); initialiser true ini; mcode print_string sem
548 | Ast.UnInit(stg,ty,id,sem) ->
549 print_option (mcode storage) stg;
550 print_option (function _ -> pr_space()) stg;
551 print_named_type ty id;
552 mcode print_string sem
553 | Ast.MacroDecl(name,lp,args,rp,sem) ->
554 ident name; mcode print_string_box lp;
555 dots (function _ -> ()) expression args;
556 close_box(); mcode print_string rp; mcode print_string sem
557 | Ast.TyDecl(ty,sem) -> fullType ty; mcode print_string sem
558 | Ast.Typedef(stg,ty,id,sem) ->
559 mcode print_string stg;
560 fullType ty; typeC id;
561 mcode print_string sem
562 | Ast.DisjDecl(_) | Ast.MetaDecl(_,_,_) -> raise CantBeInPlus
563 | Ast.Ddots(_,_) -> raise CantBeInPlus
564 | Ast.OptDecl(decl) | Ast.UniqueDecl(decl) ->
565 raise CantBeInPlus
566
567 (* --------------------------------------------------------------------- *)
568 (* Initialiser *)
569
570 and initialiser nlcomma i =
571 match Ast.unwrap i with
572 Ast.MetaInit(name,_,_) ->
573 handle_metavar name (function
574 Ast_c.MetaInitVal ini ->
575 pretty_print_c.Pretty_print_c.init ini
576 | _ -> raise Impossible)
577 | Ast.InitExpr(exp) -> expression exp
578 | Ast.InitList(lb,initlist,rb,[]) ->
579 mcode print_string lb; start_block();
580 (* awkward, because the comma is separate from the initialiser *)
581 let rec loop = function
582 [] -> ()
583 | [x] -> initialiser false x
584 | x::xs -> initialiser nlcomma x; loop xs in
585 loop initlist;
586 end_block(); mcode print_string rb
587 | Ast.InitList(lb,initlist,rb,_) -> failwith "unexpected whencode in plus"
588 | Ast.InitGccExt(designators,eq,ini) ->
589 List.iter designator designators; pr_space();
590 mcode print_string eq; pr_space(); initialiser nlcomma ini
591 | Ast.InitGccName(name,eq,ini) ->
592 ident name; mcode print_string eq; initialiser nlcomma ini
593 | Ast.IComma(comma) ->
594 mcode print_string comma;
595 if nlcomma then force_newline()
596 | Ast.OptIni(ini) | Ast.UniqueIni(ini) ->
597 raise CantBeInPlus
598
599 and designator = function
600 Ast.DesignatorField(dot,id) -> mcode print_string dot; ident id
601 | Ast.DesignatorIndex(lb,exp,rb) ->
602 mcode print_string lb; expression exp; mcode print_string rb
603 | Ast.DesignatorRange(lb,min,dots,max,rb) ->
604 mcode print_string lb; expression min; mcode print_string dots;
605 expression max; mcode print_string rb
606
607 (* --------------------------------------------------------------------- *)
608 (* Parameter *)
609
610 and parameterTypeDef p =
611 match Ast.unwrap p with
612 Ast.VoidParam(ty) -> fullType ty
613 | Ast.Param(ty,Some id) -> print_named_type ty id
614 | Ast.Param(ty,None) -> fullType ty
615
616 | Ast.MetaParam(name,_,_) ->
617 failwith "not handling MetaParam"
618 | Ast.MetaParamList(name,_,_,_) ->
619 failwith "not handling MetaParamList"
620
621 | Ast.PComma(cm) -> mcode print_string cm
622 | Ast.Pdots(dots) | Ast.Pcircles(dots) when generating ->
623 mcode print_string dots
624 | Ast.Pdots(dots) | Ast.Pcircles(dots) -> raise CantBeInPlus
625 | Ast.OptParam(param) | Ast.UniqueParam(param) -> raise CantBeInPlus
626
627 and parameter_list l =
628 let comma p =
629 parameterTypeDef p;
630 match Ast.unwrap p with
631 Ast.PComma(cm) -> pr_space()
632 | _ -> () in
633 dots (function _ -> ()) comma l
634 in
635
636
637 (* --------------------------------------------------------------------- *)
638 (* CPP code *)
639
640 let rec inc_file = function
641 Ast.Local(elems) ->
642 print_string ("\""^(String.concat "/" (List.map inc_elem elems))^"\"")
643 | Ast.NonLocal(elems) ->
644 print_string ("<"^(String.concat "/" (List.map inc_elem elems))^">")
645
646 and inc_elem = function
647 Ast.IncPath s -> s
648 | Ast.IncDots -> "..."
649
650 (* --------------------------------------------------------------------- *)
651 (* Top-level code *)
652
653 and rule_elem arity re =
654 match Ast.unwrap re with
655 Ast.FunHeader(_,_,fninfo,name,lp,params,rp) ->
656 pr_arity arity; List.iter print_fninfo fninfo;
657 ident name; mcode print_string_box lp;
658 parameter_list params; close_box(); mcode print_string rp;
659 pr_space()
660 | Ast.Decl(_,_,decl) -> pr_arity arity; declaration decl
661
662 | Ast.SeqStart(brace) ->
663 pr_arity arity; mcode print_string brace; start_block()
664 | Ast.SeqEnd(brace) ->
665 end_block(); pr_arity arity; mcode print_string brace
666
667 | Ast.ExprStatement(exp,sem) ->
668 pr_arity arity; expression exp; mcode print_string sem
669
670 | Ast.IfHeader(iff,lp,exp,rp) ->
671 pr_arity arity;
672 mcode print_string iff; pr_space(); mcode print_string_box lp;
673 expression exp; close_box(); mcode print_string rp
674 | Ast.Else(els) ->
675 pr_arity arity; mcode print_string els
676
677 | Ast.WhileHeader(whl,lp,exp,rp) ->
678 pr_arity arity;
679 mcode print_string whl; pr_space(); mcode print_string_box lp;
680 expression exp; close_box(); mcode print_string rp
681 | Ast.DoHeader(d) ->
682 pr_arity arity; mcode print_string d
683 | Ast.WhileTail(whl,lp,exp,rp,sem) ->
684 pr_arity arity;
685 mcode print_string whl; pr_space(); mcode print_string_box lp;
686 expression exp; close_box(); mcode print_string rp;
687 mcode print_string sem
688 | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) ->
689 pr_arity arity;
690 mcode print_string fr; mcode print_string_box lp;
691 print_option expression e1; mcode print_string sem1;
692 print_option expression e2; mcode print_string sem2;
693 print_option expression e3; close_box();
694 mcode print_string rp
695 | Ast.IteratorHeader(nm,lp,args,rp) ->
696 pr_arity arity;
697 ident nm; pr_space(); mcode print_string_box lp;
698 dots (function _ -> ()) expression args; close_box();
699 mcode print_string rp
700
701 | Ast.SwitchHeader(switch,lp,exp,rp) ->
702 pr_arity arity;
703 mcode print_string switch; pr_space(); mcode print_string_box lp;
704 expression exp; close_box(); mcode print_string rp
705
706 | Ast.Break(br,sem) ->
707 pr_arity arity; mcode print_string br; mcode print_string sem
708 | Ast.Continue(cont,sem) ->
709 pr_arity arity; mcode print_string cont; mcode print_string sem
710 | Ast.Label(l,dd) -> ident l; mcode print_string dd
711 | Ast.Goto(goto,l,sem) ->
712 mcode print_string goto; ident l; mcode print_string sem
713 | Ast.Return(ret,sem) ->
714 pr_arity arity; mcode print_string ret;
715 mcode print_string sem
716 | Ast.ReturnExpr(ret,exp,sem) ->
717 pr_arity arity; mcode print_string ret; pr_space();
718 expression exp; mcode print_string sem
719
720 | Ast.Exp(exp) -> pr_arity arity; expression exp
721 | Ast.TopExp(exp) -> pr_arity arity; expression exp
722 | Ast.Ty(ty) -> pr_arity arity; fullType ty
723 | Ast.TopInit(init) -> initialiser false init
724 | Ast.Include(inc,s) ->
725 mcode print_string inc; print_text " "; mcode inc_file s
726 | Ast.DefineHeader(def,id,params) ->
727 mcode print_string def; pr_space(); ident id;
728 print_define_parameters params
729 | Ast.Default(def,colon) ->
730 mcode print_string def; mcode print_string colon; pr_space()
731 | Ast.Case(case,exp,colon) ->
732 mcode print_string case; pr_space(); expression exp;
733 mcode print_string colon; pr_space()
734 | Ast.DisjRuleElem(res) ->
735 if generating
736 then
737 (pr_arity arity; print_text "\n(\n";
738 print_between (function _ -> print_text "\n|\n") (rule_elem arity)
739 res;
740 print_text "\n)")
741 else raise CantBeInPlus
742
743 | Ast.MetaRuleElem(name,_,_) ->
744 raise Impossible
745
746 | Ast.MetaStmt(name,_,_,_) ->
747 handle_metavar name (function
748 | Ast_c.MetaStmtVal stm ->
749 pretty_print_c.Pretty_print_c.statement stm
750 | _ -> raise Impossible
751 )
752 | Ast.MetaStmtList(name,_,_) ->
753 failwith
754 "MetaStmtList not supported (not even in ast_c metavars binding)"
755
756 and print_define_parameters params =
757 match Ast.unwrap params with
758 Ast.NoParams -> ()
759 | Ast.DParams(lp,params,rp) ->
760 mcode print_string lp;
761 dots (function _ -> ()) print_define_param params; mcode print_string rp
762
763 and print_define_param param =
764 match Ast.unwrap param with
765 Ast.DParam(id) -> ident id
766 | Ast.DPComma(comma) -> mcode print_string comma
767 | Ast.DPdots(dots) -> mcode print_string dots
768 | Ast.DPcircles(circles) -> mcode print_string circles
769 | Ast.OptDParam(dp) -> print_text "?"; print_define_param dp
770 | Ast.UniqueDParam(dp) -> print_text "!"; print_define_param dp
771
772 and print_fninfo = function
773 Ast.FStorage(stg) -> mcode storage stg
774 | Ast.FType(ty) -> fullType ty
775 | Ast.FInline(inline) -> mcode print_string inline; pr_space()
776 | Ast.FAttr(attr) -> mcode print_string attr; pr_space() in
777
778 let indent_if_needed s f =
779 match Ast.unwrap s with
780 Ast.Seq(lbrace,body,rbrace) -> pr_space(); f()
781 | _ ->
782 (*no newline at the end - someone else will do that*)
783 start_block(); f(); unindent() in
784
785 let rec statement arity s =
786 match Ast.unwrap s with
787 Ast.Seq(lbrace,body,rbrace) ->
788 rule_elem arity lbrace;
789 dots force_newline (statement arity) body;
790 rule_elem arity rbrace
791
792 | Ast.IfThen(header,branch,_) ->
793 rule_elem arity header;
794 indent_if_needed branch (function _ -> statement arity branch)
795 | Ast.IfThenElse(header,branch1,els,branch2,_) ->
796 rule_elem arity header;
797 indent_if_needed branch1 (function _ -> statement arity branch1);
798 force_newline();
799 rule_elem arity els;
800 indent_if_needed branch2 (function _ -> statement arity branch2)
801 | Ast.While(header,body,_) ->
802 rule_elem arity header;
803 indent_if_needed body (function _ -> statement arity body)
804 | Ast.Do(header,body,tail) ->
805 rule_elem arity header;
806 indent_if_needed body (function _ -> statement arity body);
807 rule_elem arity tail
808 | Ast.For(header,body,_) ->
809 rule_elem arity header;
810 indent_if_needed body (function _ -> statement arity body)
811 | Ast.Iterator(header,body,(_,_,_,aft)) ->
812 rule_elem arity header;
813 indent_if_needed body (function _ -> statement arity body);
814 mcode (fun _ _ _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos)
815
816 | Ast.Switch(header,lb,decls,cases,rb) ->
817 rule_elem arity header; pr_space(); rule_elem arity lb;
818 dots force_newline (statement arity) decls;
819 List.iter (function x -> case_line arity x; force_newline()) cases;
820 rule_elem arity rb
821
822 | Ast.Atomic(re) -> rule_elem arity re
823
824 | Ast.FunDecl(header,lbrace,body,rbrace) ->
825 rule_elem arity header; rule_elem arity lbrace;
826 dots force_newline (statement arity) body; rule_elem arity rbrace
827
828 | Ast.Define(header,body) ->
829 rule_elem arity header; pr_space();
830 dots force_newline (statement arity) body
831
832 | Ast.Disj([stmt_dots]) ->
833 if generating
834 then
835 (pr_arity arity;
836 dots force_newline (statement arity) stmt_dots)
837 else raise CantBeInPlus
838 | Ast.Disj(stmt_dots_list) -> (* ignores newline directive for readability *)
839 if generating
840 then
841 (pr_arity arity; print_text "\n(\n";
842 print_between (function _ -> print_text "\n|\n")
843 (dots force_newline (statement arity))
844 stmt_dots_list;
845 print_text "\n)")
846 else raise CantBeInPlus
847 | Ast.Nest(stmt_dots,whn,multi,_,_) when generating ->
848 pr_arity arity;
849 nest_dots multi (statement arity)
850 (function _ ->
851 print_between force_newline
852 (whencode (dots force_newline (statement "")) (statement "")) whn;
853 force_newline())
854 stmt_dots
855 | Ast.Nest(_) -> raise CantBeInPlus
856 | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) ->
857 if generating
858 then
859 (pr_arity arity; mcode print_string d;
860 print_between force_newline
861 (whencode (dots force_newline (statement "")) (statement "")) whn;
862 force_newline())
863 else raise CantBeInPlus
864
865 | Ast.OptStm(s) | Ast.UniqueStm(s) ->
866 raise CantBeInPlus
867
868 and whencode notfn alwaysfn = function
869 Ast.WhenNot a ->
870 print_text " WHEN != "; notfn a
871 | Ast.WhenAlways a ->
872 print_text " WHEN = "; alwaysfn a
873 | Ast.WhenModifier x -> print_text " WHEN "; print_when_modif x
874 | Ast.WhenNotTrue a ->
875 print_text " WHEN != TRUE "; rule_elem "" a
876 | Ast.WhenNotFalse a ->
877 print_text " WHEN != FALSE "; rule_elem "" a
878
879 and print_when_modif = function
880 | Ast.WhenAny -> print_text "ANY"
881 | Ast.WhenStrict -> print_text "STRICT"
882 | Ast.WhenForall -> print_text "FORALL"
883 | Ast.WhenExists -> print_text "EXISTS"
884
885 and case_line arity c =
886 match Ast.unwrap c with
887 Ast.CaseLine(header,code) ->
888 rule_elem arity header; pr_space();
889 dots force_newline (statement arity) code
890 | Ast.OptCase(case) -> raise CantBeInPlus in
891
892 let top_level t =
893 match Ast.unwrap t with
894 Ast.FILEINFO(old_file,new_file) -> raise CantBeInPlus
895 | Ast.DECL(stmt) -> statement "" stmt
896 | Ast.CODE(stmt_dots) -> dots force_newline (statement "") stmt_dots
897 | Ast.ERRORWORDS(exps) -> raise CantBeInPlus
898 in
899
900 (*
901 let rule =
902 print_between (function _ -> force_newline(); force_newline()) top_level
903 in
904 *)
905
906 let if_open_brace = function "{" -> true | _ -> false in
907
908 (* boolean result indicates whether an indent is needed *)
909 let rec pp_any = function
910 (* assert: normally there is only CONTEXT NOTHING tokens in any *)
911 Ast.FullTypeTag(x) -> fullType x; false
912 | Ast.BaseTypeTag(x) -> baseType x unknown unknown; false
913 | Ast.StructUnionTag(x) -> structUnion x unknown unknown; false
914 | Ast.SignTag(x) -> sign x unknown unknown; false
915
916 | Ast.IdentTag(x) -> ident x; false
917
918 | Ast.ExpressionTag(x) -> expression x; false
919
920 | Ast.ConstantTag(x) -> constant x unknown unknown; false
921 | Ast.UnaryOpTag(x) -> unaryOp x unknown unknown; false
922 | Ast.AssignOpTag(x) -> assignOp x unknown unknown; false
923 | Ast.FixOpTag(x) -> fixOp x unknown unknown; false
924 | Ast.BinaryOpTag(x) -> binaryOp x unknown unknown; false
925 | Ast.ArithOpTag(x) -> arithOp x unknown unknown; false
926 | Ast.LogicalOpTag(x) -> logicalOp x unknown unknown; false
927
928 | Ast.InitTag(x) -> initialiser false x; false
929 | Ast.DeclarationTag(x) -> declaration x; false
930
931 | Ast.StorageTag(x) -> storage x unknown unknown; false
932 | Ast.IncFileTag(x) -> inc_file x unknown unknown; false
933
934 | Ast.Rule_elemTag(x) -> rule_elem "" x; false
935 | Ast.StatementTag(x) -> statement "" x; false
936 | Ast.CaseLineTag(x) -> case_line "" x; false
937
938 | Ast.ConstVolTag(x) -> const_vol x unknown unknown; false
939 | Ast.Pragma(xs) -> print_between force_newline print_text xs; false
940 | Ast.Token(x,None) -> print_text x; if_open_brace x
941 | Ast.Token(x,Some info) ->
942 mcode
943 (fun x line lcol ->
944 (match x with
945 "else" -> force_newline()
946 | _ -> ());
947 print_string x line lcol)
948 (let nomcodekind = Ast.CONTEXT(Ast.DontCarePos,Ast.NOTHING) in
949 (x,info,nomcodekind,Ast.NoMetaPos));
950 if_open_brace x
951
952 | Ast.Code(x) -> let _ = top_level x in false
953
954 (* this is not '...', but a list of expr/statement/params, and
955 normally there should be no '...' inside them *)
956 | Ast.ExprDotsTag(x) -> dots (function _ -> ()) expression x; false
957 | Ast.ParamDotsTag(x) -> parameter_list x; false
958 | Ast.StmtDotsTag(x) -> dots force_newline (statement "") x; false
959 | Ast.DeclDotsTag(x) -> dots force_newline declaration x; false
960
961 | Ast.TypeCTag(x) -> typeC x; false
962 | Ast.ParamTag(x) -> parameterTypeDef x; false
963 | Ast.SgrepStartTag(x) -> failwith "unexpected start tag"
964 | Ast.SgrepEndTag(x) -> failwith "unexpected end tag"
965 in
966
967 anything := (function x -> let _ = pp_any x in ());
968
969 (* todo? imitate what is in pretty_print_cocci ? *)
970 match xxs with
971 [] -> ()
972 | x::xs ->
973 (* for many tags, we must not do a newline before the first '+' *)
974 let isfn s =
975 match Ast.unwrap s with Ast.FunDecl _ -> true | _ -> false in
976 let unindent_before = function
977 (* need to get unindent before newline for } *)
978 (Ast.Token ("}",_)::_) -> true
979 | _ -> false in
980 let prnl x =
981 (if unindent_before x then unindent());
982 force_newline() in
983 let newline_before _ =
984 if before =*= After
985 then
986 let hd = List.hd xxs in
987 match hd with
988 (Ast.StatementTag s::_) when isfn s ->
989 force_newline(); force_newline()
990 | (Ast.Pragma _::_)
991 | (Ast.Rule_elemTag _::_) | (Ast.StatementTag _::_)
992 | (Ast.InitTag _::_)
993 | (Ast.DeclarationTag _::_) | (Ast.Token ("}",_)::_) -> prnl hd
994 | _ -> () in
995 let newline_after _ =
996 if before =*= Before
997 then
998 match List.rev(List.hd(List.rev xxs)) with
999 (Ast.StatementTag s::_) ->
1000 (if isfn s then force_newline());
1001 force_newline()
1002 | (Ast.Pragma _::_)
1003 | (Ast.Rule_elemTag _::_) | (Ast.InitTag _::_)
1004 | (Ast.DeclarationTag _::_) | (Ast.Token ("{",_)::_) ->
1005 force_newline()
1006 | _ -> () in
1007 (* print a newline at the beginning, if needed *)
1008 newline_before();
1009 (* print a newline before each of the rest *)
1010 let rec loop leading_newline indent_needed = function
1011 [] -> ()
1012 | x::xs ->
1013 (if leading_newline
1014 then
1015 match (indent_needed,unindent_before x) with
1016 (true,true) -> force_newline()
1017 | (true,false) -> force_newline(); indent()
1018 | (false,true) -> unindent(); force_newline()
1019 | (false,false) -> force_newline());
1020 let space_needed_before = function
1021 Ast.ParamTag(x) ->
1022 (match Ast.unwrap x with
1023 Ast.PComma _ -> false
1024 | _ -> true)
1025 | Ast.ExpressionTag(x) ->
1026 (match Ast.unwrap x with
1027 Ast.EComma _ -> false
1028 | _ -> true)
1029 | Ast.InitTag(x) ->
1030 (match Ast.unwrap x with
1031 Ast.IComma _ -> false
1032 | _ -> true)
1033 | Ast.Token(t,_) when List.mem t [",";";";"(";")"] -> false
1034 | _ -> true in
1035 let space_needed_after = function
1036 Ast.Token(t,_) when List.mem t ["("] -> (*never needed*) false
1037 | Ast.Token(t,_) when List.mem t ["if";"for";"while";"do"] ->
1038 (* space always needed *)
1039 pr_space(); false
1040 | _ -> true in
1041 let indent_needed =
1042 let rec loop space_after indent_needed = function
1043 [] -> indent_needed
1044 | x::xs ->
1045 (if space_after && space_needed_before x
1046 then pr_space());
1047 let indent_needed = pp_any x in
1048 let space_after = space_needed_after x in
1049 loop space_after indent_needed xs in
1050 loop false false x in
1051 loop true indent_needed xs in
1052 loop false false (x::xs);
1053 (* print a newline at the end, if needed *)
1054 newline_after()
1055
1056 let rec pp_list_list_any (envs, pr, pr_celem, pr_cspace, pr_space, pr_arity,
1057 pr_barrier, indent, unindent)
1058 generating xxs before =
1059 List.iter
1060 (function env ->
1061 do_all (env, pr, pr_celem, pr_cspace, pr_space, pr_arity, pr_barrier,
1062 indent, unindent)
1063 generating xxs before)
1064 envs