X-Git-Url: https://git.hcoop.net/bpt/coccinelle.git/blobdiff_plain/978fd7e56b141f7e4c8930acdbf0a806489e63a5..5636bb2c2537506718da74f85a2b81a5ff3df16f:/parsing_cocci/parse_cocci.ml diff --git a/parsing_cocci/parse_cocci.ml b/parsing_cocci/parse_cocci.ml index 2f552e4..d4d78a4 100644 --- a/parsing_cocci/parse_cocci.ml +++ b/parsing_cocci/parse_cocci.ml @@ -1,23 +1,45 @@ (* -* Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen -* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller -* This file is part of Coccinelle. -* -* Coccinelle is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, according to version 2 of the License. -* -* Coccinelle is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Coccinelle. If not, see . -* -* The authors reserve the right to distribute this or future versions of -* Coccinelle under other licenses. -*) + * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen + * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix + * This file is part of Coccinelle. + * + * Coccinelle is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, according to version 2 of the License. + * + * Coccinelle is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Coccinelle. If not, see . + * + * The authors reserve the right to distribute this or future versions of + * Coccinelle under other licenses. + *) + + +(* + * Copyright 2005-2010, Ecole des Mines de Nantes, University of Copenhagen + * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix + * This file is part of Coccinelle. + * + * Coccinelle is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, according to version 2 of the License. + * + * Coccinelle is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Coccinelle. If not, see . + * + * The authors reserve the right to distribute this or future versions of + * Coccinelle under other licenses. + *) (* splits the entire file into minus and plus fragments, and parses each @@ -46,6 +68,7 @@ let line_type2c tok = match line_type tok with D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ":-" | D.PLUS -> ":+" + | D.PLUSPLUS -> ":++" | D.CONTEXT | D.UNIQUE | D.OPT -> "" let token2c (tok,_) = @@ -73,6 +96,7 @@ let token2c (tok,_) = | PC.TName -> "name" | PC.TRuleName str -> "rule_name-"^str | PC.TUsing -> "using" + | PC.TVirtual -> "virtual" | PC.TPathIsoFile str -> "path_iso_file-"^str | PC.TDisable -> "disable" | PC.TExtends -> "extends" @@ -110,7 +134,8 @@ let token2c (tok,_) = | PC.Tconst(clt) -> "const"^(line_type2c clt) | PC.Tvolatile(clt) -> "volatile"^(line_type2c clt) - | PC.TPragma(s,_) -> s + | PC.TPragma(Ast.Noindent s,_) -> s + | PC.TPragma(Ast.Indent s,_) -> s | PC.TIncludeL(s,clt) -> (pr "#include \"%s\"" s)^(line_type2c clt) | PC.TIncludeNL(s,clt) -> (pr "#include <%s>" s)^(line_type2c clt) | PC.TDefine(clt,_) -> "#define"^(line_type2c clt) @@ -154,6 +179,9 @@ let token2c (tok,_) = | PC.TAnd (clt) -> "&"^(line_type2c clt) | PC.TEqEq(clt) -> "=="^(line_type2c clt) | PC.TNotEq(clt) -> "!="^(line_type2c clt) + | PC.TSub(clt) -> "<="^(line_type2c clt) + | PC.TTildeEq(clt) -> "~="^(line_type2c clt) + | PC.TTildeExclEq(clt) -> "~!="^(line_type2c clt) | PC.TLogOp(op,clt) -> (match op with Ast.Inf -> "<" @@ -262,6 +290,7 @@ let token2c (tok,_) = | PC.TIsoExpression -> "Expression" | PC.TIsoArgExpression -> "ArgExpression" | PC.TIsoTestExpression -> "TestExpression" + | PC.TIsoToTestExpression -> "ToTestExpression" | PC.TIsoStatement -> "Statement" | PC.TIsoDeclaration -> "Declaration" | PC.TIsoType -> "Type" @@ -300,7 +329,8 @@ let plus_attachable only_plus (tok,_) = | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) - | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt) + | PC.TLogOp(_,clt) | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) | PC.TDmOp(_,clt) | PC.TTilde (clt) @@ -317,6 +347,9 @@ let plus_attachable only_plus (tok,_) = | PC.TWhen(clt) | PC.TWhenTrue(clt) | PC.TWhenFalse(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) + | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) + | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt) + | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt) | PC.TCPar(clt) @@ -328,16 +361,14 @@ let plus_attachable only_plus (tok,_) = | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt) | PC.TPtVirg(clt) -> - if line_type clt = D.PLUS + if List.mem (line_type clt) [D.PLUS;D.PLUSPLUS] then PLUS else if only_plus then NOTPLUS else if line_type clt = D.CONTEXT then PLUS else NOTPLUS - | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt) - | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) - | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt) - | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> NOTPLUS + | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt) -> NOTPLUS | PC.TMetaPos(nm,_,_,_) -> NOTPLUS + | PC.TSub(clt) -> NOTPLUS | _ -> SKIP @@ -365,7 +396,8 @@ let get_clt (tok,_) = | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) - | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt) + | PC.TSub(clt) | PC.TLogOp(_,clt) | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) | PC.TDmOp(_,clt) | PC.TTilde (clt) @@ -466,6 +498,8 @@ let update_clt (tok,x) clt = | PC.TAnd (_) -> (PC.TAnd (clt),x) | PC.TEqEq(_) -> (PC.TEqEq(clt),x) | PC.TNotEq(_) -> (PC.TNotEq(clt),x) + | PC.TTildeEq(_) -> (PC.TTildeEq(clt),x) + | PC.TSub(_) -> (PC.TSub(clt),x) | PC.TLogOp(op,_) -> (PC.TLogOp(op,clt),x) | PC.TShOp(op,_) -> (PC.TShOp(op,clt),x) | PC.TPlus(_) -> (PC.TPlus(clt),x) @@ -588,7 +622,7 @@ let split t clt = let (d,_,_,_,_,_,_,_) = clt in match d with D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ([t],[]) - | D.PLUS -> ([],[t]) + | D.PLUS | D.PLUSPLUS -> ([],[t]) | D.CONTEXT | D.UNIQUE | D.OPT -> ([t],[t]) let split_token ((tok,_) as t) = @@ -598,8 +632,8 @@ let split_token ((tok,_) as t) = | PC.TFunction | PC.TTypedef | PC.TDeclarer | PC.TIterator | PC.TName | PC.TType | PC.TParameter | PC.TLocal | PC.Tlist | PC.TFresh | PC.TCppConcatOp | PC.TPure - | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TDisable | PC.TExtends - | PC.TPathIsoFile(_) + | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TVirtual | PC.TDisable + | PC.TExtends | PC.TPathIsoFile(_) | PC.TDepends | PC.TOn | PC.TEver | PC.TNever | PC.TExists | PC.TForall | PC.TError | PC.TWords | PC.TGenerated | PC.TNothing -> ([t],[t]) @@ -637,14 +671,15 @@ let split_token ((tok,_) as t) = | PC.TFunDecl(clt) | PC.TWhen(clt) | PC.TWhenTrue(clt) | PC.TWhenFalse(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TLineEnd(clt) - | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) -> split t clt + | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) + | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) + | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) -> split t clt - | PC.TOEllipsis(_) | PC.TCEllipsis(_) (* clt must be context *) - | PC.TPOEllipsis(_) | PC.TPCEllipsis(_) (* clt must be context *) (* | PC.TOCircles(_) | PC.TCCircles(_) (* clt must be context *) | PC.TOStars(_) | PC.TCStars(_) (* clt must be context *) *) + | PC.TBang0 | PC.TPlus0 | PC.TWhy0 -> ([t],[t]) @@ -658,7 +693,8 @@ let split_token ((tok,_) as t) = split t clt | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) - | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt) + | PC.TTildeExclEq(clt) | PC.TSub(clt) | PC.TLogOp(_,clt) | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) | PC.TDmOp(_,clt) | PC.TTilde (clt) -> split t clt @@ -674,7 +710,8 @@ let split_token ((tok,_) as t) = | PC.TIso | PC.TRightIso | PC.TIsoExpression | PC.TIsoStatement | PC.TIsoDeclaration | PC.TIsoType - | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression -> + | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression + | PC.TIsoToTestExpression -> failwith "unexpected tokens" | PC.TScriptData s -> ([t],[t]) @@ -938,6 +975,36 @@ let rec translate_when_true_false = function (* ----------------------------------------------------------------------- *) +(* In a nest, if the nest is -, all of the nested code must also be -. +All are converted to context, because the next takes care of the -. *) +let check_nests tokens = + let is_minus t = + let (line_type,a,b,c,d,e,f,g) = get_clt t in + List.mem line_type [D.MINUS;D.OPTMINUS;D.UNIQUEMINUS] in + let drop_minus t = + let clt = try Some(get_clt t) with Failure _ -> None in + match clt with + Some (line_type,a,b,c,d,e,f,g) -> + (match line_type with + D.MINUS -> update_clt t (D.CONTEXT,a,b,c,d,e,f,g) + | D.OPTMINUS -> update_clt t (D.OPT,a,b,c,d,e,f,g) + | D.UNIQUEMINUS -> update_clt t (D.UNIQUE,a,b,c,d,e,f,g) + | _ -> failwith "minus token expected") + | None -> t in + let rec outside = function + [] -> [] + | ((PC.TPOEllipsis(clt),q) as t)::r when is_minus t -> t :: inside 0 r + | t::r -> t :: outside r + and inside stack = function + [] -> failwith "missing nest end" + | ((PC.TPCEllipsis(clt),q) as t)::r -> + (drop_minus t) + :: (if stack = 0 then outside r else inside (stack - 1) r) + | ((PC.TPOEllipsis(clt),q) as t)::r -> + (drop_minus t) :: (inside (stack + 1) r) + | t :: r -> (drop_minus t) :: (inside stack r) in + outside tokens + let check_parentheses tokens = let clt2line (_,line,_,_,_,_,_,_) = line in let rec loop seen_open = function @@ -954,7 +1021,7 @@ let check_parentheses tokens = (Printf.sprintf "unexpected close parenthesis in line %d\n" (clt2line clt)) | Common.Left _ :: seen_open -> loop seen_open rest - | Common.Right open_line :: _ -> + | Common.Right open_line :: _ -> failwith (Printf.sprintf "disjunction parenthesis in line %d column 0 matched to normal parenthesis on line %d\n" open_line (clt2line clt))) @@ -965,7 +1032,7 @@ let check_parentheses tokens = (Printf.sprintf "unexpected close parenthesis in line %d\n" (clt2line clt)) | Common.Right _ :: seen_open -> loop seen_open rest - | Common.Left open_line :: _ -> + | Common.Left open_line :: _ -> failwith (Printf.sprintf "normal parenthesis in line %d matched to disjunction parenthesis on line %d column 0\n" open_line (clt2line clt))) @@ -1101,7 +1168,7 @@ let minus_to_nothing l = let (d,_,_,_,_,_,_,_) = get_clt tok in (match d with D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> true - | D.PLUS -> false + | D.PLUS | D.PLUSPLUS -> false | D.CONTEXT | D.UNIQUE | D.OPT -> false) with _ -> false in let rec minus_loop = function @@ -1228,7 +1295,10 @@ let prepare_tokens tokens = (translate_when_true_false (* after insert_line_end *) (insert_line_end (detect_types false - (find_function_names (detect_attr (check_parentheses tokens)))))) + (find_function_names + (detect_attr + (check_nests + (check_parentheses tokens))))))) let prepare_mv_tokens tokens = detect_types false (detect_attr tokens) @@ -1250,7 +1320,7 @@ let rec consume_minus_positions = function let any_modif rule = let mcode x = match Ast0.get_mcode_mcodekind x with - Ast0.MINUS _ | Ast0.PLUS -> true + Ast0.MINUS _ | Ast0.PLUS _ -> true | _ -> false in let donothing r k e = k e in let bind x y = x or y in @@ -1263,6 +1333,15 @@ let any_modif rule = donothing donothing in List.exists fn.VT0.combiner_rec_top_level rule +let eval_virt virt = + List.iter + (function x -> + if not (List.mem x virt) + then + failwith + (Printf.sprintf "unknown virtual rule %s\n" x)) + !Flag.defined_virtual_rules + let drop_last extra l = List.rev(extra@(List.tl(List.rev l))) let partition_either l = @@ -1320,8 +1399,8 @@ let get_rule_name parse_fn starts_with_name get_tokens file prefix = | Ast.GeneratedRulename (nm,a,b,c,d,e) -> Ast.GeneratedRulename (check_name nm,a,b,c,d,e) | Ast.ScriptRulename(s,deps) -> Ast.ScriptRulename(s,deps) - | Ast.InitialScriptRulename(s) -> Ast.InitialScriptRulename(s) - | Ast.FinalScriptRulename(s) -> Ast.FinalScriptRulename(s) + | Ast.InitialScriptRulename(s,deps) -> Ast.InitialScriptRulename(s,deps) + | Ast.FinalScriptRulename(s,deps) -> Ast.FinalScriptRulename(s,deps) else Ast.CocciRulename(Some(mknm()),Ast.NoDep,[],[],Ast.Undetermined,false) in Data.in_rule_name := false; @@ -1359,7 +1438,7 @@ let parse_iso file = let (more,tokens) = get_tokens [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression; - PC.TIsoTestExpression; + PC.TIsoTestExpression; PC.TIsoToTestExpression; PC.TIsoDeclaration;PC.TIsoType;PC.TIsoTopLevel] in let next_start = List.hd(List.rev tokens) in let dummy_info = ("",(-1,-1),(-1,-1)) in @@ -1367,7 +1446,7 @@ let parse_iso file = let tokens = prepare_tokens (start@tokens) in (* print_tokens "iso tokens" tokens; - *) + å*) let entry = parse_one "iso main" PC.iso_main file tokens in let entry = List.map (List.map Test_exps.process_anything) entry in if more @@ -1407,7 +1486,45 @@ let parse_iso_files existing_isos iso_files extra_path = Data.in_iso := false; existing_isos@(List.concat (List.rev res)) -let rec parse file = +(* None = dependency not satisfied + Some dep = dependency satisfied or unknown and dep has virts optimized + away *) +let eval_depend dep virt = + let rec loop dep = + match dep with + Ast.Dep req | Ast.EverDep req -> + if List.mem req virt + then + if List.mem req !Flag.defined_virtual_rules + then Some Ast.NoDep + else None + else Some dep + | Ast.AntiDep antireq | Ast.NeverDep antireq -> + if List.mem antireq virt + then + if not(List.mem antireq !Flag.defined_virtual_rules) + then Some Ast.NoDep + else None + else Some dep + | Ast.AndDep(d1,d2) -> + (match (loop d1, loop d2) with + (None,_) | (_,None) -> None + | (Some Ast.NoDep,x) | (x,Some Ast.NoDep) -> x + | (Some x,Some y) -> Some (Ast.AndDep(x,y))) + | Ast.OrDep(d1,d2) -> + (match (loop d1, loop d2) with + (None,None) -> None + | (Some Ast.NoDep,x) | (x,Some Ast.NoDep) -> Some Ast.NoDep + | (None,x) | (x,None) -> x + | (Some x,Some y) -> Some (Ast.OrDep(x,y))) + | Ast.NoDep | Ast.FailDep -> Some dep + in + loop dep + +let parse file = + Lexer_cocci.init(); + let rec parse_loop file = + Lexer_cocci.include_init (); let table = Common.full_charpos_to_pos file in Common.with_open_infile file (fun channel -> let lexbuf = Lexing.from_channel channel in @@ -1423,16 +1540,25 @@ let rec parse file = let include_and_iso_files = parse_one "include and iso file names" PC.include_main file data in - let (include_files,iso_files) = + let (include_files,iso_files,virt) = List.fold_left - (function (include_files,iso_files) -> + (function (include_files,iso_files,virt) -> function - Data.Include s -> (s::include_files,iso_files) - | Data.Iso s -> (include_files,s::iso_files)) - ([],[]) include_and_iso_files in - - let (extra_iso_files, extra_rules) = - List.split (List.map parse include_files) in + Data.Include s -> (s::include_files,iso_files,virt) + | Data.Iso s -> (include_files,s::iso_files,virt) + | Data.Virt l -> (include_files,iso_files,l@virt)) + ([],[],[]) include_and_iso_files in + + List.iter (function x -> Hashtbl.add Lexer_cocci.rule_names x ()) + virt; + + let (extra_iso_files, extra_rules, extra_virt, extra_metas) = + let rec loop = function + [] -> ([],[],[],[]) + | (a,b,c,d)::rest -> + let (x,y,z,zz) = loop rest in + (a::x,b::y,c::z,d@zz) in + loop (List.map parse_loop include_files) in let parse_cocci_rule ruletype old_metas (rule_name, dependencies, iso, dropiso, exists, is_expression) = @@ -1443,10 +1569,10 @@ let rec parse file = (* get metavariable declarations *) let (metavars, inherited_metavars) = get_metavars PC.meta_main table file lexbuf in - Hashtbl.add Data.all_metadecls rule_name metavars; - Hashtbl.add Lexer_cocci.rule_names rule_name (); - Hashtbl.add Lexer_cocci.all_metavariables rule_name - (Hashtbl.fold + Hashtbl.add Data.all_metadecls rule_name metavars; + Hashtbl.add Lexer_cocci.rule_names rule_name (); + Hashtbl.add Lexer_cocci.all_metavariables rule_name + (Hashtbl.fold (fun key v rest -> (key,v)::rest) Lexer_cocci.metavariables []); @@ -1456,6 +1582,11 @@ let rec parse file = let (_, plus_tokens) = split_token_stream (minus_to_nothing tokens) in + (* + print_tokens "minus tokens" minus_tokens; + print_tokens "plus tokens" plus_tokens; + *) + let minus_tokens = consume_minus_positions minus_tokens in let minus_tokens = prepare_tokens minus_tokens in let plus_tokens = prepare_tokens plus_tokens in @@ -1482,7 +1613,9 @@ let rec parse file = Printf.printf "before plus parse\n"; *) let plus_res = - if !Flag.sgrep_mode2 + (* put ignore_patch_or_match with * case, which is less + constraining *) + if !Flag.sgrep_mode2 or !D.ignore_patch_or_match then (* not actually used for anything, except context_neg *) List.map (Iso_pattern.rebuild_mcode None).VT0.rebuilder_rec_top_level @@ -1506,6 +1639,16 @@ let rec parse file = (iso, dropiso, dependencies, rule_name, exists)), (plus_res, metavars), ruletype), metavars, tokens) in + let rec collect_script_tokens = function + [(PC.EOF,_)] | [(PC.TArobArob,_)] | [(PC.TArob,_)] -> "" + | (PC.TScriptData(s),_)::xs -> s^(collect_script_tokens xs) + | toks -> + List.iter + (function x -> + Printf.printf "%s\n" (token2c x)) + toks; + failwith "Malformed script rule" in + let parse_script_rule language old_metas deps = let get_tokens = tokens_script_all table file false lexbuf in @@ -1516,6 +1659,7 @@ let rec parse file = get_script_metavars PC.script_meta_main table file lexbuf) in let exists_in old_metas (py,(r,m)) = + r = "virtual" or let test (rr,mr) x = let (ro,vo) = Ast.get_meta_name x in ro = rr && vo = mr in @@ -1533,53 +1677,72 @@ let rec parse file = (* script code *) let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in - let data = - match List.hd tokens with - (PC.TScriptData(s),_) -> s - | (PC.TArobArob,_) | (PC.TArob,_) -> "" - | _ -> failwith "Malformed script rule" in + let data = collect_script_tokens tokens in (more,Ast0.ScriptRule(language, deps, metavars, data),[],tokens) in - let parse_if_script_rule k language = + let parse_if_script_rule k language _ deps = let get_tokens = tokens_script_all table file false lexbuf in (* script code *) let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in - let data = - match List.hd tokens with - (PC.TScriptData(s),_) -> s - | (PC.TArobArob,_) | (PC.TArob,_) -> "" - | _ -> failwith "Malformed script rule" in - (more,k (language, data),[],tokens) in + let data = collect_script_tokens tokens in + (more,k (language, deps, data),[],tokens) in let parse_iscript_rule = parse_if_script_rule - (function (language,data) -> - Ast0.InitialScriptRule(language,data)) in + (function (language,deps,data) -> + Ast0.InitialScriptRule(language,deps,data)) in let parse_fscript_rule = parse_if_script_rule - (function (language,data) -> - Ast0.FinalScriptRule(language,data)) in + (function (language,deps,data) -> + Ast0.FinalScriptRule(language,deps,data)) in + + let do_parse_script_rule fn l old_metas deps = + match eval_depend deps virt with + Some deps -> fn l old_metas deps + | None -> fn l old_metas Ast.FailDep in let parse_rule old_metas starts_with_name = let rulename = get_rule_name PC.rule_name starts_with_name get_tokens file "rule" in match rulename with - Ast.CocciRulename (Some s, a, b, c, d, e) -> - parse_cocci_rule Ast.Normal old_metas (s, a, b, c, d, e) - | Ast.GeneratedRulename (Some s, a, b, c, d, e) -> - Data.in_generating := true; - let res = - parse_cocci_rule Ast.Generated old_metas (s,a,b,c,d,e) in - Data.in_generating := false; - res - | Ast.ScriptRulename(l,deps) -> parse_script_rule l old_metas deps - | Ast.InitialScriptRulename(l) -> parse_iscript_rule l - | Ast.FinalScriptRulename(l) -> parse_fscript_rule l - | _ -> failwith "Malformed rule name" - in + Ast.CocciRulename (Some s, dep, b, c, d, e) -> + (match eval_depend dep virt with + Some (dep) -> + parse_cocci_rule Ast.Normal old_metas (s,dep,b,c,d,e) + | None -> + D.ignore_patch_or_match := true; + let res = + parse_cocci_rule Ast.Normal old_metas + (s, Ast.FailDep, b, c, d, e) in + D.ignore_patch_or_match := false; + res) + | Ast.GeneratedRulename (Some s, dep, b, c, d, e) -> + (match eval_depend dep virt with + Some (dep) -> + Data.in_generating := true; + let res = + parse_cocci_rule Ast.Normal old_metas (s,dep,b,c,d,e) in + Data.in_generating := false; + res + | None -> + D.ignore_patch_or_match := true; + Data.in_generating := true; + let res = + parse_cocci_rule Ast.Normal old_metas + (s, Ast.FailDep, b, c, d, e) in + D.ignore_patch_or_match := false; + Data.in_generating := false; + res) + | Ast.ScriptRulename(l,deps) -> + do_parse_script_rule parse_script_rule l old_metas deps + | Ast.InitialScriptRulename(l,deps) -> + do_parse_script_rule parse_iscript_rule l old_metas deps + | Ast.FinalScriptRulename(l,deps) -> + do_parse_script_rule parse_fscript_rule l old_metas deps + | _ -> failwith "Malformed rule name" in let rec loop old_metas starts_with_name = (!Data.init_rule)(); @@ -1594,28 +1757,37 @@ let rec parse file = let (more, rule, metavars, tokens) = parse_rule old_metas starts_with_name in + let all_metas = metavars @ old_metas in + if more then - rule:: - (loop (metavars @ old_metas) (gen_starts_with_name more tokens)) - else [rule] in + let (all_rules,all_metas) = + loop all_metas (gen_starts_with_name more tokens) in + (rule::all_rules,all_metas) + else ([rule],all_metas) in + + let (all_rules,all_metas) = + loop extra_metas (x = PC.TArob) in (List.fold_left (function prev -> function cur -> Common.union_set cur prev) iso_files extra_iso_files, - List.fold_left - (function prev -> function cur -> cur @ prev) - (loop [] (x = PC.TArob)) extra_rules) + (* included rules first *) + List.fold_left (function prev -> function cur -> cur@prev) + all_rules (List.rev extra_rules), + List.fold_left (@) virt extra_virt (*no dups allowed*), + (all_metas : 'a list)) | _ -> failwith "unexpected code before the first rule\n") | (false,[(PC.TArobArob,_)]) | (false,[(PC.TArob,_)]) -> - ([],([] : Ast0.parsed_rule list)) + ([],([] : Ast0.parsed_rule list),[] (*virtual rules*), [] (*all metas*)) | _ -> failwith "unexpected code before the first rule\n" in - res) + res) in + parse_loop file (* parse to ast0 and then convert to ast *) let process file isofile verbose = let extra_path = Filename.dirname file in - Lexer_cocci.init(); - let (iso_files, rules) = parse file in + let (iso_files, rules, virt, _metas) = parse file in + eval_virt virt; let std_isos = match isofile with None -> [] @@ -1626,8 +1798,8 @@ let process file isofile verbose = List.map (function Ast0.ScriptRule (a,b,c,d) -> [([],Ast.ScriptRule (a,b,c,d))] - | Ast0.InitialScriptRule (a,b) -> [([],Ast.InitialScriptRule (a,b))] - | Ast0.FinalScriptRule (a,b) -> [([],Ast.FinalScriptRule (a,b))] + | Ast0.InitialScriptRule (a,b,c) -> [([],Ast.InitialScriptRule (a,b,c))] + | Ast0.FinalScriptRule (a,b,c) -> [([],Ast.FinalScriptRule (a,b,c))] | Ast0.CocciRule ((minus, metavarsm, (iso, dropiso, dependencies, rule_name, exists)), @@ -1713,6 +1885,7 @@ let process file isofile verbose = let minus_ast = Ast0toast.ast0toast rule_name dependencies dropped_isos exists minus is_exp ruletype in + match function_prototypes with None -> [(extra_meta @ metavars, minus_ast)] | Some mv_fp -> [(extra_meta @ metavars, minus_ast); mv_fp]) @@ -1726,9 +1899,10 @@ let process file isofile verbose = then List.iter Pretty_print_cocci.unparse code; let grep_tokens = - Common.profile_code "get_constants" - (fun () -> Get_constants.get_constants code) in (* for grep *) + Common.profile_code "get_constants" (* for grep *) + (fun () -> Get_constants.get_constants code) in let glimpse_tokens2 = - Common.profile_code "get_glimpse_constants" - (fun () -> Get_constants2.get_constants code neg_pos) in(* for glimpse *) + Common.profile_code "get_glimpse_constants" (* for glimpse *) + (fun () -> Get_constants2.get_constants code neg_pos) in + (metavars,code,fvs,neg_pos,ua,pos,grep_tokens,glimpse_tokens2)