Remove useless cycles in the generated automaton. A state now only has at most one...
[tatoo.git] / src / xpath / compile.ml
index 6987b4c..e8ab6fc 100644 (file)
@@ -39,7 +39,7 @@ let root_set = QNameSet.singleton QName.document
    holds.
 *)
 
-let compile_axis_test axis (test,kind) phi trans states=
+let compile_axis_test axis (test,kind) phi trans states =
   let q = State.make () in
   let phi = match kind with
     Tree.NodeKind.Node -> phi
@@ -66,11 +66,10 @@ let compile_axis_test axis (test,kind) phi trans states=
          states)
     | Descendant true ->
         let q' = State.make () in
-        (F.or_ (F.stay q) (F.first_child q'),
-         (q', [ test => phi;
-               QNameSet.any => F.first_child q' ++ F.next_sibling q';
-             ])::
-         (q, [ test => phi]):: trans,
+        (F.stay q ++ F.first_child q',
+         (q', [ QNameSet.any => F.stay q ++ F.first_child q' ++ F.next_sibling q';
+              ])::
+           (q, [ test => phi]):: trans,
          states)
 
     | Parent ->
@@ -82,13 +81,12 @@ let compile_axis_test axis (test,kind) phi trans states=
          (q' @: states))
 
     | Ancestor self ->
-        let q' = State.make () in
-        let move = F.parent q ++ F.previous_sibling q' in
-        (if self then F.stay q else move),
-        (q, [ test => phi;
-              QNameSet.any => move ])
-        :: (q', [ QNameSet.any => move ]) :: trans,
-        (q' @: states)
+      let q' = State.make () in
+      let move = F.parent q' ++ F.previous_sibling q' in
+      (if self then F.stay q ++ F.stay q' else F.stay q'),
+      (q', [ QNameSet.any => move ++ F.parent q])
+      :: (q, [ test => phi ]) :: trans,
+      (q' @: states)
 
     | FollowingSibling | PrecedingSibling ->
         let move =
@@ -236,6 +234,12 @@ let path p =
       nasts) (StateSet.empty, StateSet.empty, [], StateSet.empty) p
   in
   let builder = Ata.Builder.make () in
+  (** ensure that we have a single selecting state at the end *)
+  let phi_sel = StateSet.fold (fun q acc -> F.or_ (F.stay q) acc) mstates F.false_ in
+  let q_sel = State.make () in
+  let states = StateSet.add q_sel states in
+  let mstates = StateSet.singleton q_sel in
+  let trans = (q_sel, [QNameSet.any, phi_sel]) :: trans in
   StateSet.iter
     (Ata.Builder.add_state builder ~starting:true) sstates;
   StateSet.iter