Coccinelle release 1.0.0-rc3
[bpt/coccinelle.git] / parsing_c / unparse_cocci.ml
index ea528fc..d7d5912 100644 (file)
@@ -1,20 +1,22 @@
-(* Copyright (C) 2006, 2007 Julia Lawall
+(*
+ * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
+ * Copyright (C) 2006, 2007 Julia Lawall
  *
  * 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,18 +25,22 @@ 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
 
 (*****************************************************************************)
 
 type pos = Before | After | InPlace
+type nlhint = StartBox | EndBox | SpaceOrNewline of string ref
+
+let get_string_info = function
+    Ast.Noindent s | Ast.Indent s | Ast.Space s -> s
 
 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 =
@@ -42,13 +48,16 @@ let rec pp_list_list_any
 (* Just to be able to copy paste the code from pretty_print_cocci.ml. *)
 let print_string s line lcol =
   let rcol = if lcol = unknown then unknown else lcol + (String.length s) in
-  pr s line lcol rcol in
-let print_text s = pr s unknown unknown unknown in
+  pr s line lcol rcol None in
+let print_string_with_hint hint s line lcol =
+  let rcol = if lcol = unknown then unknown else lcol + (String.length s) in
+  pr s line lcol rcol (Some hint) in
+let print_text s = pr s unknown unknown unknown None 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 end_block () = unindent true; force_newline () in
 let print_string_box s = print_string s in
 
 let print_option = Common.do_option in
@@ -64,7 +73,7 @@ let outdent _ = () (* should go to leftmost col, does nothing now *) in
 
 let pretty_print_c =
   Pretty_print_c.mk_pretty_printers pr_celem pr_cspace
-    force_newline indent outdent unindent in
+    force_newline indent outdent (function _ -> unindent true) in
 
 (* --------------------------------------------------------------------- *)
 (* Only for make_hrule, print plus code, unbound metavariables *)
@@ -98,27 +107,29 @@ 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 =
+  let print ln col s = print_string (get_string_info s) ln col in
   List.iter
-    (function (s,ln,col) -> fn1(); print_string s ln col; force_newline())
+    (function (s,ln,col) -> fn1(); print ln col s; force_newline())
     info.Ast.strbef;
   fn x;
   List.iter
-    (function (s,ln,col) -> force_newline(); fn1(); print_string s ln col)
+    (function (s,ln,col) -> force_newline(); fn1(); print ln col s)
     info.Ast.straft in
-
 let print_meta (r,x) = print_text x in
 
-let print_pos = function
-    Ast.MetaPos(name,_,_,_,_) ->
-      let name = Ast.unwrap_mcode name in
-      print_text "@"; print_meta name
-  | _ -> () in
+let print_pos l =
+  List.iter
+    (function
+       Ast.MetaPos(name,_,_,_,_) ->
+         let name = Ast.unwrap_mcode name in
+         print_text "@"; print_meta name)
+    l in
 
 (* --------------------------------------------------------------------- *)
 
@@ -134,10 +145,25 @@ let mcode fn (s,info,mc,pos) =
          (function line_before ->
            function (str,line,col) ->
              match line_before with
-               None -> print_string str line col; Some line
-             | Some lb when line =|= lb ->
+               None ->
+                 let str =
+                   match str with
+                     Ast.Noindent s -> unindent false; s
+                   | Ast.Indent s -> s
+                   | Ast.Space s -> s in
                  print_string str line col; Some line
-             | _ -> force_newline(); print_string str line col; Some line)
+             | Some lb when line =|= lb ->
+                 print_string (get_string_info str) line col; Some line
+             | _ ->
+                 force_newline();
+                 (* not super elegant to put side-effecting unindent in a let
+                    expression... *)
+                 let str =
+                   match str with
+                     Ast.Noindent s -> unindent false; s
+                   | Ast.Indent s -> s
+                   | Ast.Space s -> s in
+                 print_string str line col; Some line)
          lb comments in
       let line_before = print_comments None info.Ast.strbef in
       (match line_before with
@@ -146,20 +172,30 @@ 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 *)
       ()
       (* printing for rule generation *)
   | (true, Ast.MINUS(_,_,_,plus_stream)) ->
       force_newline();
       print_text "- ";
       fn s line lcol; print_pos pos;
-      print_anything plus_stream
+      (match plus_stream with
+       Ast.NOREPLACEMENT -> ()
+      |        Ast.REPLACEMENT(plus_stream,ct) -> print_anything plus_stream)
   | (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
 
 
@@ -186,7 +222,8 @@ let handle_metavar name fn =
        (* call mcode to preserve the -+ annotation *)
        mcode (fun _ _ _ -> fn e) name
       else fn e);
-      let rcol = if lcol = unknown then unknown else lcol + (String.length b) in
+      let rcol =
+       if lcol = unknown then unknown else lcol + (String.length b) in
       pr_barrier line rcol
 in
 (* --------------------------------------------------------------------- *)
@@ -197,74 +234,71 @@ let dots between fn d =
   | Ast.STARS(l) -> print_between between fn l
 in
 
-let nest_dots multi fn f d =
-  let mo s = if multi then "<+"^s else "<"^s in
-  let mc s = if multi then s^"+>" else s^">" in
-  match Ast.unwrap d with
-    Ast.DOTS(l) ->
-      print_text (mo "..."); f(); start_block();
-      print_between force_newline fn l;
-      end_block(); print_text (mc "...")
-  | Ast.CIRCLES(l) ->
-      print_text (mo "ooo"); f(); start_block();
-      print_between force_newline fn l;
-      end_block(); print_text (mc "ooo")
-  | Ast.STARS(l) ->
-      print_text (mo "***"); f(); start_block();
-      print_between force_newline fn l;
-      end_block(); print_text (mc "***")
+let nest_dots starter ender fn f d =
+  mcode print_string starter;
+  f(); start_block();
+  (match Ast.unwrap d with
+    Ast.DOTS(l)    -> print_between force_newline fn l
+  | Ast.CIRCLES(l) -> print_between force_newline fn l
+  | Ast.STARS(l)   -> print_between force_newline fn l);
+  end_block();
+  mcode print_string ender
 in
 
+let print_disj_list fn l =
+  print_text "\n(\n";
+  print_between (function _ -> print_text "\n|\n") fn l;
+  print_text "\n)\n" in
+
 (* --------------------------------------------------------------------- *)
 (* Identifier *)
 
 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.DisjId(id_list) ->
+       if generating
+       then print_disj_list ident id_list
+       else raise CantBeInPlus
+    | Ast.OptIdent(_) | Ast.UniqueIdent(_) ->
+       raise CantBeInPlus
 
 in
 
 (* --------------------------------------------------------------------- *)
 (* Expression *)
 
-let print_disj_list fn l =
-  print_text "\n(\n";
-  print_between (function _ -> print_text "\n|\n") fn l;
-  print_text "\n)\n" in
-
 let rec expression e =
   match Ast.unwrap e with
     Ast.Ident(id) -> ident id
   | Ast.Constant(const) -> mcode constant const
   | Ast.FunCall(fn,lp,args,rp) ->
-      expression fn; mcode print_string_box lp;
-      dots (function _ -> ()) expression args;
-      close_box(); mcode print_string rp
+      expression fn; mcode (print_string_with_hint StartBox) lp;
+      dots (function _ -> ()) arg_expression args;
+      mcode (print_string_with_hint EndBox) rp
   | Ast.Assignment(left,op,right,_) ->
       expression left; pr_space(); mcode assignOp op;
       pr_space(); expression right
   | Ast.CondExpr(exp1,why,exp2,colon,exp3) ->
       expression exp1; pr_space(); mcode print_string why;
       print_option (function e -> pr_space(); expression e) exp2;
-      pr_space(); mcode print_string colon; expression exp3
+      pr_space(); mcode print_string colon; pr_space(); expression exp3
   | Ast.Postfix(exp,op) -> expression exp; mcode fixOp op
   | Ast.Infix(exp,op) -> mcode fixOp op; expression exp
   | Ast.Unary(exp,op) -> mcode unaryOp op; expression exp
@@ -293,20 +327,22 @@ let rec expression e =
       mcode print_string rp
   | Ast.TypeExp(ty) -> fullType ty
 
-  | Ast.MetaErr(name,_,_,_) -> 
+  | Ast.MetaErr(name,_,_,_) ->
       failwith "metaErr not handled"
 
   | Ast.MetaExpr (name,_,_,_typedontcare,_formdontcare,_) ->
       handle_metavar name  (function
-        | Ast_c.MetaExprVal exp -> 
+        | Ast_c.MetaExprVal (exp,_) ->
             pretty_print_c.Pretty_print_c.expression exp
         | _ -> raise Impossible
       )
 
-  | Ast.MetaExprList (name,_,_,_) -> 
+  | Ast.MetaExprList (name,_,_,_) ->
       handle_metavar name  (function
-        | Ast_c.MetaExprListVal args -> 
+        | Ast_c.MetaExprListVal args ->
             pretty_print_c.Pretty_print_c.arg_list args
+       | Ast_c.MetaParamListVal _ ->
+           failwith "have meta param list matching meta exp list\n";
         | _ -> raise Impossible
       )
 
@@ -316,13 +352,14 @@ let rec expression e =
       if generating
       then print_disj_list expression exp_list
       else raise CantBeInPlus
-  | Ast.NestExpr(expr_dots,Some whencode,multi) when generating ->
-      nest_dots multi expression
+  | Ast.NestExpr(starter,expr_dots,ender,Some whencode,multi)
+    when generating ->
+      nest_dots starter ender expression
        (function _ -> print_text "   when != "; expression whencode)
        expr_dots
-  | Ast.NestExpr(expr_dots,None,multi) when generating ->
-      nest_dots multi expression (function _ -> ()) expr_dots
-  | Ast.NestExpr(_) -> raise CantBeInPlus
+  | Ast.NestExpr(starter,expr_dots,ender,None,multi) when generating ->
+      nest_dots starter ender expression (function _ -> ()) expr_dots
+  | Ast.NestExpr _ -> raise CantBeInPlus
   | Ast.Edots(dots,Some whencode)
   | Ast.Ecircles(dots,Some whencode)
   | Ast.Estars(dots,Some whencode) ->
@@ -339,11 +376,20 @@ let rec expression e =
       then mcode print_string dots
       else raise CantBeInPlus
 
-  | Ast.OptExp(exp) | Ast.UniqueExp(exp) -> 
+  | Ast.OptExp(exp) | Ast.UniqueExp(exp) ->
       raise CantBeInPlus
 
+and arg_expression e =
+  match Ast.unwrap e with
+    Ast.EComma(cm) ->
+      (* space is only used by add_newline, and only if not using SMPL
+        spacing.  pr_cspace uses a " " in unparse_c.ml.  Not so nice... *)
+      mcode (print_string_with_hint (SpaceOrNewline (ref " ")))  cm
+  | _ -> expression e
+
 and  unaryOp = function
     Ast.GetRef -> print_string "&"
+  | Ast.GetRefLabel -> print_string "&&"
   | Ast.DeRef -> print_string "*"
   | Ast.UnPlus -> print_string "+"
   | Ast.UnMinus -> print_string "-"
@@ -426,8 +472,14 @@ and typeC ty =
   | Ast.Array(ty,lb,size,rb) ->
       fullType ty; mcode print_string lb; print_option expression size;
       mcode print_string rb
-  | Ast.EnumName(kind,name) -> mcode print_string kind; pr_space();
-      ident name
+  | Ast.EnumName(kind,name) ->
+      mcode print_string kind;
+      print_option_prespace ident name
+  | Ast.EnumDef(ty,lb,ids,rb) ->
+      fullType ty; ft_space ty;
+      mcode print_string lb;
+      dots force_newline expression ids;
+      mcode print_string rb
   | Ast.StructUnionName(kind,name) ->
       mcode structUnion kind; print_option_prespace ident name
   | Ast.StructUnionDef(ty,lb,decls,rb) ->
@@ -436,9 +488,9 @@ and typeC ty =
       dots force_newline declaration decls;
       mcode print_string rb
   | Ast.TypeName(name)-> mcode print_string name
-  | Ast.MetaType(name,_,_) -> 
+  | Ast.MetaType(name,_,_) ->
       handle_metavar name  (function
-          Ast_c.MetaTypeVal exp -> 
+          Ast_c.MetaTypeVal exp ->
             pretty_print_c.Pretty_print_c.ty exp
         | _ -> raise Impossible)
 
@@ -451,6 +503,9 @@ and baseType = function
   | Ast.FloatType -> print_string "float"
   | Ast.LongType -> print_string "long"
   | Ast.LongLongType -> print_string "long long"
+  | Ast.SizeType -> print_string "size_t "
+  | Ast.SSizeType -> print_string "ssize_t "
+  | Ast.PtrDiffType -> print_string "ptrdiff_t "
 
 and structUnion = function
     Ast.Struct -> print_string "struct"
@@ -518,12 +573,39 @@ and ft_space ty =
     Ast.Type(cv,ty) ->
       (match Ast.unwrap ty with
        Ast.Pointer(_,_) -> ()
+      | Ast.MetaType(name,_,_) ->
+         (match List.assoc (Ast.unwrap_mcode name) env with
+            Ast_c.MetaTypeVal (tq,ty) ->
+             (match Ast_c.unwrap ty with
+               Ast_c.Pointer(_,_) -> ()
+             | _ -> pr_space())
+         | _ -> pr_space())
       | _ -> pr_space())
   | _ -> pr_space()
 
 and declaration d =
   match Ast.unwrap d with
-    Ast.Init(stg,ty,id,eq,ini,sem) ->
+    Ast.MetaDecl(name,_,_) ->
+      handle_metavar name
+       (function
+           Ast_c.MetaDeclVal d ->
+              pretty_print_c.Pretty_print_c.decl d
+          | _ -> raise Impossible)
+  | Ast.MetaField(name,_,_) ->
+      handle_metavar name
+       (function
+           Ast_c.MetaFieldVal f ->
+              pretty_print_c.Pretty_print_c.field f
+          | _ -> raise Impossible)
+
+  | Ast.MetaFieldList(name,_,_,_) ->
+      handle_metavar name
+       (function
+           Ast_c.MetaFieldListVal f ->
+             print_between force_newline pretty_print_c.Pretty_print_c.field f
+          | _ -> raise Impossible)
+
+  | Ast.Init(stg,ty,id,eq,ini,sem) ->
       print_option (mcode storage) stg;
       print_option (function _ -> pr_space()) stg;
       print_named_type ty id;
@@ -543,9 +625,9 @@ and declaration d =
       mcode print_string stg;
       fullType ty; typeC id;
       mcode print_string sem
-  | Ast.DisjDecl(_) | Ast.MetaDecl(_,_,_) -> raise CantBeInPlus
+  | Ast.DisjDecl(_) -> raise CantBeInPlus
   | Ast.Ddots(_,_) -> raise CantBeInPlus
-  | Ast.OptDecl(decl)  | Ast.UniqueDecl(decl) -> 
+  | Ast.OptDecl(decl)  | Ast.UniqueDecl(decl) ->
       raise CantBeInPlus
 
 (* --------------------------------------------------------------------- *)
@@ -553,22 +635,32 @@ and declaration d =
 
 and initialiser nlcomma i =
   match Ast.unwrap i with
-    Ast.MetaInit(name,_,_) -> 
+    Ast.MetaInit(name,_,_) ->
       handle_metavar name  (function
           Ast_c.MetaInitVal ini ->
             pretty_print_c.Pretty_print_c.init ini
         | _ -> raise Impossible)
+  | Ast.MetaInitList(name,_,_,_) ->
+      handle_metavar name  (function
+          Ast_c.MetaInitListVal ini ->
+           pretty_print_c.Pretty_print_c.init_list ini
+        | _ -> raise Impossible)
   | Ast.InitExpr(exp) -> expression exp
-  | Ast.InitList(lb,initlist,rb,[]) ->
+  | Ast.ArInitList(lb,initlist,rb) ->
+      (match Ast.undots initlist with
+       [] -> mcode print_string lb; mcode print_string rb
+      |        lst ->
+         mcode print_string lb; start_block();
+         initialiser_list nlcomma lst;
+         end_block(); mcode print_string rb)
+  | Ast.StrInitList(_,lb,[],rb,[]) ->
+      mcode print_string lb; mcode print_string rb
+  | Ast.StrInitList(_,lb,initlist,rb,[]) ->
       mcode print_string lb; start_block();
-      (* awkward, because the comma is separate from the initialiser *)
-      let rec loop = function
-         [] -> ()
-       | [x] -> initialiser false x
-       | x::xs -> initialiser nlcomma x; loop xs in
-      loop initlist;
+      initialiser_list nlcomma initlist;
       end_block(); mcode print_string rb
-  | Ast.InitList(lb,initlist,rb,_) -> failwith "unexpected whencode in plus"
+  | Ast.StrInitList(_,lb,initlist,rb,_) ->
+      failwith "unexpected whencode in plus"
   | Ast.InitGccExt(designators,eq,ini) ->
       List.iter designator designators; pr_space();
       mcode print_string eq; pr_space(); initialiser nlcomma ini
@@ -576,10 +668,27 @@ and initialiser nlcomma i =
       ident name; mcode print_string eq; initialiser nlcomma ini
   | Ast.IComma(comma) ->
       mcode print_string comma;
-      if nlcomma then force_newline()
+      if nlcomma then force_newline() else pr_space()
+  | Ast.Idots(dots,Some whencode) ->
+      if generating
+      then
+       (mcode print_string dots;
+        print_text "   when != ";
+        initialiser nlcomma whencode)
+      else raise CantBeInPlus
+  | Ast.Idots(dots,None) ->
+      if generating
+      then mcode print_string dots
+      else raise CantBeInPlus
   | Ast.OptIni(ini) | Ast.UniqueIni(ini) ->
       raise CantBeInPlus
 
+and initialiser_list nlcomma = function
+  (* awkward, because the comma is separate from the initialiser *)
+    [] -> ()
+  | [x] -> initialiser false x
+  | x::xs -> initialiser nlcomma x; initialiser_list nlcomma xs
+
 and designator = function
     Ast.DesignatorField(dot,id) -> mcode print_string dot; ident id
   | Ast.DesignatorIndex(lb,exp,rb) ->
@@ -597,10 +706,18 @@ and parameterTypeDef p =
   | Ast.Param(ty,Some id) -> print_named_type ty id
   | Ast.Param(ty,None) -> fullType ty
 
-  | Ast.MetaParam(name,_,_) -> 
-      failwith "not handling MetaParam"
-  | Ast.MetaParamList(name,_,_,_) -> 
-      failwith "not handling MetaParamList"
+  | Ast.MetaParam(name,_,_) ->
+      handle_metavar name
+       (function
+           Ast_c.MetaParamVal p ->
+              pretty_print_c.Pretty_print_c.param p
+          | _ -> raise Impossible)
+  | Ast.MetaParamList(name,_,_,_) ->
+      handle_metavar name
+       (function
+           Ast_c.MetaParamListVal p ->
+              pretty_print_c.Pretty_print_c.paramlist p
+          | _ -> raise Impossible)
 
   | Ast.PComma(cm) -> mcode print_string cm
   | Ast.Pdots(dots) | Ast.Pcircles(dots) when generating ->
@@ -608,7 +725,13 @@ and parameterTypeDef p =
   | 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
 
 
@@ -643,7 +766,7 @@ and rule_elem arity re =
       end_block(); pr_arity arity; mcode print_string brace
 
   | Ast.ExprStatement(exp,sem) ->
-      pr_arity arity; expression exp; mcode print_string sem
+      pr_arity arity; print_option expression exp; mcode print_string sem
 
   | Ast.IfHeader(iff,lp,exp,rp) ->
       pr_arity arity;
@@ -689,7 +812,7 @@ and rule_elem arity re =
   | Ast.Goto(goto,l,sem) ->
       mcode print_string goto; ident l; mcode print_string sem
   | Ast.Return(ret,sem) ->
-      pr_arity arity; mcode print_string ret; 
+      pr_arity arity; mcode print_string ret;
       mcode print_string sem
   | Ast.ReturnExpr(ret,exp,sem) ->
       pr_arity arity; mcode print_string ret; pr_space();
@@ -701,8 +824,10 @@ and rule_elem arity re =
   | Ast.TopInit(init) -> initialiser false init
   | Ast.Include(inc,s) ->
       mcode print_string inc; print_text " "; mcode inc_file s
+  | Ast.Undef(def,id) ->
+      mcode print_string def; pr_space(); ident id
   | Ast.DefineHeader(def,id,params) ->
-      mcode print_string def; pr_space(); ident id; 
+      mcode print_string def; pr_space(); ident id;
       print_define_parameters params
   | Ast.Default(def,colon) ->
       mcode print_string def; mcode print_string colon; pr_space()
@@ -758,7 +883,7 @@ let indent_if_needed s f =
     Ast.Seq(lbrace,body,rbrace) -> pr_space(); f()
   | _ ->
       (*no newline at the end - someone else will do that*)
-      start_block(); f(); unindent() in
+      start_block(); f(); unindent true in
 
 let rec statement arity s =
   match Ast.unwrap s with
@@ -789,10 +914,11 @@ let rec statement arity s =
   | Ast.Iterator(header,body,(_,_,_,aft)) ->
       rule_elem arity header;
       indent_if_needed body (function _ -> statement arity body);
-      mcode (fun _ _ _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos)
+      mcode (fun _ _ _ -> ()) ((),Ast.no_info,aft,[])
 
-  | 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
 
@@ -821,9 +947,9 @@ let rec statement arity s =
           stmt_dots_list;
         print_text "\n)")
       else raise CantBeInPlus
-  | Ast.Nest(stmt_dots,whn,multi,_,_) when generating ->
+  | Ast.Nest(starter,stmt_dots,ender,whn,multi,_,_) when generating ->
       pr_arity arity;
-      nest_dots multi (statement arity)
+      nest_dots starter ender (statement arity)
        (function _ ->
          print_between force_newline
            (whencode (dots force_newline (statement "")) (statement "")) whn;
@@ -839,7 +965,7 @@ let rec statement arity s =
         force_newline())
       else raise CantBeInPlus
 
-  | Ast.OptStm(s) | Ast.UniqueStm(s) -> 
+  | Ast.OptStm(s) | Ast.UniqueStm(s) ->
       raise CantBeInPlus
 
 and whencode notfn alwaysfn = function
@@ -869,12 +995,12 @@ and case_line arity c =
 let top_level t =
   match Ast.unwrap t with
     Ast.FILEINFO(old_file,new_file) -> raise CantBeInPlus
-  | Ast.DECL(stmt) -> statement "" stmt
+  | Ast.NONDECL(stmt) -> statement "" stmt
   | Ast.CODE(stmt_dots) -> dots force_newline (statement "") stmt_dots
   | Ast.ERRORWORDS(exps) -> raise CantBeInPlus
 in
 
-(*    
+(*
 let rule =
   print_between (function _ -> force_newline(); force_newline()) top_level
 in
@@ -913,9 +1039,22 @@ let rec pp_any = function
   | Ast.CaseLineTag(x) -> case_line "" x; false
 
   | Ast.ConstVolTag(x) -> const_vol x unknown unknown; false
-  | Ast.Pragma(xs) -> print_between force_newline print_text xs; false
+  | Ast.Pragma(xs) ->
+      (match xs with (Ast.Space s)::_ -> pr_space() | _ -> ());
+      let rec loop = function
+         [] -> ()
+       | [Ast.Noindent s] -> unindent false; print_text s
+       | [Ast.Indent s] -> print_text s
+       | (Ast.Space s) :: (((Ast.Indent _ | Ast.Noindent _) :: _) as rest) ->
+           print_text s; force_newline(); loop rest
+       | (Ast.Space s) :: rest -> print_text s; pr_space(); loop rest
+       | Ast.Noindent s :: rest ->
+           unindent false; print_text s; force_newline(); loop rest
+       | Ast.Indent s :: rest ->
+           print_text s; force_newline(); loop rest in
+      loop xs; false
   | Ast.Token(x,None) -> print_text x; if_open_brace x
-  | Ast.Token(x,Some info) -> 
+  | Ast.Token(x,Some info) ->
       mcode
        (fun x line lcol ->
          (match x with
@@ -923,12 +1062,12 @@ let rec pp_any = function
          | _ -> ());
          print_string x line lcol)
        (let nomcodekind = Ast.CONTEXT(Ast.DontCarePos,Ast.NOTHING) in
-       (x,info,nomcodekind,Ast.NoMetaPos));
+       (x,info,nomcodekind,[]));
       if_open_brace x
 
   | Ast.Code(x) -> let _ = top_level x in false
 
-  (* this is not '...', but a list of expr/statement/params, and 
+  (* this is not '...', but a list of expr/statement/params, and
      normally there should be no '...' inside them *)
   | Ast.ExprDotsTag(x) -> dots (function _ -> ()) expression x; false
   | Ast.ParamDotsTag(x) -> parameter_list x; false
@@ -941,12 +1080,14 @@ let rec pp_any = function
   | Ast.SgrepEndTag(x) -> failwith "unexpected end tag"
 in
 
+(*Printf.printf "start of the function\n";*)
+
   anything := (function x -> let _ = pp_any x in ());
 
   (* todo? imitate what is in pretty_print_cocci ? *)
   match xxs with
     [] -> ()
-  | x::xs -> 
+  | x::xs ->
       (* for many tags, we must not do a newline before the first '+' *)
       let isfn s =
        match Ast.unwrap s with Ast.FunDecl _ -> true | _ -> false in
@@ -955,14 +1096,17 @@ in
          (Ast.Token ("}",_)::_) -> true
        | _ -> false in
       let prnl x =
-       (if unindent_before x then unindent());
+       (if unindent_before x then unindent true);
        force_newline() in
       let newline_before _ =
        if before =*= After
        then
          let hd = List.hd xxs in
          match hd with
-            (Ast.StatementTag s::_) when isfn s ->
+           (Ast.Pragma l::_)
+             when List.for_all (function Ast.Space x -> true | _ -> false) l ->
+               ()
+          | (Ast.StatementTag s::_) when isfn s ->
              force_newline(); force_newline()
          | (Ast.Pragma _::_)
           | (Ast.Rule_elemTag _::_) | (Ast.StatementTag _::_)
@@ -992,7 +1136,7 @@ in
              match (indent_needed,unindent_before x) with
                (true,true) -> force_newline()
              | (true,false) -> force_newline(); indent()
-             | (false,true) -> unindent(); force_newline()
+             | (false,true) -> unindent true; force_newline()
              | (false,false) -> force_newline());
            let space_needed_before = function
                Ast.ParamTag(x) ->
@@ -1007,14 +1151,22 @@ in
                  (match Ast.unwrap x with
                    Ast.IComma _ -> false
                  | _ -> true)
-             | Ast.Token(t,_) when List.mem t [",";";";"(";")"] -> false
+             | 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 ["(";".";"->"] -> (*never needed*) false
              | Ast.Token(t,_) when List.mem t ["if";"for";"while";"do"] ->
                  (* space always needed *)
                  pr_space(); false
-             | _ -> true in
+             | Ast.ExpressionTag(e) ->
+                 (match Ast.unwrap e with
+                   Ast.EComma _ ->
+                     (* space always needed *)
+                     pr_space(); false 
+                 | _ -> true)
+             | t -> true in
            let indent_needed =
              let rec loop space_after indent_needed = function
                  [] -> indent_needed
@@ -1030,3 +1182,12 @@ in
       (* 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