5 type text_query = [ `Prefix | `Suffix | `Equals | `Contains ]
7 type tri_state = [ `Unknown | `Yes | `No ]
9 let pr_tri_state fmt v =
10 Format.fprintf fmt "%s"
12 | `Unknown -> "`Unknown"
19 trans : Transition.t list;
21 marking_states : StateSet.t;
22 bottom_states : StateSet.t;
24 bottom_up : tri_state;
25 text_pred : (text_query * string) list
30 states = StateSet.empty;
31 marking_states = StateSet.empty;
32 bottom_states = StateSet.empty;
40 let mk_phi top phi loop = if top then phi *& loop else phi
43 let () = Format.eprintf "%a -> %a in %s\n%!"
51 let rec compile_step toplevel ((axis, test, _) as _step) state cont conf last =
52 let test, cont = match test with
54 | Complex (t, p) -> t, Formula.and_ (Formula.pred_ p) cont
56 let marking = toplevel && last in
60 let loop = `Right *+ state in
61 let phi = mk_phi toplevel cont loop in
62 ( [ (Transition.make (state, test, marking, phi));
63 (Transition.make (state, TagSet.any, false, loop))],
67 let loop = `Right *+ state in
68 let phi = mk_phi toplevel cont loop in
69 ( [ (Transition.make (state, test, marking, phi));
70 (Transition.make (state, TagSet.any, false, loop))],
74 let loopfun = if toplevel then Formula.and_ else Formula.or_ in
75 let loop = loopfun (`Left *+ state) (`Right *+ state) in
76 let phi = mk_phi toplevel cont loop in
77 ( [ (Transition.make (state, test, marking, phi));
78 (Transition.make (state, TagSet.any, false, loop));
79 (*(Transition.make (state, TagSet.any, false, `Right *+ state)) *)
86 trans = trans@conf.trans;
87 states = StateSet.add state conf.states;
90 then StateSet.add state conf.marking_states
91 else conf.marking_states
94 and compile_step_list toplevel sl conf =
97 let state = State.make () in
98 let phi = `Left *+ state in
99 let loop = (`Left *+ state) *& (`Right *+ state) in
103 states = StateSet.add state conf.states;
104 bottom_states = StateSet.add state conf.bottom_states;
105 trans = (Transition.make (state, TagSet.any, false, loop)) :: conf.trans;
107 | (_, _, pred) as step :: sll ->
108 let state = State.make () in
109 let pred, conf = compile_predicate pred conf in
110 let last, cont, conf = compile_step_list toplevel sll conf in
111 let conf, new_cont = compile_step toplevel step state (pred *& cont) conf last in
112 let conf = if toplevel && last then {conf with last = state} else conf in
113 false, new_cont, conf
115 and compile_predicate predicate conf =
119 let cont1, conf1 = compile_predicate p1 conf in
120 let cont2, conf2 = compile_predicate p2 conf1 in
121 cont1 +| cont2, { conf2 with bottom_up = `No
124 let cont1, conf1 = compile_predicate p1 conf in
125 let cont2, conf2 = compile_predicate p2 conf1 in
126 cont1 *& cont2, { conf2 with bottom_up = `No
129 let cont, conf = compile_predicate p conf in
130 Formula.not_ cont, { conf with bottom_up = `No
134 and append_path p s =
136 | Relative sl -> Relative (sl @ [s])
137 | Absolute sl -> Absolute (sl @ [s])
138 | AbsoluteDoS sl -> AbsoluteDoS (sl @ [s])
140 and compile_expr expr conf =
142 | True -> Formula.true_, conf
143 | False -> Formula.false_, conf
145 let phi, conf = compile_path false p conf in
148 match conf.bottom_up with
155 [(Self, Simple (n), Expr True)]) ; String s ]) when n == TagSet.node ->
159 | "contains" -> `Contains
160 | "equals" -> `Equals
161 | "starts-with" -> `Prefix
162 | "ends-with" -> `Suffix
163 | _ -> failwith ("Unknown function : " ^ fn)
165 let pred = Tree.mk_pred f s in
167 compile_expr (Path (Relative [(Child, Complex(TagSet.pcdata, pred), Expr True)])) conf
171 text_pred = (f,s) :: conf'.text_pred;
174 match conf.bottom_up with
181 and compile_path toplevel p conf =
185 | Absolute sl -> (Child, Simple (TagSet.singleton Tag.document_node), Expr True)::sl
187 (Descendant, (Simple TagSet.node), Expr True)::sl
189 let _, cont, conf = compile_step_list toplevel sl conf in
192 let is_topdown_loop q s =
193 StateSet.cardinal (StateSet.remove q s) <= 1
194 let rec remove_topdown_marking trans l last =
198 let tr_list = Hashtbl.find trans q in
201 let _, _, m, f = Transition.node t in
202 let (_, _, stl), (_, _, str) = Formula.st f in
203 not m && is_topdown_loop q stl && is_topdown_loop q str) tr_list
204 then remove_topdown_marking trans ll q
209 let cont, conf = compile_path true path empty_info in
210 let (_, _, init), _ = Formula.st cont in
217 let table = Hashtbl.create 13 in
220 let q, ts, _, _ = Transition.node tr in
221 let l = get table q in
222 Hashtbl.replace table q ((ts, tr)::l)) conf.trans
225 id = Oo.id (object end);
226 Ata.states = conf.states;
228 Ata.last = conf.last;
230 Ata.marking_states = conf.marking_states;
231 Ata.topdown_marking_states = conf.marking_states;
232 (* StateSet.from_list (
233 remove_topdown_marking table
234 (StateSet.elements conf.marking_states)
235 (StateSet.min_elt init)
237 Ata.bottom_states = StateSet.union conf.bottom_states conf.marking_states;
238 Ata.true_states = conf.bottom_states;
240 in auto, (if conf.bottom_up = `Yes then Some conf.text_pred else None)