Add a kind element to the node tree. Improve support for XPath by
[tatoo.git] / src / auto / eval.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                     Kim Nguyen, LRI UMR8623                         *)
6 (*                   Université Paris-Sud & CNRS                       *)
7 (*                                                                     *)
8 (*  Copyright 2010-2013 Université Paris-Sud and Centre National de la *)
9 (*  Recherche Scientifique. All rights reserved.  This file is         *)
10 (*  distributed under the terms of the GNU Lesser General Public       *)
11 (*  License, with the special exception on linking described in file   *)
12 (*  ../LICENSE.                                                        *)
13 (*                                                                     *)
14 (***********************************************************************)
15
16 (*
17   Time-stamp: <Last modified on 2013-03-10 23:31:33 CET by Kim Nguyen>
18 *)
19
20 INCLUDE "utils.ml"
21 open Format
22 open Utils
23
24 module Make (T : Tree.Sig.S) = struct
25
26   type cache = (int, StateSet.t) Hashtbl.t
27
28   let get c t n =
29     try Hashtbl.find c (T.preorder t n)
30     with Not_found -> StateSet.empty
31
32   let set c t n v = Hashtbl.replace c (T.preorder t n) v
33   let eval_form  phi tree node fcs nss ps ss =
34     let rec loop phi =
35       match Ata.SFormula.expr phi with
36         Formula.True -> true
37       | Formula.False -> false
38       | Formula.Atom a ->
39           let p, b, q = Ata.Atom.node a in
40           let pos =
41             let open Ata in
42             match p with
43             | First_child -> StateSet.mem q fcs
44             | Next_sibling ->  StateSet.mem q nss
45             | Parent | Previous_sibling -> StateSet.mem q ps
46             | Stay -> StateSet.mem q ss
47             | Is_first_child ->
48                 node == (T.first_child tree (T.parent tree node))
49             | Is_next_sibling ->
50                 node == (T.next_sibling tree (T.parent tree node))
51             | Is k -> k == (T.kind tree node)
52             | Has_first_child ->
53                 T.nil != T.first_child tree node
54             | Has_next_sibling ->
55                 T.nil != T.next_sibling tree node
56           in
57           if Ata.is_move p && (not b) then
58             eprintf "Warning: Invalid negative atom %a" Ata.Atom.print a;
59           b == pos
60       | Formula.And(phi1, phi2) -> loop phi1 && loop phi2
61       | Formula.Or (phi1, phi2) -> loop phi1 || loop phi2
62     in
63     loop phi
64
65   let eval_trans l tree node fcs nss ps ss acc =
66     List.fold_left (fun (acct, accs) ((q, phi) as trs) ->
67       if StateSet.mem q accs then (acct, accs) else
68       if eval_form phi tree node fcs nss ps ss then
69         (acct, StateSet.add q accs)
70       else
71         (trs::acct, accs)
72     ) ([], acc) l
73
74   let top_down_run auto tree node cache i =
75     let redo = ref false in
76     let rec loop node =
77       if node != T.nil then begin
78         let parent = T.parent tree node in
79         let fc = T.first_child tree node in
80         let ns = T.next_sibling tree node in
81         let states0 = get cache tree node in
82         let tag = T.tag tree node in
83         let trans0 = Ata.get_trans auto auto.Ata.states tag in
84         let ps = get cache tree parent in
85         let fcs = get cache tree fc in
86         let nss = get cache tree ns in
87         eprintf "-- [Iteration % 4d] --\n node: %a\n%!" i T.print_node node;
88         List.iter (fun (q, phi) -> eprintf " %a -> %a\n"
89           State.print q Ata.SFormula.print phi) trans0;
90         eprintf "----------------------\n%!";
91         let trans1, states1 =
92           eval_trans trans0 tree node fcs nss ps states0 states0
93         in
94         if states1 != states0 then set cache tree node states1;
95         let () = loop fc in
96         let fcs1 = get cache tree fc in
97         let trans2, states2 =
98           eval_trans trans1 tree node fcs1 nss ps states1 states1
99         in
100         if states2 != states1 then set cache tree node states2;
101         let () = loop ns in
102         let _, states3 =
103           eval_trans trans2 tree node fcs1 (get cache tree ns) ps states2 states2
104         in
105         if states3 != states2 then set cache tree node states3;
106         if states0 != states3 && (not !redo) then redo := true
107       end
108     in
109     loop node;
110     !redo
111
112   let get_results auto tree node cache =
113     let rec loop node acc =
114       if node == T.nil then acc
115       else
116         let acc0 = loop (T.next_sibling tree node) acc in
117         let acc1 = loop (T.first_child tree node) acc0 in
118
119         if StateSet.intersect (get cache tree node) auto.Ata.selection_states then
120           node::acc1
121         else
122           acc1
123     in
124     loop node []
125
126   let eval auto tree node =
127     let cache = Hashtbl.create 511 in
128     let redo = ref true in
129     let iter = ref 0 in
130     while !redo do
131       redo := top_down_run auto tree node cache !iter;
132       incr iter;
133     done;
134     get_results auto tree node cache
135
136 end