Release coccinelle-0.1.11rc1
[bpt/coccinelle.git] / parsing_c / unparse_cocci.ml
index 2d7e950..b974d4a 100644 (file)
@@ -3,18 +3,18 @@
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License (GPL)
  * version 2 as published by the Free Software Foundation.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * file license.txt for more details.
- * 
+ *
  * This file was part of Coccinelle.
  *)
 open Common
 
 (*****************************************************************************)
-(* mostly a copy paste of parsing_cocci/pretty_print_cocci.ml 
+(* mostly a copy paste of parsing_cocci/pretty_print_cocci.ml
  * todo?: try to factorize ?
  *)
 (*****************************************************************************)
@@ -23,8 +23,8 @@ module Ast = Ast_cocci
 
 let term s = Ast.unwrap_mcode s
 
-(* or perhaps can have in plus, for instance a Disj, but those Disj must be 
- *  handled by interactive tool (by proposing alternatives) 
+(* or perhaps can have in plus, for instance a Disj, but those Disj must be
+ *  handled by interactive tool (by proposing alternatives)
  *)
 exception CantBeInPlus
 
@@ -34,7 +34,7 @@ type pos = Before | After | InPlace
 
 let unknown = -1
 
-let rec pp_list_list_any
+let rec do_all
     (env, pr, pr_celem, pr_cspace, pr_space, pr_arity, pr_barrier,
      indent, unindent)
     generating xxs before =
@@ -45,13 +45,19 @@ let print_string s line lcol =
   pr s line lcol rcol in
 let print_text s = pr s unknown unknown unknown in
 let close_box _ = () in
-let force_newline () = print_text "\n" in
+let force_newline _ = print_text "\n" in
 
 let start_block () = force_newline(); indent() in
 let end_block () = unindent(); force_newline () in
 let print_string_box s = print_string s in
 
 let print_option = Common.do_option in
+let print_option_prespace fn = function
+    None -> ()
+  | Some x -> pr_space(); fn x in
+let print_option_space fn = function
+    None -> ()
+  | Some x -> fn x; pr_space() in
 let print_between = Common.print_between in
 
 let outdent _ = () (* should go to leftmost col, does nothing now *) in
@@ -92,9 +98,9 @@ and print_anything_list = function
 
 let print_around printer term = function
     Ast.NOTHING -> printer term
-  | Ast.BEFORE(bef) -> print_anything bef; printer term
-  | Ast.AFTER(aft) -> printer term; print_anything aft
-  | Ast.BEFOREAFTER(bef,aft) ->
+  | Ast.BEFORE(bef,_) -> print_anything bef; printer term
+  | Ast.AFTER(aft,_) -> printer term; print_anything aft
+  | Ast.BEFOREAFTER(bef,aft,_) ->
       print_anything bef; printer term; print_anything aft in
 
 let print_string_befaft fn fn1 x info =
@@ -105,7 +111,6 @@ let print_string_befaft fn fn1 x info =
   List.iter
     (function (s,ln,col) -> force_newline(); fn1(); print_string s ln col)
     info.Ast.straft in
-
 let print_meta (r,x) = print_text x in
 
 let print_pos = function
@@ -140,6 +145,14 @@ let mcode fn (s,info,mc,pos) =
       |        _ -> force_newline());
       fn s line lcol;
       let _ = print_comments (Some info.Ast.line) info.Ast.straft in
+      (* newline after a pragma
+        should really store parsed versions of the strings, but make a cheap
+        effort here
+         print_comments takes care of interior newlines *)
+      (match List.rev info.Ast.straft with
+       (str,_,_)::_ when String.length str > 0 && String.get str 0 = '#' ->
+         force_newline()
+      |        _ -> ());
       ()
       (* printing for rule generation *)
   | (true, Ast.MINUS(_,_,_,plus_stream)) ->
@@ -150,10 +163,14 @@ let mcode fn (s,info,mc,pos) =
   | (true, Ast.CONTEXT(_,plus_streams)) ->
       let fn s = force_newline(); fn s line lcol; print_pos pos in
       print_around fn s plus_streams
-  | (true,Ast.PLUS) ->
+  | (true,Ast.PLUS Ast.ONE) ->
       let fn s =
        force_newline(); print_text "+ "; fn s line lcol; print_pos pos in
       print_string_befaft fn (function _ -> print_text "+ ") s info
+  | (true,Ast.PLUS Ast.MANY) ->
+      let fn s =
+       force_newline(); print_text "++ "; fn s line lcol; print_pos pos in
+      print_string_befaft fn (function _ -> print_text "++ ") s info
 in
 
 
@@ -214,25 +231,25 @@ in
 
 let rec ident i =
   match Ast.unwrap i with
-    Ast.Id(name) -> mcode print_string name
-  | Ast.MetaId(name,_,_,_) -> 
-      handle_metavar name (function
-        | (Ast_c.MetaIdVal id) -> print_text id
-        | _ -> raise Impossible
-        ) 
-  | Ast.MetaFunc(name,_,_,_) -> 
-      handle_metavar name (function
-        | (Ast_c.MetaFuncVal id) -> print_text id
-        | _ -> raise Impossible
-        ) 
-  | Ast.MetaLocalFunc(name,_,_,_) -> 
-      handle_metavar name (function
-        | (Ast_c.MetaLocalFuncVal id) -> print_text id
-        | _ -> raise Impossible
-        )
-
-  | Ast.OptIdent(_) | Ast.UniqueIdent(_) -> 
-      raise CantBeInPlus
+      Ast.Id(name) -> mcode print_string name
+    | Ast.MetaId(name,_,_,_) ->
+       handle_metavar name (function
+                              | (Ast_c.MetaIdVal id) -> print_text id
+                              | _ -> raise Impossible
+                           )
+    | Ast.MetaFunc(name,_,_,_) ->
+       handle_metavar name (function
+                              | (Ast_c.MetaFuncVal id) -> print_text id
+                              | _ -> raise Impossible
+                           )
+    | Ast.MetaLocalFunc(name,_,_,_) ->
+       handle_metavar name (function
+                              | (Ast_c.MetaLocalFuncVal id) -> print_text id
+                              | _ -> raise Impossible
+                           )
+
+    | Ast.OptIdent(_) | Ast.UniqueIdent(_) ->
+       raise CantBeInPlus
 
 in
 
@@ -250,7 +267,12 @@ let rec expression e =
   | Ast.Constant(const) -> mcode constant const
   | Ast.FunCall(fn,lp,args,rp) ->
       expression fn; mcode print_string_box lp;
-      dots (function _ -> ()) expression args;
+      let comma e =
+       expression e;
+       match Ast.unwrap e with
+         Ast.EComma(cm) -> pr_space()
+       | _ -> () in
+      dots (function _ -> ()) comma args;
       close_box(); mcode print_string rp
   | Ast.Assignment(left,op,right,_) ->
       expression left; pr_space(); mcode assignOp op;
@@ -304,7 +326,7 @@ let rec expression e =
         | _ -> raise Impossible
       )
 
-  | Ast.EComma(cm) -> mcode print_string cm; pr_space()
+  | Ast.EComma(cm) -> mcode print_string cm
 
   | Ast.DisjExpr(exp_list) ->
       if generating
@@ -392,9 +414,7 @@ and constant = function
 
 and fullType ft =
   match Ast.unwrap ft with
-    Ast.Type(cv,ty) ->
-      print_option (mcode const_vol) cv;
-      typeC ty
+    Ast.Type(cv,ty) -> print_option_space (mcode const_vol) cv; typeC ty
   | Ast.DisjType _ -> failwith "can't be in plus"
   | Ast.OptType(_) | Ast.UniqueType(_) ->
       raise CantBeInPlus
@@ -412,8 +432,7 @@ and typeC ty =
   match Ast.unwrap ty with
     Ast.BaseType(ty,strings) ->
       print_between pr_space (mcode print_string) strings
-  | Ast.SignedT(sgn,Some ty) -> mcode sign sgn; typeC ty
-  | Ast.SignedT(sgn,None) -> mcode signns sgn
+  | Ast.SignedT(sgn,ty) -> mcode sign sgn; print_option_prespace typeC ty
   | Ast.Pointer(ty,star) -> fullType ty; ft_space ty; mcode print_string star
   | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) ->
       print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2)
@@ -426,8 +445,7 @@ and typeC ty =
   | Ast.EnumName(kind,name) -> mcode print_string kind; pr_space();
       ident name
   | Ast.StructUnionName(kind,name) ->
-      mcode structUnion kind;
-      print_option ident name
+      mcode structUnion kind; print_option_prespace ident name
   | Ast.StructUnionDef(ty,lb,decls,rb) ->
       fullType ty; ft_space ty;
       mcode print_string lb;
@@ -451,30 +469,26 @@ and baseType = function
   | Ast.LongLongType -> print_string "long long"
 
 and structUnion = function
-    Ast.Struct -> print_string "struct "
-  | Ast.Union -> print_string "union "
+    Ast.Struct -> print_string "struct"
+  | Ast.Union -> print_string "union"
 
 and sign = function
-    Ast.Signed -> print_string "signed "
-  | Ast.Unsigned -> print_string "unsigned "
-
-and signns = function (* no space, like a normal type *)
     Ast.Signed -> print_string "signed"
   | Ast.Unsigned -> print_string "unsigned"
 
 
 and const_vol = function
-    Ast.Const -> print_string "const "
-  | Ast.Volatile -> print_string "volatile "
+    Ast.Const -> print_string "const"
+  | Ast.Volatile -> print_string "volatile"
 
 (* --------------------------------------------------------------------- *)
 (* Function declaration *)
 
 and storage = function
-    Ast.Static -> print_string "static "
-  | Ast.Auto -> print_string "auto "
-  | Ast.Register -> print_string "register "
-  | Ast.Extern -> print_string "extern "
+    Ast.Static -> print_string "static"
+  | Ast.Auto -> print_string "auto"
+  | Ast.Register -> print_string "register"
+  | Ast.Extern -> print_string "extern"
 
 (* --------------------------------------------------------------------- *)
 (* Variable declaration *)
@@ -527,11 +541,13 @@ and declaration d =
   match Ast.unwrap d with
     Ast.Init(stg,ty,id,eq,ini,sem) ->
       print_option (mcode storage) stg;
+      print_option (function _ -> pr_space()) stg;
       print_named_type ty id;
       pr_space(); mcode print_string eq;
       pr_space(); initialiser true ini; mcode print_string sem
   | Ast.UnInit(stg,ty,id,sem) ->
       print_option (mcode storage) stg;
+      print_option (function _ -> pr_space()) stg;
       print_named_type ty id;
       mcode print_string sem
   | Ast.MacroDecl(name,lp,args,rp,sem) ->
@@ -602,13 +618,19 @@ and parameterTypeDef p =
   | Ast.MetaParamList(name,_,_,_) -> 
       failwith "not handling MetaParamList"
 
-  | Ast.PComma(cm) -> mcode print_string cm; pr_space()
+  | Ast.PComma(cm) -> mcode print_string cm
   | Ast.Pdots(dots) | Ast.Pcircles(dots) when generating ->
       mcode print_string dots
   | Ast.Pdots(dots) | Ast.Pcircles(dots) -> raise CantBeInPlus
   | Ast.OptParam(param) | Ast.UniqueParam(param) -> raise CantBeInPlus
 
-and parameter_list l = dots (function _ -> ()) parameterTypeDef l
+and parameter_list l =
+  let comma p =
+    parameterTypeDef p;
+    match Ast.unwrap p with
+      Ast.PComma(cm) -> pr_space()
+    | _ -> () in
+  dots (function _ -> ()) comma l
 in
 
 
@@ -791,8 +813,9 @@ let rec statement arity s =
       indent_if_needed body (function _ -> statement arity body);
       mcode (fun _ _ _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos)
 
-  | Ast.Switch(header,lb,cases,rb) ->
+  | Ast.Switch(header,lb,decls,cases,rb) ->
       rule_elem arity header; pr_space(); rule_elem arity lb;
+      dots force_newline (statement arity) decls;
       List.iter (function x -> case_line arity x; force_newline()) cases;
       rule_elem arity rb
 
@@ -921,10 +944,7 @@ let rec pp_any = function
          (match x with
            "else" -> force_newline()
          | _ -> ());
-         print_string x line lcol;
-         (match x with
-           "else" -> pr_space()
-         | _ -> ()))
+         print_string x line lcol)
        (let nomcodekind = Ast.CONTEXT(Ast.DontCarePos,Ast.NOTHING) in
        (x,info,nomcodekind,Ast.NoMetaPos));
       if_open_brace x
@@ -997,10 +1017,48 @@ in
              | (true,false) -> force_newline(); indent()
              | (false,true) -> unindent(); force_newline()
              | (false,false) -> force_newline());
+           let space_needed_before = function
+               Ast.ParamTag(x) ->
+                 (match Ast.unwrap x with
+                   Ast.PComma _ -> false
+                 | _ -> true)
+             | Ast.ExpressionTag(x) ->
+                 (match Ast.unwrap x with
+                   Ast.EComma _ -> false
+                 | _ -> true)
+             | Ast.InitTag(x) ->
+                 (match Ast.unwrap x with
+                   Ast.IComma _ -> false
+                 | _ -> true)
+             | Ast.Token(t,_) when List.mem t [",";";";"(";")"] -> false
+             | _ -> true in
+           let space_needed_after = function
+               Ast.Token(t,_) when List.mem t ["("] -> (*never needed*) false
+             | Ast.Token(t,_) when List.mem t ["if";"for";"while";"do"] ->
+                 (* space always needed *)
+                 pr_space(); false
+             | _ -> true in
            let indent_needed =
-             List.fold_left (function indent_needed -> pp_any) false x in
+             let rec loop space_after indent_needed = function
+                 [] -> indent_needed
+               | x::xs ->
+                   (if space_after && space_needed_before x
+                   then pr_space());
+                   let indent_needed = pp_any x in
+                   let space_after = space_needed_after x in
+                   loop space_after indent_needed xs in
+             loop false false x in
            loop true indent_needed xs in
       loop false false (x::xs);
       (* print a newline at the end, if needed *)
       newline_after()
 
+let rec pp_list_list_any (envs, pr, pr_celem, pr_cspace, pr_space, pr_arity,
+                         pr_barrier, indent, unindent)
+    generating xxs before =
+  List.iter
+    (function env ->
+      do_all (env, pr, pr_celem, pr_cspace, pr_space, pr_arity, pr_barrier,
+             indent, unindent)
+       generating xxs before)
+    envs