Coccinelle release 0.2.5-rc9
[bpt/coccinelle.git] / parsing_cocci / iso_pattern.ml
index 0c83e25..ff9fb68 100644 (file)
@@ -1,31 +1,11 @@
-(*
- * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen
- * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
- * This file is part of Coccinelle.
- *
- * Coccinelle is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, according to version 2 of the License.
- *
- * Coccinelle 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
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Coccinelle.  If not, see <http://www.gnu.org/licenses/>.
- *
- * The authors reserve the right to distribute this or future versions of
- * Coccinelle under other licenses.
- *)
-
-
 (* Potential problem: offset of mcode is not updated when an iso is
 instantiated, implying that a term may end up with many mcodes with the
 same offset.  On the other hand, at the moment offset only seems to be used
 before this phase.  Furthermore add_dot_binding relies on the offset to
 remain the same between matching an iso and instantiating it with bindings. *)
 
+(* Consider whether ... in iso should match <... ...> in smpl? *)
+
 (* --------------------------------------------------------------------- *)
 (* match a SmPL expression against a SmPL abstract syntax tree,
 either - or + *)
@@ -121,6 +101,7 @@ type reason =
   | ContextRequired of Ast0.anything
   | NonMatch
   | Braces of Ast0.statement
+  | Nest of Ast0.statement
   | Position of Ast.meta_name
   | TypeMatch of reason list
 
@@ -156,6 +137,10 @@ let rec interpret_reason name line reason printer =
       Printf.printf "braces must be all minus (plus code allowed) or all\ncontext (plus code not allowed in the body) to match:\n";
       Unparse_ast0.statement "" s;
       Format.print_newline()
+  | Nest(s) ->
+      Printf.printf "iso with nest doesn't match whencode (TODO):\n";
+      Unparse_ast0.statement "" s;
+      Format.print_newline()
   | Position(rule,name) ->
       Printf.printf "position variable %s.%s conflicts with an isomorphism\n"
        rule name;
@@ -404,6 +389,14 @@ let match_maker checks_needed context_required whencode_allowed =
          Ast0.MetaParam(name,pure) | Ast0.MetaParamList(name,_,pure) -> pure
        | _ -> Ast0.Impure) in
 
+    let decl r k d =
+      bind (bind (pure_mcodekind (Ast0.get_mcodekind d)) (k d))
+       (match Ast0.unwrap d with
+         Ast0.MetaDecl(name,pure) | Ast0.MetaField(name,pure)
+       | Ast0.MetaFieldList(name,_,pure) ->
+           pure
+       | _ -> Ast0.Impure) in
+
     let stmt r k s =
       bind (bind (pure_mcodekind (Ast0.get_mcodekind s)) (k s))
        (match Ast0.unwrap s with
@@ -413,7 +406,7 @@ let match_maker checks_needed context_required whencode_allowed =
     V0.flat_combiner bind option_default
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
       donothing donothing donothing donothing donothing donothing
-      ident expression typeC init param donothing stmt donothing
+      ident expression typeC init param decl stmt donothing
       donothing in
 
   let add_pure_list_binding name pure is_pure builder1 builder2 lst =
@@ -485,6 +478,8 @@ let match_maker checks_needed context_required whencode_allowed =
              if mcode_equal namea nameb
              then check_mcode namea nameb
              else return false
+         | (Ast0.DisjId(_,ids,_,_),_) ->
+             failwith "not allowed in the pattern of an isomorphism"
          | (Ast0.OptIdent(ida),Ast0.OptIdent(idb))
          | (Ast0.UniqueIdent(ida),Ast0.UniqueIdent(idb)) ->
              match_ident ida idb
@@ -774,9 +769,16 @@ let match_maker checks_needed context_required whencode_allowed =
              conjunct_many_bindings
                [check_mcode lb1 lb; check_mcode rb1 rb;
                  match_typeC tya tyb; match_option match_expr sizea sizeb]
-         | (Ast0.EnumName(kinda,namea),Ast0.EnumName(kindb,nameb)) ->
+         | (Ast0.EnumName(kinda,Some namea),
+            Ast0.EnumName(kindb,Some nameb)) ->
              conjunct_bindings (check_mcode kinda kindb)
                (match_ident namea nameb)
+         | (Ast0.EnumDef(tya,lb1,idsa,rb1),
+            Ast0.EnumDef(tyb,lb,idsb,rb)) ->
+              conjunct_many_bindings
+                [check_mcode lb1 lb; check_mcode rb1 rb;
+                  match_typeC tya tyb;
+                  match_dots match_expr no_list do_nolist_match idsa idsb]
          | (Ast0.StructUnionName(kinda,Some namea),
             Ast0.StructUnionName(kindb,Some nameb)) ->
               if mcode_equal kinda kindb
@@ -794,7 +796,7 @@ let match_maker checks_needed context_required whencode_allowed =
              if mcode_equal namea nameb
              then check_mcode namea nameb
              else return false
-         | (Ast0.DisjType(_,typesa,_,_),Ast0.DisjType(_,typesb,_,_)) ->
+         | (Ast0.DisjType(_,typesa,_,_),_) ->
              failwith "not allowed in the pattern of an isomorphism"
          | (Ast0.OptType(tya),Ast0.OptType(tyb))
          | (Ast0.UniqueType(tya),Ast0.UniqueType(tyb)) -> match_typeC tya tyb
@@ -804,63 +806,74 @@ let match_maker checks_needed context_required whencode_allowed =
        else return_false (ContextRequired (Ast0.TypeCTag t))
 
   and match_decl pattern d =
-    if not(checks_needed) or not(context_required) or is_context d
-    then
-      match (Ast0.unwrap pattern,Ast0.unwrap d) with
-       (Ast0.Init(stga,tya,ida,eq1,inia,sc1),
-        Ast0.Init(stgb,tyb,idb,eq,inib,sc)) ->
-         if bool_match_option mcode_equal stga stgb
-         then
-           conjunct_many_bindings
-             [check_mcode eq1 eq; check_mcode sc1 sc;
-               match_option check_mcode stga stgb;
-               match_typeC tya tyb; match_ident ida idb;
-               match_init inia inib]
-         else return false
-      | (Ast0.UnInit(stga,tya,ida,sc1),Ast0.UnInit(stgb,tyb,idb,sc)) ->
-         if bool_match_option mcode_equal stga stgb
-         then
-           conjunct_many_bindings
-             [check_mcode sc1 sc; match_option check_mcode stga stgb;
-               match_typeC tya tyb; match_ident ida idb]
-         else return false
-      | (Ast0.MacroDecl(namea,lp1,argsa,rp1,sc1),
-        Ast0.MacroDecl(nameb,lp,argsb,rp,sc)) ->
-          conjunct_many_bindings
-            [match_ident namea nameb;
-              check_mcode lp1 lp; check_mcode rp1 rp;
-              check_mcode sc1 sc;
-              match_dots match_expr is_elist_matcher do_elist_match
-                argsa argsb]
-      | (Ast0.TyDecl(tya,sc1),Ast0.TyDecl(tyb,sc)) ->
-         conjunct_bindings (check_mcode sc1 sc) (match_typeC tya tyb)
-      | (Ast0.Typedef(stga,tya,ida,sc1),Ast0.Typedef(stgb,tyb,idb,sc)) ->
-         conjunct_bindings (check_mcode sc1 sc)
-           (conjunct_bindings (match_typeC tya tyb) (match_typeC ida idb))
-      | (Ast0.DisjDecl(_,declsa,_,_),Ast0.DisjDecl(_,declsb,_,_)) ->
-         failwith "not allowed in the pattern of an isomorphism"
-      | (Ast0.Ddots(d1,None),Ast0.Ddots(d,None)) -> check_mcode d1 d
-      |        (Ast0.Ddots(dd,None),Ast0.Ddots(d,Some wc)) ->
-         conjunct_bindings (check_mcode dd d)
+    match Ast0.unwrap pattern with
+      Ast0.MetaDecl(name,pure) ->
+       add_pure_binding name pure pure_sp_code.VT0.combiner_rec_declaration
+         (function d -> Ast0.DeclTag d)
+         d
+    | Ast0.MetaField(name,pure) ->
+       add_pure_binding name pure pure_sp_code.VT0.combiner_rec_declaration
+         (function d -> Ast0.DeclTag d)
+         d
+    | Ast0.MetaFieldList(name,_,pure) -> failwith "metafieldlist not supporte"
+    | up ->
+       if not(checks_needed) or not(context_required) or is_context d
+       then
+         match (up,Ast0.unwrap d) with
+           (Ast0.Init(stga,tya,ida,eq1,inia,sc1),
+            Ast0.Init(stgb,tyb,idb,eq,inib,sc)) ->
+              if bool_match_option mcode_equal stga stgb
+              then
+                conjunct_many_bindings
+                  [check_mcode eq1 eq; check_mcode sc1 sc;
+                    match_option check_mcode stga stgb;
+                    match_typeC tya tyb; match_ident ida idb;
+                    match_init inia inib]
+              else return false
+         | (Ast0.UnInit(stga,tya,ida,sc1),Ast0.UnInit(stgb,tyb,idb,sc)) ->
+             if bool_match_option mcode_equal stga stgb
+             then
+               conjunct_many_bindings
+                 [check_mcode sc1 sc; match_option check_mcode stga stgb;
+                   match_typeC tya tyb; match_ident ida idb]
+             else return false
+         | (Ast0.MacroDecl(namea,lp1,argsa,rp1,sc1),
+            Ast0.MacroDecl(nameb,lp,argsb,rp,sc)) ->
+              conjunct_many_bindings
+                [match_ident namea nameb;
+                  check_mcode lp1 lp; check_mcode rp1 rp;
+                  check_mcode sc1 sc;
+                  match_dots match_expr is_elist_matcher do_elist_match
+                    argsa argsb]
+         | (Ast0.TyDecl(tya,sc1),Ast0.TyDecl(tyb,sc)) ->
+             conjunct_bindings (check_mcode sc1 sc) (match_typeC tya tyb)
+         | (Ast0.Typedef(stga,tya,ida,sc1),Ast0.Typedef(stgb,tyb,idb,sc)) ->
+             conjunct_bindings (check_mcode sc1 sc)
+               (conjunct_bindings (match_typeC tya tyb) (match_typeC ida idb))
+         | (Ast0.DisjDecl(_,declsa,_,_),_) ->
+             failwith "not allowed in the pattern of an isomorphism"
+         | (Ast0.Ddots(d1,None),Ast0.Ddots(d,None)) -> check_mcode d1 d
+         |     (Ast0.Ddots(dd,None),Ast0.Ddots(d,Some wc)) ->
+             conjunct_bindings (check_mcode dd d)
            (* hope that mcode of ddots is unique somehow *)
-           (let (ddots_whencode_allowed,_,_) = whencode_allowed in
-           if ddots_whencode_allowed
-           then add_dot_binding dd (Ast0.DeclTag wc)
-           else
-             (Printf.printf "warning: not applying iso because of whencode";
-              return false))
-      | (Ast0.Ddots(_,Some _),_) ->
-         failwith "whencode not allowed in a pattern1"
-
-      | (Ast0.OptDecl(decla),Ast0.OptDecl(declb))
-      | (Ast0.UniqueDecl(decla),Ast0.UniqueDecl(declb)) ->
-         match_decl decla declb
-      | (_,Ast0.OptDecl(declb))
-      | (_,Ast0.UniqueDecl(declb)) ->
-         match_decl pattern declb
-      | _ -> return false
-    else return_false (ContextRequired (Ast0.DeclTag d))
-
+               (let (ddots_whencode_allowed,_,_) = whencode_allowed in
+               if ddots_whencode_allowed
+               then add_dot_binding dd (Ast0.DeclTag wc)
+               else
+                 (Printf.printf "warning: not applying iso because of whencode";
+                  return false))
+         | (Ast0.Ddots(_,Some _),_) ->
+             failwith "whencode not allowed in a pattern1"
+               
+         | (Ast0.OptDecl(decla),Ast0.OptDecl(declb))
+         | (Ast0.UniqueDecl(decla),Ast0.UniqueDecl(declb)) ->
+             match_decl decla declb
+         | (_,Ast0.OptDecl(declb))
+         | (_,Ast0.UniqueDecl(declb)) ->
+             match_decl pattern declb
+         | _ -> return false
+       else return_false (ContextRequired (Ast0.DeclTag d))
+           
   and match_init pattern i =
     match Ast0.unwrap pattern with
       Ast0.MetaInit(name,pure) ->
@@ -873,8 +886,9 @@ let match_maker checks_needed context_required whencode_allowed =
          match (up,Ast0.unwrap i) with
            (Ast0.InitExpr(expa),Ast0.InitExpr(expb)) ->
              match_expr expa expb
-         | (Ast0.InitList(lb1,initlista,rb1),Ast0.InitList(lb,initlistb,rb))
-           ->
+         | (Ast0.InitList(lb1,initlista,rb1,oa),
+            Ast0.InitList(lb,initlistb,rb,ob))
+           when oa = ob ->
              conjunct_many_bindings
                [check_mcode lb1 lb; check_mcode rb1 rb;
                  match_dots match_init no_list do_nolist_match
@@ -1080,8 +1094,25 @@ let match_maker checks_needed context_required whencode_allowed =
                [check_mcode r1 r; check_mcode sc1 sc; match_expr expa expb]
          | (Ast0.Disj(_,statement_dots_lista,_,_),_) ->
              failwith "disj not supported in patterns"
+         | (Ast0.Nest(_,stmt_dotsa,_,[],multia),
+            Ast0.Nest(_,stmt_dotsb,_,wc,multib)) ->
+              if multia = multib
+              then
+                (match wc with
+                  [] ->
+                 (* not sure this is correct, perhaps too restrictive *)
+                    if not(checks_needed) or is_minus s or
+                      (is_context s &&
+                       List.for_all is_pure_context (Ast0.undots stmt_dotsb))
+                    then
+                      match_dots match_statement
+                        is_slist_matcher do_slist_match
+                        stmt_dotsa stmt_dotsb
+                    else return_false (Braces(s))
+                | _ -> return_false (Nest(s)))
+              else return false (* diff kind of nest *)
          | (Ast0.Nest(_,stmt_dotsa,_,_,_),_) ->
-             failwith "nest not supported in patterns"
+             failwith "nest with whencode not supported in patterns"
          | (Ast0.Exp(expa),Ast0.Exp(expb)) -> match_expr expa expb
          | (Ast0.TopExp(expa),Ast0.TopExp(expb)) -> match_expr expa expb
          | (Ast0.Exp(expa),Ast0.TopExp(expb)) -> match_expr expa expb
@@ -1762,7 +1793,25 @@ let instantiate bindings mv_bindings =
   let declfn r k e =
     let e = k e in
     match Ast0.unwrap e with
-      Ast0.Ddots(d,_) ->
+      Ast0.MetaDecl(name,pure) ->
+       (rebuild_mcode None).VT0.rebuilder_rec_declaration
+         (match lookup name bindings mv_bindings with
+           Common.Left(Ast0.DeclTag(d)) -> d
+         | Common.Left(_) -> failwith "not possible 1"
+         | Common.Right(new_mv) ->
+             Ast0.rewrap e
+               (Ast0.MetaDecl(Ast0.set_mcode_data new_mv name, pure)))
+    | Ast0.MetaField(name,pure) ->
+       (rebuild_mcode None).VT0.rebuilder_rec_declaration
+         (match lookup name bindings mv_bindings with
+           Common.Left(Ast0.DeclTag(d)) -> d
+         | Common.Left(_) -> failwith "not possible 1"
+         | Common.Right(new_mv) ->
+             Ast0.rewrap e
+               (Ast0.MetaField(Ast0.set_mcode_data new_mv name, pure)))
+    | Ast0.MetaFieldList(name,lenname,pure) ->
+       failwith "metafieldlist not supported"
+    | Ast0.Ddots(d,_) ->
        (try
          (match List.assoc (dot_term d) bindings with
            Ast0.DeclTag(exp) -> Ast0.rewrap e (Ast0.Ddots(d,Some exp))
@@ -1797,7 +1846,7 @@ let instantiate bindings mv_bindings =
   let stmtfn r k e =
     let e = k e in
     match Ast0.unwrap e with
-    Ast0.MetaStmt(name,pure) ->
+      Ast0.MetaStmt(name,pure) ->
        (rebuild_mcode None).VT0.rebuilder_rec_statement
          (match lookup name bindings mv_bindings with
            Common.Left(Ast0.StmtTag(stm)) -> stm
@@ -1977,7 +2026,9 @@ let new_mv (_,s) =
   "_"^s^"_"^(string_of_int ct)
 
 let get_name = function
-    Ast.MetaIdDecl(ar,nm) ->
+    Ast.MetaMetaDecl(ar,nm) ->
+      (nm,function nm -> Ast.MetaMetaDecl(ar,nm))
+  | Ast.MetaIdDecl(ar,nm) ->
       (nm,function nm -> Ast.MetaIdDecl(ar,nm))
   | Ast.MetaFreshIdDecl(nm,seed) ->
       (nm,function nm -> Ast.MetaFreshIdDecl(nm,seed))
@@ -2003,6 +2054,12 @@ let get_name = function
       (nm,function nm -> Ast.MetaLocalIdExpDecl(ar,nm,ty))
   | Ast.MetaExpListDecl(ar,nm,nm1) ->
       (nm,function nm -> Ast.MetaExpListDecl(ar,nm,nm1))
+  | Ast.MetaDeclDecl(ar,nm) ->
+      (nm,function nm -> Ast.MetaDeclDecl(ar,nm))
+  | Ast.MetaFieldListDecl(ar,nm,nm1) ->
+      (nm,function nm -> Ast.MetaFieldListDecl(ar,nm,nm1))
+  | Ast.MetaFieldDecl(ar,nm) ->
+      (nm,function nm -> Ast.MetaFieldDecl(ar,nm))
   | Ast.MetaStmDecl(ar,nm) ->
       (nm,function nm -> Ast.MetaStmDecl(ar,nm))
   | Ast.MetaStmListDecl(ar,nm) ->
@@ -2039,7 +2096,7 @@ let do_nothing x = x
 
 let mkdisj matcher metavars alts e instantiater mkiso disj_maker minusify
     rebuild_mcodes name printer extra_plus update_others has_context =
-  let call_instantiate bindings mv_bindings alts has_context =
+  let call_instantiate bindings mv_bindings alts pattern has_context =
     List.concat
       (List.map
         (function (a,_,_,_) ->
@@ -2054,6 +2111,9 @@ let mkdisj matcher metavars alts e instantiater mkiso disj_maker minusify
                    then
                      copy_plus printer minusify e (extra_plus e instantiated)
                    else instantiated in
+                 if pattern = a
+                 then plus_added
+                 else (* iso tracking *)
                  Ast0.set_iso plus_added
                    ((name,mkiso a)::(Ast0.get_iso e))) (* keep count, not U *)
                bindings))
@@ -2097,7 +2157,7 @@ let mkdisj matcher metavars alts e instantiater mkiso disj_maker minusify
                  make_new_metavars metavars (nub(List.concat bindings)) in
                Common.Right
                  (new_metavars,
-                  call_instantiate bindings mv_bindings all_alts
+                  call_instantiate bindings mv_bindings all_alts pattern
                     (has_context pattern)))) in
   let rec outer_loop prev_ecount prev_icount prev_dcount = function
       [] | [[_]] (*only one alternative*)  -> (0,[],e) (* nothing matched *)