Release coccinelle-0.2.4rc3
[bpt/coccinelle.git] / parsing_cocci / plus.ml
CommitLineData
c491d8ee
C
1(*
2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
7 *
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
11 *
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
34e49164
C
25(* The plus fragments are converted to a list of lists of lists.
26Innermost list: Elements have type anything. For any pair of successive
27elements, n and n+1, the ending line of n is the same as the starting line
28of n+1.
29Middle lists: For any pair of successive elements, n and n+1, the ending
30line of n is one less than the starting line of n+1.
31Outer list: For any pair of successive elements, n and n+1, the ending
32line of n is more than one less than the starting line of n+1. *)
33
34(* For nests and disjs, we are relying on the fact that <... ...> ( | )
35must appear on lines by themselves, meaning that the various + fragments
36can't be contiguous to each other or to unrelated things. *)
37
38module Ast = Ast_cocci
39module V = Visitor_ast
40
41(* --------------------------------------------------------------------- *)
42
43type res =
44 Open of Ast.anything * int * int * int * int
45 | Closed of (Ast.anything * int * int * int * int) list
46
47let mcode fn = function
48 (term, Ast.PLUS(info)) ->
49 let line = info.Ast.line in
50 let lline = info.Ast.logical_line in
51 [Open (fn term,line,line,lline,lline)]
52 | _ -> [Closed []]
53
54let mk_fullType x = Ast.FullTypeTag x
55let mk_baseType x = Ast.BaseTypeTag x
56let mk_structUnion x = Ast.StructUnionTag x
57let mk_sign x = Ast.SignTag x
58let mk_ident x = Ast.IdentTag x
59let mk_expression x = Ast.ExpressionTag x
60let mk_constant x = Ast.ConstantTag x
61let mk_unaryOp x = Ast.UnaryOpTag x
62let mk_assignOp x = Ast.AssignOpTag x
63let mk_fixOp x = Ast.FixOpTag x
64let mk_binaryOp x = Ast.BinaryOpTag x
65let mk_arithOp x = Ast.ArithOpTag x
66let mk_logicalOp x = Ast.LogicalOpTag x
67let mk_declaration x = Ast.DeclarationTag x
68let mk_storage x = Ast.StorageTag x
69let mk_rule_elem x = Ast.Rule_elemTag x
70let mk_const_vol x = Ast.ConstVolTag x
71let mk_token x = Ast.Token x
72
73let get_real_start = function
74 Open (_,line,_,_,_) -> line
75 | _ -> failwith "not possible"
76
77let get_real_finish = function
78 Open (_,_,line,_,_) -> line
79 | _ -> failwith "not possible"
80
81let get_start = function
82 Open (_,_,_,line,_) -> line
83 | _ -> failwith "not possible"
84
85let get_finish = function
86 Open (_,_,_,_,line) -> line
87 | _ -> failwith "not possible"
88
89let get_option fn = function
90 None -> []
91 | Some x -> [fn x]
92
93(* --------------------------------------------------------------------- *)
94(* --------------------------------------------------------------------- *)
95(* Step 1: coalesce + terms, record starting and ending line numbers *)
96
97let rec close l =
98 let rec loop = function
99 [] -> []
100 | Open(x,start,finish,lstart,lfinish)::rest ->
101 (x,start,finish,lstart,lfinish)::(loop rest)
102 | (Closed l)::rest -> l @ (loop rest) in
103 Closed (loop l)
104
105let test term subterms =
106 if List.for_all (function Open(_,_,_,_,_) -> true | _ -> false) subterms
107 then [Open(term,
108 get_real_start (List.hd subterms),
109 get_real_finish (List.hd (List.rev subterms)),
110 get_start (List.hd subterms),
111 get_finish (List.hd (List.rev subterms)))]
112 else [close subterms]
113
114(* --------------------------------------------------------------------- *)
115(* Dots *)
116
117let dots recursor k dotlist = [close (k dotlist)]
118
119(* --------------------------------------------------------------------- *)
120(* Identifier *)
121
122let ident recursor k i = test (Ast.IdentTag i) (k i)
123
124(* --------------------------------------------------------------------- *)
125(* Expression *)
126
127let expression recursor k = function
128 Ast.DisjExpr(exps) ->
129 [close (List.concat(List.map recursor.V.combiner_expression exps))]
130 | Ast.Edots(_,_) -> [Closed []] (* must be context *)
131 | Ast.Ecircles(_,_) -> [Closed []] (* must be context *)
132 | Ast.Estars(_,_) -> [Closed []] (* must be context *)
133 | Ast.OptExp(_) | Ast.UniqueExp(_) | Ast.MultiExp(_) -> failwith "impossible"
134 | e -> test (Ast.ExpressionTag e) (k e)
135
136(* --------------------------------------------------------------------- *)
137(* Types *)
138
139and fullType recursor k ft = test (Ast.FullTypeTag ft) (k ft)
140
141and typeC recursor k t = k t
142
143(* --------------------------------------------------------------------- *)
144(* Variable declaration *)
145(* Even if the Cocci program specifies a list of declarations, they are
146 split out into multiple declarations of a single variable each. *)
147
148let declaration recursor k d = test (Ast.DeclarationTag d) (k d)
149
150(* --------------------------------------------------------------------- *)
151(* Parameter *)
152
153let parameterTypeDef recursor k = function
154 Ast.Pdots(_) -> [Closed []]
155 | Ast.Pcircles(_) -> [Closed []]
156 | p -> test (Ast.ParameterTypeDefTag p) (k p)
157
158(* --------------------------------------------------------------------- *)
159(* Top-level code *)
160
161let rec rule_elem recursor k re = test (Ast.Rule_elemTag re) (k re)
162
163let rec statement recursor k = function
164 Ast.Disj(stmt_dots_list) ->
165 [close
166 (List.concat
167 (List.map recursor.V.combiner_statement_dots stmt_dots_list))]
168 | Ast.Dots(_,_,_) -> [Closed []]
169 | Ast.Circles(_,_,_) -> [Closed []]
170 | Ast.Stars(_,_,_) -> [Closed []]
171 | s -> test (Ast.StatementTag s) (k s)
172
173let rec meta recursor k m = test (Ast.MetaTag m) (k m)
174
175let top_level recursor k = function
176 Ast.FILEINFO(_,_) -> [Closed []]
177 | Ast.ERRORWORDS(exps) -> [Closed []]
178 | t -> test (Ast.Code t) (k t)
179
180let anything recursor k a = failwith "not called"
181
182let collect_tokens =
183 let recursor =
184 V.combiner (@) []
185 (mcode mk_token) (mcode mk_constant) (mcode mk_assignOp) (mcode mk_fixOp)
186 (mcode mk_unaryOp) (mcode mk_binaryOp) (mcode mk_const_vol)
187 (mcode mk_baseType) (mcode mk_sign) (mcode mk_structUnion)
188 (mcode mk_storage) dots dots dots
189 ident expression fullType typeC parameterTypeDef declaration
190 rule_elem statement meta top_level anything in
191 recursor.V.combiner_top_level
192
193let rule code = List.concat(List.map collect_tokens code)
194
195(* --------------------------------------------------------------------- *)
196(* --------------------------------------------------------------------- *)
197(* Step 2: find neighbors *)
198
199let rec find_neighbors = function
200 [] -> []
201 | (x1,real_start1,real_finish1,start1,finish1)::rest ->
202 (match find_neighbors rest with
203 ((((x2,real_start2,real_finish2,start2,finish2)::
204 rest_inner)::rest_middle)::rest_outer)
205 as rest ->
206 if finish1 = start2
faf9a90c 207 then
34e49164
C
208 ((((x1,real_start1,real_finish1,start1,finish1)::
209 (x2,real_start2,real_finish2,start2,finish2)::rest_inner)::
210 rest_middle)::
211 rest_outer)
212 else if finish1 + 1 = start2
213 then
214 (([(x1,real_start1,real_finish1,start1,finish1)]::
215 ((x2,real_start2,real_finish2,start2,finish2)::rest_inner)::
216 rest_middle)::
217 rest_outer)
218 else [[(x1,real_start1,real_finish1,start1,finish1)]]::rest
219 | _ -> [[[(x1,real_start1,real_finish1,start1,finish1)]]])
220 (* rest must be [] *)
faf9a90c 221
34e49164
C
222(* --------------------------------------------------------------------- *)
223(* --------------------------------------------------------------------- *)
224(* Entry point *)
225
226let plus ast =
227 match close (rule ast) with
228 Closed l -> find_neighbors l
229 | _ -> failwith "impossible"