Release coccinelle-0.2.3rc3
[bpt/coccinelle.git] / parsing_cocci / get_constants2.ml
CommitLineData
9f8e26f4 1(*
90aeb998
C
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
5636bb2c
C
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
25module Ast = Ast_cocci
26module V = Visitor_ast
27module TC = Type_cocci
28
29(* Issues:
30
311. If a rule X depends on a rule Y (in a positive way), then we can ignore
32 the constants in X.
33
342. If a rule X contains a metavariable that is not under a disjunction and
35 that is inherited from rule Y, then we can ignore the constants in X.
36
373. If a rule contains a constant x in + code then subsequent rules that
38 have it in - or context should not include it in their list of required
39 constants.
40*)
41
90aeb998
C
42(* This doesn't do the . -> trick of get_constants for record fields, as
43 that does not fit well with the recursive structure. It was not clear
44 that that was completely safe either, although eg putting a newline
45 after the . or -> is probably unusual. *)
46
34e49164
C
47(* ----------------------------------------------------------------------- *)
48(* This phase collects everything. One can then filter out what it not
49wanted *)
50
51(* True means nothing was found
52 False should never drift to the top, it is the neutral element of or
53 and an or is never empty *)
54type combine =
55 And of combine list | Or of combine list | Elem of string | False | True
56
951c7801 57let interpret_glimpse strict x =
34e49164
C
58 let rec loop = function
59 Elem x -> x
60 | And [x] -> loop x
61 | Or [x] -> loop x
62 | And l -> Printf.sprintf "{%s}" (String.concat ";" (List.map loop l))
63 | Or l -> Printf.sprintf "{%s}" (String.concat "," (List.map loop l))
90aeb998
C
64 | True ->
65 if strict
66 then failwith "True should not be in the final result"
67 else "True"
34e49164
C
68 | False ->
69 if strict
70 then failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
71 else "False" in
72 match x with
73 True -> None
74 | False when strict ->
75 failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
951c7801
C
76 | _ -> Some [(loop x)]
77
90aeb998
C
78(* grep only does or *)
79let interpret_grep strict x =
80 let rec loop = function
81 Elem x -> [x]
82 | And l -> List.concat (List.map loop l)
83 | Or l -> List.concat (List.map loop l)
84 | True ->
85 if strict
86 then failwith "True should not be in the final result"
87 else ["True"]
88 | False ->
89 if strict
90 then failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
91 else ["False"] in
92 match x with
93 True -> None
94 | False when strict ->
95 failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
96 | _ -> Some (loop x)
97
951c7801
C
98let interpret_google strict x =
99 (* convert to dnf *)
100 let rec dnf = function
101 Elem x -> [x]
102 | Or l -> List.fold_left Common.union_set [] (List.map dnf l)
103 | And l ->
104 let l = List.map dnf l in
105 List.fold_left
106 (function prev ->
107 function cur ->
108 List.fold_left Common.union_set []
109 (List.map
110 (function x ->
111 List.map (function y -> Printf.sprintf "%s %s" x y) prev)
112 cur))
113 [] l
114 | True -> ["True"]
115 | False ->
116 if strict
117 then failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
118 else ["False"] in
119 match x with
120 True -> None
121 | False when strict ->
122 failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
123 | _ -> Some (dnf x)
124
34e49164 125let combine2c x =
90aeb998 126 match interpret_glimpse false x with
34e49164 127 None -> "None"
951c7801 128 | Some x -> String.concat " || " x
34e49164
C
129
130let norm = function
131 And l -> And (List.sort compare l)
132 | Or l -> Or (List.sort compare l)
133 | x -> x
134
135let rec merge l1 l2 =
136 match (l1,l2) with
137 ([],l2) -> l2
138 | (l1,[]) -> l1
139 | (x::xs,y::ys) ->
140 (match compare x y with
141 -1 -> x::(merge xs l2)
142 | 0 -> x::(merge xs ys)
143 | 1 -> y::(merge l1 ys)
144 | _ -> failwith "not possible")
145
146let intersect l1 l2 = List.filter (function l1e -> List.mem l1e l2) l1
147
148let minus_set l1 l2 = List.filter (function l1e -> not (List.mem l1e l2)) l1
149
150let rec insert x l = merge [x] l
151
152let rec build_and x y =
153 if x = y
154 then x
155 else
156 match (x,y) with
157 (True,x) | (x,True) -> x
158 | (False,x) | (x,False) -> False
159 | (And l1,And l2) -> And (merge l1 l2)
160 | (x,Or l) when List.mem x l -> x
161 | (Or l,x) when List.mem x l -> x
162 | (Or l1,Or l2) when not ((intersect l1 l2) = []) ->
163 let inner =
164 build_and
165 (List.fold_left build_or False (minus_set l1 l2))
166 (List.fold_left build_or False (minus_set l2 l1)) in
167 List.fold_left build_or inner (intersect l1 l2)
168 | (x,And l) | (And l,x) ->
169 if List.mem x l
170 then And l
171 else
172 let others =
173 List.filter
174 (function
175 Or l -> not(List.mem x l)
176 | _ -> true)
177 l in
178 And (insert x others)
179 | (x,y) -> norm(And [x;y])
180
181and build_or x y =
182 if x = y
183 then x
184 else
185 match (x,y) with
186 (True,x) | (x,True) -> True
187 | (False,x) | (x,False) -> x
188 | (Or l1,Or l2) -> Or (merge l1 l2)
189 | (x,And l) when List.mem x l -> x
190 | (And l,x) when List.mem x l -> x
191 | (And l1,And l2) when not ((intersect l1 l2) = []) ->
192 let inner =
193 build_or
194 (List.fold_left build_and True (minus_set l1 l2))
195 (List.fold_left build_and True (minus_set l2 l1)) in
196 List.fold_left build_and inner (intersect l1 l2)
197 | (x,Or l) | (Or l,x) ->
198 if List.mem x l
199 then Or l
200 else
201 let others =
202 List.filter
203 (function
204 And l -> not(List.mem x l)
205 | _ -> true)
206 l in
207 Or (insert x others)
208 | (x,y) -> norm(Or [x;y])
209
210let keep x = Elem x
211let drop x = True
212
213let do_get_constants constants keywords env neg_pos =
214 let donothing r k e = k e in
215 let option_default = True in
216 let bind = build_and in
217 let inherited ((nm1,_) as x) =
ae4735db
C
218 (* ignore virtuals *)
219 if nm1 = "virtual" then option_default
34e49164 220 (* perhaps inherited, but value not required, so no constraints *)
ae4735db
C
221 else if List.mem x neg_pos then option_default
222 else (try List.assoc nm1 env with Not_found -> False) in
34e49164
C
223 let minherited name = inherited (Ast.unwrap_mcode name) in
224 let mcode _ x =
225 match Ast.get_pos_var x with
226 Ast.MetaPos(name,constraints,_,keep,inh) -> minherited name
227 | _ -> option_default in
228
229 (* if one branch gives no information, then we have to take anything *)
230 let disj_union_all = List.fold_left build_or False in
231
232 let ident r k i =
233 match Ast.unwrap i with
234 Ast.Id(name) ->
235 bind (k i)
236 (match Ast.unwrap_mcode name with
237 "NULL" -> keywords "NULL"
238 | nm -> constants nm)
239 | Ast.MetaId(name,_,_,_) | Ast.MetaFunc(name,_,_,_)
240 | Ast.MetaLocalFunc(name,_,_,_) -> bind (k i) (minherited name)
241 | _ -> k i in
242
243 let rec type_collect res = function
244 TC.ConstVol(_,ty) | TC.Pointer(ty) | TC.FunctionPointer(ty)
245 | TC.Array(ty) -> type_collect res ty
ae4735db
C
246 | TC.MetaType(tyname,_,_) ->
247 inherited tyname
34e49164 248 | TC.TypeName(s) -> constants s
faf9a90c 249 | TC.EnumName(false,s) -> constants s
34e49164
C
250 | TC.StructUnionName(_,false,s) -> constants s
251 | ty -> res in
252
253 (* no point to do anything special for records because glimpse is
254 word-oriented *)
255 let expression r k e =
256 match Ast.unwrap e with
257 Ast.Constant(const) ->
258 bind (k e)
259 (match Ast.unwrap_mcode const with
260 Ast.String s -> constants s
261 | Ast.Char "\\0" -> option_default (* glimpse doesn't like it *)
fc1ad971 262 | Ast.Char s -> option_default (* probably not chars either *)
34e49164 263 (* the following were eg keywords "1", but not good for glimpse *)
fc1ad971
C
264 | Ast.Int s -> option_default (* glimpse doesn't index integers *)
265 | Ast.Float s -> option_default (* probably not floats either *))
34e49164
C
266 | Ast.MetaExpr(name,_,_,Some type_list,_,_) ->
267 let types = List.fold_left type_collect option_default type_list in
268 bind (k e) (bind (minherited name) types)
269 | Ast.MetaErr(name,_,_,_) | Ast.MetaExpr(name,_,_,_,_,_) ->
270 bind (k e) (minherited name)
271 | Ast.MetaExprList(name,None,_,_) -> minherited name
272 | Ast.MetaExprList(name,Some (lenname,_,_),_,_) ->
273 bind (k e) (bind (minherited name) (minherited lenname))
274 | Ast.SizeOfExpr(sizeof,exp) -> bind (keywords "sizeof") (k e)
275 | Ast.SizeOfType(sizeof,lp,ty,rp) -> bind (keywords "sizeof") (k e)
5636bb2c
C
276 | Ast.NestExpr(starter,expr_dots,ender,wc,false) -> option_default
277 | Ast.NestExpr(starter,expr_dots,ender,wc,true) ->
34e49164
C
278 r.V.combiner_expression_dots expr_dots
279 | Ast.DisjExpr(exps) ->
280 disj_union_all (List.map r.V.combiner_expression exps)
281 | Ast.OptExp(exp) -> option_default
282 | Ast.Edots(_,_) | Ast.Ecircles(_,_) | Ast.Estars(_,_) -> option_default
283 | _ -> k e in
faf9a90c 284
34e49164
C
285 let fullType r k ft =
286 match Ast.unwrap ft with
287 Ast.DisjType(decls) ->
288 disj_union_all (List.map r.V.combiner_fullType decls)
289 | Ast.OptType(ty) -> option_default
290 | _ -> k ft in
faf9a90c 291
34e49164
C
292 let baseType = function
293 Ast.VoidType -> keywords "void "
294 | Ast.CharType -> keywords "char "
295 | Ast.ShortType -> keywords "short "
296 | Ast.IntType -> keywords "int "
297 | Ast.DoubleType -> keywords "double "
298 | Ast.FloatType -> keywords "float "
faf9a90c 299 | Ast.LongType | Ast.LongLongType -> keywords "long " in
34e49164
C
300
301 let typeC r k ty =
302 match Ast.unwrap ty with
faf9a90c 303 Ast.BaseType(ty1,strings) -> bind (k ty) (baseType ty1)
34e49164
C
304 | Ast.TypeName(name) -> bind (k ty) (constants (Ast.unwrap_mcode name))
305 | Ast.MetaType(name,_,_) -> bind (minherited name) (k ty)
306 | _ -> k ty in
307
308 let declaration r k d =
309 match Ast.unwrap d with
310 Ast.DisjDecl(decls) ->
311 disj_union_all (List.map r.V.combiner_declaration decls)
312 | Ast.OptDecl(decl) -> option_default
313 | Ast.Ddots(dots,whencode) -> option_default
314 | _ -> k d in
315
316 let initialiser r k i =
317 match Ast.unwrap i with
318 Ast.OptIni(ini) -> option_default
319 | _ -> k i in
320
321 let parameter r k p =
322 match Ast.unwrap p with
323 Ast.OptParam(param) -> option_default
324 | Ast.MetaParam(name,_,_) -> bind (k p) (minherited name)
325 | Ast.MetaParamList(name,None,_,_) -> bind (k p) (minherited name)
326 | Ast.MetaParamList(name,Some(lenname,_,_),_,_) ->
327 bind (minherited name) (bind (minherited lenname) (k p))
328 | _ -> k p in
faf9a90c 329
34e49164
C
330 let rule_elem r k re =
331 match Ast.unwrap re with
332 Ast.MetaRuleElem(name,_,_) | Ast.MetaStmt(name,_,_,_)
333 | Ast.MetaStmtList(name,_,_) -> bind (minherited name) (k re)
334 | Ast.WhileHeader(whl,lp,exp,rp) ->
335 bind (keywords "while") (k re)
336 | Ast.WhileTail(whl,lp,exp,rp,sem) ->
337 bind (keywords "do") (k re)
338 | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) ->
339 bind (keywords "for") (k re)
340 | Ast.SwitchHeader(switch,lp,exp,rp) ->
341 bind (keywords "switch") (k re)
342 | Ast.Break(br,sem) ->
343 bind (keywords "break") (k re)
344 | Ast.Continue(cont,sem) ->
345 bind (keywords "continue") (k re)
346 | Ast.Goto(_,i,_) ->
347 bind (keywords "goto") (k re)
348 | Ast.Default(def,colon) ->
349 bind (keywords "default") (k re)
350 | Ast.Include(inc,s) ->
351 bind (k re)
352 (match Ast.unwrap_mcode s with
353 Ast.Local l | Ast.NonLocal l ->
354 let strings =
355 List.fold_left
356 (function prev ->
357 function
358 (* just take the last thing, probably the most
359 specific. everything is necessary anyway. *)
360 Ast.IncPath s -> [Elem s]
361 | Ast.IncDots -> prev)
362 [] l in
363 (match strings with
364 [] -> True
365 | x::xs -> List.fold_left bind x xs))
366 | Ast.DisjRuleElem(res) ->
367 disj_union_all (List.map r.V.combiner_rule_elem res)
368 | _ -> k re in
faf9a90c 369
34e49164
C
370 let statement r k s =
371 match Ast.unwrap s with
372 Ast.Disj(stmt_dots) ->
373 disj_union_all (List.map r.V.combiner_statement_dots stmt_dots)
5636bb2c
C
374 | Ast.Nest(starter,stmt_dots,ender,whn,false,_,_) -> option_default
375 | Ast.Nest(starter,stmt_dots,ender,whn,true,_,_) ->
34e49164
C
376 r.V.combiner_statement_dots stmt_dots
377 | Ast.OptStm(s) -> option_default
378 | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) ->
379 option_default
380 | _ -> k s in
381
382 V.combiner bind option_default
383 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
384 donothing donothing donothing donothing
385 ident expression fullType typeC initialiser parameter declaration
386 rule_elem statement donothing donothing donothing
387
388(* ------------------------------------------------------------------------ *)
389
390let filter_combine combine to_drop =
391 let rec and_loop = function
392 Elem x when List.mem x to_drop -> True
393 | Or l -> List.fold_left build_or False (List.map or_loop l)
394 | x -> x
395 and or_loop = function
396 Elem x when List.mem x to_drop -> False
397 | And l -> List.fold_left build_and True (List.map and_loop l)
398 | x -> x in
399 or_loop combine
400
401(* ------------------------------------------------------------------------ *)
402
403let get_all_constants minus_only =
404 let donothing r k e = k e in
405 let bind = Common.union_set in
406 let option_default = [] in
407 let mcode r (x,_,mcodekind,_) =
408 match mcodekind with
708f4980 409 Ast.MINUS(_,_,_,_) -> [x]
34e49164
C
410 | _ when minus_only -> []
411 | _ -> [x] in
412 let other r _ = [] in
413
414 V.combiner bind option_default
415 other mcode other other other other other other other other other other
34e49164
C
416
417 donothing donothing donothing donothing
418 donothing donothing donothing donothing donothing donothing donothing
419 donothing donothing donothing donothing donothing
420
421(* ------------------------------------------------------------------------ *)
422
423let get_plus_constants =
424 let donothing r k e = k e in
425 let bind = Common.union_set in
426 let option_default = [] in
90aeb998
C
427
428 let recurse l =
429 List.fold_left
430 (List.fold_left
431 (function prev ->
432 function cur ->
433 bind ((get_all_constants false).V.combiner_anything cur) prev))
434 [] l in
435 let process_mcodekind = function
708f4980 436 Ast.MINUS(_,_,_,anythings) -> recurse anythings
951c7801
C
437 | Ast.CONTEXT(_,Ast.BEFORE(a,_)) -> recurse a
438 | Ast.CONTEXT(_,Ast.AFTER(a,_)) -> recurse a
439 | Ast.CONTEXT(_,Ast.BEFOREAFTER(a1,a2,_)) ->
34e49164
C
440 Common.union_set (recurse a1) (recurse a2)
441 | _ -> [] in
442
90aeb998
C
443 let mcode r mc = process_mcodekind (Ast.get_mcodekind mc) in
444 let end_info (_,_,_,mc) = process_mcodekind mc in
445
446 let rule_elem r k e =
447 match Ast.unwrap e with
448 Ast.FunHeader(bef,_,_,_,_,_,_)
449 | Ast.Decl(bef,_,_) -> bind (process_mcodekind bef) (k e)
450 | _ -> k e in
451
452 let statement r k e =
453 match Ast.unwrap e with
454 Ast.IfThen(_,_,ei) | Ast.IfThenElse(_,_,_,_,ei)
455 | Ast.While(_,_,ei) | Ast.For(_,_,ei)
456 | Ast.Iterator(_,_,ei) -> bind (k e) (end_info ei)
457 | _ -> k e in
458
34e49164
C
459 V.combiner bind option_default
460 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
461 donothing donothing donothing donothing
462 donothing donothing donothing donothing donothing donothing donothing
90aeb998 463 rule_elem statement donothing donothing donothing
34e49164
C
464
465(* ------------------------------------------------------------------------ *)
466
467(* true means the rule should be analyzed, false means it should be ignored *)
468let rec dependencies env = function
469 Ast.Dep s -> (try List.assoc s env with Not_found -> False)
470 | Ast.AntiDep s -> True
471 | Ast.EverDep s -> (try List.assoc s env with Not_found -> False)
472 | Ast.NeverDep s -> True
473 | Ast.AndDep (d1,d2) -> build_and (dependencies env d1) (dependencies env d2)
474 | Ast.OrDep (d1,d2) -> build_or (dependencies env d1) (dependencies env d2)
475 | Ast.NoDep -> True
7f004419 476 | Ast.FailDep -> False
34e49164
C
477
478(* ------------------------------------------------------------------------ *)
479
480let all_context =
481 let bind x y = x && y in
482 let option_default = true in
483
484 let donothing recursor k e = k e in
485
90aeb998 486 let process_mcodekind = function
34e49164
C
487 Ast.CONTEXT(_,Ast.NOTHING) -> true
488 | _ -> false in
489
90aeb998
C
490 let mcode r e = process_mcodekind (Ast.get_mcodekind e) in
491
492 let end_info (_,_,_,mc) = process_mcodekind mc in
493
494 let initialiser r k e =
495 match Ast.unwrap e with
496 Ast.InitList(all_minus,_,_,_,_) ->
497 not all_minus && k e
498 | _ -> k e in
499
500 let rule_elem r k e =
501 match Ast.unwrap e with
502 Ast.FunHeader(bef,_,_,_,_,_,_)
503 | Ast.Decl(bef,_,_) -> bind (process_mcodekind bef) (k e)
504 | _ -> k e in
505
506 let statement r k e =
507 match Ast.unwrap e with
508 Ast.IfThen(_,_,ei) | Ast.IfThenElse(_,_,_,_,ei)
509 | Ast.While(_,_,ei) | Ast.For(_,_,ei)
510 | Ast.Iterator(_,_,ei) -> bind (k e) (end_info ei)
511 | _ -> k e in
512
34e49164
C
513 V.combiner bind option_default
514 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164 515 donothing donothing donothing donothing
90aeb998
C
516 donothing donothing donothing donothing initialiser donothing
517 donothing rule_elem statement donothing donothing donothing
34e49164
C
518
519(* ------------------------------------------------------------------------ *)
520
521let rule_fn tls in_plus env neg_pos =
522 List.fold_left
523 (function (rest_info,in_plus) ->
524 function (cur,neg_pos) ->
525 let minuses =
ae4735db
C
526 let getter = do_get_constants keep drop env neg_pos in
527 getter.V.combiner_top_level cur in
34e49164
C
528 let all_minuses =
529 if !Flag.sgrep_mode2
530 then [] (* nothing removed for sgrep *)
531 else (get_all_constants true).V.combiner_top_level cur in
532 let plusses = get_plus_constants.V.combiner_top_level cur in
533 (* the following is for eg -foo(2) +foo(x) then in another rule
534 -foo(10); don't want to consider that foo is guaranteed to be
535 created by the rule. not sure this works completely: what if foo is
536 in both - and +, but in an or, so the cases aren't related?
537 not sure this whole thing is a good idea. how do we know that
538 something that is only in plus is really freshly created? *)
539 let plusses = Common.minus_set plusses all_minuses in
540 let was_bot = minuses = True in
541 let new_minuses = filter_combine minuses in_plus in
542 let new_plusses = Common.union_set plusses in_plus in
543 (* perhaps it should be build_and here? we don't realy have multiple
544 minirules anymore anyway. *)
545 match new_minuses with
546 True ->
ae4735db
C
547 let getter = do_get_constants drop keep env neg_pos in
548 let retry = getter.V.combiner_top_level cur in
34e49164
C
549 (match retry with
550 True when not was_bot -> (rest_info, new_plusses)
551 | x -> (build_or x rest_info, new_plusses))
552 | x -> (build_or x rest_info, new_plusses))
553 (False,in_plus) (List.combine tls neg_pos)
554
90aeb998
C
555let run rules neg_pos_vars =
556 let (info,_,_,_) =
557 List.fold_left
558 (function (rest_info,in_plus,env,locals(*dom of env*)) ->
559 function
174d1640 560 (Ast.ScriptRule (_,_,deps,mv,_),_) ->
90aeb998
C
561 let extra_deps =
562 List.fold_left
563 (function prev ->
174d1640 564 function (_,(rule,_),_) ->
90aeb998
C
565 if rule = "virtual"
566 then prev
567 else Ast.AndDep (Ast.Dep rule,prev))
568 deps mv in
569 (match dependencies env extra_deps with
570 False -> (rest_info, in_plus, env, locals)
571 | dependencies ->
572 (build_or dependencies rest_info, in_plus, env, locals))
174d1640
C
573 | (Ast.InitialScriptRule (_,_,deps,_),_)
574 | (Ast.FinalScriptRule (_,_,deps,_),_) ->
aa721442
C
575 (* initialize and finalize dependencies are irrelevant to
576 get_constants *)
90aeb998
C
577 (rest_info, in_plus, env, locals)
578 | (Ast.CocciRule (nm,(dep,_,_),cur,_,_),neg_pos_vars) ->
579 let (cur_info,cur_plus) =
580 rule_fn cur in_plus ((nm,True)::env)
581 neg_pos_vars in
582 (match dependencies env dep with
583 False -> (rest_info,cur_plus,env,locals)
584 | dependencies ->
585 if List.for_all all_context.V.combiner_top_level cur
586 then (rest_info,cur_plus,(nm,cur_info)::env,nm::locals)
587 else
34e49164
C
588 (* no constants if dependent on another rule; then we need to
589 find the constants of that rule *)
90aeb998
C
590 (build_or (build_and dependencies cur_info) rest_info,
591 cur_plus,env,locals)))
592 (False,[],[],[])
593 (List.combine (rules : Ast.rule list) neg_pos_vars) in
594 info
595
596let get_constants rules neg_pos_vars =
597 match !Flag.scanner with
598 Flag.NoScanner -> (None,None)
599 | Flag.Grep ->
600 let res = run rules neg_pos_vars in
601 (interpret_grep true res,None)
602 | Flag.Glimpse ->
603 let res = run rules neg_pos_vars in
604 (interpret_grep true res,interpret_glimpse true res)
605 | Flag.Google _ ->
606 let res = run rules neg_pos_vars in
607 (interpret_grep true res,interpret_google true res)
608