Temporary commit
[SXSI/xpathcomp.git] / src / runtime.ml
1 INCLUDE "debug.ml"
2 INCLUDE "trace.ml"
3 INCLUDE "utils.ml"
4
5 open Format
6 open Ata
7 module type S = sig
8   type result_set
9   val top_down_run : Ata.t -> Tree.t -> Tree.node -> result_set
10   val bottom_up_run : Ata.t -> Tree.t -> Compile.text_query * string -> result_set
11   val grammar_run : Ata.t -> Grammar2.t -> unit -> result_set
12   val naive_top_down_run : Ata.t -> Tree.t -> Tree.node -> result_set
13   val twopass_top_down_run : Ata.t -> Tree.t -> Tree.node -> result_set
14 end
15
16 module Make (U : ResJIT.S) : S with type result_set = U.NS.t =
17   struct
18
19     type result_set = U.NS.t;;
20
21     let eval_form auto s1 s2 f =
22       let rec loop f =
23         match Formula.expr f with
24           | Formula.False | Formula.True | Formula.Pred _ -> f, []
25           | Formula.Atom(`Left, b, q) ->
26               Formula.of_bool (b == (StateSet.mem q s1)),
27               if b && StateSet.mem q auto.topdown_marking_states then [ResJIT.LEFT q] else []
28           | Formula.Atom (`Right, b, q) ->
29               Formula.of_bool(b == (StateSet.mem q s2)),
30               if b && StateSet.mem q auto.topdown_marking_states then [ResJIT.RIGHT q] else []
31           | Formula.Atom (`Epsilon, _, _) -> assert false
32
33           | Formula.Or(f1, f2) ->
34               let b1, i1 = loop f1 in
35               let b2, i2 = loop f2 in
36               Formula.or_pred b1 b2, i1 @ i2
37           | Formula.And(f1, f2) ->
38               let b1, i1 = loop f1 in
39               let b2, i2 = loop f2 in
40               Formula.and_pred b1 b2, i1 @ i2
41       in
42       loop f
43
44
45     let eval_trans auto s1 s2 trans =
46       TRACE("top-down-run", 2, __ "Evaluating transition list:\n%!");
47       TRACE("top-down-run", 2, __ "%a\n%!" Translist.print trans);
48       Translist.fold
49         (fun t ((a_st, a_op, a_todo) as acc)->
50            let q, _, m, f = Transition.node t in
51            let form, ops = eval_form auto s1 s2 f in
52            match Formula.expr form with
53              | Formula.True ->
54                StateSet.add q a_st,
55                (q, (if m then (ResJIT.SELF() :: ops) else ops)):: a_op,
56                a_todo
57              | Formula.False -> acc
58              | Formula.Pred p -> a_st, a_op,
59                (p.Tree.Predicate.node, q, [(q,(if m then (ResJIT.SELF() :: ops) else ops))]) :: a_todo
60              | _ -> assert false
61         ) trans (StateSet.empty, [], [])
62
63
64
65     module L3JIT =
66       struct
67
68         type opcode = (t -> t -> t -> Tree.t -> Tree.node -> StateSet.t * t)
69
70         type t = opcode Cache.Lvl3.t
71
72         let dummy _ _ _ _ _ = failwith "Uninitialized L3JIT"
73
74
75         let show_stats a =
76           let count = ref 0 in
77           Cache.Lvl3.iteri (fun _ _ _ _ b -> if not b then incr count) a;
78           eprintf "%!L3JIT: %i used entries\n%!" !count
79         let create () =
80           let v = Cache.Lvl3.create 1024 dummy in
81           if !Options.verbose then at_exit (fun () -> show_stats v);
82           v
83
84         let find t tlist s1 s2 =
85           Cache.Lvl3.find t
86             (Uid.to_int s2.StateSet.Node.id)
87             (Uid.to_int s1.StateSet.Node.id)
88             (Uid.to_int tlist.Translist.Node.id)
89
90         let add t tlist s1 s2 v =
91           Cache.Lvl3.add t
92             (Uid.to_int s2.StateSet.Node.id)
93             (Uid.to_int s1.StateSet.Node.id)
94             (Uid.to_int tlist.Translist.Node.id)
95             v
96
97         let compile auto trl s1 s2 =
98           let orig_s1, orig_s2 =
99             Translist.fold (fun t (a1, a2) ->
100                           let _, _, _, f = Transition.node t in
101                           let fs1, fs2 = Formula.st f in
102                             (StateSet.union a1 fs1, StateSet.union a2 fs2)
103                        ) trl (StateSet.empty, StateSet.empty)
104           in
105           let ns1 = StateSet.inter s1 orig_s1
106           and ns2 = StateSet.inter s2 orig_s2 in
107           let res, ops, todo = eval_trans auto orig_s1 orig_s2 trl in
108           let code, not_marking = ResJIT.compile ops in
109           let todo_code, todo_notmarking =
110             List.fold_left (fun (l, b) (p, q, o) -> let c, b' = ResJIT.compile o in
111                                          (p, q, c)::l, b && b')
112               ([], not_marking) todo
113           in
114           let opcode = res, code, todo_notmarking, todo_code in
115           opcode
116
117         let gen_code auto tlist s1 s2 =
118           let res, code, not_marking, todo_code = compile auto tlist s1 s2 in
119           let f =
120             if todo_code == [] then
121               if not_marking then begin fun empty_slot sl1 sl2 _ node ->
122                 let slot1_empty = sl1 == empty_slot
123                 and slot2_empty = sl2 == empty_slot in
124                 if slot1_empty && slot2_empty then res,sl2
125                 else
126                   let sl =
127                     if slot2_empty then
128                       if slot1_empty then
129                         Array.copy empty_slot
130                       else sl1
131                     else sl2
132                   in
133                   eprintf "Here 1\n%!";
134                   U.exec sl sl1 sl2 node code;
135                   res, sl
136               end
137               else (* marking *) begin fun empty_slot sl1 sl2 _ node ->
138                 let sl =
139                   if sl2 == empty_slot  then
140                     if sl1 == empty_slot then
141                       Array.copy empty_slot
142                     else sl1
143                   else sl2
144                 in
145                   eprintf "Here 2\n%!";
146                 U.exec sl sl1 sl2 node code;
147                 res, sl
148               end
149               else (* todo != [] *)
150               begin fun empty_slot sl1 sl2 tree node ->
151                 let sl =
152                   if sl2 == empty_slot  then
153                     if sl1 == empty_slot then
154                       Array.copy empty_slot
155                     else sl1
156                   else sl2
157                 in
158                 U.exec sl sl1 sl2 node code;
159                 List.fold_left
160                   (fun ares (p, q, code) ->
161                     if !p tree node then begin
162                       if code != ResJIT.Nil then U.exec sl sl1 sl2 node code;
163                       StateSet.add q ares
164                     end
165                     else ares) res todo_code, sl
166
167               end
168           in
169           f
170
171         let cache_apply cache auto tlist s1 s2 =
172           let f = gen_code auto tlist s1 s2 in
173           TRACE("grammar", 2, __ "Inserting: %i, %a, %a\n%!"
174             (Uid.to_int tlist.Translist.Node.id) StateSet.print s1 StateSet.print s2);
175           add cache tlist s1 s2 f; f
176       end
177
178 DEFINE LOOP (t, states, ctx) = (
179   let _t = t in
180   TRACE("top-down-run", 3,
181         __ "Entering node %i with loop (tag %s, context %i) with states %a\n%!"
182           (Node.to_int _t)
183           (Tag.to_string (Tree.tag tree _t))
184           (Node.to_int (ctx))
185           (StateSet.print) (states));
186   if _t == Tree.nil then nil_res
187   else
188     let tag = Tree.tag tree _t in
189       l2jit_dispatch
190         _t tag (states) (ctx) (L2JIT.find cache2 tag (states))
191 )
192
193 DEFINE LOOP_TAG (t, states, tag, ctx) = (
194   let _t = (t) in (* to avoid duplicating expression t *)
195   TRACE("top-down-run", 3,
196         __ "Entering node %i with loop_tag (tag %s, context %i) with states %a\n%!"
197           (Node.to_int _t)
198           (Tag.to_string (tag))
199           (Node.to_int (ctx))
200           (StateSet.print) (states));
201   if _t == Tree.nil then nil_res
202   else
203     l2jit_dispatch
204       _t (tag) (states) (ctx) (L2JIT.find cache2 (tag) (states)))
205
206     let top_down_run auto tree root states ctx =
207       let res_len = StateSet.max_elt auto.states + 1 in
208       let empty_slot = Array.create res_len U.NS.empty in
209       let nil_res = auto.bottom_states, empty_slot in
210       let cache3 = L3JIT.create () in
211       let mark_subtree  =
212         fun s subtree -> if subtree != U.NS.empty then
213           let r = Array.copy empty_slot in
214           r.(auto.last) <- subtree;
215           s,r
216         else
217           s,empty_slot
218       in
219       let l3jit_dispatch trl s1 s2 t sl1 sl2 =
220         let f = L3JIT.find cache3 trl s1 s2 in
221         if f == L3JIT.dummy then (L3JIT.cache_apply cache3 auto trl s1 s2) empty_slot sl1 sl2 tree t
222         else f empty_slot sl1 sl2 tree t
223
224       in
225       let cache2 = L2JIT.create () in
226
227       let rec l2jit_dispatch t tag states ctx opcode =
228         match opcode with
229           | L2JIT.RETURN -> nil_res
230           | L2JIT.CACHE ->
231             eprintf "New configuration\n%!";
232             let opcode = L2JIT.compile cache2 auto tree tag states in
233             l2jit_dispatch t tag states ctx opcode
234
235           | L2JIT.LEFT (tr_list, instr) ->
236               let res1, slot1 =
237                 l2jit_dispatch_instr t (Tree.closing tree t) instr
238               in
239                 l3jit_dispatch tr_list res1 auto.bottom_states t slot1 empty_slot
240
241           | L2JIT.RIGHT (tr_list, instr) ->
242             let res2, slot2 =
243               l2jit_dispatch_instr t ctx instr
244             in
245             l3jit_dispatch tr_list auto.bottom_states res2 t empty_slot slot2
246
247           | L2JIT.BOTH (tr_list, instr1, instr2) ->
248               let res1, slot1 =
249                 l2jit_dispatch_instr t (Tree.closing tree t) instr1
250               in
251               let res2, slot2 =
252                 l2jit_dispatch_instr t ctx instr2
253               in
254                 l3jit_dispatch tr_list res1 res2 t slot1 slot2
255
256     and l2jit_dispatch_instr t ctx instr =
257       match instr with
258         | L2JIT.FIRST_CHILD s -> LOOP ((Tree.first_child tree t), s, ctx)
259         | L2JIT.NEXT_SIBLING s -> LOOP ((Tree.next_sibling tree t), s, ctx)
260
261         | L2JIT.FIRST_ELEMENT s -> LOOP ((Tree.first_element tree t), s, ctx)
262         | L2JIT.NEXT_ELEMENT s -> LOOP ((Tree.next_element tree t), s, ctx)
263
264         | L2JIT.TAGGED_DESCENDANT (s, tag) ->
265           LOOP_TAG ((Tree.tagged_descendant tree t tag), s, tag, ctx)
266
267         | L2JIT.TAGGED_FOLLOWING (s, tag) ->
268           LOOP_TAG((Tree.tagged_following_before tree t tag ctx), s, tag, ctx)
269
270         | L2JIT.SELECT_DESCENDANT (s, _, us) ->
271           LOOP((Tree.select_descendant tree t us), s, ctx)
272
273         | L2JIT.SELECT_FOLLOWING (s, pt, us) ->
274           LOOP ((Tree.select_following_before tree t us ctx), s, ctx)
275
276         | L2JIT.TAGGED_CHILD (s, tag) ->
277           LOOP_TAG((Tree.tagged_child tree t tag), s, tag, ctx)
278
279         | L2JIT.TAGGED_FOLLOWING_SIBLING (s, tag) ->
280           LOOP_TAG((Tree.tagged_following_sibling tree t tag), s, tag, ctx)
281
282         | L2JIT.SELECT_CHILD (s, _, us) ->
283           LOOP ((Tree.select_child tree t us), s, ctx)
284
285         | L2JIT.SELECT_FOLLOWING_SIBLING (s, _, us) ->
286           LOOP ((Tree.select_following_sibling tree t us), s, ctx)
287
288         | L2JIT.TAGGED_SUBTREE(s, tag) ->
289           mark_subtree s (U.NS.subtree_tags tree t tag)
290
291         | L2JIT.ELEMENT_SUBTREE(s) ->
292           mark_subtree s (U.NS.subtree_elements tree t)
293       in
294       let r = LOOP (root, states, ctx) in
295       (*L3JIT.stats err_formatter cache3; *)
296       r
297
298     let full_top_down_run auto states tree root =
299       (*Ata.init (); *)
300       top_down_run auto tree root states (Tree.closing tree root)
301
302     let top_down_run auto tree root =
303       (*Ata.init (); *)
304       let res, slot = full_top_down_run auto auto.init tree root in
305
306       slot.(StateSet.min_elt auto.topdown_marking_states)
307
308
309     (*** Bottom-up evaluation function **)
310
311     let ns_print fmt t =
312       Format.fprintf fmt "{ ";
313       U.NS.iter begin fun node ->
314         Format.fprintf fmt "%a " Node.print node;
315       end t;
316       Format.fprintf fmt "}"
317
318     let slot_print fmt t =
319       Array.iteri begin fun state ns ->
320         Format.eprintf "%a -> %a\n" State.print state ns_print ns;
321       end t
322
323
324     let eval_trans auto tree parent res1 res2 = assert false
325
326     let rec uniq = function
327       | ([] | [ _ ]) as l -> l
328       | e1 :: ((e2 :: ll) as l) -> if e1 == e2 then uniq l
329         else e1 :: e2 :: (uniq ll);;
330
331     let bottom_up_run auto tree (query, pat) =
332       let array = time ~msg:"Timing text query" (Tree.full_text_query query tree) pat in
333       let leaves = Array.to_list array in
334       let states = auto.states in
335       let res_len = (StateSet.max_elt states) + 1 in
336       let empty_slot = Array.create res_len U.NS.empty in
337       let nil_res = auto.bottom_states, empty_slot in
338       let cache = Cache.Lvl3.create 1024 L3JIT.dummy in
339       let rec loop_leaves l acc =
340         match l with
341             [] -> acc
342           | node :: ll ->
343             let res, lll = bottom_up_next node ll Tree.nil in
344             if (lll <> []) then
345               begin
346                 eprintf "Leftover nodes: %i\n" (List.length lll);
347               end;
348             res
349
350       and bottom_up_next node rest stop =
351         let fs = Tree.first_child tree node in
352         let res1 =
353           if fs == Tree.nil then nil_res
354           else full_top_down_run auto states tree fs
355         in
356         move_up node res1 true rest stop
357
358       and move_up node res is_left rest stop =
359         if node == stop then res, rest
360         else
361           let prev_sibling = Tree.prev_sibling tree node in
362           let is_left' = prev_sibling == Tree.nil in
363           let real_parent = Tree.parent tree node in
364           let parent =
365             if is_left' then real_parent else max (Tree.first_child tree real_parent) stop
366           in
367           (* let parent = if is_left' then Tree.parent tree node else prev_sibling in *)
368           let (s1, sl1), (s2, sl2), rest' =
369             if is_left then match rest with
370                 [] -> res, nil_res, rest
371               | next :: rest' ->
372                 if Tree.is_right_descendant tree node next
373                 then
374                   let res2, rest' = bottom_up_next next rest' node in
375                   res, res2, rest'
376                 else res, nil_res, rest
377             else
378               nil_res, res, rest
379           in
380           let tag = Tree.tag tree node in
381           let id1 = Uid.to_int s1.StateSet.Node.id in
382           let id2 = Uid.to_int s2.StateSet.Node.id in
383           let code =
384             let code = Cache.Lvl3.find cache tag id1 id2 in
385             if code == L3JIT.dummy then
386               let trl =
387                 StateSet.fold
388                   (fun q acc ->
389                     List.fold_left (fun acc' (labels, tr) ->
390                       if labels == TagSet.any || TagSet.mem tag labels
391                       then Translist.cons tr acc' else acc')
392                       acc
393                       (Hashtbl.find auto.trans q)
394                   )
395                   states
396                   Translist.nil
397               in
398               let code = L3JIT.gen_code auto trl s1 s2 in
399               Cache.Lvl3.add cache tag id1 id2 code; code
400             else code
401           in
402           let res' = code empty_slot sl1 sl2 tree node in
403           move_up parent res' is_left' rest' stop
404       in
405       let _, slot = loop_leaves leaves (nil_res) in
406       slot.(StateSet.min_elt auto.topdown_marking_states)
407
408 let get_trans g auto tag states =
409   StateSet.fold (fun q tr_acc ->
410     List.fold_left
411       (fun ((lstates, rstates, tacc) as acc) (ts, trs) ->
412         if TagSet.mem (Tag.translate tag) ts then
413           if not (TagSet.mem Tag.attribute ts) && Grammar2.is_attribute g tag
414           then acc
415               else
416             let _, _, _, phi = Transition.node trs in
417                 let l, r = Formula.st phi in
418                 (StateSet.union l lstates,
419                  StateSet.union r rstates,
420                  Translist.cons trs tacc)
421         else acc)
422       tr_acc (Hashtbl.find auto.trans q)
423   ) states (StateSet.empty, StateSet.empty, Translist.nil)
424
425 (*  Grammar run *)
426 let dispatch_param0 conf id2 y0 y1 =
427   match conf with
428   | Grammar2.C0 | Grammar2.C2 -> Grammar2.Node0 id2
429   | Grammar2.C1 | Grammar2.C5 -> Grammar2.Node1(id2,y0)
430   | Grammar2.C3 | Grammar2.C6 -> y0
431   | Grammar2.C4 -> Grammar2.Node2(id2, y0, y1)
432
433 let dispatch_param1 conf id2 y0 y1 =
434   match conf with
435   | Grammar2.C2 -> y0
436   | Grammar2.C3 -> Grammar2.Node0 id2
437   | Grammar2.C5 -> y1
438   | Grammar2.C6 -> Grammar2.Node1(id2, y1)
439   | _ -> Grammar2.dummy_param
440
441     module K_down = struct
442       type t = Grammar2.n_symbol * StateSet.t
443       let hash (x,y) = HASHINT2(Node.to_int x, Uid.to_int y.StateSet.Node.id)
444       let equal (x1,y1) (x2,y2) = x1 == x2 && y1 == y2
445     end
446
447     module K_up = struct
448       type t = Grammar2.n_symbol * StateSet.t * StateSet.t * StateSet.t
449       let hash (a,b,c,d) =
450         HASHINT4 (Node.to_int a,
451                   Uid.to_int b.StateSet.Node.id,
452                   Uid.to_int c.StateSet.Node.id,
453                   Uid.to_int d.StateSet.Node.id)
454       let equal (a1, b1, c1, d1) (a2, b2, c2, d2) =
455         a1 == a2 && b1  == b2 && c1 == c2 && d1 == d2
456     end
457
458     module DCache =
459       struct
460         include Hashtbl.Make(K_down)
461         let dummy = StateSet.singleton State.dummy
462         let notfound l = l.(0) == dummy && l.(1) == dummy
463         let find h k =
464           try
465             find h k
466           with
467             Not_found ->
468               let a = [| dummy; dummy |] in
469               add h k a;
470               a
471       end
472     module UCache = Hashtbl.Make(K_up)
473     type result = {
474       in0 : StateSet.t;
475       in1 : StateSet.t;
476       out0 : StateSet.t * U.t;
477       out1 : StateSet.t * U.t;
478       main : StateSet.t * U.t
479     }
480     let mk_empty e =
481       { in0 = StateSet.empty;
482         in1 = StateSet.empty;
483         out0 = e;
484         out1 = e;
485         main = e
486       }
487     let mk_nil s v  =
488       {
489         mk_empty (s,v) with
490           out0 = StateSet.empty,v;
491           out1 = StateSet.empty,v;
492       }
493
494     let grammar_run auto g () =
495       let dummy_leaf = Grammar2.dummy_param in
496       let dummy_set = StateSet.singleton State.dummy in
497       let res_len = (StateSet.max_elt auto.states) + 1 in
498       let empty_slot = Array.create res_len U.NS.empty in
499       let nil_res = mk_nil auto.bottom_states empty_slot in
500       let empty_res = mk_empty (StateSet.empty, empty_slot) in
501       let cache3 = L3JIT.create () in
502       let dummy2 = (StateSet.empty, StateSet.empty, Translist.nil) in
503       let cache2 = Cache.Lvl2.create 512 dummy2 in
504       let rule_counter = ref 0 in
505       let preorder_counter = ref 0 in
506       let dcache = DCache.create 1023 in
507       let ucache = UCache.create 1023 in
508       let term_array = [| StateSet.empty; StateSet.empty |] in
509       let get_trans tag states =
510         let c = Cache.Lvl2.find cache2 tag (Uid.to_int states.StateSet.Node.id) in
511         if c == dummy2 then
512           let c = get_trans g auto tag states in
513           begin
514             Cache.Lvl2.add cache2 tag (Uid.to_int states.StateSet.Node.id) c;
515             c
516           end
517         else c
518       in
519       let lambda = ref 0 in
520       let rec start_loop idx states =
521         TRACE("grammar", 2, __ "Node %i\n%!" (Node.to_int idx));
522         if states == dummy_set then nil_res else
523         if idx < Node.null then nil_res
524         else begin
525           let symbol = Grammar2.start_tag g idx in
526           let fc = Grammar2.start_first_child g idx in
527           let ns = Grammar2.start_next_sibling g fc in
528           if Grammar2.is_terminal g symbol then
529             let t = Grammar2.terminal symbol in
530               terminal_loop t states (Grammar2.Leaf (~-1,0,term_array, fc)) (Grammar2.Leaf (~-1,1,term_array, ns))
531           else
532             let nt = Grammar2.non_terminal symbol in
533             incr lambda;
534             let lmbd = !lambda in
535             let y0 = (Grammar2.Leaf (lmbd,0, term_array, fc))
536             and y1 = (Grammar2.Leaf (lmbd,1, term_array, ns)) in
537             rule_loop nt states y0 y1
538         end
539       and rule_loop (t : Grammar2.n_symbol) states y0 y1 =
540         if t = Node.nil || states == dummy_set then nil_res else
541           let () = incr rule_counter in
542           if !rule_counter land 65535 == 0 then begin Gc.minor() end;
543 (*        let k = (t, states) in*)
544 (*        let pstates = DCache.find dcache k in
545           let notfound = DCache.notfound pstates in *)
546           let rhs = Grammar2.get_rule g t in
547           let id1 = Grammar2.get_id1 rhs in
548           let id2 = Grammar2.get_id2 rhs in
549           let conf = Grammar2.get_conf rhs in
550 (*        if notfound then*)
551             let ny0 = dispatch_param0 conf id2 y0 y1 in
552             let ny1 = dispatch_param1 conf id2 y0 y1 in
553             let res = dispatch_loop id1 states ny0 ny1 in
554 (*          pstates.(0) <- res.in0;
555             pstates.(1) <- res.in1; *)
556             res (*
557             UCache.add ucache (t, states, fst res.out0, fst res.out1)
558               res.main;
559             let h = Hashtbl.create 7 in
560             for i = 0 to res_len - 1 do
561               Hashtbl.add h (0, i) (snd res.out0).(i);
562               Hashtbl.add h (1, i) (snd res.out1).(i);
563             done;
564             { res with
565               main = ((fst res.main), (U.close h (snd res.main)));
566             } *)
567 (*
568             else
569               let res0 = partial_loop y0 pstates.(0) in
570               let res1 = partial_loop y1 pstates.(1) in
571               let k2 = (t, states, fst res0.main, fst res1.main) in
572               let s, r =
573                 try
574                   UCache.find ucache k2
575                 with
576                 Not_found ->
577                   let ores0 = { res0 with main = fst res0.main, U.var 0 (snd res0.main) }
578                   and ores1 = { res1 with main = fst res1.main, U.var 1 (snd res1.main) }
579                   in
580                   let res = dispatch_loop id1 states (Grammar2.Cache (0,ores0)) (Grammar2.Cache (1, ores1)) in
581                   UCache.add ucache k2 res.main;
582                   res.main
583               in
584               let h = Hashtbl.create 7 in
585               for i = 0 to res_len - 1 do
586                 Hashtbl.add h (0, i) (snd res0.main).(i);
587                 Hashtbl.add h (1, i) (snd res1.main).(i);
588               done;
589               { in0 = pstates.(0);
590                 in1 = pstates.(1);
591                 out0 = res0.main;
592                 out1 = res1.main;
593                 main = s, U.close h r;
594               }
595 *)
596       and dispatch_loop id1 states ny0 ny1 =
597           if Grammar2.is_non_terminal g id1 then
598             rule_loop (Grammar2.non_terminal id1) states ny0 ny1
599           else
600             terminal_loop (Grammar2.terminal id1) states ny0 ny1
601
602       and terminal_loop (symbol : Grammar2.t_symbol) states y0 y1 =
603
604         if symbol == Grammar2.nil_symbol || symbol = Node.nil || states == dummy_set then nil_res else begin
605           let tag = Grammar2.tag symbol in
606           let lst, rst, trans = get_trans tag states in
607           let res0 = partial_loop y0 lst in
608           let res1 = partial_loop y1 rst in
609           let s1, slot1 = res0.main
610           and s2, slot2 = res1.main in
611           let opcode = L3JIT.find cache3 trans s1 s2 in
612           let node = Node.of_int !preorder_counter in
613           incr preorder_counter;
614           let res =
615             if opcode == L3JIT.dummy then
616               (L3JIT.cache_apply cache3 auto trans s1 s2) empty_slot slot1 slot2 (Obj.magic ()) node
617             else
618               opcode empty_slot slot1 slot2 (Obj.magic())  (node)
619           in
620           { in0 = lst;
621             in1 = rst;
622             out0 = res0.main;
623             out1 = res1.main;
624             main = res }
625         end
626
627       and partial_loop l states =
628         if l == dummy_leaf then nil_res else
629           match l with
630           | Grammar2.Cache (_, r) -> r
631           | Grammar2.Leaf (_,_, _, id) -> start_loop id states
632           | Grammar2.Node0 id ->
633             if (Grammar2.terminal id) == Grammar2.nil_symbol then nil_res
634             else
635               rule_loop (Grammar2.non_terminal id) states dummy_leaf dummy_leaf
636
637           | Grammar2.Node1 (id, y0) ->
638             rule_loop (Grammar2.non_terminal id) states y0 dummy_leaf
639           | Grammar2.Node2 (id, y0, y1) ->
640             if Grammar2.is_terminal g id then
641             terminal_loop (Grammar2.terminal id) states y0 y1
642             else
643               rule_loop (Grammar2.non_terminal id) states y0 y1
644       in
645
646       let (_, slot) = (start_loop (Node.null) auto.init).main in
647       slot.(StateSet.min_elt auto.topdown_marking_states)
648     ;;
649
650
651     (* Slow reference top-down implementation *)
652     let naive_top_down auto tree root states ctx =
653       let res_len = StateSet.max_elt auto.states + 1 in
654       let empty_slot = Array.create res_len U.NS.empty in
655       let nil_res = auto.bottom_states, empty_slot in
656       let cache3 = L3JIT.create () in
657       let l3jit_dispatch trl s1 s2 t sl1 sl2 =
658         let f = L3JIT.find cache3 trl s1 s2 in
659         if f == L3JIT.dummy then (L3JIT.cache_apply cache3 auto trl s1 s2) empty_slot sl1 sl2 tree t
660         else f empty_slot sl1 sl2 tree t
661       in
662       let dummy = Translist.nil, StateSet.singleton State.dummy, StateSet.singleton State.dummy in
663       let cache2 = Cache.Lvl2.create 512 dummy in
664       let rec loop t states ctx =
665         if states == StateSet.empty then nil_res
666         else if t == Tree.nil then (*StateSet.inter states auto.bottom_states, empty_slot *) nil_res
667         else
668           let tag = Tree.tag tree t in
669
670           let trans, lstates, rstates =
671             let c = Cache.Lvl2.find cache2 (Uid.to_int states.StateSet.Node.id) tag in
672             if c == dummy then
673               let c = Ata.get_trans auto states tag in
674               Cache.Lvl2.add cache2 (Uid.to_int states.StateSet.Node.id) tag c;
675               c
676             else c
677           in
678           let s1, res1 = loop (Tree.first_child tree t) lstates ctx
679           and s2, res2 = loop (Tree.next_sibling tree t) rstates ctx in
680           l3jit_dispatch trans s1 s2 t res1 res2
681       in
682       loop root states ctx
683
684
685
686
687     let naive_top_down_run auto tree root =
688       let res, slot = naive_top_down auto tree root auto.init (Tree.closing tree root) in
689       slot.(StateSet.min_elt auto.topdown_marking_states)
690
691
692
693     let eval_form auto s1 s2 f =
694       let rec loop f =
695         match Formula.expr f with
696           | Formula.False | Formula.True | Formula.Pred _ -> f
697           | Formula.Atom(`Left, b, q) ->
698               Formula.of_bool (b == (StateSet.mem q s1))
699           | Formula.Atom (`Right, b, q) ->
700               Formula.of_bool(b == (StateSet.mem q s2))
701           | Formula.Atom (`Epsilon, _, _) -> assert false
702
703           | Formula.Or(f1, f2) ->
704               let b1 = loop f1 in
705               let b2 = loop f2 in
706               Formula.or_pred b1 b2
707           | Formula.And(f1, f2) ->
708               let b1 = loop f1 in
709               let b2 = loop f2 in
710               Formula.and_pred b1 b2
711       in
712       loop f
713
714     let eval_trans auto s1 s2 trans =
715       Translist.fold
716         (fun t ((a_st, mark) as acc)->
717            let q, _, m, f = Transition.node t in
718            let form = eval_form auto s1 s2 f in
719            match Formula.expr form with
720              | Formula.True -> StateSet.add q a_st, mark || m
721              | Formula.False -> acc
722              | _ -> assert false
723         ) trans (StateSet.empty, false)
724
725
726     let set a i v =
727       TRACE("twopass", 2, __ "Setting node %i to state %a\n%!"
728         i StateSet.print v);
729       a.(i) <- v
730
731     let twopass_top_down states_array auto tree root states ctx =
732       let dummy3 = StateSet.singleton State.dummy in
733       let cache3 = Cache.Lvl3.create 512  dummy3 in
734       let dummy2 = Translist.nil, StateSet.singleton State.dummy, StateSet.singleton State.dummy in
735       let cache2 = Cache.Lvl2.create 512 dummy2 in
736       let attributes = TagSet.inj_positive (Tree.attribute_tags tree) in
737       let rec loop t states ctx =
738         if t == Tree.nil then auto.bottom_states
739         else if states == StateSet.empty then
740           let () = set states_array (Node.to_int t) auto.bottom_states in
741           auto.bottom_states
742         else
743           let tag = Tree.tag tree t in
744           TRACE("twopass", 2, __ "Traversing node %i (tag %s) in states %a\n%!" (Node.to_int t) (Tag.to_string tag)
745           StateSet.print states
746           );
747           let trans, lstates, rstates =
748             let c = Cache.Lvl2.find cache2 (Uid.to_int states.StateSet.Node.id) tag in
749             if c == dummy2 then
750               let c = Ata.get_trans ~attributes:attributes auto states tag in
751               Cache.Lvl2.add cache2 (Uid.to_int states.StateSet.Node.id) tag c;
752               c
753             else c
754           in
755           TRACE("twopass", 2, __ "\nTransitions are:\n%!");
756           TRACE("twopass", 2, __ "\nTransitions are:\n%a\n%!" 
757             Translist.print trans
758           );
759           let s1 = loop (Tree.first_child tree t) lstates ctx
760           and s2 = loop (Tree.next_sibling tree t) rstates ctx in
761           let st =
762             let c = Cache.Lvl3.find cache3
763               (Uid.to_int s1.StateSet.Node.id)
764               (Uid.to_int s2.StateSet.Node.id)
765               (Uid.to_int trans.Translist.Node.id)
766             in
767             if c == dummy3 then
768               let c, _ = eval_trans auto s1 s2 trans in
769               Cache.Lvl3.add cache3
770                 (Uid.to_int s1.StateSet.Node.id)
771                 (Uid.to_int s2.StateSet.Node.id)
772                 (Uid.to_int trans.Translist.Node.id) c;c
773             else c
774           in
775           set states_array (Node.to_int t) st;
776           st
777       in
778       loop root states ctx, (dummy2, cache2)
779
780
781     type action = Nop | Mark | Dummy
782
783     let twopass_top_down_scan states_array (dummy2, cache2) auto tree root states ctx =
784       let attributes = TagSet.inj_positive (Tree.attribute_tags tree) in
785       let cache3 = Cache.Lvl3.create 512  Dummy in
786       let rec loop t states acc =
787         if states == StateSet.empty || t = Tree.nil then acc
788         else
789           let tag = Tree.tag tree t in
790           let trans, _, _ =
791           let c = Cache.Lvl2.find cache2 (Uid.to_int states.StateSet.Node.id) tag in
792             if c == dummy2 then
793               let c = Ata.get_trans  ~attributes:attributes auto states tag in 
794               Cache.Lvl2.add cache2 (Uid.to_int states.StateSet.Node.id) tag c;
795               c
796             else c
797           in
798           let fs = Tree.first_child tree t in
799           let ns = Tree.next_sibling tree t in
800           let s1 = if fs != Tree.nil then states_array.(Node.to_int fs) else auto.bottom_states
801           and s2 = if ns != Tree.nil then states_array.(Node.to_int ns) else auto.bottom_states
802           in
803           let mark =
804             let c = Cache.Lvl3.find cache3
805               (Uid.to_int s1.StateSet.Node.id)
806               (Uid.to_int s2.StateSet.Node.id)
807               (Uid.to_int trans.Translist.Node.id)
808             in
809             if c == Dummy then
810               let _, c = eval_trans auto s1 s2 trans in
811               let c = if c then Mark else Nop in
812                Cache.Lvl3.add cache3
813                  (Uid.to_int s1.StateSet.Node.id)
814                  (Uid.to_int s2.StateSet.Node.id)
815                  (Uid.to_int trans.Translist.Node.id) c;c
816             else c
817           in
818           TRACE("twopass", 2, __ "Evaluating node %i (tag %s).\n%!States=%a\n%!"
819             (Node.to_int t)
820             (Tag.to_string tag)
821             StateSet.print states
822           );
823           TRACE("twopass", 2, __ "Translist=%a\nLeft=%a\nRight=%a\nMark=%s\n\n%!"
824             Translist.print trans
825             StateSet.print s1
826             StateSet.print s2
827             (match mark with
828               Dummy -> "Dummy"
829             | Mark -> "Mark"
830             | Nop -> "Nop"));
831           if mark == Mark then
832             loop ns s2 (loop fs s1 (U.NS.snoc acc t))
833           else
834             loop ns s2 (loop fs s1 acc)
835       in
836       loop root states U.NS.empty
837
838     let twopass_top_down_run auto tree root =
839       let len = Node.to_int (Tree.closing tree root) + 1 in
840       TRACE("twopass", 2, __ "Creating array of size: %i\n%!" len);
841       let states_array = Array.make len StateSet.empty in
842       let _, cache =
843         twopass_top_down states_array auto tree root auto.init Tree.nil
844       in
845       twopass_top_down_scan states_array cache auto tree root auto.init Tree.nil
846
847
848
849
850
851
852
853
854
855
856   end
857