Release coccinelle-0.1.9-rc1
[bpt/coccinelle.git] / parsing_cocci / insert_plus.ml
index 795d46c..b828c12 100644 (file)
@@ -1,5 +1,5 @@
 (*
-* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
+* Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
 * This file is part of Coccinelle.
 * 
@@ -32,8 +32,11 @@ tokens, and then merge them. *)
 module Ast = Ast_cocci
 module Ast0 = Ast0_cocci
 module V0 = Visitor_ast0
+module VT0 = Visitor_ast0_types
 module CN = Context_neg
 
+let empty_isos = ref false
+
 let get_option f = function
     None -> []
   | Some x -> f x
@@ -86,16 +89,15 @@ it *)
   let topfn r k e = Ast0.TopTag(e) :: (k e) in
 
   let res =
-    V0.combiner bind option_default
+    V0.flat_combiner bind option_default
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
-      mcode
       (donothing Ast0.dotsExpr) (donothing Ast0.dotsInit)
       (donothing Ast0.dotsParam) (donothing Ast0.dotsStmt)
       (donothing Ast0.dotsDecl) (donothing Ast0.dotsCase)
       (donothing Ast0.ident) expression (donothing Ast0.typeC) initialiser
       (donothing Ast0.param) (donothing Ast0.decl) statement
       (donothing Ast0.case_line) topfn in
-  res.V0.combiner_top_level e
+  res.VT0.combiner_rec_top_level e
 
 (* --------------------------------------------------------------------- *)
 (* --------------------------------------------------------------------- *)
@@ -156,8 +158,8 @@ let collect_minus_join_points root =
   let bind x y = x @ y in
   let option_default = [] in
 
-  let mcode (_,_,info,mcodekind,_) =
-    if List.mem (info.Ast0.offset) unfavored_tokens
+  let mcode (_,_,info,mcodekind,_,_) =
+    if List.mem (info.Ast0.pos_info.Ast0.offset) unfavored_tokens
     then [(Unfavored,info,mcodekind)]
     else [(Favored,info,mcodekind)] in
 
@@ -187,12 +189,12 @@ bind to that; not good for isomorphisms *)
     | Ast0.CIRCLES(l) -> multibind (List.map f l)
     | Ast0.STARS(l) -> multibind (List.map f l) in
 
-  let edots r k d = dots r.V0.combiner_expression k d in
-  let idots r k d = dots r.V0.combiner_initialiser k d in
-  let pdots r k d = dots r.V0.combiner_parameter k d in
-  let sdots r k d = dots r.V0.combiner_statement k d in
-  let ddots r k d = dots r.V0.combiner_declaration k d in
-  let cdots r k d = dots r.V0.combiner_case_line k d in
+  let edots r k d = dots r.VT0.combiner_rec_expression k d in
+  let idots r k d = dots r.VT0.combiner_rec_initialiser k d in
+  let pdots r k d = dots r.VT0.combiner_rec_parameter k d in
+  let sdots r k d = dots r.VT0.combiner_rec_statement k d in
+  let ddots r k d = dots r.VT0.combiner_rec_declaration k d in
+  let cdots r k d = dots r.VT0.combiner_rec_case_line k d in
 
   (* a case for everything that has a Opt *)
 
@@ -236,45 +238,46 @@ bind to that; not good for isomorphisms *)
        (Toplevel,info,bef)::(k s)
     | Ast0.Decl((info,bef),decl) -> (Decl,info,bef)::(k s)
     | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
-       mcode starter @ r.V0.combiner_statement_dots stmt_dots @ mcode ender
+       mcode starter @ r.VT0.combiner_rec_statement_dots stmt_dots @
+       mcode ender
     | Ast0.Dots(d,whencode) | Ast0.Circles(d,whencode)
     | Ast0.Stars(d,whencode) -> mcode d (* ignore whencode *)
     | Ast0.OptStm s | Ast0.UniqueStm s ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_statement s
+       r.VT0.combiner_rec_statement s
     | _ -> do_nothing r k s in
 
   let expression r k e =
     match Ast0.unwrap e with
       Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) ->
        mcode starter @
-       r.V0.combiner_expression_dots expr_dots @ mcode ender
+       r.VT0.combiner_rec_expression_dots expr_dots @ mcode ender
     | Ast0.Edots(d,whencode) | Ast0.Ecircles(d,whencode)
     | Ast0.Estars(d,whencode) -> mcode d (* ignore whencode *)
     | Ast0.OptExp e | Ast0.UniqueExp e ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_expression e
+       r.VT0.combiner_rec_expression e
     | _ -> do_nothing r k e in
 
   let ident r k e =
     match Ast0.unwrap e with
       Ast0.OptIdent i | Ast0.UniqueIdent i ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_ident i
+       r.VT0.combiner_rec_ident i
     | _ -> do_nothing r k e in
 
   let typeC r k e =
     match Ast0.unwrap e with
       Ast0.OptType t | Ast0.UniqueType t ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_typeC t
+       r.VT0.combiner_rec_typeC t
     | _ -> do_nothing r k e in
 
   let decl r k e =
     match Ast0.unwrap e with
       Ast0.OptDecl d | Ast0.UniqueDecl d ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_declaration d
+       r.VT0.combiner_rec_declaration d
     | _ -> do_nothing r k e in
 
   let initialiser r k e =
@@ -282,28 +285,27 @@ bind to that; not good for isomorphisms *)
       Ast0.Idots(d,whencode) -> mcode d (* ignore whencode *)
     | Ast0.OptIni i | Ast0.UniqueIni i ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_initialiser i
+       r.VT0.combiner_rec_initialiser i
     | _ -> do_nothing r k e in
 
   let param r k e =
     match Ast0.unwrap e with
       Ast0.OptParam p | Ast0.UniqueParam p ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_parameter p
+       r.VT0.combiner_rec_parameter p
     | _ -> do_nothing r k e in
 
   let case_line r k e =
     match Ast0.unwrap e with
       Ast0.OptCase c ->
        (* put the + code on the thing, not on the opt *)
-       r.V0.combiner_case_line c
+       r.VT0.combiner_rec_case_line c
     | _ -> do_nothing r k e in
 
   let do_top r k (e: Ast0.top_level) = k e in
 
-  V0.combiner bind option_default
+  V0.flat_combiner bind option_default
     mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
-    mcode
     edots idots pdots sdots ddots cdots
     ident expression typeC initialiser param decl statement case_line do_top
 
@@ -315,51 +317,51 @@ let call_collect_minus context_nodes :
       match e with
        Ast0.DotsExprTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_expression_dots e)
+          (collect_minus_join_points e).VT0.combiner_rec_expression_dots e)
       | Ast0.DotsInitTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_initialiser_list e)
+          (collect_minus_join_points e).VT0.combiner_rec_initialiser_list e)
       | Ast0.DotsParamTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_parameter_list e)
+          (collect_minus_join_points e).VT0.combiner_rec_parameter_list e)
       | Ast0.DotsStmtTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_statement_dots e)
+          (collect_minus_join_points e).VT0.combiner_rec_statement_dots e)
       | Ast0.DotsDeclTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_declaration_dots e)
+          (collect_minus_join_points e).VT0.combiner_rec_declaration_dots e)
       | Ast0.DotsCaseTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_case_line_dots e)
+          (collect_minus_join_points e).VT0.combiner_rec_case_line_dots e)
       | Ast0.IdentTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_ident e)
+          (collect_minus_join_points e).VT0.combiner_rec_ident e)
       | Ast0.ExprTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_expression e)
+          (collect_minus_join_points e).VT0.combiner_rec_expression e)
       | Ast0.ArgExprTag(e) | Ast0.TestExprTag(e) ->
          failwith "not possible - iso only"
       | Ast0.TypeCTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_typeC e)
+          (collect_minus_join_points e).VT0.combiner_rec_typeC e)
       | Ast0.ParamTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_parameter e)
+          (collect_minus_join_points e).VT0.combiner_rec_parameter e)
       | Ast0.InitTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_initialiser e)
+          (collect_minus_join_points e).VT0.combiner_rec_initialiser e)
       | Ast0.DeclTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_declaration e)
+          (collect_minus_join_points e).VT0.combiner_rec_declaration e)
       | Ast0.StmtTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_statement e)
+          (collect_minus_join_points e).VT0.combiner_rec_statement e)
       | Ast0.CaseLineTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_case_line e)
+          (collect_minus_join_points e).VT0.combiner_rec_case_line e)
       | Ast0.TopTag(e) ->
          (Ast0.get_index e,
-          (collect_minus_join_points e).V0.combiner_top_level e)
+          (collect_minus_join_points e).VT0.combiner_rec_top_level e)
       | Ast0.IsoWhenTag(_) -> failwith "only within iso phase"
       | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase"
       | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase"
@@ -372,10 +374,10 @@ let verify l =
   let get_info = function
       (Favored,info,_) | (Unfavored,info,_) | (Toplevel,info,_)
     | (Decl,info,_) -> info in
-  let token_start_line      x = (get_info x).Ast0.logical_start in
-  let token_end_line        x = (get_info x).Ast0.logical_end in
-  let token_real_start_line x = (get_info x).Ast0.line_start in
-  let token_real_end_line   x = (get_info x).Ast0.line_end in
+  let token_start_line    x = (get_info x).Ast0.pos_info.Ast0.logical_start in
+  let token_end_line        x = (get_info x).Ast0.pos_info.Ast0.logical_end in
+  let token_real_start_line x = (get_info x).Ast0.pos_info.Ast0.line_start in
+  let token_real_end_line   x = (get_info x).Ast0.pos_info.Ast0.line_end in
   List.iter
     (function
        (index,((_::_) as l1)) ->
@@ -411,7 +413,6 @@ let process_minus minus =
 (* --------------------------------------------------------------------- *)
 (* collect the plus tokens *)
 
-let mk_baseType x         = Ast.BaseTypeTag x
 let mk_structUnion x      = Ast.StructUnionTag x
 let mk_sign x             = Ast.SignTag x
 let mk_ident x            = Ast.IdentTag (Ast0toast.ident x)
@@ -449,14 +450,42 @@ let collect_plus_nodes root =
   let bind x y = x @ y in
   let option_default = [] in
 
-  let mcode fn (term,_,info,mcodekind,_) =
-    match mcodekind with Ast0.PLUS -> [(info,fn term)] | _ -> [] in
+  let extract_strings info =
+    let adjust_info =
+      {info with Ast0.strings_before = [];  Ast0.strings_after = []} in
+    let extract = function
+       [] -> []
+      |        strings_before ->
+         let (_,first) = List.hd strings_before in
+         let (_,last) = List.hd (List.rev strings_before) in
+         let new_pos_info =
+           {Ast0.line_start = first.Ast0.line_start;
+             Ast0.line_end = last.Ast0.line_start;
+             Ast0.logical_start = first.Ast0.logical_start;
+             Ast0.logical_end = last.Ast0.logical_start;
+             Ast0.column = first.Ast0.column;
+             Ast0.offset = first.Ast0.offset} in
+         let new_info = {adjust_info with Ast0.pos_info = new_pos_info} in
+         let string = List.map (function (s,_) -> s) strings_before in
+         [(new_info, Ast.Pragma (string))] in
+    let bef = extract info.Ast0.strings_before in
+    let aft = extract info.Ast0.strings_after in
+    (bef,aft) in
+
+  let mcode fn (term,_,info,mcodekind,_,_) =
+    match mcodekind with
+      Ast0.PLUS -> [(info,fn term)]
+    | Ast0.CONTEXT _ -> let (bef,aft) = extract_strings info in bef@aft
+    | _ -> [] in
 
-  let imcode fn (term,_,info,mcodekind,_) =
+  let imcode fn (term,_,info,mcodekind,_,_) =
     match mcodekind with
       Ast0.PLUS -> [(info,fn term (Ast0toast.convert_info info))]
+    | Ast0.CONTEXT _ -> let (bef,aft) = extract_strings info in bef@aft
     | _ -> [] in
 
+  let info (i,_) = let (bef,aft) = extract_strings i in bef@aft in
+
   let do_nothing fn r k e =
     match Ast0.get_mcodekind e with
       (Ast0.CONTEXT(_)) when not(Ast0.get_index e = root_index) -> []
@@ -464,13 +493,27 @@ let collect_plus_nodes root =
     | _ -> k e in
 
   (* case for everything that is just a wrapper for a simpler thing *)
+  (* case for things with bef aft *)
   let stmt r k e =
     match Ast0.unwrap e with
-      Ast0.Exp(exp) -> r.V0.combiner_expression exp
-    | Ast0.TopExp(exp) -> r.V0.combiner_expression exp
-    | Ast0.Ty(ty) -> r.V0.combiner_typeC ty
-    | Ast0.TopInit(init) -> r.V0.combiner_initialiser init
-    | Ast0.Decl(_,decl) -> r.V0.combiner_declaration decl
+      Ast0.Exp(exp) -> r.VT0.combiner_rec_expression exp
+    | Ast0.TopExp(exp) -> r.VT0.combiner_rec_expression exp
+    | Ast0.Ty(ty) -> r.VT0.combiner_rec_typeC ty
+    | Ast0.TopInit(init) -> r.VT0.combiner_rec_initialiser init
+    | Ast0.Decl(bef,decl) ->
+       (info bef) @ (do_nothing mk_statement r k e)
+    | Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) ->
+       (info bef) @ (do_nothing mk_statement r k e)
+    | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) ->
+       (do_nothing mk_statement r k e) @ (info aft)
+    | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) ->
+       (do_nothing mk_statement r k e) @ (info aft)
+    | Ast0.While(whl,lp,exp,rp,body,aft) ->
+       (do_nothing mk_statement r k e) @ (info aft)
+    | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,aft) ->
+       (do_nothing mk_statement r k e) @ (info aft)
+    | Ast0.Iterator(nm,lp,args,rp,body,aft) ->
+       (do_nothing mk_statement r k e) @ (info aft)
     | _ -> do_nothing mk_statement r k e in
 
   (* statementTag is preferred, because it indicates that one statement is
@@ -478,22 +521,22 @@ let collect_plus_nodes root =
   let stmt_dots r k e =
     match Ast0.unwrap e with
       Ast0.DOTS([s]) | Ast0.CIRCLES([s]) | Ast0.STARS([s]) ->
-       r.V0.combiner_statement s
+       r.VT0.combiner_rec_statement s
     | _ -> do_nothing mk_stmtdots r k e in
 
   let toplevel r k e =
     match Ast0.unwrap e with
-      Ast0.DECL(s) -> r.V0.combiner_statement s
-    | Ast0.CODE(sdots) -> r.V0.combiner_statement_dots sdots
+      Ast0.DECL(s) -> r.VT0.combiner_rec_statement s
+    | Ast0.CODE(sdots) -> r.VT0.combiner_rec_statement_dots sdots
     | _ -> do_nothing mk_code r k e in
 
   let initdots r k e = k e in
 
-  V0.combiner bind option_default
+  V0.flat_combiner bind option_default
     (imcode mk_meta) (imcode mk_token) (mcode mk_constant) (mcode mk_assignOp)
     (mcode mk_fixOp)
     (mcode mk_unaryOp) (mcode mk_binaryOp) (mcode mk_const_vol)
-    (mcode mk_baseType) (mcode mk_sign) (mcode mk_structUnion)
+    (mcode mk_sign) (mcode mk_structUnion)
     (mcode mk_storage) (mcode mk_inc_file)
     (do_nothing mk_exprdots) initdots
     (do_nothing mk_paramdots) stmt_dots (do_nothing mk_decldots)
@@ -510,51 +553,51 @@ let call_collect_plus context_nodes :
       match e with
        Ast0.DotsExprTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_expression_dots e)
+          (collect_plus_nodes e).VT0.combiner_rec_expression_dots e)
       | Ast0.DotsInitTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_initialiser_list e)
+          (collect_plus_nodes e).VT0.combiner_rec_initialiser_list e)
       | Ast0.DotsParamTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_parameter_list e)
+          (collect_plus_nodes e).VT0.combiner_rec_parameter_list e)
       | Ast0.DotsStmtTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_statement_dots e)
+          (collect_plus_nodes e).VT0.combiner_rec_statement_dots e)
       | Ast0.DotsDeclTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_declaration_dots e)
+          (collect_plus_nodes e).VT0.combiner_rec_declaration_dots e)
       | Ast0.DotsCaseTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_case_line_dots e)
+          (collect_plus_nodes e).VT0.combiner_rec_case_line_dots e)
       | Ast0.IdentTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_ident e)
+          (collect_plus_nodes e).VT0.combiner_rec_ident e)
       | Ast0.ExprTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_expression e)
+          (collect_plus_nodes e).VT0.combiner_rec_expression e)
       | Ast0.ArgExprTag(_) | Ast0.TestExprTag(_) ->
          failwith "not possible - iso only"
       | Ast0.TypeCTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_typeC e)
+          (collect_plus_nodes e).VT0.combiner_rec_typeC e)
       | Ast0.InitTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_initialiser e)
+          (collect_plus_nodes e).VT0.combiner_rec_initialiser e)
       | Ast0.ParamTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_parameter e)
+          (collect_plus_nodes e).VT0.combiner_rec_parameter e)
       | Ast0.DeclTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_declaration e)
+          (collect_plus_nodes e).VT0.combiner_rec_declaration e)
       | Ast0.StmtTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_statement e)
+          (collect_plus_nodes e).VT0.combiner_rec_statement e)
       | Ast0.CaseLineTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_case_line e)
+          (collect_plus_nodes e).VT0.combiner_rec_case_line e)
       | Ast0.TopTag(e) ->
          (Ast0.get_index e,
-          (collect_plus_nodes e).V0.combiner_top_level e)
+          (collect_plus_nodes e).VT0.combiner_rec_top_level e)
       | Ast0.IsoWhenTag(_) -> failwith "only within iso phase"
       | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase"
       | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase"
@@ -570,11 +613,15 @@ line of n is one less than the starting line of n+1.
 Outer list: For any pair of successive elements, n and n+1, the ending
 line of n is more than one less than the starting line of n+1. *)
 
-let logstart info = info.Ast0.logical_start
-let logend info = info.Ast0.logical_end
+let logstart info = info.Ast0.pos_info.Ast0.logical_start
+let logend info = info.Ast0.pos_info.Ast0.logical_end
 
 let redo info start finish =
-  {{info with Ast0.logical_start = start} with Ast0.logical_end = finish}
+  let new_pos_info =
+    {info.Ast0.pos_info with
+      Ast0.logical_start = start;
+      Ast0.logical_end = finish} in
+  {info with Ast0.pos_info = new_pos_info}
 
 let rec find_neighbors (index,l) :
     int * (Ast0.info * (Ast.anything list list)) list =
@@ -633,11 +680,11 @@ let merge_one = function
 
 (* end of first argument < start/end of second argument *)
 let less_than_start info1 info2 =
-  info1.Ast0.logical_end < info2.Ast0.logical_start
+  info1.Ast0.pos_info.Ast0.logical_end < info2.Ast0.pos_info.Ast0.logical_start
 let less_than_end info1 info2 =
-  info1.Ast0.logical_end < info2.Ast0.logical_end
+  info1.Ast0.pos_info.Ast0.logical_end < info2.Ast0.pos_info.Ast0.logical_end
 let greater_than_end info1 info2 =
-  info1.Ast0.logical_start > info2.Ast0.logical_end
+  info1.Ast0.pos_info.Ast0.logical_start > info2.Ast0.pos_info.Ast0.logical_end
 let good_start info = info.Ast0.attachable_start
 let good_end info = info.Ast0.attachable_end
 
@@ -660,7 +707,8 @@ let predecl_code =
     | Ast.StatementTag _
     | Ast.Rule_elemTag _
     | Ast.StmtDotsTag _
-    | Ast.Code _ -> true
+    | Ast.Code _
+    | Ast.Pragma _ -> true
       (* the following should definitely be false *)
     | Ast.FullTypeTag _ | Ast.BaseTypeTag _ | Ast.StructUnionTag _
     | Ast.SignTag _
@@ -674,9 +722,9 @@ let pr = Printf.sprintf
 let insert thing thinginfo into intoinfo =
   let get_last l = let l = List.rev l in (List.rev(List.tl l),List.hd l) in
   let get_first l = (List.hd l,List.tl l) in
-  let thing_start = thinginfo.Ast0.logical_start in
-  let thing_end = thinginfo.Ast0.logical_end in
-  let thing_offset = thinginfo.Ast0.offset in
+  let thing_start = thinginfo.Ast0.pos_info.Ast0.logical_start in
+  let thing_end = thinginfo.Ast0.pos_info.Ast0.logical_end in
+  let thing_offset = thinginfo.Ast0.pos_info.Ast0.offset in
   let into_start = intoinfo.Ast0.tline_start in
   let into_end = intoinfo.Ast0.tline_end in
   let into_left_offset = intoinfo.Ast0.left_offset in
@@ -716,10 +764,10 @@ let insert thing thinginfo into intoinfo =
 
 let init thing info =
   (thing,
-   {Ast0.tline_start = info.Ast0.logical_start;
-     Ast0.tline_end = info.Ast0.logical_end;
-     Ast0.left_offset = info.Ast0.offset;
-     Ast0.right_offset = info.Ast0.offset})
+   {Ast0.tline_start = info.Ast0.pos_info.Ast0.logical_start;
+     Ast0.tline_end = info.Ast0.pos_info.Ast0.logical_end;
+     Ast0.left_offset = info.Ast0.pos_info.Ast0.offset;
+     Ast0.right_offset = info.Ast0.pos_info.Ast0.offset})
 
 let attachbefore (infop,p) = function
     Ast0.MINUS(replacements) ->
@@ -732,7 +780,7 @@ let attachbefore (infop,p) = function
        Ast.BEFORE(bef) ->
          let (bef,ti1) = insert p infop bef ti1 in
          neighbors := (Ast.BEFORE(bef),ti1,ti2)
-      |        Ast.AFTER(aft) -> 
+      |        Ast.AFTER(aft) ->
          let (bef,ti1) = init p infop in
          neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2)
       |        Ast.BEFOREAFTER(bef,aft) ->
@@ -754,7 +802,7 @@ let attachafter (infop,p) = function
        Ast.BEFORE(bef) ->
          let (aft,ti2) = init p infop in
          neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2)
-      |        Ast.AFTER(aft) -> 
+      |        Ast.AFTER(aft) ->
          let (aft,ti2) = insert p infop aft ti2 in
          neighbors := (Ast.AFTER(aft),ti1,ti2)
       |        Ast.BEFOREAFTER(bef,aft) ->
@@ -772,9 +820,9 @@ let attach_all_after ps m =
   List.iter (function x -> attachafter x m) ps
 
 let split_at_end info ps =
-  let split_point =  info.Ast0.logical_end in
+  let split_point =  info.Ast0.pos_info.Ast0.logical_end in
   List.partition
-    (function (info,_) -> info.Ast0.logical_end < split_point)
+    (function (info,_) -> info.Ast0.pos_info.Ast0.logical_end < split_point)
     ps
 
 let allminus = function
@@ -791,7 +839,8 @@ let rec before_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
        then (attachbefore p m1; before_m1 x1 x2 rest ps)
        else
          failwith
-           (pr "%d: no available token to attach to" infop.Ast0.line_start)
+           (pr "%d: no available token to attach to"
+              infop.Ast0.pos_info.Ast0.line_start)
       else after_m1 x1 x2 rest all
 
 and after_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
@@ -805,7 +854,7 @@ and after_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
         what it can infer from something being CONTEXT with no top-level
         modifications.  for the moment, we thus give an error, asking the
         user to rewrite the semantic patch. *)
-      if greater_than_end infop infom1
+      if greater_than_end infop infom1 or is_minus m1 or !empty_isos
       then
        if less_than_start infop infom2
        then
@@ -827,19 +876,29 @@ and after_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
          then before_m2 x2 rest all
          else
            failwith
-             (pr "%d: no available token to attach to" infop.Ast0.line_start)
+             (pr "%d: no available token to attach to"
+                infop.Ast0.pos_info.Ast0.line_start)
        else after_m2 x2 rest all
       else
        begin
          Printf.printf "between: p start %d p end %d m1 start %d m1 end %d m2 start %d m2 end %d\n"
-           infop.Ast0.line_start infop.Ast0.line_end
-           infom1.Ast0.line_start infom1.Ast0.line_end
-           infom2.Ast0.line_start infom2.Ast0.line_end;
+           infop.Ast0.pos_info.Ast0.line_start
+           infop.Ast0.pos_info.Ast0.line_end
+           infom1.Ast0.pos_info.Ast0.line_start
+           infom1.Ast0.pos_info.Ast0.line_end
+           infom2.Ast0.pos_info.Ast0.line_start
+           infom2.Ast0.pos_info.Ast0.line_end;
          Pretty_print_cocci.print_anything "" pcode;
          failwith
            "The semantic patch is structured in a way that may give bad results with isomorphisms.  Please try to rewrite it by moving + code out from -/context terms."
        end
 
+(* not sure this is safe.  if have iso problems, consider changing this
+to always return false *)
+and is_minus = function
+    Ast0.MINUS _ -> true
+  | _ -> false
+
 and before_m2 ((f2,infom2,m2) as x2) rest
     (p : (Ast0.info * Ast.anything list list) list) =
   match (rest,p) with
@@ -850,7 +909,8 @@ and before_m2 ((f2,infom2,m2) as x2) rest
       then (attach_all_before bef_m2 m2; after_m2 x2 rest aft_m2)
       else
        failwith
-         (pr "%d: no available token to attach to" infop.Ast0.line_start)
+         (pr "%d: no available token to attach to"
+            infop.Ast0.pos_info.Ast0.line_start)
   | (m::ms,_) -> before_m1 x2 m ms p
 
 and after_m2 ((f2,infom2,m2) as x2) rest
@@ -862,7 +922,8 @@ and after_m2 ((f2,infom2,m2) as x2) rest
       then attach_all_after p m2
       else
        failwith
-         (pr "%d: no available token to attach to" infop.Ast0.line_start)
+         (pr "%d: no available token to attach to"
+            infop.Ast0.pos_info.Ast0.line_start)
   | (m::ms,_) -> after_m1 x2 m ms p
 
 let merge_one : (minus_join_point * Ast0.info * 'a) list *
@@ -872,15 +933,19 @@ let merge_one : (minus_join_point * Ast0.info * 'a) list *
   List.iter
     (function (_,info,_) ->
       Printf.printf "start %d end %d real_start %d real_end %d\n"
-       info.Ast0.logical_start info.Ast0.logical_end
-       info.Ast0.line_start info.Ast0.line_end)
+       info.Ast0.pos_info.Ast0.logical_start
+       info.Ast0.pos_info.Ast0.logical_end
+       info.Ast0.pos_info.Ast0.line_start
+       info.Ast0.pos_info.Ast0.line_end)
     m;
   Printf.printf "plus code\n";
   List.iter
     (function (info,p) ->
       Printf.printf "start %d end %d real_start %d real_end %d\n"
-       info.Ast0.logical_start info.Ast0.logical_end
-       info.Ast0.line_end info.Ast0.line_end;
+       info.Ast0.pos_info.Ast0.logical_start
+       info.Ast0.pos_info.Ast0.logical_end
+       info.Ast0.pos_info.Ast0.line_end
+       info.Ast0.pos_info.Ast0.line_end;
       Pretty_print_cocci.print_anything "" p;
       Format.print_newline())
     p;
@@ -915,7 +980,12 @@ let reevaluate_contextness =
    let bind = (@) in
    let option_default = [] in
 
-   let mcode (_,_,_,mc,_) =
+   let mcode (_,_,_,mc,_,_) =
+     match mc with
+       Ast0.CONTEXT(mc) -> let (ba,_,_) = !mc in [ba]
+     | _ -> [] in
+
+   let info (_,mc) =
      match mc with
        Ast0.CONTEXT(mc) -> let (ba,_,_) = !mc in [ba]
      | _ -> [] in
@@ -928,19 +998,38 @@ let reevaluate_contextness =
         []
      | _ -> let _ = k e in [] in
 
+   (* a case for everything with bef or aft *)
+   let stmt r k e =
+     match Ast0.unwrap e with
+       Ast0.Decl(bef,decl) ->
+        (info bef) @ (donothing r k e)
+     | Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) ->
+        (info bef) @ (donothing r k e)
+     | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) ->
+        (donothing r k e) @ (info aft)
+     | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) ->
+        (donothing r k e) @ (info aft)
+     | Ast0.While(whl,lp,exp,rp,body,aft) ->
+        (donothing r k e) @ (info aft)
+     | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,aft) ->
+        (donothing r k e) @ (info aft)
+     | Ast0.Iterator(nm,lp,args,rp,body,aft) ->
+        (donothing r k e) @ (info aft)
+     | _ -> donothing r k e in
+
   let res =
-    V0.combiner bind option_default
+    V0.flat_combiner bind option_default
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
-      mcode
       donothing donothing donothing donothing donothing donothing donothing
       donothing
-      donothing donothing donothing donothing donothing donothing donothing in
-  res.V0.combiner_top_level
+      donothing donothing donothing donothing stmt donothing donothing in
+  res.VT0.combiner_rec_top_level
 
 (* --------------------------------------------------------------------- *)
 (* --------------------------------------------------------------------- *)
 
-let insert_plus minus plus =
+let insert_plus minus plus ei =
+  empty_isos := ei;
   let minus_stream = process_minus minus in
   let plus_stream = process_plus plus in
   merge minus_stream plus_stream;