Coccinelle release-1.0.0-rc11
[bpt/coccinelle.git] / parsing_cocci / insert_plus.ml
CommitLineData
f537ebc4 1(*
17ba0788
C
2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
f537ebc4
C
5 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
6 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
7 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
8 * This file is part of Coccinelle.
9 *
10 * Coccinelle is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, according to version 2 of the License.
13 *
14 * Coccinelle is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
24 *)
25
26
34e49164
C
27(* The error message "no available token to attach to" often comes in an
28argument list of unbounded length. In this case, one should move a comma so
29that there is a comma after the + code. *)
30
31(* Start at all of the corresponding BindContext nodes in the minus and
32plus trees, and traverse their children. We take the same strategy as
33before: collect the list of minus/context nodes/tokens and the list of plus
34tokens, and then merge them. *)
35
36module Ast = Ast_cocci
37module Ast0 = Ast0_cocci
38module V0 = Visitor_ast0
b1b2de81 39module VT0 = Visitor_ast0_types
34e49164
C
40module CN = Context_neg
41
faf9a90c
C
42let empty_isos = ref false
43
34e49164
C
44let get_option f = function
45 None -> []
46 | Some x -> f x
47
48(* --------------------------------------------------------------------- *)
49(* Collect root and all context nodes in a tree *)
50
51let collect_context e =
52 let bind x y = x @ y in
53 let option_default = [] in
54
55 let mcode _ = [] in
56
57 let donothing builder r k e =
58 match Ast0.get_mcodekind e with
59 Ast0.CONTEXT(_) -> (builder e) :: (k e)
60 | _ -> k e in
61
62(* special case for everything that contains whencode, so that we skip over
63it *)
64 let expression r k e =
65 donothing Ast0.expr r k
66 (Ast0.rewrap e
67 (match Ast0.unwrap e with
68 Ast0.NestExpr(starter,exp,ender,whencode,multi) ->
69 Ast0.NestExpr(starter,exp,ender,None,multi)
70 | Ast0.Edots(dots,whencode) -> Ast0.Edots(dots,None)
71 | Ast0.Ecircles(dots,whencode) -> Ast0.Ecircles(dots,None)
72 | Ast0.Estars(dots,whencode) -> Ast0.Estars(dots,None)
73 | e -> e)) in
74
75 let initialiser r k i =
76 donothing Ast0.ini r k
77 (Ast0.rewrap i
78 (match Ast0.unwrap i with
79 Ast0.Idots(dots,whencode) -> Ast0.Idots(dots,None)
80 | i -> i)) in
81
82 let statement r k s =
83 donothing Ast0.stmt r k
84 (Ast0.rewrap s
85 (match Ast0.unwrap s with
86 Ast0.Nest(started,stm_dots,ender,whencode,multi) ->
87 Ast0.Nest(started,stm_dots,ender,[],multi)
88 | Ast0.Dots(dots,whencode) -> Ast0.Dots(dots,[])
89 | Ast0.Circles(dots,whencode) -> Ast0.Circles(dots,[])
90 | Ast0.Stars(dots,whencode) -> Ast0.Stars(dots,[])
91 | s -> s)) in
92
93 let topfn r k e = Ast0.TopTag(e) :: (k e) in
94
95 let res =
b1b2de81 96 V0.flat_combiner bind option_default
34e49164 97 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
98 (donothing Ast0.dotsExpr) (donothing Ast0.dotsInit)
99 (donothing Ast0.dotsParam) (donothing Ast0.dotsStmt)
100 (donothing Ast0.dotsDecl) (donothing Ast0.dotsCase)
101 (donothing Ast0.ident) expression (donothing Ast0.typeC) initialiser
102 (donothing Ast0.param) (donothing Ast0.decl) statement
103 (donothing Ast0.case_line) topfn in
b1b2de81 104 res.VT0.combiner_rec_top_level e
34e49164
C
105
106(* --------------------------------------------------------------------- *)
107(* --------------------------------------------------------------------- *)
108(* collect the possible join points, in order, among the children of a
109BindContext. Dots are not allowed. Nests and disjunctions are no problem,
110because their delimiters take up a line by themselves *)
111
112(* An Unfavored token is one that is in a BindContext node; using this causes
113 the node to become Neither, meaning that isomorphisms can't be applied *)
114(* Toplevel is for the bef token of a function declaration and is for
115attaching top-level definitions that should come before the complete
116declaration *)
117type minus_join_point = Favored | Unfavored | Toplevel | Decl
118
119(* Maps the index of a node to the indices of the mcodes it contains *)
120let root_token_table = (Hashtbl.create(50) : (int, int list) Hashtbl.t)
121
122let create_root_token_table minus =
123 Hashtbl.iter
124 (function tokens ->
125 function (node,_) ->
126 let key =
127 match node with
128 Ast0.DotsExprTag(d) -> Ast0.get_index d
129 | Ast0.DotsInitTag(d) -> Ast0.get_index d
130 | Ast0.DotsParamTag(d) -> Ast0.get_index d
131 | Ast0.DotsStmtTag(d) -> Ast0.get_index d
132 | Ast0.DotsDeclTag(d) -> Ast0.get_index d
133 | Ast0.DotsCaseTag(d) -> Ast0.get_index d
134 | Ast0.IdentTag(d) -> Ast0.get_index d
135 | Ast0.ExprTag(d) -> Ast0.get_index d
136 | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) ->
137 failwith "not possible - iso only"
138 | Ast0.TypeCTag(d) -> Ast0.get_index d
139 | Ast0.ParamTag(d) -> Ast0.get_index d
140 | Ast0.InitTag(d) -> Ast0.get_index d
141 | Ast0.DeclTag(d) -> Ast0.get_index d
142 | Ast0.StmtTag(d) -> Ast0.get_index d
143 | Ast0.CaseLineTag(d) -> Ast0.get_index d
144 | Ast0.TopTag(d) -> Ast0.get_index d
145 | Ast0.IsoWhenTag(_) -> failwith "only within iso phase"
1be43e12
C
146 | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase"
147 | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase"
17ba0788
C
148 | Ast0.MetaPosTag(p) -> failwith "not in plus code"
149 | Ast0.HiddenVarTag(p) -> failwith "only within iso phase"
34e49164
C
150 in
151 Hashtbl.add root_token_table key tokens)
152 CN.minus_table;
153 List.iter
154 (function r ->
155 let index = Ast0.get_index r in
156 try let _ = Hashtbl.find root_token_table index in ()
157 with Not_found -> Hashtbl.add root_token_table index [])
158 minus
159
160let collect_minus_join_points root =
161 let root_index = Ast0.get_index root in
162 let unfavored_tokens = Hashtbl.find root_token_table root_index in
163 let bind x y = x @ y in
164 let option_default = [] in
165
7f004419 166 let mcode (x,_,info,mcodekind,_,_) =
0708f913 167 if List.mem (info.Ast0.pos_info.Ast0.offset) unfavored_tokens
34e49164
C
168 then [(Unfavored,info,mcodekind)]
169 else [(Favored,info,mcodekind)] in
170
171 let do_nothing r k e =
172 let info = Ast0.get_info e in
173 let index = Ast0.get_index e in
174 match Ast0.get_mcodekind e with
175 (Ast0.MINUS(_)) as mc -> [(Favored,info,mc)]
176 | (Ast0.CONTEXT(_)) as mc when not(index = root_index) ->
177 (* This was unfavored at one point, but I don't remember why *)
178 [(Favored,info,mc)]
179 | _ -> k e in
180
181(* don't want to attach to the outside of DOTS, because metavariables can't
182bind to that; not good for isomorphisms *)
183
184 let dots f k d =
185 let multibind l =
186 let rec loop = function
187 [] -> option_default
188 | [x] -> x
189 | x::xs -> bind x (loop xs) in
190 loop l in
191
192 match Ast0.unwrap d with
193 Ast0.DOTS(l) -> multibind (List.map f l)
194 | Ast0.CIRCLES(l) -> multibind (List.map f l)
195 | Ast0.STARS(l) -> multibind (List.map f l) in
196
b1b2de81
C
197 let edots r k d = dots r.VT0.combiner_rec_expression k d in
198 let idots r k d = dots r.VT0.combiner_rec_initialiser k d in
199 let pdots r k d = dots r.VT0.combiner_rec_parameter k d in
200 let sdots r k d = dots r.VT0.combiner_rec_statement k d in
201 let ddots r k d = dots r.VT0.combiner_rec_declaration k d in
202 let cdots r k d = dots r.VT0.combiner_rec_case_line k d in
34e49164
C
203
204 (* a case for everything that has a Opt *)
205
206 let statement r k s =
207 (*
208 let redo_branched res (ifinfo,aftmc) =
209 let redo fv info mc rest =
210 let new_info = {info with Ast0.attachable_end = false} in
211 List.rev ((Favored,ifinfo,aftmc)::(fv,new_info,mc)::rest) in
212 match List.rev res with
213 [(fv,info,mc)] ->
214 (match mc with
215 Ast0.MINUS(_) | Ast0.CONTEXT(_) ->
216 (* even for -, better for isos not to integrate code after an
217 if into the if body.
218 but the problem is that this can extend the region in
219 which a variable is bound, because a variable bound in the
220 aft node would seem to have to be live in the whole if,
221 whereas we might like it to be live in only one branch.
222 ie ideally, if we can keep the minus code in the right
223 order, we would like to drop it as close to the bindings
224 of its free variables. This could be anywhere in the minus
225 code. Perhaps we would like to do this after the
226 application of isomorphisms, though.
227 *)
228 redo fv info mc []
229 | _ -> res)
230 | (fv,info,mc)::rest ->
231 (match mc with
232 Ast0.CONTEXT(_) -> redo fv info mc rest
233 | _ -> res)
234 | _ -> failwith "unexpected empty code" in *)
235 match Ast0.unwrap s with
236 (* Ast0.IfThen(_,_,_,_,_,aft)
237 | Ast0.IfThenElse(_,_,_,_,_,_,_,aft)
238 | Ast0.While(_,_,_,_,_,aft)
239 | Ast0.For(_,_,_,_,_,_,_,_,_,aft)
240 | Ast0.Iterator(_,_,_,_,_,aft) ->
241 redo_branched (do_nothing r k s) aft*)
242 | Ast0.FunDecl((info,bef),fninfo,name,lp,params,rp,lbrace,body,rbrace) ->
243 (Toplevel,info,bef)::(k s)
244 | Ast0.Decl((info,bef),decl) -> (Decl,info,bef)::(k s)
245 | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) ->
b1b2de81
C
246 mcode starter @ r.VT0.combiner_rec_statement_dots stmt_dots @
247 mcode ender
34e49164
C
248 | Ast0.Dots(d,whencode) | Ast0.Circles(d,whencode)
249 | Ast0.Stars(d,whencode) -> mcode d (* ignore whencode *)
250 | Ast0.OptStm s | Ast0.UniqueStm s ->
251 (* put the + code on the thing, not on the opt *)
b1b2de81 252 r.VT0.combiner_rec_statement s
34e49164
C
253 | _ -> do_nothing r k s in
254
255 let expression r k e =
256 match Ast0.unwrap e with
257 Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) ->
258 mcode starter @
b1b2de81 259 r.VT0.combiner_rec_expression_dots expr_dots @ mcode ender
34e49164
C
260 | Ast0.Edots(d,whencode) | Ast0.Ecircles(d,whencode)
261 | Ast0.Estars(d,whencode) -> mcode d (* ignore whencode *)
262 | Ast0.OptExp e | Ast0.UniqueExp e ->
263 (* put the + code on the thing, not on the opt *)
b1b2de81 264 r.VT0.combiner_rec_expression e
34e49164
C
265 | _ -> do_nothing r k e in
266
267 let ident r k e =
268 match Ast0.unwrap e with
269 Ast0.OptIdent i | Ast0.UniqueIdent i ->
270 (* put the + code on the thing, not on the opt *)
b1b2de81 271 r.VT0.combiner_rec_ident i
34e49164
C
272 | _ -> do_nothing r k e in
273
274 let typeC r k e =
275 match Ast0.unwrap e with
276 Ast0.OptType t | Ast0.UniqueType t ->
277 (* put the + code on the thing, not on the opt *)
b1b2de81 278 r.VT0.combiner_rec_typeC t
34e49164
C
279 | _ -> do_nothing r k e in
280
281 let decl r k e =
282 match Ast0.unwrap e with
283 Ast0.OptDecl d | Ast0.UniqueDecl d ->
284 (* put the + code on the thing, not on the opt *)
b1b2de81 285 r.VT0.combiner_rec_declaration d
34e49164
C
286 | _ -> do_nothing r k e in
287
288 let initialiser r k e =
289 match Ast0.unwrap e with
290 Ast0.Idots(d,whencode) -> mcode d (* ignore whencode *)
291 | Ast0.OptIni i | Ast0.UniqueIni i ->
292 (* put the + code on the thing, not on the opt *)
b1b2de81 293 r.VT0.combiner_rec_initialiser i
34e49164
C
294 | _ -> do_nothing r k e in
295
296 let param r k e =
297 match Ast0.unwrap e with
298 Ast0.OptParam p | Ast0.UniqueParam p ->
299 (* put the + code on the thing, not on the opt *)
b1b2de81 300 r.VT0.combiner_rec_parameter p
34e49164
C
301 | _ -> do_nothing r k e in
302
303 let case_line r k e =
304 match Ast0.unwrap e with
305 Ast0.OptCase c ->
306 (* put the + code on the thing, not on the opt *)
b1b2de81 307 r.VT0.combiner_rec_case_line c
34e49164
C
308 | _ -> do_nothing r k e in
309
310 let do_top r k (e: Ast0.top_level) = k e in
311
b1b2de81 312 V0.flat_combiner bind option_default
34e49164 313 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
314 edots idots pdots sdots ddots cdots
315 ident expression typeC initialiser param decl statement case_line do_top
316
317
318let call_collect_minus context_nodes :
319 (int * (minus_join_point * Ast0.info * Ast0.mcodekind) list) list =
320 List.map
321 (function e ->
322 match e with
323 Ast0.DotsExprTag(e) ->
324 (Ast0.get_index e,
b1b2de81 325 (collect_minus_join_points e).VT0.combiner_rec_expression_dots e)
34e49164
C
326 | Ast0.DotsInitTag(e) ->
327 (Ast0.get_index e,
b1b2de81 328 (collect_minus_join_points e).VT0.combiner_rec_initialiser_list e)
34e49164
C
329 | Ast0.DotsParamTag(e) ->
330 (Ast0.get_index e,
b1b2de81 331 (collect_minus_join_points e).VT0.combiner_rec_parameter_list e)
34e49164
C
332 | Ast0.DotsStmtTag(e) ->
333 (Ast0.get_index e,
b1b2de81 334 (collect_minus_join_points e).VT0.combiner_rec_statement_dots e)
34e49164
C
335 | Ast0.DotsDeclTag(e) ->
336 (Ast0.get_index e,
b1b2de81 337 (collect_minus_join_points e).VT0.combiner_rec_declaration_dots e)
34e49164
C
338 | Ast0.DotsCaseTag(e) ->
339 (Ast0.get_index e,
b1b2de81 340 (collect_minus_join_points e).VT0.combiner_rec_case_line_dots e)
34e49164
C
341 | Ast0.IdentTag(e) ->
342 (Ast0.get_index e,
b1b2de81 343 (collect_minus_join_points e).VT0.combiner_rec_ident e)
34e49164
C
344 | Ast0.ExprTag(e) ->
345 (Ast0.get_index e,
b1b2de81 346 (collect_minus_join_points e).VT0.combiner_rec_expression e)
34e49164
C
347 | Ast0.ArgExprTag(e) | Ast0.TestExprTag(e) ->
348 failwith "not possible - iso only"
349 | Ast0.TypeCTag(e) ->
350 (Ast0.get_index e,
b1b2de81 351 (collect_minus_join_points e).VT0.combiner_rec_typeC e)
34e49164
C
352 | Ast0.ParamTag(e) ->
353 (Ast0.get_index e,
b1b2de81 354 (collect_minus_join_points e).VT0.combiner_rec_parameter e)
34e49164
C
355 | Ast0.InitTag(e) ->
356 (Ast0.get_index e,
b1b2de81 357 (collect_minus_join_points e).VT0.combiner_rec_initialiser e)
34e49164
C
358 | Ast0.DeclTag(e) ->
359 (Ast0.get_index e,
b1b2de81 360 (collect_minus_join_points e).VT0.combiner_rec_declaration e)
34e49164
C
361 | Ast0.StmtTag(e) ->
362 (Ast0.get_index e,
b1b2de81 363 (collect_minus_join_points e).VT0.combiner_rec_statement e)
34e49164
C
364 | Ast0.CaseLineTag(e) ->
365 (Ast0.get_index e,
b1b2de81 366 (collect_minus_join_points e).VT0.combiner_rec_case_line e)
34e49164
C
367 | Ast0.TopTag(e) ->
368 (Ast0.get_index e,
b1b2de81 369 (collect_minus_join_points e).VT0.combiner_rec_top_level e)
34e49164 370 | Ast0.IsoWhenTag(_) -> failwith "only within iso phase"
1be43e12
C
371 | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase"
372 | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase"
17ba0788
C
373 | Ast0.MetaPosTag(p) -> failwith "not in plus code"
374 | Ast0.HiddenVarTag(p) -> failwith "only within iso phase")
34e49164
C
375 context_nodes
376
377(* result of collecting the join points should be sorted in nondecreasing
378 order by line *)
379let verify l =
380 let get_info = function
381 (Favored,info,_) | (Unfavored,info,_) | (Toplevel,info,_)
382 | (Decl,info,_) -> info in
0708f913
C
383 let token_start_line x = (get_info x).Ast0.pos_info.Ast0.logical_start in
384 let token_end_line x = (get_info x).Ast0.pos_info.Ast0.logical_end in
385 let token_real_start_line x = (get_info x).Ast0.pos_info.Ast0.line_start in
386 let token_real_end_line x = (get_info x).Ast0.pos_info.Ast0.line_end in
34e49164
C
387 List.iter
388 (function
389 (index,((_::_) as l1)) ->
390 let _ =
391 List.fold_left
392 (function (prev,real_prev) ->
393 function cur ->
394 let ln = token_start_line cur in
395 if ln < prev
396 then
397 failwith
398 (Printf.sprintf
7f004419 399 "error in collection of - tokens: line %d less than line %d"
34e49164
C
400 (token_real_start_line cur) real_prev);
401 (token_end_line cur,token_real_end_line cur))
402 (token_end_line (List.hd l1), token_real_end_line (List.hd l1))
403 (List.tl l1) in
404 ()
405 | _ -> ()) (* dots, in eg f() has no join points *)
406 l
407
408let process_minus minus =
3a314143 409 Hashtbl.clear root_token_table;
34e49164
C
410 create_root_token_table minus;
411 List.concat
412 (List.map
413 (function x ->
414 let res = call_collect_minus (collect_context x) in
415 verify res;
416 res)
417 minus)
418
419(* --------------------------------------------------------------------- *)
420(* --------------------------------------------------------------------- *)
421(* collect the plus tokens *)
422
34e49164
C
423let mk_structUnion x = Ast.StructUnionTag x
424let mk_sign x = Ast.SignTag x
425let mk_ident x = Ast.IdentTag (Ast0toast.ident x)
426let mk_expression x = Ast.ExpressionTag (Ast0toast.expression x)
427let mk_constant x = Ast.ConstantTag x
428let mk_unaryOp x = Ast.UnaryOpTag x
429let mk_assignOp x = Ast.AssignOpTag x
430let mk_fixOp x = Ast.FixOpTag x
431let mk_binaryOp x = Ast.BinaryOpTag x
432let mk_arithOp x = Ast.ArithOpTag x
433let mk_logicalOp x = Ast.LogicalOpTag x
434let mk_declaration x = Ast.DeclarationTag (Ast0toast.declaration x)
435let mk_topdeclaration x = Ast.DeclarationTag (Ast0toast.declaration x)
436let mk_storage x = Ast.StorageTag x
437let mk_inc_file x = Ast.IncFileTag x
438let mk_statement x = Ast.StatementTag (Ast0toast.statement x)
439let mk_case_line x = Ast.CaseLineTag (Ast0toast.case_line x)
440let mk_const_vol x = Ast.ConstVolTag x
441let mk_token x info = Ast.Token (x,Some info)
442let mk_meta (_,x) info = Ast.Token (x,Some info)
443let mk_code x = Ast.Code (Ast0toast.top_level x)
444
445let mk_exprdots x = Ast.ExprDotsTag (Ast0toast.expression_dots x)
446let mk_paramdots x = Ast.ParamDotsTag (Ast0toast.parameter_list x)
447let mk_stmtdots x = Ast.StmtDotsTag (Ast0toast.statement_dots x)
448let mk_decldots x = Ast.DeclDotsTag (Ast0toast.declaration_dots x)
449let mk_casedots x = failwith "+ case lines not supported"
17ba0788 450let mk_typeC x = Ast.FullTypeTag (Ast0toast.typeC false x)
34e49164
C
451let mk_init x = Ast.InitTag (Ast0toast.initialiser x)
452let mk_param x = Ast.ParamTag (Ast0toast.parameterTypeDef x)
453
454let collect_plus_nodes root =
455 let root_index = Ast0.get_index root in
456
457 let bind x y = x @ y in
458 let option_default = [] in
459
0708f913
C
460 let extract_strings info =
461 let adjust_info =
462 {info with Ast0.strings_before = []; Ast0.strings_after = []} in
463 let extract = function
464 [] -> []
465 | strings_before ->
466 let (_,first) = List.hd strings_before in
467 let (_,last) = List.hd (List.rev strings_before) in
468 let new_pos_info =
469 {Ast0.line_start = first.Ast0.line_start;
470 Ast0.line_end = last.Ast0.line_start;
471 Ast0.logical_start = first.Ast0.logical_start;
472 Ast0.logical_end = last.Ast0.logical_start;
473 Ast0.column = first.Ast0.column;
474 Ast0.offset = first.Ast0.offset} in
475 let new_info = {adjust_info with Ast0.pos_info = new_pos_info} in
476 let string = List.map (function (s,_) -> s) strings_before in
951c7801 477 [(new_info,Ast.ONE(*?*),Ast.Pragma (string))] in
0708f913
C
478 let bef = extract info.Ast0.strings_before in
479 let aft = extract info.Ast0.strings_after in
480 (bef,aft) in
481
708f4980 482 let mcode fn (term,_,info,mcodekind,_,_) =
0708f913 483 match mcodekind with
951c7801 484 Ast0.PLUS c -> [(info,c,fn term)]
0708f913
C
485 | Ast0.CONTEXT _ -> let (bef,aft) = extract_strings info in bef@aft
486 | _ -> [] in
34e49164 487
708f4980 488 let imcode fn (term,_,info,mcodekind,_,_) =
34e49164 489 match mcodekind with
951c7801 490 Ast0.PLUS c -> [(info,c,fn term (Ast0toast.convert_info info))]
0708f913 491 | Ast0.CONTEXT _ -> let (bef,aft) = extract_strings info in bef@aft
34e49164
C
492 | _ -> [] in
493
0708f913
C
494 let info (i,_) = let (bef,aft) = extract_strings i in bef@aft in
495
34e49164
C
496 let do_nothing fn r k e =
497 match Ast0.get_mcodekind e with
498 (Ast0.CONTEXT(_)) when not(Ast0.get_index e = root_index) -> []
951c7801 499 | Ast0.PLUS c -> [(Ast0.get_info e,c,fn e)]
34e49164
C
500 | _ -> k e in
501
502 (* case for everything that is just a wrapper for a simpler thing *)
0708f913 503 (* case for things with bef aft *)
34e49164
C
504 let stmt r k e =
505 match Ast0.unwrap e with
b1b2de81
C
506 Ast0.Exp(exp) -> r.VT0.combiner_rec_expression exp
507 | Ast0.TopExp(exp) -> r.VT0.combiner_rec_expression exp
508 | Ast0.Ty(ty) -> r.VT0.combiner_rec_typeC ty
509 | Ast0.TopInit(init) -> r.VT0.combiner_rec_initialiser init
0708f913
C
510 | Ast0.Decl(bef,decl) ->
511 (info bef) @ (do_nothing mk_statement r k e)
512 | Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) ->
513 (info bef) @ (do_nothing mk_statement r k e)
514 | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) ->
515 (do_nothing mk_statement r k e) @ (info aft)
516 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) ->
517 (do_nothing mk_statement r k e) @ (info aft)
518 | Ast0.While(whl,lp,exp,rp,body,aft) ->
519 (do_nothing mk_statement r k e) @ (info aft)
520 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,aft) ->
521 (do_nothing mk_statement r k e) @ (info aft)
522 | Ast0.Iterator(nm,lp,args,rp,body,aft) ->
523 (do_nothing mk_statement r k e) @ (info aft)
34e49164
C
524 | _ -> do_nothing mk_statement r k e in
525
526 (* statementTag is preferred, because it indicates that one statement is
527 replaced by one statement, in single_statement *)
528 let stmt_dots r k e =
529 match Ast0.unwrap e with
530 Ast0.DOTS([s]) | Ast0.CIRCLES([s]) | Ast0.STARS([s]) ->
b1b2de81 531 r.VT0.combiner_rec_statement s
34e49164
C
532 | _ -> do_nothing mk_stmtdots r k e in
533
534 let toplevel r k e =
535 match Ast0.unwrap e with
65038c61 536 Ast0.NONDECL(s) -> r.VT0.combiner_rec_statement s
b1b2de81 537 | Ast0.CODE(sdots) -> r.VT0.combiner_rec_statement_dots sdots
34e49164
C
538 | _ -> do_nothing mk_code r k e in
539
540 let initdots r k e = k e in
541
b1b2de81 542 V0.flat_combiner bind option_default
34e49164
C
543 (imcode mk_meta) (imcode mk_token) (mcode mk_constant) (mcode mk_assignOp)
544 (mcode mk_fixOp)
545 (mcode mk_unaryOp) (mcode mk_binaryOp) (mcode mk_const_vol)
faf9a90c 546 (mcode mk_sign) (mcode mk_structUnion)
34e49164
C
547 (mcode mk_storage) (mcode mk_inc_file)
548 (do_nothing mk_exprdots) initdots
549 (do_nothing mk_paramdots) stmt_dots (do_nothing mk_decldots)
550 (do_nothing mk_casedots)
551 (do_nothing mk_ident) (do_nothing mk_expression)
552 (do_nothing mk_typeC) (do_nothing mk_init) (do_nothing mk_param)
553 (do_nothing mk_declaration)
554 stmt (do_nothing mk_case_line) toplevel
555
556let call_collect_plus context_nodes :
951c7801 557 (int * (Ast0.info * Ast.count * Ast.anything) list) list =
34e49164
C
558 List.map
559 (function e ->
560 match e with
561 Ast0.DotsExprTag(e) ->
562 (Ast0.get_index e,
b1b2de81 563 (collect_plus_nodes e).VT0.combiner_rec_expression_dots e)
34e49164
C
564 | Ast0.DotsInitTag(e) ->
565 (Ast0.get_index e,
b1b2de81 566 (collect_plus_nodes e).VT0.combiner_rec_initialiser_list e)
34e49164
C
567 | Ast0.DotsParamTag(e) ->
568 (Ast0.get_index e,
b1b2de81 569 (collect_plus_nodes e).VT0.combiner_rec_parameter_list e)
34e49164
C
570 | Ast0.DotsStmtTag(e) ->
571 (Ast0.get_index e,
b1b2de81 572 (collect_plus_nodes e).VT0.combiner_rec_statement_dots e)
34e49164
C
573 | Ast0.DotsDeclTag(e) ->
574 (Ast0.get_index e,
b1b2de81 575 (collect_plus_nodes e).VT0.combiner_rec_declaration_dots e)
34e49164
C
576 | Ast0.DotsCaseTag(e) ->
577 (Ast0.get_index e,
b1b2de81 578 (collect_plus_nodes e).VT0.combiner_rec_case_line_dots e)
34e49164
C
579 | Ast0.IdentTag(e) ->
580 (Ast0.get_index e,
b1b2de81 581 (collect_plus_nodes e).VT0.combiner_rec_ident e)
34e49164
C
582 | Ast0.ExprTag(e) ->
583 (Ast0.get_index e,
b1b2de81 584 (collect_plus_nodes e).VT0.combiner_rec_expression e)
34e49164
C
585 | Ast0.ArgExprTag(_) | Ast0.TestExprTag(_) ->
586 failwith "not possible - iso only"
587 | Ast0.TypeCTag(e) ->
588 (Ast0.get_index e,
b1b2de81 589 (collect_plus_nodes e).VT0.combiner_rec_typeC e)
34e49164
C
590 | Ast0.InitTag(e) ->
591 (Ast0.get_index e,
b1b2de81 592 (collect_plus_nodes e).VT0.combiner_rec_initialiser e)
34e49164
C
593 | Ast0.ParamTag(e) ->
594 (Ast0.get_index e,
b1b2de81 595 (collect_plus_nodes e).VT0.combiner_rec_parameter e)
34e49164
C
596 | Ast0.DeclTag(e) ->
597 (Ast0.get_index e,
b1b2de81 598 (collect_plus_nodes e).VT0.combiner_rec_declaration e)
34e49164
C
599 | Ast0.StmtTag(e) ->
600 (Ast0.get_index e,
b1b2de81 601 (collect_plus_nodes e).VT0.combiner_rec_statement e)
34e49164
C
602 | Ast0.CaseLineTag(e) ->
603 (Ast0.get_index e,
b1b2de81 604 (collect_plus_nodes e).VT0.combiner_rec_case_line e)
34e49164
C
605 | Ast0.TopTag(e) ->
606 (Ast0.get_index e,
b1b2de81 607 (collect_plus_nodes e).VT0.combiner_rec_top_level e)
34e49164 608 | Ast0.IsoWhenTag(_) -> failwith "only within iso phase"
1be43e12
C
609 | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase"
610 | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase"
17ba0788
C
611 | Ast0.MetaPosTag(p) -> failwith "not visible here"
612 | Ast0.HiddenVarTag(_) -> failwith "only within iso phase")
34e49164
C
613 context_nodes
614
615(* The plus fragments are converted to a list of lists of lists.
616Innermost list: Elements have type anything. For any pair of successive
617elements, n and n+1, the ending line of n is the same as the starting line
618of n+1.
619Middle lists: For any pair of successive elements, n and n+1, the ending
620line of n is one less than the starting line of n+1.
621Outer list: For any pair of successive elements, n and n+1, the ending
622line of n is more than one less than the starting line of n+1. *)
623
0708f913
C
624let logstart info = info.Ast0.pos_info.Ast0.logical_start
625let logend info = info.Ast0.pos_info.Ast0.logical_end
34e49164
C
626
627let redo info start finish =
0708f913
C
628 let new_pos_info =
629 {info.Ast0.pos_info with
630 Ast0.logical_start = start;
631 Ast0.logical_end = finish} in
632 {info with Ast0.pos_info = new_pos_info}
34e49164
C
633
634let rec find_neighbors (index,l) :
951c7801 635 int * (Ast0.info * Ast.count * (Ast.anything list list)) list =
34e49164
C
636 let rec loop = function
637 [] -> []
951c7801 638 | (i,c,x)::rest ->
34e49164 639 (match loop rest with
951c7801 640 ((i1,c1,(x1::rest_inner))::rest_middle)::rest_outer ->
34e49164
C
641 let finish1 = logend i in
642 let start2 = logstart i1 in
643 if finish1 = start2
644 then
951c7801
C
645 ((if not (c = c1) then failwith "inconsistent + code");
646 ((redo i (logstart i) (logend i1),c,(x::x1::rest_inner))
34e49164 647 ::rest_middle)
951c7801 648 ::rest_outer)
34e49164 649 else if finish1 + 1 = start2
951c7801
C
650 then ((i,c,[x])::(i1,c1,(x1::rest_inner))::rest_middle)::rest_outer
651 else
652 [(i,c,[x])]::((i1,c1,(x1::rest_inner))::rest_middle)::rest_outer
653 | _ -> [[(i,c,[x])]]) (* rest must be [] *) in
34e49164
C
654 let res =
655 List.map
656 (function l ->
951c7801
C
657 let (start_info,start_count,_) = List.hd l in
658 let (end_info,end_count,_) = List.hd (List.rev l) in
659 (if not (start_count = end_count) then failwith "inconsistent + code");
34e49164 660 (redo start_info (logstart start_info) (logend end_info),
951c7801
C
661 start_count,
662 List.map (function (_,_,x) -> x) l))
34e49164
C
663 (loop l) in
664 (index,res)
665
666let process_plus plus :
951c7801 667 (int * (Ast0.info * Ast.count * Ast.anything list list) list) list =
34e49164
C
668 List.concat
669 (List.map
670 (function x ->
671 List.map find_neighbors (call_collect_plus (collect_context x)))
672 plus)
673
674(* --------------------------------------------------------------------- *)
675(* --------------------------------------------------------------------- *)
676(* merge *)
677(*
678let merge_one = function
679 (m1::m2::minus_info,p::plus_info) ->
680 if p < m1, then
681 attach p to the beginning of m1.bef if m1 is Good, fail if it is bad
682 if p > m1 && p < m2, then consider the following possibilities, in order
683 m1 is Good and favored: attach to the beginning of m1.aft
684 m2 is Good and favored: attach to the beginning of m2.bef; drop m1
685 m1 is Good and unfavored: attach to the beginning of m1.aft
686 m2 is Good and unfavored: attach to the beginning of m2.bef; drop m1
687 also flip m1.bef if the first where > m1
688 if we drop m1, then flip m1.aft first
689 if p > m2
690 m2 is Good and favored: attach to the beginning of m2.aft; drop m1
691*)
692
693(* end of first argument < start/end of second argument *)
694let less_than_start info1 info2 =
0708f913 695 info1.Ast0.pos_info.Ast0.logical_end < info2.Ast0.pos_info.Ast0.logical_start
34e49164 696let less_than_end info1 info2 =
0708f913 697 info1.Ast0.pos_info.Ast0.logical_end < info2.Ast0.pos_info.Ast0.logical_end
34e49164 698let greater_than_end info1 info2 =
0708f913 699 info1.Ast0.pos_info.Ast0.logical_start > info2.Ast0.pos_info.Ast0.logical_end
34e49164
C
700let good_start info = info.Ast0.attachable_start
701let good_end info = info.Ast0.attachable_end
702
703let toplevel = function Toplevel -> true | Favored | Unfavored | Decl -> false
704let decl = function Decl -> true | Favored | Unfavored | Toplevel -> false
705let favored = function Favored -> true | Unfavored | Toplevel | Decl -> false
706
707let top_code =
90aeb998
C
708 List.for_all
709 (List.for_all (function Ast.Code _ | Ast.Pragma _ -> true | _ -> false))
710
711let storage_code =
712 List.for_all
713 (List.for_all (function Ast.StorageTag _ -> true | _ -> false))
34e49164
C
714
715(* The following is probably not correct. The idea is to detect what
716should be placed completely before the declaration. So type/storage
717related things do not fall into this category, and complete statements do
718fall into this category. But perhaps other things should be in this
719category as well, such as { or ;? *)
720let predecl_code =
721 let tester = function
722 (* the following should definitely be true *)
723 Ast.DeclarationTag _
724 | Ast.StatementTag _
725 | Ast.Rule_elemTag _
726 | Ast.StmtDotsTag _
0708f913
C
727 | Ast.Code _
728 | Ast.Pragma _ -> true
34e49164
C
729 (* the following should definitely be false *)
730 | Ast.FullTypeTag _ | Ast.BaseTypeTag _ | Ast.StructUnionTag _
731 | Ast.SignTag _
732 | Ast.StorageTag _ | Ast.ConstVolTag _ | Ast.TypeCTag _ -> false
733 (* not sure about the rest *)
734 | _ -> false in
735 List.for_all (List.for_all tester)
736
737let pr = Printf.sprintf
738
739let insert thing thinginfo into intoinfo =
740 let get_last l = let l = List.rev l in (List.rev(List.tl l),List.hd l) in
741 let get_first l = (List.hd l,List.tl l) in
0708f913
C
742 let thing_start = thinginfo.Ast0.pos_info.Ast0.logical_start in
743 let thing_end = thinginfo.Ast0.pos_info.Ast0.logical_end in
744 let thing_offset = thinginfo.Ast0.pos_info.Ast0.offset in
34e49164
C
745 let into_start = intoinfo.Ast0.tline_start in
746 let into_end = intoinfo.Ast0.tline_end in
747 let into_left_offset = intoinfo.Ast0.left_offset in
748 let into_right_offset = intoinfo.Ast0.right_offset in
34e49164
C
749 if thing_end < into_start && thing_start < into_start
750 then (thing@into,
751 {{intoinfo with Ast0.tline_start = thing_start}
752 with Ast0.left_offset = thing_offset})
753 else if thing_end = into_start && thing_offset < into_left_offset
754 then
755 let (prev,last) = get_last thing in
756 let (first,rest) = get_first into in
757 (prev@[last@first]@rest,
758 {{intoinfo with Ast0.tline_start = thing_start}
759 with Ast0.left_offset = thing_offset})
760 else if thing_start > into_end && thing_end > into_end
761 then (into@thing,
762 {{intoinfo with Ast0.tline_end = thing_end}
763 with Ast0.right_offset = thing_offset})
764 else if thing_start = into_end && thing_offset > into_right_offset
765 then
766 let (first,rest) = get_first thing in
767 let (prev,last) = get_last into in
768 (prev@[last@first]@rest,
769 {{intoinfo with Ast0.tline_end = thing_end}
770 with Ast0.right_offset = thing_offset})
771 else
772 begin
773 Printf.printf "thing start %d thing end %d into start %d into end %d\n"
774 thing_start thing_end into_start into_end;
775 Printf.printf "thing offset %d left offset %d right offset %d\n"
776 thing_offset into_left_offset into_right_offset;
777 Pretty_print_cocci.print_anything "" thing;
1be43e12 778 Pretty_print_cocci.print_anything "" into;
34e49164
C
779 failwith "can't figure out where to put the + code"
780 end
781
782let init thing info =
783 (thing,
0708f913
C
784 {Ast0.tline_start = info.Ast0.pos_info.Ast0.logical_start;
785 Ast0.tline_end = info.Ast0.pos_info.Ast0.logical_end;
786 Ast0.left_offset = info.Ast0.pos_info.Ast0.offset;
787 Ast0.right_offset = info.Ast0.pos_info.Ast0.offset})
34e49164 788
8babbc8f
C
789let it2c = function Ast.ONE -> "one" | Ast.MANY -> "many"
790
951c7801 791let attachbefore (infop,c,p) = function
34e49164 792 Ast0.MINUS(replacements) ->
951c7801 793 let (repl,ti) = !replacements in
8babbc8f
C
794 (match repl with
795 Ast.NOREPLACEMENT ->
796 let (bef,ti) = init p infop in
8babbc8f
C
797 replacements := (Ast.REPLACEMENT(bef,c),ti)
798 | Ast.REPLACEMENT(repl,it) ->
8babbc8f
C
799 let it = Ast.lub_count it c in
800 let (bef,ti) = insert p infop repl ti in
801 replacements := (Ast.REPLACEMENT(bef,it),ti))
34e49164
C
802 | Ast0.CONTEXT(neighbors) ->
803 let (repl,ti1,ti2) = !neighbors in
804 (match repl with
951c7801 805 Ast.BEFORE(bef,it) ->
34e49164 806 let (bef,ti1) = insert p infop bef ti1 in
951c7801
C
807 let it = Ast.lub_count it c in
808 neighbors := (Ast.BEFORE(bef,it),ti1,ti2)
809 | Ast.AFTER(aft,it) ->
34e49164 810 let (bef,ti1) = init p infop in
951c7801
C
811 let it = Ast.lub_count it c in
812 neighbors := (Ast.BEFOREAFTER(bef,aft,it),ti1,ti2)
813 | Ast.BEFOREAFTER(bef,aft,it) ->
34e49164 814 let (bef,ti1) = insert p infop bef ti1 in
951c7801
C
815 let it = Ast.lub_count it c in
816 neighbors := (Ast.BEFOREAFTER(bef,aft,it),ti1,ti2)
34e49164
C
817 | Ast.NOTHING ->
818 let (bef,ti1) = init p infop in
951c7801 819 neighbors := (Ast.BEFORE(bef,c),ti1,ti2))
34e49164
C
820 | _ -> failwith "not possible for attachbefore"
821
951c7801 822let attachafter (infop,c,p) = function
34e49164 823 Ast0.MINUS(replacements) ->
951c7801 824 let (repl,ti) = !replacements in
8babbc8f
C
825 (match repl with
826 Ast.NOREPLACEMENT ->
827 let (aft,ti) = init p infop in
828 replacements := (Ast.REPLACEMENT(aft,c),ti)
829 | Ast.REPLACEMENT(repl,it) ->
830 let it = Ast.lub_count it c in
831 let (aft,ti) = insert p infop repl ti in
832 replacements := (Ast.REPLACEMENT(aft,it),ti))
34e49164
C
833 | Ast0.CONTEXT(neighbors) ->
834 let (repl,ti1,ti2) = !neighbors in
835 (match repl with
951c7801 836 Ast.BEFORE(bef,it) ->
34e49164 837 let (aft,ti2) = init p infop in
951c7801
C
838 let it = Ast.lub_count it c in
839 neighbors := (Ast.BEFOREAFTER(bef,aft,it),ti1,ti2)
840 | Ast.AFTER(aft,it) ->
34e49164 841 let (aft,ti2) = insert p infop aft ti2 in
951c7801
C
842 let it = Ast.lub_count it c in
843 neighbors := (Ast.AFTER(aft,it),ti1,ti2)
844 | Ast.BEFOREAFTER(bef,aft,it) ->
34e49164 845 let (aft,ti2) = insert p infop aft ti2 in
951c7801
C
846 let it = Ast.lub_count it c in
847 neighbors := (Ast.BEFOREAFTER(bef,aft,it),ti1,ti2)
34e49164
C
848 | Ast.NOTHING ->
849 let (aft,ti2) = init p infop in
951c7801 850 neighbors := (Ast.AFTER(aft,c),ti1,ti2))
34e49164
C
851 | _ -> failwith "not possible for attachbefore"
852
853let attach_all_before ps m =
854 List.iter (function x -> attachbefore x m) ps
855
856let attach_all_after ps m =
857 List.iter (function x -> attachafter x m) ps
858
859let split_at_end info ps =
0708f913 860 let split_point = info.Ast0.pos_info.Ast0.logical_end in
34e49164 861 List.partition
951c7801 862 (function (info,_,_) -> info.Ast0.pos_info.Ast0.logical_end < split_point)
34e49164
C
863 ps
864
865let allminus = function
866 Ast0.MINUS(_) -> true
867 | _ -> false
868
869let rec before_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
870 [] -> ()
90aeb998 871 | (((infop,_,pcode) as p) :: ps) as all ->
34e49164
C
872 if less_than_start infop infom1 or
873 (allminus m1 && less_than_end infop infom1) (* account for trees *)
874 then
90aeb998
C
875 if toplevel f1
876 then
877 if storage_code pcode
878 then before_m2 x2 rest all (* skip fake token for storage *)
879 else (attachbefore p m1; before_m1 x1 x2 rest ps)
34e49164 880 else
90aeb998
C
881 if good_start infom1
882 then (attachbefore p m1; before_m1 x1 x2 rest ps)
883 else
884 failwith
885 (pr "%d: no available token to attach to"
886 infop.Ast0.pos_info.Ast0.line_start)
34e49164
C
887 else after_m1 x1 x2 rest all
888
889and after_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function
890 [] -> ()
951c7801 891 | (((infop,count,pcode) as p) :: ps) as all ->
34e49164
C
892 (* if the following is false, then some + code is stuck in the middle
893 of some context code (m1). could drop down to the token level.
894 this might require adjustments in ast0toast as well, when + code on
895 expressions is dropped down to + code on expressions. it might
896 also break some invariants on which iso depends, particularly on
897 what it can infer from something being CONTEXT with no top-level
898 modifications. for the moment, we thus give an error, asking the
899 user to rewrite the semantic patch. *)
faf9a90c 900 if greater_than_end infop infom1 or is_minus m1 or !empty_isos
34e49164
C
901 then
902 if less_than_start infop infom2
903 then
904 if predecl_code pcode && good_end infom1 && decl f1
905 then (attachafter p m1; after_m1 x1 x2 rest ps)
906 else if predecl_code pcode && good_start infom2 && decl f2
907 then before_m2 x2 rest all
908 else if top_code pcode && good_end infom1 && toplevel f1
909 then (attachafter p m1; after_m1 x1 x2 rest ps)
910 else if top_code pcode && good_start infom2 && toplevel f2
911 then before_m2 x2 rest all
912 else if good_end infom1 && favored f1
913 then (attachafter p m1; after_m1 x1 x2 rest ps)
914 else if good_start infom2 && favored f2
915 then before_m2 x2 rest all
916 else if good_end infom1
917 then (attachafter p m1; after_m1 x1 x2 rest ps)
918 else if good_start infom2
919 then before_m2 x2 rest all
920 else
921 failwith
0708f913
C
922 (pr "%d: no available token to attach to"
923 infop.Ast0.pos_info.Ast0.line_start)
34e49164
C
924 else after_m2 x2 rest all
925 else
926 begin
927 Printf.printf "between: p start %d p end %d m1 start %d m1 end %d m2 start %d m2 end %d\n"
0708f913
C
928 infop.Ast0.pos_info.Ast0.line_start
929 infop.Ast0.pos_info.Ast0.line_end
930 infom1.Ast0.pos_info.Ast0.line_start
931 infom1.Ast0.pos_info.Ast0.line_end
932 infom2.Ast0.pos_info.Ast0.line_start
933 infom2.Ast0.pos_info.Ast0.line_end;
34e49164
C
934 Pretty_print_cocci.print_anything "" pcode;
935 failwith
936 "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."
937 end
938
faf9a90c
C
939(* not sure this is safe. if have iso problems, consider changing this
940to always return false *)
941and is_minus = function
942 Ast0.MINUS _ -> true
943 | _ -> false
944
34e49164 945and before_m2 ((f2,infom2,m2) as x2) rest
951c7801 946 (p : (Ast0.info * Ast.count * Ast.anything list list) list) =
34e49164
C
947 match (rest,p) with
948 (_,[]) -> ()
951c7801 949 | ([],((infop,_,_)::_)) ->
34e49164
C
950 let (bef_m2,aft_m2) = split_at_end infom2 p in (* bef_m2 isn't empty *)
951 if good_start infom2
952 then (attach_all_before bef_m2 m2; after_m2 x2 rest aft_m2)
953 else
954 failwith
0708f913
C
955 (pr "%d: no available token to attach to"
956 infop.Ast0.pos_info.Ast0.line_start)
34e49164
C
957 | (m::ms,_) -> before_m1 x2 m ms p
958
959and after_m2 ((f2,infom2,m2) as x2) rest
951c7801 960 (p : (Ast0.info * Ast.count * Ast.anything list list) list) =
34e49164
C
961 match (rest,p) with
962 (_,[]) -> ()
951c7801 963 | ([],((infop,_,_)::_)) ->
34e49164
C
964 if good_end infom2
965 then attach_all_after p m2
966 else
967 failwith
0708f913
C
968 (pr "%d: no available token to attach to"
969 infop.Ast0.pos_info.Ast0.line_start)
34e49164
C
970 | (m::ms,_) -> after_m1 x2 m ms p
971
972let merge_one : (minus_join_point * Ast0.info * 'a) list *
951c7801
C
973 (Ast0.info * Ast.count * Ast.anything list list) list -> unit =
974 function (m,p) ->
34e49164
C
975 (*
976 Printf.printf "minus code\n";
977 List.iter
978 (function (_,info,_) ->
8babbc8f
C
979 Printf.printf
980 "start %d end %d real_start %d real_end %d attachable start %b attachable end %b\n"
0708f913
C
981 info.Ast0.pos_info.Ast0.logical_start
982 info.Ast0.pos_info.Ast0.logical_end
983 info.Ast0.pos_info.Ast0.line_start
8babbc8f
C
984 info.Ast0.pos_info.Ast0.line_end
985 info.Ast0.attachable_start
986 info.Ast0.attachable_end)
34e49164
C
987 m;
988 Printf.printf "plus code\n";
989 List.iter
5636bb2c 990 (function (info,_,p) ->
34e49164 991 Printf.printf "start %d end %d real_start %d real_end %d\n"
0708f913
C
992 info.Ast0.pos_info.Ast0.logical_start
993 info.Ast0.pos_info.Ast0.logical_end
994 info.Ast0.pos_info.Ast0.line_end
995 info.Ast0.pos_info.Ast0.line_end;
34e49164
C
996 Pretty_print_cocci.print_anything "" p;
997 Format.print_newline())
998 p;
999 *)
1000 match (m,p) with
1001 (_,[]) -> ()
1002 | (m1::m2::restm,p) -> before_m1 m1 m2 restm p
1003 | ([m],p) -> before_m2 m [] p
1004 | ([],_) -> failwith "minus tree ran out before the plus tree"
1005
1006let merge minus_list plus_list =
1007 (*
1008 Printf.printf "minus list %s\n"
1009 (String.concat " "
1010 (List.map (function (x,_) -> string_of_int x) minus_list));
1011 Printf.printf "plus list %s\n"
1012 (String.concat " "
1013 (List.map (function (x,_) -> string_of_int x) plus_list));
1014 *)
1015 List.iter
1016 (function (index,minus_info) ->
1017 let plus_info = List.assoc index plus_list in
1018 merge_one (minus_info,plus_info))
1019 minus_list
1020
1021(* --------------------------------------------------------------------- *)
1022(* --------------------------------------------------------------------- *)
1023(* Need to check that CONTEXT nodes have nothing attached to their tokens.
1024If they do, they become MIXED *)
1025
1026let reevaluate_contextness =
1027 let bind = (@) in
1028 let option_default = [] in
1029
708f4980 1030 let mcode (_,_,_,mc,_,_) =
34e49164
C
1031 match mc with
1032 Ast0.CONTEXT(mc) -> let (ba,_,_) = !mc in [ba]
1033 | _ -> [] in
1034
0708f913
C
1035 let info (_,mc) =
1036 match mc with
1037 Ast0.CONTEXT(mc) -> let (ba,_,_) = !mc in [ba]
1038 | _ -> [] in
1039
34e49164
C
1040 let donothing r k e =
1041 match Ast0.get_mcodekind e with
1042 Ast0.CONTEXT(mc) ->
1043 if List.exists (function Ast.NOTHING -> false | _ -> true) (k e)
1044 then Ast0.set_mcodekind e (Ast0.MIXED(mc));
1045 []
1046 | _ -> let _ = k e in [] in
1047
0708f913
C
1048 (* a case for everything with bef or aft *)
1049 let stmt r k e =
1050 match Ast0.unwrap e with
1051 Ast0.Decl(bef,decl) ->
1052 (info bef) @ (donothing r k e)
1053 | Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) ->
1054 (info bef) @ (donothing r k e)
1055 | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) ->
1056 (donothing r k e) @ (info aft)
1057 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) ->
1058 (donothing r k e) @ (info aft)
1059 | Ast0.While(whl,lp,exp,rp,body,aft) ->
1060 (donothing r k e) @ (info aft)
1061 | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,aft) ->
1062 (donothing r k e) @ (info aft)
1063 | Ast0.Iterator(nm,lp,args,rp,body,aft) ->
1064 (donothing r k e) @ (info aft)
1065 | _ -> donothing r k e in
1066
34e49164 1067 let res =
b1b2de81 1068 V0.flat_combiner bind option_default
34e49164 1069 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
1070 donothing donothing donothing donothing donothing donothing donothing
1071 donothing
0708f913 1072 donothing donothing donothing donothing stmt donothing donothing in
b1b2de81 1073 res.VT0.combiner_rec_top_level
34e49164
C
1074
1075(* --------------------------------------------------------------------- *)
1076(* --------------------------------------------------------------------- *)
1077
faf9a90c
C
1078let insert_plus minus plus ei =
1079 empty_isos := ei;
34e49164
C
1080 let minus_stream = process_minus minus in
1081 let plus_stream = process_plus plus in
1082 merge minus_stream plus_stream;
1083 List.iter (function x -> let _ = reevaluate_contextness x in ()) minus