*)
-(*
- * Copyright 2010, INRIA, University of Copenhagen
- * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
- * Copyright 2005-2009, 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.
- *)
-
-
(* Detects subtrees that are all minus/plus and nodes that are "binding
context nodes". The latter is a node whose structure and immediate tokens
are the same in the minus and plus trees, and such that for every child,
(* no whencode in plus tree so have to drop it *)
(* need special cases for dots, nests, and disjs *)
+ let ident r k e =
+ compute_result Ast0.ident e
+ (match Ast0.unwrap e with
+ Ast0.DisjId(starter,id_list,_,ender) ->
+ disj_cases e starter id_list r.VT0.combiner_rec_ident ender
+ | _ -> k e) in
+
let expression r k e =
compute_result Ast0.expr e
(match Ast0.unwrap e with
(do_nothing Ast0.dotsExpr) (do_nothing Ast0.dotsInit)
(do_nothing Ast0.dotsParam) (do_nothing Ast0.dotsStmt)
(do_nothing Ast0.dotsDecl) (do_nothing Ast0.dotsCase)
- (do_nothing Ast0.ident) expression typeC initialiser param declaration
+ ident expression typeC initialiser param declaration
statement case_line (do_top Ast0.top) in
combiner.VT0.combiner_rec_top_level code
let rec equal_ident i1 i2 =
match (Ast0.unwrap i1,Ast0.unwrap i2) with
(Ast0.Id(name1),Ast0.Id(name2)) -> equal_mcode name1 name2
- | (Ast0.MetaId(name1,_,_),Ast0.MetaId(name2,_,_)) ->
+ | (Ast0.MetaId(name1,_,_,_),Ast0.MetaId(name2,_,_,_)) ->
equal_mcode name1 name2
| (Ast0.MetaFunc(name1,_,_),Ast0.MetaFunc(name2,_,_)) ->
equal_mcode name1 name2
| (Ast0.MetaLocalFunc(name1,_,_),Ast0.MetaLocalFunc(name2,_,_)) ->
equal_mcode name1 name2
+ | (Ast0.DisjId(starter1,_,mids1,ender1),
+ Ast0.DisjId(starter2,_,mids2,ender2)) ->
+ equal_mcode starter1 starter2 &&
+ List.for_all2 equal_mcode mids1 mids2 &&
+ equal_mcode ender1 ender2
| (Ast0.OptIdent(_),Ast0.OptIdent(_)) -> true
| (Ast0.UniqueIdent(_),Ast0.UniqueIdent(_)) -> true
| _ -> false
let equal_declaration d1 d2 =
match (Ast0.unwrap d1,Ast0.unwrap d2) with
(Ast0.MetaDecl(name1,_),Ast0.MetaDecl(name2,_))
- | (Ast0.MetaField(name1,_),Ast0.MetaField(name2,_)) ->
+ | (Ast0.MetaField(name1,_),Ast0.MetaField(name2,_))
+ | (Ast0.MetaFieldList(name1,_,_),Ast0.MetaFieldList(name2,_,_)) ->
equal_mcode name1 name2
| (Ast0.Init(stg1,_,_,eq1,_,sem1),Ast0.Init(stg2,_,_,eq2,_,sem2)) ->
equal_option stg1 stg2 && equal_mcode eq1 eq2 && equal_mcode sem1 sem2
match (Ast0.unwrap i1,Ast0.unwrap i2) with
(Ast0.MetaInit(name1,_),Ast0.MetaInit(name2,_)) ->
equal_mcode name1 name2
+ | (Ast0.MetaInitList(name1,_,_),Ast0.MetaInitList(name2,_,_)) ->
+ equal_mcode name1 name2
| (Ast0.InitExpr(_),Ast0.InitExpr(_)) -> true
| (Ast0.InitList(lb1,_,rb1,o1),Ast0.InitList(lb2,_,rb2,o2)) ->
(* can't compare orderedness, because this can differ between -
| (Ast0.Stars(d1,_),Ast0.Stars(d2,_)) -> equal_mcode d1 d2
| (Ast0.Include(inc1,name1),Ast0.Include(inc2,name2)) ->
equal_mcode inc1 inc2 && equal_mcode name1 name2
+ | (Ast0.Undef(def1,_),Ast0.Undef(def2,_)) ->
+ equal_mcode def1 def2
| (Ast0.Define(def1,_,_,_),Ast0.Define(def2,_,_,_)) ->
equal_mcode def1 def2
| (Ast0.OptStm(_),Ast0.OptStm(_)) -> true
let rec equal_top_level t1 t2 =
match (Ast0.unwrap t1,Ast0.unwrap t2) with
- (Ast0.DECL(_),Ast0.DECL(_)) -> true
+ (Ast0.NONDECL(_),Ast0.NONDECL(_)) -> true
| (Ast0.FILEINFO(old_file1,new_file1),Ast0.FILEINFO(old_file2,new_file2)) ->
equal_mcode old_file1 old_file2 && equal_mcode new_file1 new_file2
| (Ast0.CODE(_),Ast0.CODE(_)) -> true
let iscode t =
match Ast0.unwrap t with
- Ast0.DECL(_) -> true
+ Ast0.NONDECL(_) -> true
| Ast0.FILEINFO(_) -> true
| Ast0.ERRORWORDS(_) -> false
| Ast0.CODE(_) -> true
+ | Ast0.TOPCODE(_)
| Ast0.OTHER(_) -> failwith "unexpected top level code"
(* ------------------------------------------------------------------- *)
[] -> []
| x::rest ->
(match Ast0.unwrap x with
- Ast0.DECL(s) -> let stms = loop rest in s::stms
+ Ast0.NONDECL(s) -> let stms = loop rest in s::stms
| Ast0.CODE(ss) ->
let stms = loop rest in
(match Ast0.unwrap ss with
Ast0.Decl(_,e) -> true
| Ast0.FunDecl(_,_,_,_,_,_,_,_,_) -> true
| Ast0.Disj(_,stmts,_,_) -> isall is_toplevel stmts
- | Ast0.ExprStatement(fc,_) ->
+ | Ast0.ExprStatement(Some fc,_) ->
(match Ast0.unwrap fc with
Ast0.FunCall(_,_,_,_) -> true
| _ -> false)
| Ast0.Include(_,_) -> true
+ | Ast0.Undef(_,_) -> true
| Ast0.Define(_,_,_,_) -> true
| _ -> false
+(* consider code and topcode to be the same; difference handled
+in top_level.ml *)
let check_compatible m p =
let fail _ =
failwith
"incompatible minus and plus code starting on lines %d and %d"
(Ast0.get_line m) (Ast0.get_line p)) in
match (Ast0.unwrap m, Ast0.unwrap p) with
- (Ast0.DECL(decl1),Ast0.DECL(decl2)) ->
+ (Ast0.NONDECL(decl1),Ast0.NONDECL(decl2)) ->
if not (is_decl decl1 && is_decl decl2)
then fail()
- | (Ast0.DECL(decl1),Ast0.CODE(code2)) ->
+ | (Ast0.NONDECL(decl1),Ast0.CODE(code2)) ->
+ (* This is probably the only important case. We don't want to
+ replace top-level declarations by arbitrary code. *)
let v1 = is_decl decl1 in
let v2 = List.for_all is_toplevel (Ast0.undots code2) in
- if !Flag.make_hrule = None && v1 && not v2 then fail()
- | (Ast0.CODE(code1),Ast0.DECL(decl2)) ->
+ if !Flag.make_hrule = None && v1 && not v2
+ then fail()
+ | (Ast0.CODE(code1),Ast0.NONDECL(decl2)) ->
let v1 = List.for_all is_toplevel (Ast0.undots code1) in
let v2 = is_decl decl2 in
- if v1 && not v2 then fail()
+ if v1 && not v2
+ then fail()
| (Ast0.CODE(code1),Ast0.CODE(code2)) ->
let v1 = isonly is_init code1 in
let v2a = isonly is_init code2 in
testers;
let v1 = isonly is_fndecl code1 in
let v2 = List.for_all is_toplevel (Ast0.undots code2) in
- if !Flag.make_hrule = None && v1 && not v2 then fail()
+ if !Flag.make_hrule = None && v1 && not v2
+ then fail()
| (Ast0.FILEINFO(_,_),Ast0.FILEINFO(_,_)) -> ()
| (Ast0.OTHER(_),Ast0.OTHER(_)) -> ()
| _ -> fail()
List.map
(function m ->
classify true
- (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info)))
+ (function _ ->
+ Ast0.MINUS(ref(Ast.NOREPLACEMENT,Ast0.default_token_info)))
minus_table m)
minus in
[]
collect_plus_lines p;
let _ =
classify true
- (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info)))
+ (function _ ->
+ Ast0.MINUS(ref(Ast.NOREPLACEMENT,Ast0.default_token_info)))
minus_table m in
let _ = classify false (function c -> Ast0.PLUS c) plus_table p in
traverse minus_table plus_table;
plus_lines := [];
let _ =
classify true
- (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info)))
+ (function _ ->
+ Ast0.MINUS(ref(Ast.NOREPLACEMENT,
+ Ast0.default_token_info)))
minus_table m in
loop(minus,pall)
end