2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
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.
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.
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.
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/>.
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
27 module Ast
= Ast_cocci
28 module V
= Visitor_ast
29 module TC
= Type_cocci
33 1. If a rule X depends on a rule Y (in a positive way), then we can ignore
36 2. If a rule X contains a metavariable that is not under a disjunction and
37 that is inherited from rule Y, then we can ignore the constants in X.
39 3. If a rule contains a constant x in + code then subsequent rules that
40 have it in - or context should not include it in their list of required
44 (* This doesn't do the . -> trick of get_constants for record fields, as
45 that does not fit well with the recursive structure. It was not clear
46 that that was completely safe either, although eg putting a newline
47 after the . or -> is probably unusual. *)
49 (* ----------------------------------------------------------------------- *)
50 (* This phase collects everything. One can then filter out what it not
53 (* True means nothing was found
54 False should never drift to the top, it is the neutral element of or
55 and an or is never empty *)
57 And
of combine list
| Or
of combine list
| Elem
of string | False
| True
59 (* glimpse often fails on large queries. We can safely remove arguments of
60 && as long as we don't remove all of them (note that there is no negation).
61 This tries just removing one of them and then orders the results by
62 increasing number of ors (ors are long, increasing the chance of failure,
63 and are less restrictive, possibly increasing the chance of irrelevant
65 let reduce_glimpse x
=
69 | And
[x
] -> loop x
(function changed_l
-> k
(And
[changed_l
])) q
72 (function changed_l
-> k
(And changed_l
))
79 rloop xs
(function changed_xs
-> k
(x
:: changed_xs
)) in
80 rloop l
(function changed_l
-> k
(And changed_l
)))
81 | Or l
-> kloop l
(function changed_l
-> k
(Or changed_l
)) q
82 | _
-> failwith
"not possible"
88 (function changed_x
-> k
(changed_x
::xs
))
91 (function changed_xs
-> k
(x
:: changed_xs
))
93 let rec count_ors = function
95 | And l
-> List.fold_left
(+) 0 (List.map
count_ors l
)
97 ((List.length l
) - 1) +
98 (List.fold_left
(+) 0 (List.map
count_ors l
))
99 | _
-> failwith
"not possible" in
100 let res = loop x
(function x
-> x
) (function _
-> []) in
101 let res = List.map
(function x
-> (count_ors x
,x
)) res in
102 let res = List.sort compare
res in
103 List.map
(function (_
,x
) -> x
) res
105 let interpret_glimpse strict x
=
106 let rec loop = function
110 | And l
-> Printf.sprintf
"{%s}" (String.concat
";" (List.map
loop l
))
111 | Or l
-> Printf.sprintf
"{%s}" (String.concat
"," (List.map
loop l
))
114 then failwith
"True should not be in the final result"
118 then failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
122 | False
when strict
->
123 failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
125 Some
(if strict
then List.map
loop (x
::reduce_glimpse x
) else [loop x
])
127 (* grep only does or *)
128 let interpret_grep strict x
=
129 let rec loop = function
131 | And l
-> List.concat
(List.map
loop l
)
132 | Or l
-> List.concat
(List.map
loop l
)
135 then failwith
"True should not be in the final result"
139 then failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
143 | False
when strict
->
144 failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
147 let interpret_google strict x
=
149 let rec dnf = function
151 | Or l
-> List.fold_left
Common.union_set
[] (List.map
dnf l
)
153 let l = List.map
dnf l in
157 List.fold_left
Common.union_set
[]
160 List.map
(function y
-> Printf.sprintf
"%s %s" x y
) prev
)
166 then failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
170 | False
when strict
->
171 failwith
"False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code"
175 match interpret_glimpse false x
with
177 | Some x
-> String.concat
" || " x
180 And
l -> And
(List.sort compare
l)
181 | Or
l -> Or
(List.sort compare
l)
184 let rec merge l1 l2
=
189 (match compare x y
with
190 -1 -> x
::(merge xs l2
)
191 | 0 -> x
::(merge xs ys
)
192 | 1 -> y
::(merge l1 ys
)
193 | _
-> failwith
"not possible")
195 let intersect l1 l2
= List.filter
(function l1e
-> List.mem l1e l2
) l1
197 let minus_set l1 l2
= List.filter
(function l1e
-> not
(List.mem l1e l2
)) l1
199 let rec insert x
l = merge [x
] l
201 let rec build_and x y
=
206 (True
,x
) | (x
,True
) -> x
207 | (False
,x
) | (x
,False
) -> False
208 | (And l1
,And l2
) -> And
(merge l1 l2
)
209 | (x
,Or
l) when List.mem x
l -> x
210 | (Or
l,x
) when List.mem x
l -> x
211 | (Or l1
,Or l2
) when not
((intersect l1 l2
) = []) ->
214 (List.fold_left build_or False
(minus_set l1 l2
))
215 (List.fold_left build_or False
(minus_set l2 l1
)) in
216 List.fold_left build_or
inner (intersect l1 l2
)
217 | (x
,And
l) | (And
l,x
) ->
224 Or
l -> not
(List.mem x
l)
227 And
(insert x
others)
228 | (x
,y
) -> norm(And
[x
;y
])
235 (True
,x
) | (x
,True
) -> True
236 | (False
,x
) | (x
,False
) -> x
237 | (Or l1
,Or l2
) -> Or
(merge l1 l2
)
238 | (x
,And
l) when List.mem x
l -> x
239 | (And
l,x
) when List.mem x
l -> x
240 | (And l1
,And l2
) when not
((intersect l1 l2
) = []) ->
243 (List.fold_left
build_and True
(minus_set l1 l2
))
244 (List.fold_left
build_and True
(minus_set l2 l1
)) in
245 List.fold_left
build_and inner (intersect l1 l2
)
246 | (x
,Or
l) | (Or
l,x
) ->
253 And
l -> not
(List.mem x
l)
257 | (x
,y
) -> norm(Or
[x
;y
])
262 let do_get_constants constants keywords env neg_pos
=
263 let donothing r k e
= k e
in
264 let option_default = True
in
265 let bind = build_and in
266 let inherited ((nm1
,_
) as x
) =
267 (* ignore virtuals *)
268 if nm1
= "virtual" then option_default
269 (* perhaps inherited, but value not required, so no constraints *)
270 else if List.mem x neg_pos
then option_default
271 else (try List.assoc nm1 env
with Not_found
-> False
) in
272 let minherited name
= inherited (Ast.unwrap_mcode name
) in
274 List.fold_left
bind option_default
276 (function Ast.MetaPos
(name
,constraints
,_
,keep,inh
) -> minherited name
)
277 (Ast.get_pos_var x
)) in
279 (* if one branch gives no information, then we have to take anything *)
280 let disj_union_all = List.fold_left build_or False
in
283 match Ast.unwrap i
with
286 (match Ast.unwrap_mcode name
with
287 "NULL" -> keywords
"NULL"
288 | nm
-> constants nm
)
289 | Ast.MetaId
(name
,_
,_
,_
) | Ast.MetaFunc
(name
,_
,_
,_
)
290 | Ast.MetaLocalFunc
(name
,_
,_
,_
) -> bind (k i
) (minherited name
)
291 | Ast.DisjId
(ids
) -> disj_union_all (List.map r
.V.combiner_ident ids
)
294 let rec type_collect res = function
295 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
296 | TC.Array
(ty
) -> type_collect res ty
297 | TC.MetaType
(tyname
,_
,_
) ->
299 | TC.TypeName
(s
) -> constants s
300 | TC.EnumName
(TC.Name s
) -> constants s
301 | TC.StructUnionName
(_
,TC.Name s
) -> constants s
304 (* no point to do anything special for records because glimpse is
306 let expression r k e
=
307 match Ast.unwrap e
with
308 Ast.Constant
(const
) ->
310 (match Ast.unwrap_mcode const
with
311 Ast.String s
-> constants s
312 | Ast.Char
"\\0" -> option_default (* glimpse doesn't like it *)
313 | Ast.Char s
-> option_default (* probably not chars either *)
314 (* the following were eg keywords "1", but not good for glimpse *)
315 | Ast.Int s
-> option_default (* glimpse doesn't index integers *)
316 | Ast.Float s
-> option_default (* probably not floats either *))
317 | Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
318 let types = List.fold_left
type_collect option_default type_list
in
319 bind (k e
) (bind (minherited name
) types)
320 | Ast.MetaErr
(name
,_
,_
,_
) | Ast.MetaExpr
(name
,_
,_
,_
,_
,_
) ->
321 bind (k e
) (minherited name
)
322 | Ast.MetaExprList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
323 bind (k e
) (bind (minherited name
) (minherited lenname
))
324 | Ast.MetaExprList
(name
,_
,_
,_
) -> minherited name
325 | Ast.SizeOfExpr
(sizeof
,exp
) -> bind (keywords
"sizeof") (k e
)
326 | Ast.SizeOfType
(sizeof
,lp
,ty
,rp
) -> bind (keywords
"sizeof") (k e
)
327 | Ast.NestExpr
(starter
,expr_dots
,ender
,wc
,false) -> option_default
328 | Ast.NestExpr
(starter
,expr_dots
,ender
,wc
,true) ->
329 r
.V.combiner_expression_dots expr_dots
330 | Ast.DisjExpr
(exps
) ->
331 disj_union_all (List.map r
.V.combiner_expression exps
)
332 | Ast.OptExp
(exp
) -> option_default
333 | Ast.Edots
(_
,_
) | Ast.Ecircles
(_
,_
) | Ast.Estars
(_
,_
) -> option_default
336 let fullType r k ft
=
337 match Ast.unwrap ft
with
338 Ast.DisjType
(decls
) ->
339 disj_union_all (List.map r
.V.combiner_fullType decls
)
340 | Ast.OptType
(ty
) -> option_default
343 let baseType = function
344 Ast.VoidType
-> keywords
"void"
345 | Ast.CharType
-> keywords
"char"
346 | Ast.ShortType
-> keywords
"short"
347 | Ast.ShortIntType
-> keywords
"short"
348 | Ast.IntType
-> keywords
"int"
349 | Ast.DoubleType
-> keywords
"double"
350 | Ast.LongDoubleType
-> keywords
"double"
351 | Ast.FloatType
-> keywords
"float"
352 | Ast.LongType
| Ast.LongLongType
353 | Ast.LongIntType
| Ast.LongLongIntType
-> keywords
"long"
354 | Ast.SizeType
-> keywords
"size_t"
355 | Ast.SSizeType
-> keywords
"ssize_t"
356 | Ast.PtrDiffType
-> keywords
"ptrdiff_t" in
359 match Ast.unwrap ty
with
360 Ast.BaseType
(ty1
,strings
) -> bind (k ty
) (baseType ty1
)
361 | Ast.TypeName
(name
) -> bind (k ty
) (constants
(Ast.unwrap_mcode name
))
362 | Ast.MetaType
(name
,_
,_
) -> bind (minherited name
) (k ty
)
365 let declaration r k d
=
366 match Ast.unwrap d
with
367 Ast.MetaDecl
(name
,_
,_
) | Ast.MetaField
(name
,_
,_
) ->
368 bind (k d
) (minherited name
)
369 | Ast.MetaFieldList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
370 bind (minherited name
) (bind (minherited lenname
) (k d
))
371 | Ast.DisjDecl
(decls
) ->
372 disj_union_all (List.map r
.V.combiner_declaration decls
)
373 | Ast.OptDecl
(decl
) -> option_default
374 | Ast.Ddots
(dots
,whencode
) -> option_default
377 let initialiser r k i
=
378 match Ast.unwrap i
with
379 Ast.OptIni
(ini
) -> option_default
382 let parameter r k p
=
383 match Ast.unwrap p
with
384 Ast.OptParam
(param
) -> option_default
385 | Ast.MetaParam
(name
,_
,_
) -> bind (k p
) (minherited name
)
386 | Ast.MetaParamList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
387 bind (minherited name
) (bind (minherited lenname
) (k p
))
388 | Ast.MetaParamList
(name
,_
,_
,_
) -> bind (k p
) (minherited name
)
391 let rule_elem r k re
=
392 match Ast.unwrap re
with
393 Ast.MetaRuleElem
(name
,_
,_
) | Ast.MetaStmt
(name
,_
,_
,_
)
394 | Ast.MetaStmtList
(name
,_
,_
) -> bind (minherited name
) (k re
)
395 | Ast.WhileHeader
(whl
,lp
,exp
,rp
) ->
396 bind (keywords
"while") (k re
)
397 | Ast.WhileTail
(whl
,lp
,exp
,rp
,sem
) ->
398 bind (keywords
"do") (k re
)
399 | Ast.ForHeader
(fr
,lp
,e1
,sem1
,e2
,sem2
,e3
,rp
) ->
400 bind (keywords
"for") (k re
)
401 | Ast.SwitchHeader
(switch
,lp
,exp
,rp
) ->
402 bind (keywords
"switch") (k re
)
403 | Ast.Break
(br
,sem
) ->
404 bind (keywords
"break") (k re
)
405 | Ast.Continue
(cont
,sem
) ->
406 bind (keywords
"continue") (k re
)
408 bind (keywords
"goto") (k re
)
409 | Ast.Default
(def
,colon
) ->
410 bind (keywords
"default") (k re
)
411 | Ast.Include
(inc
,s
) ->
413 (match Ast.unwrap_mcode s
with
414 Ast.Local
l | Ast.NonLocal
l ->
419 (* just take the last thing, probably the most
420 specific. everything is necessary anyway. *)
421 Ast.IncPath s
-> [Elem s
]
422 | Ast.IncDots
-> prev
)
426 | x
::xs
-> List.fold_left
bind x xs
))
427 | Ast.DisjRuleElem
(res) ->
428 disj_union_all (List.map r
.V.combiner_rule_elem
res)
431 let statement r k s
=
432 match Ast.unwrap s
with
433 Ast.Disj
(stmt_dots
) ->
434 disj_union_all (List.map r
.V.combiner_statement_dots stmt_dots
)
435 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,false,_
,_
) -> option_default
436 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,true,_
,_
) ->
437 r
.V.combiner_statement_dots stmt_dots
438 | Ast.OptStm
(s
) -> option_default
439 | Ast.Dots
(d
,whn
,_
,_
) | Ast.Circles
(d
,whn
,_
,_
) | Ast.Stars
(d
,whn
,_
,_
) ->
443 V.combiner
bind option_default
444 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
445 donothing donothing donothing donothing donothing
446 ident expression fullType typeC initialiser parameter declaration
447 rule_elem statement donothing donothing donothing
449 (* ------------------------------------------------------------------------ *)
451 let filter_combine combine to_drop
=
452 let rec and_loop = function
453 Elem x
when List.mem x to_drop
-> True
454 | Or
l -> List.fold_left build_or False
(List.map or_loop
l)
456 and or_loop
= function
457 Elem x
when List.mem x to_drop
-> False
458 | And
l -> List.fold_left
build_and True
(List.map
and_loop l)
462 (* ------------------------------------------------------------------------ *)
464 let get_all_constants minus_only
=
465 let donothing r k e
= k e
in
466 let bind = Common.union_set
in
467 let option_default = [] in
468 let mcode r
(x
,_
,mcodekind
,_
) =
470 Ast.MINUS
(_
,_
,_
,_
) -> [x
]
471 | _
when minus_only
-> []
473 let other r _
= [] in
475 V.combiner
bind option_default
476 other mcode other other other other other other other other other other
478 donothing donothing donothing donothing donothing
479 donothing donothing donothing donothing donothing donothing donothing
480 donothing donothing donothing donothing donothing
482 (* ------------------------------------------------------------------------ *)
484 let get_plus_constants =
485 let donothing r k e
= k e
in
486 let bind = Common.union_set
in
487 let option_default = [] in
494 bind ((get_all_constants false).V.combiner_anything cur
) prev
))
496 let process_mcodekind = function
497 Ast.MINUS
(_
,_
,_
,Ast.REPLACEMENT
(anythings
,_
)) -> recurse anythings
498 | Ast.CONTEXT
(_
,Ast.BEFORE
(a
,_
)) -> recurse a
499 | Ast.CONTEXT
(_
,Ast.AFTER
(a
,_
)) -> recurse a
500 | Ast.CONTEXT
(_
,Ast.BEFOREAFTER
(a1
,a2
,_
)) ->
501 Common.union_set
(recurse a1
) (recurse a2
)
504 let mcode r mc
= process_mcodekind (Ast.get_mcodekind mc
) in
505 let end_info (_
,_
,_
,mc
) = process_mcodekind mc
in
507 let rule_elem r k e
=
508 match Ast.unwrap e
with
509 Ast.FunHeader
(bef
,_
,_
,_
,_
,_
,_
)
510 | Ast.Decl
(bef
,_
,_
) -> bind (process_mcodekind bef
) (k e
)
513 let statement r k e
=
514 match Ast.unwrap e
with
515 Ast.IfThen
(_
,_
,ei
) | Ast.IfThenElse
(_
,_
,_
,_
,ei
)
516 | Ast.While
(_
,_
,ei
) | Ast.For
(_
,_
,ei
)
517 | Ast.Iterator
(_
,_
,ei
) -> bind (k e
) (end_info ei
)
520 V.combiner
bind option_default
521 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
522 donothing donothing donothing donothing donothing
523 donothing donothing donothing donothing donothing donothing donothing
524 rule_elem statement donothing donothing donothing
526 (* ------------------------------------------------------------------------ *)
528 (* true means the rule should be analyzed, false means it should be ignored *)
529 let rec dependencies env
= function
530 Ast.Dep s
-> (try List.assoc s env
with Not_found
-> False
)
531 | Ast.AntiDep s
-> True
532 | Ast.EverDep s
-> (try List.assoc s env
with Not_found
-> False
)
533 | Ast.NeverDep s
-> True
534 | Ast.AndDep
(d1
,d2
) -> build_and (dependencies env d1
) (dependencies env d2
)
535 | Ast.OrDep
(d1
,d2
) -> build_or
(dependencies env d1
) (dependencies env d2
)
537 | Ast.FailDep
-> False
539 (* ------------------------------------------------------------------------ *)
542 let bind x y
= x
&& y
in
543 let option_default = true in
545 let donothing recursor k e
= k e
in
547 let process_mcodekind = function
548 Ast.CONTEXT
(_
,Ast.NOTHING
) -> true
551 let mcode r e
= process_mcodekind (Ast.get_mcodekind e
) in
553 let end_info (_
,_
,_
,mc
) = process_mcodekind mc
in
555 let initialiser r k e
=
556 match Ast.unwrap e
with
557 Ast.StrInitList
(all_minus
,_
,_
,_
,_
) ->
561 let rule_elem r k e
=
562 match Ast.unwrap e
with
563 Ast.FunHeader
(bef
,_
,_
,_
,_
,_
,_
)
564 | Ast.Decl
(bef
,_
,_
) -> bind (process_mcodekind bef
) (k e
)
567 let statement r k e
=
568 match Ast.unwrap e
with
569 Ast.IfThen
(_
,_
,ei
) | Ast.IfThenElse
(_
,_
,_
,_
,ei
)
570 | Ast.While
(_
,_
,ei
) | Ast.For
(_
,_
,ei
)
571 | Ast.Iterator
(_
,_
,ei
) -> bind (k e
) (end_info ei
)
574 V.combiner
bind option_default
575 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
576 donothing donothing donothing donothing donothing
577 donothing donothing donothing donothing initialiser donothing
578 donothing rule_elem statement donothing donothing donothing
580 (* ------------------------------------------------------------------------ *)
582 let rule_fn tls in_plus env neg_pos
=
584 (function (rest_info
,in_plus
) ->
585 function (cur
,neg_pos
) ->
587 let getter = do_get_constants keep drop env neg_pos
in
588 getter.V.combiner_top_level cur
in
591 then [] (* nothing removed for sgrep *)
592 else (get_all_constants true).V.combiner_top_level cur
in
593 let plusses = get_plus_constants.V.combiner_top_level cur
in
594 (* the following is for eg -foo(2) +foo(x) then in another rule
595 -foo(10); don't want to consider that foo is guaranteed to be
596 created by the rule. not sure this works completely: what if foo is
597 in both - and +, but in an or, so the cases aren't related?
598 not sure this whole thing is a good idea. how do we know that
599 something that is only in plus is really freshly created? *)
600 let plusses = Common.minus_set plusses all_minuses in
601 let was_bot = minuses = True
in
602 let new_minuses = filter_combine minuses in_plus
in
603 let new_plusses = Common.union_set
plusses in_plus
in
604 (* perhaps it should be build_and here? we don't realy have multiple
605 minirules anymore anyway. *)
606 match new_minuses with
608 let getter = do_get_constants drop keep env neg_pos
in
609 let retry = getter.V.combiner_top_level cur
in
611 True
when not
was_bot -> (rest_info
, new_plusses)
612 | x
-> (build_or x rest_info
, new_plusses))
613 | x
-> (build_or x rest_info
, new_plusses))
614 (False
,in_plus
) (List.combine tls neg_pos
)
616 let run rules neg_pos_vars
=
619 (function (rest_info
,in_plus
,env
,locals
(*dom of env*)) ->
621 (Ast.ScriptRule
(nm
,_
,deps
,mv
,_
,_
),_
) ->
625 function (_
,(rule
,_
),_
) ->
628 else Ast.AndDep
(Ast.Dep rule
,prev
))
630 (match dependencies env
extra_deps with
631 False
-> (rest_info
, in_plus
, (nm
,True
)::env
, nm
::locals
)
633 (build_or
dependencies rest_info
, in_plus
, env
, locals
))
634 | (Ast.InitialScriptRule
(_
,_
,deps
,_
),_
)
635 | (Ast.FinalScriptRule
(_
,_
,deps
,_
),_
) ->
636 (* initialize and finalize dependencies are irrelevant to
638 (rest_info
, in_plus
, env
, locals
)
639 | (Ast.CocciRule
(nm
,(dep
,_
,_
),cur
,_
,_
),neg_pos_vars
) ->
640 let (cur_info
,cur_plus
) =
641 rule_fn cur in_plus
((nm
,True
)::env
) neg_pos_vars
in
642 (match dependencies env dep
with
643 False
-> (rest_info
,cur_plus
,env
,locals
)
645 if List.for_all
all_context.V.combiner_top_level cur
647 let cur_info = build_and dependencies cur_info in
648 (rest_info
,cur_plus
,(nm
,cur_info)::env
,nm
::locals
)
650 (* no constants if dependent on another rule; then we need to
651 find the constants of that rule *)
652 (build_or
(build_and dependencies cur_info) rest_info
,
653 cur_plus
,(nm
,cur_info)::env
,locals
)))
655 (List.combine
(rules
: Ast.rule list
) neg_pos_vars
) in
658 let get_constants rules neg_pos_vars
=
659 match !Flag.scanner
with
660 Flag.NoScanner
-> (None
,None
,None
)
662 let res = run rules neg_pos_vars
in
663 (interpret_grep true res,None
,None
)
665 let res = run rules neg_pos_vars
in
666 (interpret_grep true res,interpret_glimpse true res,None
)
668 let res = run rules neg_pos_vars
in
669 (interpret_grep true res,interpret_google true res,None
)
671 let res = run rules neg_pos_vars
in
672 (interpret_grep true res,None
,Some
res)