packages feed

regex-tdfa 1.0.0 → 1.1.0

raw patch · 15 files changed

+2135/−985 lines, 15 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Text.Regex.TDFA.NewDFA: matchAll :: Regex -> String -> [MatchArray]
- Text.Regex.TDFA.NewDFA: matchCount :: Regex -> String -> Int
- Text.Regex.TDFA.NewDFA: matchOnce :: Regex -> String -> Maybe MatchArray
- Text.Regex.TDFA.NewDFA: matchTest :: Regex -> String -> Bool
- Text.Regex.TDFA.TDFA: isDFAFrontAnchored :: DFA -> Bool
+ Text.Regex.TDFA.Common: regex_isFrontAnchored :: Regex -> Bool
+ Text.Regex.TDFA.NewDFA.Engine: execMatch :: (Uncons text) => Regex -> Position -> Char -> text -> [MatchArray]
+ Text.Regex.TDFA.NewDFA.Engine_FA: execMatch :: (Uncons text) => Regex -> Position -> Char -> text -> [MatchArray]
+ Text.Regex.TDFA.NewDFA.Engine_NC: execMatch :: (Uncons text) => Regex -> Position -> Char -> text -> [MatchArray]
+ Text.Regex.TDFA.NewDFA.Engine_NC: instance Show WScratch
+ Text.Regex.TDFA.NewDFA.Engine_NC_FA: execMatch :: (Uncons text) => Regex -> Position -> Char -> text -> [MatchArray]
+ Text.Regex.TDFA.NewDFA.Tester: matchTest :: (Uncons text) => Regex -> text -> Bool
+ Text.Regex.TDFA.NewDFA.Uncons: class Uncons a
+ Text.Regex.TDFA.NewDFA.Uncons: instance Uncons (Seq Char)
+ Text.Regex.TDFA.NewDFA.Uncons: instance Uncons ByteString
+ Text.Regex.TDFA.NewDFA.Uncons: instance Uncons [Char]
+ Text.Regex.TDFA.NewDFA.Uncons: uncons :: (Uncons a) => a -> Maybe (Char, a)
+ Text.Regex.TDFA.Wrap: regex_isFrontAnchored :: Regex -> Bool
- Text.Regex.TDFA.Common: Regex :: DFA -> Index -> (Index, Index) -> (Tag, Tag) -> TrieSet DFA -> Array Tag OP -> Array GroupIndex [GroupInfo] -> CompOption -> ExecOption -> Regex
+ Text.Regex.TDFA.Common: Regex :: DFA -> Index -> (Index, Index) -> (Tag, Tag) -> TrieSet DFA -> Array Tag OP -> Array GroupIndex [GroupInfo] -> Bool -> CompOption -> ExecOption -> Regex
- Text.Regex.TDFA.Common: Simple' :: IntMap Instructions -> CharMap Transition -> Maybe Transition -> DT
+ Text.Regex.TDFA.Common: Simple' :: IntMap Instructions -> CharMap Transition -> Transition -> DT
- Text.Regex.TDFA.Common: dt_other :: DT -> Maybe Transition
+ Text.Regex.TDFA.Common: dt_other :: DT -> Transition
- Text.Regex.TDFA.TDFA: Simple' :: IntMap Instructions -> CharMap Transition -> Maybe Transition -> DT
+ Text.Regex.TDFA.TDFA: Simple' :: IntMap Instructions -> CharMap Transition -> Transition -> DT
- Text.Regex.TDFA.TDFA: dt_other :: DT -> Maybe Transition
+ Text.Regex.TDFA.TDFA: dt_other :: DT -> Transition
- Text.Regex.TDFA.TDFA: nfaToDFA :: ((Index, Array Index QNFA), Array Tag OP, Array GroupIndex [GroupInfo]) -> (CompOption -> ExecOption -> Regex)
+ Text.Regex.TDFA.TDFA: nfaToDFA :: ((Index, Array Index QNFA), Array Tag OP, Array GroupIndex [GroupInfo]) -> CompOption -> ExecOption -> Regex
- Text.Regex.TDFA.Wrap: Regex :: DFA -> Index -> (Index, Index) -> (Tag, Tag) -> TrieSet DFA -> Array Tag OP -> Array GroupIndex [GroupInfo] -> CompOption -> ExecOption -> Regex
+ Text.Regex.TDFA.Wrap: Regex :: DFA -> Index -> (Index, Index) -> (Tag, Tag) -> TrieSet DFA -> Array Tag OP -> Array GroupIndex [GroupInfo] -> Bool -> CompOption -> ExecOption -> Regex

Files

Text/Regex/TDFA/ByteString.hs view
@@ -8,6 +8,7 @@ This exports instances of the high level API and the medium level API of 'compile','execute', and 'regexec'. -}+{- By Chris Kuklewicz, 2009. BSD License, see the LICENSE file. -} module Text.Regex.TDFA.ByteString(   Regex  ,CompOption@@ -25,9 +26,12 @@ import Text.Regex.TDFA.ReadRegex(parseRegex) import Text.Regex.TDFA.String() -- piggyback on RegexMaker for String import Text.Regex.TDFA.TDFA(patternToRegex)-import Text.Regex.TDFA.Wrap(Regex(..),CompOption,ExecOption)+import Text.Regex.TDFA.Common(Regex(..),CompOption,ExecOption(captureGroups))+import Text.Regex.TDFA.Wrap() -{- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}+import Data.Maybe(listToMaybe)+import Text.Regex.TDFA.NewDFA.Engine(execMatch)+import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)  instance RegexContext Regex B.ByteString B.ByteString where   match = polymatch@@ -37,10 +41,11 @@   makeRegexOptsM c e source = makeRegexOptsM c e (B.unpack source)  instance RegexLike Regex B.ByteString where-  matchOnce r = matchOnce r . B.unpack-  matchAll r = matchAll r . B.unpack-  matchCount r = matchCount r . B.unpack-  matchTest r = matchTest r . B.unpack+  matchOnce r s = listToMaybe (matchAll r s)+  matchAll r s = execMatch r 0 '\n' s+  matchCount r s = length (matchAll r' s)+    where r' = r { regex_execOptions = (regex_execOptions r) {captureGroups = False} }+  matchTest = Tester.matchTest   matchOnceText regex source =      fmap (\ma -> let (o,l) = ma!0                  in (B.take o source
Text/Regex/TDFA/ByteString/Lazy.hs view
@@ -17,7 +17,7 @@  ,regexec  ) where -import Data.Array((!),elems)+import Data.Array.IArray((!),elems,amap) import qualified Data.ByteString.Lazy.Char8 as L  import Text.Regex.Base(MatchArray,RegexContext(..),RegexMaker(..),RegexLike(..))@@ -25,8 +25,13 @@ import Text.Regex.TDFA.ReadRegex(parseRegex) import Text.Regex.TDFA.String() -- piggyback on RegexMaker for String import Text.Regex.TDFA.TDFA(patternToRegex)-import Text.Regex.TDFA.Wrap(Regex(..),CompOption,ExecOption)+import Text.Regex.TDFA.Common(Regex(..),CompOption,ExecOption(captureGroups))+import Text.Regex.TDFA.Wrap() +import Data.Maybe(listToMaybe)+import Text.Regex.TDFA.NewDFA.Engine(execMatch)+import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)+ {- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}  instance RegexContext Regex L.ByteString L.ByteString where@@ -37,10 +42,11 @@   makeRegexOptsM c e source = makeRegexOptsM c e (L.unpack source)  instance RegexLike Regex L.ByteString where-  matchOnce r = matchOnce r . L.unpack-  matchAll r = matchAll r . L.unpack-  matchCount r = matchCount r . L.unpack-  matchTest r = matchTest r . L.unpack+  matchOnce r s = listToMaybe (matchAll r s)+  matchAll r s = execMatch r 0 '\n' s+  matchCount r s = length (matchAll r' s)+    where r' = r { regex_execOptions = (regex_execOptions r) {captureGroups = False} }+  matchTest = Tester.matchTest   matchOnceText regex source =      fmap (\ma ->             let (o32,l32) = ma!0@@ -54,8 +60,14 @@                ,L.drop (o+l) source))          (matchOnce regex source)   matchAllText regex source =-    map (fmap (\ol@(off32,len32) -> (L.take (fi len32) (L.drop (fi off32) source),ol)))-        (matchAll regex source)+    let go i _ _ | i `seq` False = undefined+        go i t [] = []+        go i t (x:xs) =+          let (off0,len0) = x!0+              trans pair@(off32,len32) = (L.take (fi len32) (L.drop (fi (off32-i)) t),pair)+              t' = L.drop (fi (off0+len0-i)) t+          in amap trans x : seq t' (go (i+off0+len0) t' xs) +    in go 0 source (matchAll regex source)  fi = fromIntegral 
Text/Regex/TDFA/Common.hs view
@@ -121,6 +121,7 @@                    ,regex_trie :: TrieSet DFA                    -- ^ All DFA states                    ,regex_tags :: Array Tag OP                   -- ^ information about each tag                    ,regex_groups :: Array GroupIndex [GroupInfo] -- ^ information about each group+                   ,regex_isFrontAnchored :: Bool                -- ^ used for optimizing execution                    ,regex_compOptions :: CompOption              --                     ,regex_execOptions :: ExecOption} @@ -178,7 +179,7 @@ -- | Internal to the DFA node data DT = Simple' { dt_win :: IntMap {- Source Index -} Instructions -- ^ Actions to perform to win                   , dt_trans :: CharMap Transition -- ^ Transition to accept Char-                  , dt_other :: Maybe Transition -- ^ Optional default accepting transition+                  , dt_other :: Transition -- ^ default accepting transition                   }         | Testing' { dt_test :: WhichTest -- ^ The test to perform                    , dt_dopas :: EnumSet DoPa -- ^ location(s) of the anchor(s) in the original regexp@@ -273,8 +274,7 @@                                   ,seeDTrans dtrans                                   ,")"]) (Map.assocs t) -  seeOther1 Nothing = "None"-  seeOther1 (Just (Transition {trans_many=dfa,trans_single=dfa2,trans_how=dtrans})) =+  seeOther1 (Transition {trans_many=dfa,trans_single=dfa2,trans_how=dtrans}) =     concat ["(MANY "            ,show (d_id dfa)            ,", SINGLE "
− Text/Regex/TDFA/NewDFA.hs
@@ -1,884 +0,0 @@--- | This is the "rewrite" of RunMutState ++ MutRun.  It is supposed--- to never backtrack in the consumption of the input.  This is more--- complicated then RunMutState which only considered a single--- starting offset, and MutRun which incremented the starting offset--- by one with each failed match.------ This is not optimized for speed.-module Text.Regex.TDFA.NewDFA(matchAll,matchOnce,matchCount,matchTest) where--import Control.Monad(when,forM,forM_,liftM2,foldM,join,MonadPlus(..),filterM)-import Data.Array.Base(unsafeRead,unsafeWrite,STUArray(..))--- #ifdef __GLASGOW_HASKELL__-import GHC.Arr(STArray(..))-import GHC.ST(ST(..))-import GHC.Prim(MutableByteArray#,RealWorld,Int#,sizeofMutableByteArray#,unsafeCoerce#)-{---- #else-import Control.Monad.ST(ST)-import Data.Array.ST(STArray)--- #endif--}-import Prelude hiding ((!!))--import Data.Array.MArray(MArray(..),unsafeFreeze,getAssocs)-import Data.Array.IArray(Array,bounds,assocs)---import qualified Data.Foldable as F-import qualified Data.IntMap.CharMap2 as CMap(lookup)-import Data.IntMap(IntMap)-import qualified Data.IntMap as IMap(null,toList,lookup,insert)-import Data.Ix(Ix,rangeSize,range)-import Data.Maybe(catMaybes,listToMaybe)-import Data.Monoid(Monoid(..))---import Data.IntSet(IntSet)-import qualified Data.IntSet as ISet(toAscList)-import qualified Data.Array.ST-import Data.Array.IArray((!))-import qualified Data.Array.MArray-import Data.List(partition,sort,foldl',sortBy,groupBy)-import Data.STRef-import qualified Control.Monad.ST.Lazy as L-import qualified Control.Monad.ST.Strict as S-import Data.Sequence(ViewL(..),viewl)-import qualified Data.Sequence as Seq--import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)-import qualified Text.Regex.TDFA.IntArrTrieSet as Trie-import Text.Regex.TDFA.Common hiding (indent)-import Text.Regex.TDFA.TDFA(isDFAFrontAnchored)----import Debug.Trace---- trace :: String -> a -> a--- trace _ a = a--err :: String -> a-err s = common_error "Text.Regex.TDFA.NewDFA"  s--{-# INLINE (!!) #-}-(!!) :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> S.ST s e-(!!) = unsafeRead-{-# INLINE set #-}-set :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> e -> S.ST s ()-set = unsafeWrite- -matchAll :: Regex -> String -> [MatchArray]-matchAll r s = execMatch r 0 '\n' s--matchOnce :: Regex -> String -> Maybe MatchArray-matchOnce r s = listToMaybe (matchAll r s)--matchCount :: Regex -> String -> Int-matchCount regexIn stringIn = length (matchAll regexNC stringIn)-  where regexNC = regexIn { regex_execOptions = (regex_execOptions regexIn) {captureGroups = False} }--matchTest :: Regex -> String -> Bool-matchTest regexIn stringIn = not (null (matchAll regexNC stringIn))-  where regexNC = regexIn { regex_execOptions = (regex_execOptions regexIn) {captureGroups = False,testMatch = True} }--execMatch :: Regex -> Position -> Char -> String -> [MatchArray]-execMatch (Regex { regex_dfa = dfaIn-                 , regex_init = startState-                 , regex_b_index = b_index-                 , regex_b_tags = b_tags_all-                 , regex_trie = trie-                 , regex_tags = aTags-                 , regex_groups = aGroups-                 , regex_compOptions = CompOption { multiline = newline }-                 , regex_execOptions = ExecOption { captureGroups = capture-                                                  , testMatch = _checkMatch }})-          offsetIn prevIn inputIn = L.runST runCaptureGroup where--{--  msg = "subCapture "++show subCapture-        ++ ", frontAnchored "++show (frontAnchored,(not newline,isDFAFrontAnchored dfaIn))-        ++ ", b_index "++show b_index-        ++ ", b_tags "++show b_tags-        ++ ", orbitTags "++show orbitTags--}--  subCapture,frontAnchored :: Bool-  !subCapture = capture && (1<=rangeSize (bounds aGroups))-  !frontAnchored = (not newline) && isDFAFrontAnchored dfaIn--  b_tags :: (Tag,Tag)-  !b_tags | subCapture = b_tags_all-          | otherwise = (0,1)--  orbitTags :: [Tag]-  !orbitTags = map fst . filter ((Orbit==).snd) . assocs $ aTags--  test :: WhichTest -> Index -> Char -> String -> Bool-  !test = mkTest newline         --  spawnStart :: (Tag,Tag) -> BlankScratch s -> Index -> MScratch s -> Position -> S.ST s Position-  spawnStart | frontAnchored = \ _ _ _ _ _ -> return maxBound-             | otherwise = spawnAt -- regardless of subCapture--  doActions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()-  doActions | subCapture = doAllActions-            | otherwise = \ _ _ _ -> return ()--  doFinalActions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()-  doFinalActions | subCapture = doAllActions-                 | otherwise = do01Actions--  comp :: C s-  comp | subCapture = {-# SCC "matchHere.comp" #-} ditzyComp'3 aTags-       | otherwise = comp01--  tagsToGroupsST | subCapture = tagsToAllGroupsST-                 | otherwise = tagsToGroup0ST--  runCaptureGroup :: L.ST s [MatchArray]-  runCaptureGroup = {-# SCC "runCaptureGroup" #-} do-    obtainNext <- L.strictToLazyST constructNewEngine-    let loop = do vals <- L.strictToLazyST obtainNext-                  if null vals -- force vals before defining valsRest-                    then return []-                    else do valsRest <- loop-                            return (vals ++ valsRest)-    loop----  constructNewEngine :: forall s. S.ST s (S.ST s [MatchArray])-  constructNewEngine =  {-# SCC "constructNewEngine" #-} do-    (SScratch s1In s2In restScratch@(_winQ,blank,_which)) <- newScratch b_index b_tags-    spawnAt b_tags blank startState s1In offsetIn-    storeNext <- newSTRef undefined-    writeSTRef storeNext (goNext storeNext restScratch s1In s2In dfaIn offsetIn prevIn inputIn)-    let obtainNext = join (readSTRef storeNext)-    return obtainNext--  goNext storeNext (winQ,blank,which) s1In' s2In' dfaIn' offsetIn' prevIn' inputIn' = {-# SCC "goNext" #-} do-    writeSTRef storeNext (err "obtainNext called while goNext is running!")-    eliminatedStateFlag <- newSTRef False-    eliminatedRespawnFlag <- newSTRef False-    let next s1 s2 did dt offset prev input = {-# SCC "goNext.next" #-}-          case dt of-            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->-              if test wt offset prev input-                then next s1 s2 did a offset prev input-                else next s1 s2 did b offset prev input-            Simple' {dt_win=w} -> do-              if IMap.null w then proceedNow s1 s2 did dt offset prev input-                else newWinnerThenProceed s1 s2 did dt offset prev input--        proceedNow | frontAnchored = proceedNowSingle-                   | otherwise = proceedNowMany--        proceedNowSingle s1 s2 did dt offset prev input = {-# SCC "goNext.proceedNowSingle" #-}-          case dt of-            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->-              if test wt offset prev input-                then proceedNow s1 s2 did a offset prev input-                else proceedNow s1 s2 did b offset prev input-            Simple' {dt_trans=t, dt_other=o} ->-              case input of-                [] -> finalizeWinners-                (c:input') -> do-                  case (CMap.lookup c t) `mplus` o of-                    Nothing -> return []-                    Just (Transition {trans_single=dfa',trans_how=dtrans}) ->-                      findTrans s1 s2 (d_id dfa') (d_dt dfa') dtrans offset c input'--        proceedNowMany s1 s2 did dt offset prev input = {-# SCC "goNext.proceedNowMany" #-}-          case dt of-            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->-              if test wt offset prev input-                then proceedNow s1 s2 did a offset prev input-                else proceedNow s1 s2 did b offset prev input-            Simple' {dt_trans=t, dt_other=o} ->-              case input of-                [] -> finalizeWinners-                (c:input') -> do-                  case (CMap.lookup c t) `mplus` o of-                    Nothing -> error "proceedNowMany found no destination (should always include startstate)"-                    Just (Transition {trans_many=dfa',trans_how=dtrans}) ->-                      findTrans s1 s2 (d_id dfa') (d_dt dfa') dtrans offset c input'---- compressOrbits gets all the current Tag-0 start information from--- the NFA states; then it loops through all the Orbit tags with--- compressOrbit.------ compressOrbit on such a Tag loops through all the NFS states'--- m_orbit record, discardind ones that are Nothing and discarding--- ones that are too new to care about (after the cutoff value).------ compressOrbit then groups the Orbits records by the Tag-0 start--- position and the basePos position.  Entried in different groups--- will never be comparable in the future so they can be processed--- separately.  Groups could probably be even more finely--- distinguished, as a futher optimization, but the justification will--- be tricky.------ Current Tag-0 values are at most offset and all newly spawned--- groups will have Tag-0 of at least (succ offset) so the current--- groups are closed to those spawned in the future.  The basePos may--- be as large as offset and may be overwritten later with values of--- offset or larger (and this will also involve deleting the Orbits--- record).  Thus there could be a future collision between a current--- group with basePos==offset and an updated record that acquires--- basePos==offset.  By excluding groups with basePos before the--- current offset the collision between existing and future records--- is avoided.------ An entry in a group can only collide with that group's--- descendents. compressOrbit sends each group to the compressGroup--- command.------ compressGroup on a single record checks whether it's Seq can be--- cleared and if so it will clear it (and set ordinal to Nothing but--- this this not particularly important).------ compressGroup on many records sorts and groups the members and zips--- the groups with their new ordinal value.  The comparision is based--- on the old ordinal value, then the inOrbit value, and then the (Seq--- Position) data.------ The old ordinals of the group will all be Nothing or all be Just,--- but this condition is neither checked nor violations detected.--- This comparision is justified because once records get different--- ordinals assigned they will never change places.------ The inOrbit Bool is only different if one of them has set the stop--- position to at most (succ offset).  They will obly be compared if--- the other one leaves, an its stop position will be at least offset.--- The previous sentence is justified by inspectin of the "assemble"--- function in the TDFA module: there is no (PostUpdate--- LeaveOrbitTask) so the largest possible value for the stop Tag is--- (pred offset). Thus the record with inOrbit==False would beat (be--- GT than) the record with inOrbit==True.------ The Seq comparison is safe because the largest existing Position--- value is (pred offset) and the smallest future Position value is--- offset.  The previous sentence is justified by inspectin of the--- "assemble" function in the TDFA module: there is no (PostUpdate--- EnterOrbitTags) so the largest possible value in the Seq is (pred--- offset).------ The updated Orbits get the new ordinal value and an empty (Seq--- Position).--        compressOrbits s1 did offset = do-          let getStart state = do start <- maybe (err "compressOrbit,1") (!! 0) =<< m_pos s1 !! state-                                  return (state,start)-              cutoff = offset - 50 -- Require: cutoff <= offset, MAGIC TUNABLE CONSTANT 50-          ss <- mapM getStart (ISet.toAscList did)-          let compressOrbit tag = do-                mos <- forM ss ( \ p@(state,_start) -> do-                                  mo <- fmap (IMap.lookup tag) (m_orbit s1 !! state)-                                  case mo of-                                    Just orbits | basePos orbits < cutoff -> return (Just (p,orbits))-                                                | otherwise -> return Nothing-                                    _ -> return Nothing )-                let compressGroup [((state,_),orbit)] | Seq.null (getOrbits orbit) = return ()-                                                      | otherwise =-                      set (m_orbit s1) state -                      . (IMap.insert tag $! (orbit { ordinal = Nothing, getOrbits = mempty}))-                      =<< m_orbit s1 !! state--                    compressGroup gs = do-                      let sortPos (_,b1) (_,b2) = compare (ordinal b1) (ordinal b2) `mappend`-                                                  compare (inOrbit b2) (inOrbit b1) `mappend`-                                                  comparePos (viewl (getOrbits b1)) (viewl (getOrbits b2))-                          groupPos (_,b1) (_,b2) = ordinal b1 == ordinal b2 && getOrbits b1 == getOrbits b2-                          gs' = zip [(1::Int)..] (groupBy groupPos . sortBy sortPos $ gs)-                      forM_ gs' $ \ (!n,eqs) -> do-                        forM_ eqs $ \ ((state,_),orbit) ->-                          set (m_orbit s1) state-                           . (IMap.insert tag $! (orbit { ordinal = Just n, getOrbits = mempty }))-                            =<< m_orbit s1 !! state-                let sorter ((_,a1),b1) ((_,a2),b2) = compare a1 a2 `mappend` compare (basePos b1) (basePos b2)-                    grouper ((_,a1),b1) ((_,a2),b2) = a1==a2 && basePos b1 == basePos b2-                    orbitGroups = groupBy grouper . sortBy sorter . catMaybes $ mos-                mapM_ compressGroup orbitGroups-          mapM_ compressOrbit orbitTags---- findTrans has to (part 1) decide, for each destination, "which" of--- zero or more source NFA states will be the chosen source.  Then it--- has to (part 2) perform the transition or spawn.  It keeps track of--- the starting index while doing so, and compares the earliest start--- with the stored winners.  (part 3) If some winners are ready to be--- released then the future continuation of the search is placed in--- "storeNext".  If no winners are ready to be released then the--- computation continues immediately.--        findTrans s1 s2 did' dt' dtrans offset prev' input' =  {-# SCC "goNext.findTrans" #-} do-          -- findTrans part 0-          -- MAGIC TUNABLE CONSTANT 100 (and 100-1). TODO: (offset .&. 127 == 127) instead?-          when (not (null orbitTags) && (offset `rem` 100 == 99)) (compressOrbits s1 did' offset)-          -- findTrans part 1-          let findTransTo (destIndex,sources) | IMap.null sources =-                set which destIndex ((-1,Instructions { newPos = [(0,SetPost)], newOrbits = Nothing })-                                    ,blank_pos blank,mempty)-                                              | otherwise = do-                let prep (sourceIndex,(_dopa,instructions)) = {-# SCC "goNext.findTrans.prep" #-} do-{--                      ms1 <- showMS s1 sourceIndex-                      let msg = unlines $ [ "findTrans prep: "++show (sourceIndex,destIndex) ++ " at offset "++show offset ++ "for d_id of "++show did'-                                          , ms1-                                          , show instructions-                                          ]-                      trace msg $ do--}-                      pos <- maybe (err $ "findTrans,1 : "++show (sourceIndex,destIndex,did')) return-                               =<< m_pos s1 !! sourceIndex-                      orbit <- m_orbit s1 !! sourceIndex-                      let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)-                      return ((sourceIndex,instructions),pos,orbit')-                    challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.findTrans.challenge" #-} do-                      check <- comp offset x1 (newPos ins1) x2 (newPos ins2)-{--                      ms1 <- showMS s1 _si1-                      ms2 <- showMS s1 _si2-                      let msg = unlines $ [ "findTrans challenge: "++show ((_si1,_si2),destIndex) ++ " at offset "++show offset ++ "for d_id of "++show did'-                                          , ms1-                                          , show ins1-                                          , show _o1-                                          , ms2-                                          , show ins2-                                          , show _o2-                                          , "Result "++show check-                                          ]-                      trace msg $ do--}-                      if check==LT then return x2 else return x1-                (first:rest) <- mapM prep (IMap.toList sources)-                set which destIndex =<< foldM challenge first rest-          let dl = IMap.toList dtrans-          mapM_ findTransTo dl-          -- findTrans part 2-          let performTransTo (destIndex,_) = {-# SCC "goNext.findTrans.performTransTo" #-} do-                x@((sourceIndex,_instructions),_pos,_orbit') <- which !! destIndex-                if sourceIndex == (-1)-                  then spawnStart b_tags blank destIndex s2 (succ offset)-                  else updateCopy doActions x offset s2 destIndex-          earlyStart <- fmap minimum $ mapM performTransTo dl-          -- findTrans part 3-          earlyWin <- readSTRef (mq_earliest winQ)-          if earlyWin < earlyStart -            then do-              winners <- fmap (foldl' (\ rest ws -> ws : rest) []) $-                           getMQ earlyStart winQ-              writeSTRef storeNext (next s2 s1 did' dt' (succ offset) prev' input')-              mapM (tagsToGroupsST aGroups) winners-            else do-              let offset' = succ offset in seq offset' $ next s2 s1 did' dt' offset' prev' input'---- The "newWinnerThenProceed" can find both a new non-empty winner and--- a new empty winner.  A new non-empty winner can cause some of the--- NFA states that comprise the DFA state to be eliminated, and if the--- startState is eliminated then it must then be respawned.  And--- imperative flag setting and resetting style is used.------ A non-empty winner from the startState might obscure a potential--- empty winner (form the startState at the current offset).  This--- winEmpty possibility is also checked for. (unit test pattern ".*")--- (futher test "(.+|.+.)*" on "aa\n")--        newWinnerThenProceed s1 s2 did dt offset prev input = {-# SCC "goNext.newWinnerThenProceed" #-}-          case dt of-            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->-              if test wt offset prev input-                then newWinnerThenProceed s1 s2 did a offset prev input-                else newWinnerThenProceed s1 s2 did b offset prev input-            Simple' {dt_win=w} -> do-              let prep x@(sourceIndex,instructions) = {-# SCC "goNext.newWinnerThenProceed.prep" #-} do-                    pos <- maybe (err "newWinnerThenProceed,1") return =<< m_pos s1 !! sourceIndex-                    startPos <- pos !! 0-                    orbit <- m_orbit s1 !! sourceIndex-                    let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)-                    return (startPos,(x,pos,orbit'))-                  challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.newWinnerThenProceed.challenge" #-} do-                    check <- comp offset x1 (newPos ins1) x2 (newPos ins2)-{--                    ms1 <- showMS s1 _si1-                    ms2 <- showMS s1 _si2-                    let msg = unlines $ [ "newWinnerThenProceed challenge: "++show (_si1,_si2) ++ " at offset "++show offset-                                        , ms1-                                        , show ins1-                                        , show _o1-                                        , ms2-                                        , show ins2-                                        , show _o2-                                        , "Result "++show check-                                        ]-                    trace msg $ do--}-                    if check==LT then return x2 else return x1-              prep'd <- mapM prep (IMap.toList w)-              let (emptyFalse,emptyTrue) = partition ((offset >) . fst) prep'd-              mayID <- {-# SCC "goNext.newWinnerThenProceed.mayID" #-}-                       case map snd emptyFalse of-                        [] -> return Nothing-                        (first:rest) -> do-                          best@((_sourceIndex,_instructions),bp,_orbit') <- foldM challenge first rest-                          newWinner offset best-                          startWin <- bp !! 0-                          let states = ISet.toAscList did-                              keepState i1 = do-                                pos <- maybe (err "newWinnerThenProceed,2") return =<< m_pos s1 !! i1-                                startsAt <- pos !! 0-                                let keep = (startsAt <= startWin) || (offset <= startsAt)-                                when (not keep) $ do-                                  writeSTRef eliminatedStateFlag True-                                  when (i1 == startState) (writeSTRef eliminatedRespawnFlag True)-                                return keep-                          states' <- filterM keepState states-                          changed <- readSTRef eliminatedStateFlag-                          if changed then return (Just states') else return Nothing-              case emptyTrue of-                [] -> case IMap.lookup startState w of-                       Nothing -> return ()-                       Just ins -> winEmpty offset ins-                [first] -> newWinner offset (snd first)-                _ -> err "newWinnerThenProceed,3 : too many emptyTrue values"-              case mayID of-                Nothing -> proceedNow s1 s2 did dt offset prev input-                Just states' -> do-                  writeSTRef eliminatedStateFlag False-                  respawn <- readSTRef eliminatedRespawnFlag-                  if respawn-                    then do-                      writeSTRef eliminatedRespawnFlag False-                      spawnStart b_tags blank startState s1 (succ offset)-                      let dfa' = Trie.lookupAsc trie (sort (states'++[startState]))-                      proceedNow s1 s2 (d_id dfa') (d_dt dfa') offset prev input-                    else do-                      let dfa' = Trie.lookupAsc trie states'-                      proceedNow s1 s2 (d_id dfa') (d_dt dfa') offset prev input--        winEmpty preTag winInstructions = {-# SCC "goNext.winEmpty" #-} do-          newerPos <- newA_ b_tags-          copySTU (blank_pos blank) newerPos-          set newerPos 0 preTag-          doFinalActions preTag newerPos (newPos winInstructions)-          putMQ (WScratch newerPos) winQ-                -        newWinner preTag ((_sourceIndex,winInstructions),oldPos,_newOrbit) = {-# SCC "goNext.newWinner" #-} do-          newerPos <- newA_ b_tags-          copySTU oldPos newerPos-          doFinalActions preTag newerPos (newPos winInstructions)-          putMQ (WScratch newerPos) winQ--        finalizeWinners = do-          winners <- fmap (foldl' (\ rest mqa -> mqa_ws mqa : rest) []) $-                       readSTRef (mq_list winQ) -- reverses the winner list-          resetMQ winQ-          writeSTRef storeNext (return [])-          mapM (tagsToGroupsST aGroups) winners--    -- goNext then ends with the next statement-    next s1In' s2In' (d_id dfaIn') (d_dt dfaIn') offsetIn' prevIn' inputIn'--{-# INLINE do01Actions #-}-do01Actions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()-do01Actions preTag pos ins = doAllActions preTag pos (filter ((1>=) . fst) ins)--{-# INLINE doAllActions #-}-doAllActions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()-doAllActions preTag pos ins = mapM_ doAction ins where-  postTag = succ preTag-  doAction (tag,SetPre) = set pos tag preTag-  doAction (tag,SetPost) = set pos tag postTag-  doAction (tag,SetVal v) = set pos tag v---{---Lets say that NFA states start at positions 0,1,2,3,4,5 and offset is 5.-Thus none are in the startState.-We are about to process the 6th character.-The first winner is now found, and it starts with the index 2 and ends at index 5 (always the offset).-In addition a null winner starting and ending at 5 is found (between 5th and 6th characters).-Lets also say that the 0,2,4 NFA states _may_ transition next to include the startState-position 0 -> keep (might win startState, which is okay)-position 1 -> keep (normal keep case)-position 2 -> keep (just created winner, may be extended)-position 3 -> drop (normal drop case)-position 4 -> drop (must not win startState)-position 5 -> keep (just created empty winner)--if "position 0" does feed a start state then a new one will be respawn, starting with "position 6".---}--------{-# INLINE mkTest #-}-mkTest :: Bool -> WhichTest -> Index -> Char -> String -> Bool-mkTest isMultiline = if isMultiline then test_multiline else test_singleline-  where test_multiline Test_BOL _off prev _input = prev == '\n'-        test_multiline Test_EOL _off _prev input = case input of-                                                     [] -> True-                                                     (next:_) -> next == '\n'-        test_singleline Test_BOL off _prev _input = off == 0-        test_singleline Test_EOL _off _prev input = null input--------{- MUTABLE WINNER QUEUE -}--data MQA s = MQA {mqa_start :: !Position, mqa_ws :: !(WScratch s)}--data MQ s = MQ { mq_earliest :: !(STRef s Position)-               , mq_list :: !(STRef s [MQA s])-               }--newMQ :: S.ST s (MQ s)-newMQ = do-  earliest <- newSTRef maxBound-  list <- newSTRef []-  return (MQ earliest list)--resetMQ :: MQ s -> S.ST s ()-resetMQ (MQ {mq_earliest=earliest,mq_list=list}) = do-  writeSTRef earliest maxBound-  writeSTRef list []--putMQ :: WScratch s -> MQ s -> S.ST s ()-putMQ ws (MQ {mq_earliest=earliest,mq_list=list}) = do-{--  sws <-s howWS ws-  let msg = "putMQ\n"++sws-  trace msg $ do--}-  start <- w_pos ws !! 0-  let mqa = MQA start ws-  startE <- readSTRef earliest-  if start <= startE-    then writeSTRef earliest start >> writeSTRef list [mqa]-    else do-  old <- readSTRef list-  let !rest = dropWhile (\ m -> start <= mqa_start m) old -      !new = mqa : rest-  writeSTRef list new--getMQ :: Position -> MQ s -> ST s [WScratch s]-getMQ pos (MQ {mq_earliest=earliest,mq_list=list}) = do-  old <- readSTRef list-  case span (\m -> pos <= mqa_start m) old of-    ([],ans) -> do-      writeSTRef earliest maxBound-      writeSTRef list []-      return (map mqa_ws ans)-    (new,ans) -> do-      writeSTRef earliest (mqa_start (last new))-      writeSTRef list new-      return (map mqa_ws ans)--{- MUTABLE SCRATCH DATA STRUCTURES -}--data SScratch s = SScratch { _s_1 :: !(MScratch s)-                           , _s_2 :: !(MScratch s)-                           , _s_rest :: !( MQ s-                                        , BlankScratch s-                                        , STArray s Index ((Index,Instructions),STUArray s Tag Position,OrbitLog)-                                        )-                           }-data MScratch s = MScratch { m_pos :: !(STArray s Index (Maybe (STUArray s Tag Position)))-                           , m_orbit :: !(STArray s Index OrbitLog)-                           }-newtype BlankScratch s = BlankScratch { blank_pos :: (STUArray s Tag Position)-                                      }-newtype WScratch s = WScratch { w_pos :: (STUArray s Tag Position)-                              }--{- DEBUGGING HELPERS -}--{--indent :: String -> String-indent xs = ' ':' ':xs--showMS :: MScratch s -> Index -> ST s String-showMS s i = do-  ma <- m_pos s !! i-  mc <- m_orbit s !! i-  a <- case ma of-        Nothing -> return "No pos"-        Just pos -> fmap show (getAssocs pos)-  let c = show mc-  return $ unlines [ "MScratch, index = "++show i-                   , indent a-                   , indent c]--showWS :: WScratch s -> ST s String-showWS (WScratch pos) = do-  a <- getAssocs pos-  return $ unlines [ "WScratch" -                   , indent (show a)]--}-{- CREATING INITIAL MUTABLE SCRATCH DATA STRUCTURES -}--{-# INLINE newA #-}-newA :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> e -> S.ST s (STUArray s Tag e)-newA b_tags initial = newArray b_tags initial--{-# INLINE newA_ #-}-newA_ :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> S.ST s (STUArray s Tag e)-newA_ b_tags = newArray_ b_tags--newScratch :: (Index,Index) -> (Tag,Tag) -> S.ST s (SScratch s)-newScratch b_index b_tags = do-  s1 <- newMScratch b_index-  s2 <- newMScratch b_index-  winQ <- newMQ-  blank <- fmap BlankScratch (newA b_tags (-1))-  which <- (newArray b_index ((-1,err "newScratch which 1"),err "newScratch which 2",err "newScratch which 3"))-  return (SScratch s1 s2 (winQ,blank,which))--newMScratch :: (Index,Index) -> S.ST s (MScratch s)-newMScratch b_index = do-  pos's <- newArray b_index Nothing-  orbit's <- newArray b_index mempty-  return (MScratch pos's orbit's)--{- COMPOSE A FUNCTION CLOSURE TO COMPARE TAG VALUES -}--newtype F s = F ([F s] -> C s)-type C s = Position-	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)-	  -> [(Int, Action)]-	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)-	  -> [(Int, Action)]-	  -> ST s Ordering--{-# INLINE orderOf #-}-orderOf :: Action -> Action -> Ordering-orderOf post1 post2 =-  case (post1,post2) of-    (SetPre,SetPre) -> EQ-    (SetPost,SetPost) -> EQ-    (SetPre,SetPost) -> LT-    (SetPost,SetPre) -> GT-    (SetVal v1,SetVal v2) -> compare v1 v2-    _ -> err $ "bestTrans.compareWith.choose sees incomparable "++show (post1,post2)--comp01 :: C s-comp01 preTag (_state1,pos1,_orbit1') np1 (_state2,pos2,_orbit2') np2 = do-  c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize-  case c of-    EQ -> challenge1-    answer -> return answer- where-  challenge1 = do-    case np1 of-      ((t1,b1):_rest1) | t1==1 -> do-        let p1 = case b1 of SetPre -> preTag-                            SetPost -> succ preTag-                            SetVal v -> v-        case np2 of-          ((t2,b2):_rest2) | t2==1 -> do-            let p2 = case b2 of SetPre -> preTag-                                SetPost -> succ preTag-                                SetVal v -> v-            return (compare p1 p2)-          _ -> do-            p2 <- pos2 !! 1-            return (compare p1 p2)-      _ -> do-        p1 <- pos1 !! 1-        case np2 of-          ((t2,b2):_rest2) | t2==1 -> do-            let p2 = case b2 of SetPre -> preTag-                                SetPost -> succ preTag-                                SetVal v -> v-            return (compare p1 p2)-          _ -> do-            p2 <- pos2 !! 1-            return (compare p1 p2)--ditzyComp'3 :: forall s. Array Tag OP -> C s-ditzyComp'3 aTagOP = comp0 where-  (F comp1:compsRest) = allcomps 1--  comp0 :: C s-  comp0 preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 = do-    c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize-    case c of-      EQ -> comp1 compsRest preTag x1 np1 x2 np2-      answer -> return answer--  allcomps :: Tag -> [F s]-  allcomps tag | tag > top = [F (\ _ _ _ _ _ _ -> return EQ)]-               | otherwise = -    case aTagOP ! tag of-      Orbit -> F (challenge_Orb tag) : allcomps (succ tag)-      Maximize -> F (challenge_Max tag) : allcomps (succ tag)-      Ignore -> F (challenge_Ignore tag) : allcomps (succ tag)-      Minimize -> err "allcomps Minimize"-   where top = snd (bounds aTagOP)--  challenge_Ignore !tag (F next:comps) preTag x1 np1 x2 np2 =-    case np1 of-      ((t1,_):rest1) | t1==tag ->-        case np2 of-          ((t2,_):rest2) | t2==tag -> next comps preTag x1 rest1 x2 rest2-          _ -> next comps preTag x1 rest1 x2 np2-      _ -> do-        case np2 of-          ((t2,_):rest2) | t2==tag -> next comps preTag x1 np1 x2 rest2-          _ ->  next comps preTag x1 np1 x2 np2-  challenge_Ignore _ [] _ _ _ _ _ = err "impossible 2347867"--  challenge_Max !tag (F next:comps) preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 =-    case np1 of-      ((t1,b1):rest1) | t1==tag ->-        case np2 of-          ((t2,b2):rest2) | t2==tag ->-            if b1==b2 then next comps preTag x1 rest1 x2 rest2-              else return (orderOf b1 b2)-          _ -> do-            p2 <- pos2 !! tag-            let p1 = case b1 of SetPre -> preTag-                                SetPost -> succ preTag-                                SetVal v -> v-            if p1==p2 then next comps preTag x1 rest1 x2 np2-              else return (compare p1 p2)-      _ -> do-        p1 <- pos1 !! tag-        case np2 of-          ((t2,b2):rest2) | t2==tag -> do-            let p2 = case b2 of SetPre -> preTag-                                SetPost -> succ preTag-                                SetVal v -> v-            if p1==p2 then next comps preTag x1 np1 x2 rest2-              else return (compare p1 p2)-          _ -> do-            p2 <- pos2 !! tag-            if p1==p2 then next comps preTag x1 np1 x2 np2-              else return (compare p1 p2)-  challenge_Max _ [] _ _ _ _ _ = err "impossible 9384324"--  challenge_Orb !tag (F next:comps) preTag x1@(_state1,_pos1,orbit1') np1 x2@(_state2,_pos2,orbit2') np2 = -    let s1 = IMap.lookup tag orbit1'-        s2 = IMap.lookup tag orbit2'-    in case (s1,s2) of-         (Nothing,Nothing) -> next comps preTag x1 np1 x2 np2-         (Just o1,Just o2) | inOrbit o1 == inOrbit o2 ->-            case compare (ordinal o1) (ordinal o2) `mappend`-                 comparePos (viewl (getOrbits o1)) (viewl (getOrbits o2)) of-              EQ -> next comps preTag x1 np1 x2 np2-              answer -> return answer-         _ -> err $ unlines [ "challenge_Orb is too stupid to handle mismatched orbit data :"-                           , show(tag,preTag,np1,np2)-                           , show s1-                           , show s2-                           ]-  challenge_Orb _ [] _ _ _ _ _ = err "impossible 0298347"--comparePos :: (ViewL Position) -> (ViewL Position) -> Ordering-comparePos EmptyL EmptyL = EQ-comparePos EmptyL _      = GT-comparePos _      EmptyL = LT-comparePos (p1 :< ps1) (p2 :< ps2) = -  compare p1 p2 `mappend` comparePos (viewl ps1) (viewl ps2)--{- CONVERT WINNERS TO MATCHARRAY -}--tagsToGroup0ST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray-tagsToGroup0ST _aGroups (WScratch {w_pos=pos})= do-  ma <- newArray (0,0) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))-  startPos0 <- pos !! 0-  stopPos0 <- pos !! 1-  set ma 0 (startPos0,stopPos0-startPos0)-  unsafeFreeze ma--tagsToAllGroupsST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray-tagsToAllGroupsST aGroups (WScratch {w_pos=pos})= do-  let b_max = snd (bounds (aGroups))-  ma <- newArray (0,b_max) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))-  startPos0 <- pos !! 0-  stopPos0 <- pos !! 1-  set ma 0 (startPos0,stopPos0-startPos0)-  let act _this_index [] = return ()-      act this_index ((GroupInfo _ parent start stop flagtag):gs) = do-        flagVal <- pos !! flagtag-        if (-1) == flagVal then act this_index gs-          else do-        startPos <- pos !! start-        stopPos <- pos !! stop-        (startParent,lengthParent) <- ma !! parent-        let ok = (0 <= startParent &&-                  0 <= lengthParent &&-                  startParent <= startPos &&-                  stopPos <= startPos + lengthParent)-        if not ok then act this_index gs-          else set ma this_index (startPos,stopPos-startPos)-  forM_ (range (1,b_max)) $ (\i -> act i (aGroups!i))-  unsafeFreeze ma--{- MUTABLE TAGGED TRANSITION (returning Tag-0 value) -}--{-# INLINE spawnAt #-}--- Reset the entry at "Index", or allocate such an entry.--- set tag 0 to the "Position"-spawnAt :: (Tag,Tag) -> BlankScratch s -> Index -> MScratch s -> Position -> S.ST s Position-spawnAt b_tags (BlankScratch blankPos) i s1 thisPos = do-  oldPos <- m_pos s1 !! i-  pos <- case oldPos of-           Nothing -> do-             pos' <- newA_ b_tags-             set (m_pos s1) i (Just pos')-             return pos'-           Just pos -> return pos-  copySTU blankPos pos-  set (m_orbit s1) i $! mempty-  set pos 0 thisPos-  return thisPos--{-# INLINE updateCopy #-}-updateCopy :: (Index -> STUArray s Tag Position -> [(Tag, Action)] -> ST s a)-           -> ((Index, Instructions), STUArray s Tag Position, OrbitLog)-           -> Index-           -> MScratch s-           -> Int-           -> ST s Position-updateCopy doActions ((_i1,instructions),oldPos,newOrbit) preTag s2 i2 = do-  b_tags <- getBounds oldPos-  newerPos <- maybe (do-    a <- newA_ b_tags-    set (m_pos s2) i2 (Just a)-    return a) return =<< m_pos s2 !! i2-  copySTU oldPos newerPos-  doActions preTag newerPos (newPos instructions)-  set (m_orbit s2) i2 $! newOrbit-  newerPos !! 0--{- USING memcpy TO COPY STUARRAY DATA -}---- #ifdef __GLASGOW_HASKELL__-foreign import ccall unsafe "memcpy"-    memcpy :: MutableByteArray# RealWorld -> MutableByteArray# RealWorld -> Int# -> IO ()--{--Prelude Data.Array.Base> :i STUArray-data STUArray s i e-  = STUArray !i !i !Int (GHC.Prim.MutableByteArray# s)-  	-- Defined in Data.Array.Base--}--- This has been updated for ghc 6.8.3 and still works with ghc 6.10.1-{-# INLINE copySTU #-}-copySTU :: (Show i,Ix i,MArray (STUArray s) e (S.ST s)) => STUArray s i e -> STUArray s i e -> S.ST s (STUArray s i e)-copySTU _souce@(STUArray _ _ _ msource) destination@(STUArray _ _ _ mdest) =--- do b1 <- getBounds s1---  b2 <- getBounds s2---  when (b1/=b2) (error ("\n\nWTF copySTU: "++show (b1,b2)))-  ST $ \s1# ->-    case sizeofMutableByteArray# msource        of { n# ->-    case unsafeCoerce# memcpy mdest msource n# s1# of { (# s2#, () #) ->-    (# s2#, destination #) }}-{--#else /* !__GLASGOW_HASKELL__ */--copySTU :: (MArray (STUArray s) e (S.ST s))=> STUArray s Tag e -> STUArray s Tag e -> S.ST s (STUArray s i e)-copySTU source destination = do-  b@(start,stop) <- getBounds source-  b' <- getBounds destination-  -- traceCopy ("> copySTArray "++show b) $ do-  when (b/=b') (fail $ "Text.Regex.TDFA.RunMutState copySTUArray bounds mismatch"++show (b,b'))-  forM_ (range b) $ \index ->-    set destination index =<< source !! index-  return destination-#endif /* !__GLASGOW_HASKELL__ */--}
+ Text/Regex/TDFA/NewDFA/Engine.hs view
@@ -0,0 +1,774 @@+-- | This is the code for the main engine.  This captures the posix subexpressions. This 'execMatch'+-- also dispatches to "Engine_NC", "Engine_FA", and "Engine_FC_NA"+-- +-- It is polymorphic over the internal Uncons type class, and specialized to produce the needed+-- variants.+module Text.Regex.TDFA.NewDFA.Engine(execMatch) where++import Control.Monad(when,forM,forM_,liftM2,foldM,join,MonadPlus(..),filterM)+import Data.Array.Base(unsafeRead,unsafeWrite,STUArray(..))+-- #ifdef __GLASGOW_HASKELL__+import GHC.Arr(STArray(..))+import GHC.ST(ST(..))+import GHC.Prim(MutableByteArray#,RealWorld,Int#,sizeofMutableByteArray#,unsafeCoerce#)+{-+-- #else+import Control.Monad.ST(ST)+import Data.Array.ST(STArray)+-- #endif+-}+import Prelude hiding ((!!))++import Data.Array.MArray(MArray(..),unsafeFreeze,getAssocs)+import Data.Array.IArray(Array,bounds,assocs)+--import qualified Data.Foldable as F+import qualified Data.IntMap.CharMap2 as CMap(lookup,findWithDefault)+import Data.IntMap(IntMap)+import qualified Data.IntMap as IMap(null,toList,lookup,insert)+import Data.Ix(Ix,rangeSize,range)+import Data.Maybe(catMaybes,listToMaybe)+import Data.Monoid(Monoid(..))+--import Data.IntSet(IntSet)+import qualified Data.IntSet as ISet(toAscList,null)+import qualified Data.Array.ST+import Data.Array.IArray((!))+import qualified Data.Array.MArray+import Data.List(partition,sort,foldl',sortBy,groupBy)+import Data.STRef+import qualified Control.Monad.ST.Lazy as L+import qualified Control.Monad.ST.Strict as S+import Data.Sequence(Seq,ViewL(..),viewl)+import qualified Data.Sequence as Seq+import qualified Data.ByteString.Char8 as SBS+import qualified Data.ByteString.Lazy.Char8 as LBS++import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)+import qualified Text.Regex.TDFA.IntArrTrieSet as Trie+import Text.Regex.TDFA.Common hiding (indent)+import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons))+import qualified Text.Regex.TDFA.NewDFA.Engine_FA as FA(execMatch)+import qualified Text.Regex.TDFA.NewDFA.Engine_NC as NC(execMatch)+import qualified Text.Regex.TDFA.NewDFA.Engine_NC_FA as NC_FA(execMatch)++--import Debug.Trace++-- trace :: String -> a -> a+-- trace _ a = a++err :: String -> a+err s = common_error "Text.Regex.TDFA.NewDFA"  s++{-# INLINE (!!) #-}+(!!) :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> S.ST s e+(!!) = unsafeRead+{-# INLINE set #-}+set :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> e -> S.ST s ()+set = unsafeWrite+ +{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> ([] Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> (Seq Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> SBS.ByteString -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> LBS.ByteString -> [MatchArray] #-}+execMatch :: Uncons text => Regex -> Position -> Char -> text -> [MatchArray]+execMatch r@(Regex { regex_dfa = DFA {d_id=didIn,d_dt=dtIn}+                   , regex_init = startState+                   , regex_b_index = b_index+                   , regex_b_tags = b_tags_all+                   , regex_trie = trie+                   , regex_tags = aTags+                   , regex_groups = aGroups+                   , regex_isFrontAnchored = frontAnchored+                   , regex_compOptions = CompOption { multiline = newline }+                   , regex_execOptions = ExecOption { captureGroups = capture+                                                    , testMatch = _checkMatch }})+          offsetIn prevIn inputIn = case (subCapture,frontAnchored) of+                                      (True  ,False) -> L.runST runCaptureGroup+                                      (True  ,True)  -> FA.execMatch r offsetIn prevIn inputIn+                                      (False ,False) -> NC.execMatch r offsetIn prevIn inputIn+                                      (False ,True)  -> NC_FA.execMatch r offsetIn prevIn inputIn+ where+  subCapture :: Bool+  subCapture = capture && (1<=rangeSize (bounds aGroups))++  b_tags :: (Tag,Tag)+  !b_tags = b_tags_all++  orbitTags :: [Tag]+  !orbitTags = map fst . filter ((Orbit==).snd) . assocs $ aTags++  !test = mkTest newline         ++  comp :: C s+  comp = {-# SCC "matchHere.comp" #-} ditzyComp'3 aTags++  runCaptureGroup :: L.ST s [MatchArray]+  runCaptureGroup = {-# SCC "runCaptureGroup" #-} do+    obtainNext <- L.strictToLazyST constructNewEngine+    let loop = do vals <- L.strictToLazyST obtainNext+                  if null vals -- force vals before defining valsRest+                    then return [] -- end of capturing+                    else do valsRest <- loop+                            return (vals ++ valsRest)+    loop++  constructNewEngine :: S.ST s (S.ST s [MatchArray])+  constructNewEngine =  {-# SCC "constructNewEngine" #-} do+    storeNext <- newSTRef undefined+    writeSTRef storeNext (goNext storeNext)+    let obtainNext = join (readSTRef storeNext)+    return obtainNext++  goNext storeNext = {-# SCC "goNext" #-} do+    (SScratch s1In s2In (winQ,blank,which)) <- newScratch b_index b_tags+    spawnStart b_tags blank startState s1In offsetIn+    eliminatedStateFlag <- newSTRef False+    eliminatedRespawnFlag <- newSTRef False+    let next s1 s2 did dt offset prev input = {-# SCC "goNext.next" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset prev input+                then next s1 s2 did a offset prev input+                else next s1 s2 did b offset prev input+            Simple' {dt_win=w,dt_trans=t, dt_other=o}+              | IMap.null w ->+                  case uncons input of+                    Nothing -> finalizeWinners+                    Just (c,input') ->+                      case CMap.findWithDefault o c t of+                        Transition {trans_many=DFA {d_id=did',d_dt=dt'},trans_how=dtrans} ->+                          findTrans s1 s2 did' dt' dtrans offset c input'+              | otherwise -> do+                  (did',dt') <- processWinner s1 did dt w offset+                  next' s1 s2 did' dt' offset prev input++        next' s1 s2 did dt offset prev input = {-# SCC "goNext.next'" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset prev input+                then next' s1 s2 did a offset prev input+                else next' s1 s2 did b offset prev input+            Simple' {dt_win=w,dt_trans=t, dt_other=o} ->+              case uncons input of+                Nothing -> finalizeWinners+                Just (c,input') ->+                  case CMap.findWithDefault o c t of+                    Transition {trans_many=DFA {d_id=did',d_dt=dt'},trans_how=dtrans} ->+                      findTrans s1 s2 did' dt' dtrans offset c input'++-- compressOrbits gets all the current Tag-0 start information from+-- the NFA states; then it loops through all the Orbit tags with+-- compressOrbit.+--+-- compressOrbit on such a Tag loops through all the NFS states'+-- m_orbit record, discardind ones that are Nothing and discarding+-- ones that are too new to care about (after the cutoff value).+--+-- compressOrbit then groups the Orbits records by the Tag-0 start+-- position and the basePos position.  Entried in different groups+-- will never be comparable in the future so they can be processed+-- separately.  Groups could probably be even more finely+-- distinguished, as a futher optimization, but the justification will+-- be tricky.+--+-- Current Tag-0 values are at most offset and all newly spawned+-- groups will have Tag-0 of at least (succ offset) so the current+-- groups are closed to those spawned in the future.  The basePos may+-- be as large as offset and may be overwritten later with values of+-- offset or larger (and this will also involve deleting the Orbits+-- record).  Thus there could be a future collision between a current+-- group with basePos==offset and an updated record that acquires+-- basePos==offset.  By excluding groups with basePos before the+-- current offset the collision between existing and future records+-- is avoided.+--+-- An entry in a group can only collide with that group's+-- descendents. compressOrbit sends each group to the compressGroup+-- command.+--+-- compressGroup on a single record checks whether it's Seq can be+-- cleared and if so it will clear it (and set ordinal to Nothing but+-- this this not particularly important).+--+-- compressGroup on many records sorts and groups the members and zips+-- the groups with their new ordinal value.  The comparision is based+-- on the old ordinal value, then the inOrbit value, and then the (Seq+-- Position) data.+--+-- The old ordinals of the group will all be Nothing or all be Just,+-- but this condition is neither checked nor violations detected.+-- This comparision is justified because once records get different+-- ordinals assigned they will never change places.+--+-- The inOrbit Bool is only different if one of them has set the stop+-- position to at most (succ offset).  They will obly be compared if+-- the other one leaves, an its stop position will be at least offset.+-- The previous sentence is justified by inspectin of the "assemble"+-- function in the TDFA module: there is no (PostUpdate+-- LeaveOrbitTask) so the largest possible value for the stop Tag is+-- (pred offset). Thus the record with inOrbit==False would beat (be+-- GT than) the record with inOrbit==True.+--+-- The Seq comparison is safe because the largest existing Position+-- value is (pred offset) and the smallest future Position value is+-- offset.  The previous sentence is justified by inspectin of the+-- "assemble" function in the TDFA module: there is no (PostUpdate+-- EnterOrbitTags) so the largest possible value in the Seq is (pred+-- offset).+--+-- The updated Orbits get the new ordinal value and an empty (Seq+-- Position).++        compressOrbits s1 did offset = do+          let getStart state = do start <- maybe (err "compressOrbit,1") (!! 0) =<< m_pos s1 !! state+                                  return (state,start)+              cutoff = offset - 50 -- Require: cutoff <= offset, MAGIC TUNABLE CONSTANT 50+          ss <- mapM getStart (ISet.toAscList did)+          let compressOrbit tag = do+                mos <- forM ss ( \ p@(state,_start) -> do+                                  mo <- fmap (IMap.lookup tag) (m_orbit s1 !! state)+                                  case mo of+                                    Just orbits | basePos orbits < cutoff -> return (Just (p,orbits))+                                                | otherwise -> return Nothing+                                    _ -> return Nothing )+                let compressGroup [((state,_),orbit)] | Seq.null (getOrbits orbit) = return ()+                                                      | otherwise =+                      set (m_orbit s1) state +                      . (IMap.insert tag $! (orbit { ordinal = Nothing, getOrbits = mempty}))+                      =<< m_orbit s1 !! state++                    compressGroup gs = do+                      let sortPos (_,b1) (_,b2) = compare (ordinal b1) (ordinal b2) `mappend`+                                                  compare (inOrbit b2) (inOrbit b1) `mappend`+                                                  comparePos (viewl (getOrbits b1)) (viewl (getOrbits b2))+                          groupPos (_,b1) (_,b2) = ordinal b1 == ordinal b2 && getOrbits b1 == getOrbits b2+                          gs' = zip [(1::Int)..] (groupBy groupPos . sortBy sortPos $ gs)+                      forM_ gs' $ \ (!n,eqs) -> do+                        forM_ eqs $ \ ((state,_),orbit) ->+                          set (m_orbit s1) state+                           . (IMap.insert tag $! (orbit { ordinal = Just n, getOrbits = mempty }))+                            =<< m_orbit s1 !! state+                let sorter ((_,a1),b1) ((_,a2),b2) = compare a1 a2 `mappend` compare (basePos b1) (basePos b2)+                    grouper ((_,a1),b1) ((_,a2),b2) = a1==a2 && basePos b1 == basePos b2+                    orbitGroups = groupBy grouper . sortBy sorter . catMaybes $ mos+                mapM_ compressGroup orbitGroups+          mapM_ compressOrbit orbitTags++-- findTrans has to (part 1) decide, for each destination, "which" of+-- zero or more source NFA states will be the chosen source.  Then it+-- has to (part 2) perform the transition or spawn.  It keeps track of+-- the starting index while doing so, and compares the earliest start+-- with the stored winners.  (part 3) If some winners are ready to be+-- released then the future continuation of the search is placed in+-- "storeNext".  If no winners are ready to be released then the+-- computation continues immediately.++        findTrans s1 s2 did' dt' dtrans offset prev' input' =  {-# SCC "goNext.findTrans" #-} do+          -- findTrans part 0+          -- MAGIC TUNABLE CONSTANT 100 (and 100-1). TODO: (offset .&. 127 == 127) instead?+          when (not (null orbitTags) && (offset `rem` 100 == 99)) (compressOrbits s1 did' offset)+          -- findTrans part 1+          let findTransTo (destIndex,sources) | IMap.null sources =+                set which destIndex ((-1,Instructions { newPos = [(0,SetPost)], newOrbits = Nothing })+                                    ,blank_pos blank,mempty)+                                              | otherwise = do+                let prep (sourceIndex,(_dopa,instructions)) = {-# SCC "goNext.findTrans.prep" #-} do+                      pos <- maybe (err $ "findTrans,1 : "++show (sourceIndex,destIndex,did')) return+                               =<< m_pos s1 !! sourceIndex+                      orbit <- m_orbit s1 !! sourceIndex+                      let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)+                      return ((sourceIndex,instructions),pos,orbit')+                    challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.findTrans.challenge" #-} do+                      check <- comp offset x1 (newPos ins1) x2 (newPos ins2)+                      if check==LT then return x2 else return x1+                (first:rest) <- mapM prep (IMap.toList sources)+                set which destIndex =<< foldM challenge first rest+          let dl = IMap.toList dtrans+          mapM_ findTransTo dl+          -- findTrans part 2+          let performTransTo (destIndex,_) = {-# SCC "goNext.findTrans.performTransTo" #-} do+                x@((sourceIndex,_instructions),_pos,_orbit') <- which !! destIndex+                if sourceIndex == (-1)+                  then spawnStart b_tags blank destIndex s2 (succ offset)+                  else updateCopy doActions x offset s2 destIndex+          earlyStart <- fmap minimum $ mapM performTransTo dl+          -- findTrans part 3+          earlyWin <- readSTRef (mq_earliest winQ)+          if earlyWin < earlyStart +            then do+              winners <- fmap (foldl' (\ rest ws -> ws : rest) []) $+                           getMQ earlyStart winQ+              writeSTRef storeNext (next s2 s1 did' dt' (succ offset) prev' input')+              mapM (tagsToGroupsST aGroups) winners+            else do+              let offset' = succ offset in seq offset' $ next s2 s1 did' dt' offset' prev' input'++-- The "newWinnerThenProceed" can find both a new non-empty winner and+-- a new empty winner.  A new non-empty winner can cause some of the+-- NFA states that comprise the DFA state to be eliminated, and if the+-- startState is eliminated then it must then be respawned.  And+-- imperative flag setting and resetting style is used.+--+-- A non-empty winner from the startState might obscure a potential+-- empty winner (form the startState at the current offset).  This+-- winEmpty possibility is also checked for. (unit test pattern ".*")+-- (futher test "(.+|.+.)*" on "aa\n")++        {-# INLINE processWinner #-}+        processWinner s1 did dt w offset = {-# SCC "goNext.newWinnerThenProceed" #-} do+          let prep x@(sourceIndex,instructions) = {-# SCC "goNext.newWinnerThenProceed.prep" #-} do+                pos <- maybe (err "newWinnerThenProceed,1") return =<< m_pos s1 !! sourceIndex+                startPos <- pos !! 0+                orbit <- m_orbit s1 !! sourceIndex+                let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)+                return (startPos,(x,pos,orbit'))+              challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.newWinnerThenProceed.challenge" #-} do+                check <- comp offset x1 (newPos ins1) x2 (newPos ins2)+                if check==LT then return x2 else return x1+          prep'd <- mapM prep (IMap.toList w)+          let (emptyFalse,emptyTrue) = partition ((offset >) . fst) prep'd+          mayID <- {-# SCC "goNext.newWinnerThenProceed.mayID" #-}+                   case map snd emptyFalse of+                    [] -> return Nothing+                    (first:rest) -> do+                      best@((_sourceIndex,_instructions),bp,_orbit') <- foldM challenge first rest+                      newWinner offset best+                      startWin <- bp !! 0+                      let states = ISet.toAscList did+                          keepState i1 = do+                            pos <- maybe (err "newWinnerThenProceed,2") return =<< m_pos s1 !! i1+                            startsAt <- pos !! 0+                            let keep = (startsAt <= startWin) || (offset <= startsAt)+                            when (not keep) $ do+                              writeSTRef eliminatedStateFlag True+                              when (i1 == startState) (writeSTRef eliminatedRespawnFlag True)+                            return keep+                      states' <- filterM keepState states+                      changed <- readSTRef eliminatedStateFlag+                      if changed then return (Just states') else return Nothing+          case emptyTrue of+            [] -> case IMap.lookup startState w of+                   Nothing -> return ()+                   Just ins -> winEmpty offset ins+            [first] -> newWinner offset (snd first)+            _ -> err "newWinnerThenProceed,3 : too many emptyTrue values"+          case mayID of+            Nothing -> return (did,dt) -- proceedNow s1 s2 did dt offset prev input+            Just states' -> do+              writeSTRef eliminatedStateFlag False+              respawn <- readSTRef eliminatedRespawnFlag+              DFA {d_id=did',d_dt=dt'} <-+                if respawn+                  then do+                    writeSTRef eliminatedRespawnFlag False+                    spawnStart b_tags blank startState s1 (succ offset)+                    return (Trie.lookupAsc trie (sort (states'++[startState])))+                  else return (Trie.lookupAsc trie states')+              return (did',dt')++        winEmpty preTag winInstructions = {-# SCC "goNext.winEmpty" #-} do+          newerPos <- newA_ b_tags+          copySTU (blank_pos blank) newerPos+          set newerPos 0 preTag+          doActions preTag newerPos (newPos winInstructions)+          putMQ (WScratch newerPos) winQ+                +        newWinner preTag ((_sourceIndex,winInstructions),oldPos,_newOrbit) = {-# SCC "goNext.newWinner" #-} do+          newerPos <- newA_ b_tags+          copySTU oldPos newerPos+          doActions preTag newerPos (newPos winInstructions)+          putMQ (WScratch newerPos) winQ++        finalizeWinners = do+          winners <- fmap (foldl' (\ rest mqa -> mqa_ws mqa : rest) []) $+                       readSTRef (mq_list winQ) -- reverses the winner list+          resetMQ winQ+          writeSTRef storeNext (return [])+          mapM (tagsToGroupsST aGroups) winners++    -- goNext then ends with the next statement+    next s1In s2In didIn dtIn offsetIn prevIn inputIn++{-# INLINE doActions #-}+doActions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()+doActions preTag pos ins = mapM_ doAction ins where+  postTag = succ preTag+  doAction (tag,SetPre) = set pos tag preTag+  doAction (tag,SetPost) = set pos tag postTag+  doAction (tag,SetVal v) = set pos tag v++----++{-# INLINE mkTest #-}+mkTest :: Uncons text => Bool -> WhichTest -> Index -> Char -> text -> Bool+mkTest isMultiline = if isMultiline then test_multiline else test_singleline+  where test_multiline Test_BOL _off prev _input = prev == '\n'+        test_multiline Test_EOL _off _prev input = case uncons input of+                                                     Nothing -> True+                                                     Just (next,_) -> next == '\n'+        test_singleline Test_BOL off _prev _input = off == 0+        test_singleline Test_EOL _off _prev input = case uncons input of+                                                      Nothing -> True+                                                      _ -> False++----++{- MUTABLE WINNER QUEUE -}++data MQA s = MQA {mqa_start :: !Position, mqa_ws :: !(WScratch s)}++data MQ s = MQ { mq_earliest :: !(STRef s Position)+               , mq_list :: !(STRef s [MQA s])+               }++newMQ :: S.ST s (MQ s)+newMQ = do+  earliest <- newSTRef maxBound+  list <- newSTRef []+  return (MQ earliest list)++resetMQ :: MQ s -> S.ST s ()+resetMQ (MQ {mq_earliest=earliest,mq_list=list}) = do+  writeSTRef earliest maxBound+  writeSTRef list []++putMQ :: WScratch s -> MQ s -> S.ST s ()+putMQ ws (MQ {mq_earliest=earliest,mq_list=list}) = do+  start <- w_pos ws !! 0+  let mqa = MQA start ws+  startE <- readSTRef earliest+  if start <= startE+    then writeSTRef earliest start >> writeSTRef list [mqa]+    else do+  old <- readSTRef list+  let !rest = dropWhile (\ m -> start <= mqa_start m) old +      !new = mqa : rest+  writeSTRef list new++getMQ :: Position -> MQ s -> ST s [WScratch s]+getMQ pos (MQ {mq_earliest=earliest,mq_list=list}) = do+  old <- readSTRef list+  case span (\m -> pos <= mqa_start m) old of+    ([],ans) -> do+      writeSTRef earliest maxBound+      writeSTRef list []+      return (map mqa_ws ans)+    (new,ans) -> do+      writeSTRef earliest (mqa_start (last new))+      writeSTRef list new+      return (map mqa_ws ans)++{- MUTABLE SCRATCH DATA STRUCTURES -}++data SScratch s = SScratch { _s_1 :: !(MScratch s)+                           , _s_2 :: !(MScratch s)+                           , _s_rest :: !( MQ s+                                        , BlankScratch s+                                        , STArray s Index ((Index,Instructions),STUArray s Tag Position,OrbitLog)+                                        )+                           }+data MScratch s = MScratch { m_pos :: !(STArray s Index (Maybe (STUArray s Tag Position)))+                           , m_orbit :: !(STArray s Index OrbitLog)+                           }+newtype BlankScratch s = BlankScratch { blank_pos :: (STUArray s Tag Position)+                                      }+newtype WScratch s = WScratch { w_pos :: (STUArray s Tag Position)+                              }++{- DEBUGGING HELPERS -}++{-+indent :: String -> String+indent xs = ' ':' ':xs++showMS :: MScratch s -> Index -> ST s String+showMS s i = do+  ma <- m_pos s !! i+  mc <- m_orbit s !! i+  a <- case ma of+        Nothing -> return "No pos"+        Just pos -> fmap show (getAssocs pos)+  let c = show mc+  return $ unlines [ "MScratch, index = "++show i+                   , indent a+                   , indent c]++showWS :: WScratch s -> ST s String+showWS (WScratch pos) = do+  a <- getAssocs pos+  return $ unlines [ "WScratch" +                   , indent (show a)]+-}+{- CREATING INITIAL MUTABLE SCRATCH DATA STRUCTURES -}++{-# INLINE newA #-}+newA :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> e -> S.ST s (STUArray s Tag e)+newA b_tags initial = newArray b_tags initial++{-# INLINE newA_ #-}+newA_ :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> S.ST s (STUArray s Tag e)+newA_ b_tags = newArray_ b_tags++newScratch :: (Index,Index) -> (Tag,Tag) -> S.ST s (SScratch s)+newScratch b_index b_tags = do+  s1 <- newMScratch b_index+  s2 <- newMScratch b_index+  winQ <- newMQ+  blank <- fmap BlankScratch (newA b_tags (-1))+  which <- (newArray b_index ((-1,err "newScratch which 1"),err "newScratch which 2",err "newScratch which 3"))+  return (SScratch s1 s2 (winQ,blank,which))++newMScratch :: (Index,Index) -> S.ST s (MScratch s)+newMScratch b_index = do+  pos's <- newArray b_index Nothing+  orbit's <- newArray b_index mempty+  return (MScratch pos's orbit's)++{- COMPOSE A FUNCTION CLOSURE TO COMPARE TAG VALUES -}++newtype F s = F ([F s] -> C s)+type C s = Position+	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)+	  -> [(Int, Action)]+	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)+	  -> [(Int, Action)]+	  -> ST s Ordering++{-# INLINE orderOf #-}+orderOf :: Action -> Action -> Ordering+orderOf post1 post2 =+  case (post1,post2) of+    (SetPre,SetPre) -> EQ+    (SetPost,SetPost) -> EQ+    (SetPre,SetPost) -> LT+    (SetPost,SetPre) -> GT+    (SetVal v1,SetVal v2) -> compare v1 v2+    _ -> err $ "bestTrans.compareWith.choose sees incomparable "++show (post1,post2)++comp01 :: C s+comp01 preTag (_state1,pos1,_orbit1') np1 (_state2,pos2,_orbit2') np2 = do+  c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize+  case c of+    EQ -> challenge1+    answer -> return answer+ where+  challenge1 = do+    case np1 of+      ((t1,b1):_rest1) | t1==1 -> do+        let p1 = case b1 of SetPre -> preTag+                            SetPost -> succ preTag+                            SetVal v -> v+        case np2 of+          ((t2,b2):_rest2) | t2==1 -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! 1+            return (compare p1 p2)+      _ -> do+        p1 <- pos1 !! 1+        case np2 of+          ((t2,b2):_rest2) | t2==1 -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! 1+            return (compare p1 p2)++ditzyComp'3 :: forall s. Array Tag OP -> C s+ditzyComp'3 aTagOP = comp0 where+  (F comp1:compsRest) = allcomps 1++  comp0 :: C s+  comp0 preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 = do+    c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize+    case c of+      EQ -> comp1 compsRest preTag x1 np1 x2 np2+      answer -> return answer++  allcomps :: Tag -> [F s]+  allcomps tag | tag > top = [F (\ _ _ _ _ _ _ -> return EQ)]+               | otherwise = +    case aTagOP ! tag of+      Orbit -> F (challenge_Orb tag) : allcomps (succ tag)+      Maximize -> F (challenge_Max tag) : allcomps (succ tag)+      Ignore -> F (challenge_Ignore tag) : allcomps (succ tag)+      Minimize -> err "allcomps Minimize"+   where top = snd (bounds aTagOP)++  challenge_Ignore !tag (F next:comps) preTag x1 np1 x2 np2 =+    case np1 of+      ((t1,_):rest1) | t1==tag ->+        case np2 of+          ((t2,_):rest2) | t2==tag -> next comps preTag x1 rest1 x2 rest2+          _ -> next comps preTag x1 rest1 x2 np2+      _ -> do+        case np2 of+          ((t2,_):rest2) | t2==tag -> next comps preTag x1 np1 x2 rest2+          _ ->  next comps preTag x1 np1 x2 np2+  challenge_Ignore _ [] _ _ _ _ _ = err "impossible 2347867"++  challenge_Max !tag (F next:comps) preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 =+    case np1 of+      ((t1,b1):rest1) | t1==tag ->+        case np2 of+          ((t2,b2):rest2) | t2==tag ->+            if b1==b2 then next comps preTag x1 rest1 x2 rest2+              else return (orderOf b1 b2)+          _ -> do+            p2 <- pos2 !! tag+            let p1 = case b1 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            if p1==p2 then next comps preTag x1 rest1 x2 np2+              else return (compare p1 p2)+      _ -> do+        p1 <- pos1 !! tag+        case np2 of+          ((t2,b2):rest2) | t2==tag -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            if p1==p2 then next comps preTag x1 np1 x2 rest2+              else return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! tag+            if p1==p2 then next comps preTag x1 np1 x2 np2+              else return (compare p1 p2)+  challenge_Max _ [] _ _ _ _ _ = err "impossible 9384324"++  challenge_Orb !tag (F next:comps) preTag x1@(_state1,_pos1,orbit1') np1 x2@(_state2,_pos2,orbit2') np2 = +    let s1 = IMap.lookup tag orbit1'+        s2 = IMap.lookup tag orbit2'+    in case (s1,s2) of+         (Nothing,Nothing) -> next comps preTag x1 np1 x2 np2+         (Just o1,Just o2) | inOrbit o1 == inOrbit o2 ->+            case compare (ordinal o1) (ordinal o2) `mappend`+                 comparePos (viewl (getOrbits o1)) (viewl (getOrbits o2)) of+              EQ -> next comps preTag x1 np1 x2 np2+              answer -> return answer+         _ -> err $ unlines [ "challenge_Orb is too stupid to handle mismatched orbit data :"+                           , show(tag,preTag,np1,np2)+                           , show s1+                           , show s2+                           ]+  challenge_Orb _ [] _ _ _ _ _ = err "impossible 0298347"++comparePos :: (ViewL Position) -> (ViewL Position) -> Ordering+comparePos EmptyL EmptyL = EQ+comparePos EmptyL _      = GT+comparePos _      EmptyL = LT+comparePos (p1 :< ps1) (p2 :< ps2) = +  compare p1 p2 `mappend` comparePos (viewl ps1) (viewl ps2)++{- CONVERT WINNERS TO MATCHARRAY -}++tagsToGroup0ST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray+tagsToGroup0ST _aGroups (WScratch {w_pos=pos})= do+  ma <- newArray (0,0) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))+  startPos0 <- pos !! 0+  stopPos0 <- pos !! 1+  set ma 0 (startPos0,stopPos0-startPos0)+  unsafeFreeze ma++tagsToGroupsST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray+tagsToGroupsST aGroups (WScratch {w_pos=pos})= do+  let b_max = snd (bounds (aGroups))+  ma <- newArray (0,b_max) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))+  startPos0 <- pos !! 0+  stopPos0 <- pos !! 1+  set ma 0 (startPos0,stopPos0-startPos0)+  let act _this_index [] = return ()+      act this_index ((GroupInfo _ parent start stop flagtag):gs) = do+        flagVal <- pos !! flagtag+        if (-1) == flagVal then act this_index gs+          else do+        startPos <- pos !! start+        stopPos <- pos !! stop+        (startParent,lengthParent) <- ma !! parent+        let ok = (0 <= startParent &&+                  0 <= lengthParent &&+                  startParent <= startPos &&+                  stopPos <= startPos + lengthParent)+        if not ok then act this_index gs+          else set ma this_index (startPos,stopPos-startPos)+  forM_ (range (1,b_max)) $ (\i -> act i (aGroups!i))+  unsafeFreeze ma++{- MUTABLE TAGGED TRANSITION (returning Tag-0 value) -}++{-# INLINE spawnStart #-}+-- Reset the entry at "Index", or allocate such an entry.+-- set tag 0 to the "Position"+spawnStart :: (Tag,Tag) -> BlankScratch s -> Index -> MScratch s -> Position -> S.ST s Position+spawnStart b_tags (BlankScratch blankPos) i s1 thisPos = do+  oldPos <- m_pos s1 !! i+  pos <- case oldPos of+           Nothing -> do+             pos' <- newA_ b_tags+             set (m_pos s1) i (Just pos')+             return pos'+           Just pos -> return pos+  copySTU blankPos pos+  set (m_orbit s1) i $! mempty+  set pos 0 thisPos+  return thisPos++{-# INLINE updateCopy #-}+updateCopy :: (Index -> STUArray s Tag Position -> [(Tag, Action)] -> ST s a)+           -> ((Index, Instructions), STUArray s Tag Position, OrbitLog)+           -> Index+           -> MScratch s+           -> Int+           -> ST s Position+updateCopy doActions ((_i1,instructions),oldPos,newOrbit) preTag s2 i2 = do+  b_tags <- getBounds oldPos+  newerPos <- maybe (do+    a <- newA_ b_tags+    set (m_pos s2) i2 (Just a)+    return a) return =<< m_pos s2 !! i2+  copySTU oldPos newerPos+  doActions preTag newerPos (newPos instructions)+  set (m_orbit s2) i2 $! newOrbit+  newerPos !! 0++{- USING memcpy TO COPY STUARRAY DATA -}++-- #ifdef __GLASGOW_HASKELL__+foreign import ccall unsafe "memcpy"+    memcpy :: MutableByteArray# RealWorld -> MutableByteArray# RealWorld -> Int# -> IO ()++{-+Prelude Data.Array.Base> :i STUArray+data STUArray s i e+  = STUArray !i !i !Int (GHC.Prim.MutableByteArray# s)+  	-- Defined in Data.Array.Base+-}+-- This has been updated for ghc 6.8.3 and still works with ghc 6.10.1+{-# INLINE copySTU #-}+copySTU :: (Show i,Ix i,MArray (STUArray s) e (S.ST s)) => STUArray s i e -> STUArray s i e -> S.ST s (STUArray s i e)+copySTU _souce@(STUArray _ _ _ msource) destination@(STUArray _ _ _ mdest) =+-- do b1 <- getBounds s1+--  b2 <- getBounds s2+--  when (b1/=b2) (error ("\n\nWTF copySTU: "++show (b1,b2)))+  ST $ \s1# ->+    case sizeofMutableByteArray# msource        of { n# ->+    case unsafeCoerce# memcpy mdest msource n# s1# of { (# s2#, () #) ->+    (# s2#, destination #) }}+{-+#else /* !__GLASGOW_HASKELL__ */++copySTU :: (MArray (STUArray s) e (S.ST s))=> STUArray s Tag e -> STUArray s Tag e -> S.ST s (STUArray s i e)+copySTU source destination = do+  b@(start,stop) <- getBounds source+  b' <- getBounds destination+  -- traceCopy ("> copySTArray "++show b) $ do+  when (b/=b') (fail $ "Text.Regex.TDFA.RunMutState copySTUArray bounds mismatch"++show (b,b'))+  forM_ (range b) $ \index ->+    set destination index =<< source !! index+  return destination+#endif /* !__GLASGOW_HASKELL__ */+-}
+ Text/Regex/TDFA/NewDFA/Engine_FA.hs view
@@ -0,0 +1,652 @@+-- | This is the code for the main engine.  This captures the posix+-- subexpressions.  There is also a non-capturing engine, and a+-- testing engine.+-- +-- It is polymorphic over the internal Uncons type class, and+-- specialized to produce the needed variants.+module Text.Regex.TDFA.NewDFA.Engine_FA(execMatch) where++import Control.Monad(when,unless,forM,forM_,liftM2,foldM,join,MonadPlus(..),filterM)+import Data.Array.Base(unsafeRead,unsafeWrite,STUArray(..))+-- #ifdef __GLASGOW_HASKELL__+import GHC.Arr(STArray(..))+import GHC.ST(ST(..))+import GHC.Prim(MutableByteArray#,RealWorld,Int#,sizeofMutableByteArray#,unsafeCoerce#)+{-+-- #else+import Control.Monad.ST(ST)+import Data.Array.ST(STArray)+-- #endif+-}+import Prelude hiding ((!!))++import Data.Array.MArray(MArray(..),unsafeFreeze,getAssocs)+import Data.Array.IArray(Array,bounds,assocs)+--import qualified Data.Foldable as F+import qualified Data.IntMap.CharMap2 as CMap(lookup,findWithDefault)+import Data.IntMap(IntMap)+import qualified Data.IntMap as IMap(null,toList,lookup,insert)+import Data.Ix(Ix,rangeSize,range)+import Data.Maybe(catMaybes,listToMaybe)+import Data.Monoid(Monoid(..))+--import Data.IntSet(IntSet)+import qualified Data.IntSet as ISet(toAscList,null)+import qualified Data.Array.ST+import Data.Array.IArray((!))+import qualified Data.Array.MArray+import Data.List(partition,sort,foldl',sortBy,groupBy)+import Data.STRef+import qualified Control.Monad.ST.Lazy as L+import qualified Control.Monad.ST.Strict as S+import Data.Sequence(Seq,ViewL(..),viewl)+import qualified Data.Sequence as Seq+import qualified Data.ByteString.Char8 as SBS+import qualified Data.ByteString.Lazy.Char8 as LBS++import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)+import qualified Text.Regex.TDFA.IntArrTrieSet as Trie+import Text.Regex.TDFA.Common hiding (indent)+import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons))++--import Debug.Trace++-- trace :: String -> a -> a+-- trace _ a = a++err :: String -> a+err s = common_error "Text.Regex.TDFA.NewDFA"  s++{-# INLINE (!!) #-}+(!!) :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> S.ST s e+(!!) = unsafeRead+{-# INLINE set #-}+set :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> e -> S.ST s ()+set = unsafeWrite++noSource :: ((Index, Instructions),STUArray s Tag Position,OrbitLog)+noSource = ((-1,err "noSource"),err "noSource",err "noSource")+ +{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> ([] Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> (Seq Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> SBS.ByteString -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> LBS.ByteString -> [MatchArray] #-}+execMatch :: Uncons text => Regex -> Position -> Char -> text -> [MatchArray]+execMatch r@(Regex { regex_dfa =  DFA {d_id=didIn,d_dt=dtIn}+                   , regex_init = startState+                   , regex_b_index = b_index+                   , regex_b_tags = b_tags_all+                   , regex_trie = trie+                   , regex_tags = aTags+                   , regex_groups = aGroups+                   , regex_compOptions = CompOption { multiline = newline }+                   , regex_execOptions = ExecOption { captureGroups = capture+                                                    , testMatch = _checkMatch }})+          offsetIn prevIn inputIn = S.runST goNext where++  b_tags :: (Tag,Tag)+  !b_tags = b_tags_all++  orbitTags :: [Tag]+  !orbitTags = map fst . filter ((Orbit==).snd) . assocs $ aTags++  !test = mkTest newline         ++  comp :: C s+  comp = {-# SCC "matchHere.comp" #-} ditzyComp'3 aTags++  goNext = {-# SCC "goNext" #-} do+    (SScratch s1In s2In (winQ,blank,which)) <- newScratch b_index b_tags+    spawnAt b_tags blank startState s1In offsetIn+    let next s1 s2 did dt offset prev input = {-# SCC "goNext.next" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset prev input+                then next s1 s2 did a offset prev input+                else next s1 s2 did b offset prev input+            Simple' {dt_win=w,dt_trans=t,dt_other=o} -> do+              unless (IMap.null w) $+                processWinner s1 w offset+              case uncons input of+                Nothing -> finalizeWinner+                Just (c,input') ->+                  case CMap.findWithDefault o c t of+                    Transition {trans_single=DFA {d_id=did',d_dt=dt'},trans_how=dtrans}+                      | ISet.null did' -> finalizeWinner+                      | otherwise -> findTrans s1 s2 did' dt' dtrans offset c input'++-- compressOrbits gets all the current Tag-0 start information from+-- the NFA states; then it loops through all the Orbit tags with+-- compressOrbit.+--+-- compressOrbit on such a Tag loops through all the NFS states'+-- m_orbit record, discardind ones that are Nothing and discarding+-- ones that are too new to care about (after the cutoff value).+--+-- compressOrbit then groups the Orbits records by the Tag-0 start+-- position and the basePos position.  Entried in different groups+-- will never be comparable in the future so they can be processed+-- separately.  Groups could probably be even more finely+-- distinguished, as a futher optimization, but the justification will+-- be tricky.+--+-- Current Tag-0 values are at most offset and all newly spawned+-- groups will have Tag-0 of at least (succ offset) so the current+-- groups are closed to those spawned in the future.  The basePos may+-- be as large as offset and may be overwritten later with values of+-- offset or larger (and this will also involve deleting the Orbits+-- record).  Thus there could be a future collision between a current+-- group with basePos==offset and an updated record that acquires+-- basePos==offset.  By excluding groups with basePos before the+-- current offset the collision between existing and future records+-- is avoided.+--+-- An entry in a group can only collide with that group's+-- descendents. compressOrbit sends each group to the compressGroup+-- command.+--+-- compressGroup on a single record checks whether it's Seq can be+-- cleared and if so it will clear it (and set ordinal to Nothing but+-- this this not particularly important).+--+-- compressGroup on many records sorts and groups the members and zips+-- the groups with their new ordinal value.  The comparision is based+-- on the old ordinal value, then the inOrbit value, and then the (Seq+-- Position) data.+--+-- The old ordinals of the group will all be Nothing or all be Just,+-- but this condition is neither checked nor violations detected.+-- This comparision is justified because once records get different+-- ordinals assigned they will never change places.+--+-- The inOrbit Bool is only different if one of them has set the stop+-- position to at most (succ offset).  They will obly be compared if+-- the other one leaves, an its stop position will be at least offset.+-- The previous sentence is justified by inspectin of the "assemble"+-- function in the TDFA module: there is no (PostUpdate+-- LeaveOrbitTask) so the largest possible value for the stop Tag is+-- (pred offset). Thus the record with inOrbit==False would beat (be+-- GT than) the record with inOrbit==True.+--+-- The Seq comparison is safe because the largest existing Position+-- value is (pred offset) and the smallest future Position value is+-- offset.  The previous sentence is justified by inspectin of the+-- "assemble" function in the TDFA module: there is no (PostUpdate+-- EnterOrbitTags) so the largest possible value in the Seq is (pred+-- offset).+--+-- The updated Orbits get the new ordinal value and an empty (Seq+-- Position).++        compressOrbits s1 did offset = do+          let getStart state = do start <- maybe (err "compressOrbit,1") (!! 0) =<< m_pos s1 !! state+                                  return (state,start)+              cutoff = offset - 50 -- Require: cutoff <= offset, MAGIC TUNABLE CONSTANT 50+          ss <- mapM getStart (ISet.toAscList did)+          let compressOrbit tag = do+                mos <- forM ss ( \ p@(state,_start) -> do+                                  mo <- fmap (IMap.lookup tag) (m_orbit s1 !! state)+                                  case mo of+                                    Just orbits | basePos orbits < cutoff -> return (Just (p,orbits))+                                                | otherwise -> return Nothing+                                    _ -> return Nothing )+                let compressGroup [((state,_),orbit)] | Seq.null (getOrbits orbit) = return ()+                                                      | otherwise =+                      set (m_orbit s1) state +                      . (IMap.insert tag $! (orbit { ordinal = Nothing, getOrbits = mempty}))+                      =<< m_orbit s1 !! state++                    compressGroup gs = do+                      let sortPos (_,b1) (_,b2) = compare (ordinal b1) (ordinal b2) `mappend`+                                                  compare (inOrbit b2) (inOrbit b1) `mappend`+                                                  comparePos (viewl (getOrbits b1)) (viewl (getOrbits b2))+                          groupPos (_,b1) (_,b2) = ordinal b1 == ordinal b2 && getOrbits b1 == getOrbits b2+                          gs' = zip [(1::Int)..] (groupBy groupPos . sortBy sortPos $ gs)+                      forM_ gs' $ \ (!n,eqs) -> do+                        forM_ eqs $ \ ((state,_),orbit) ->+                          set (m_orbit s1) state+                           . (IMap.insert tag $! (orbit { ordinal = Just n, getOrbits = mempty }))+                            =<< m_orbit s1 !! state+                let sorter ((_,a1),b1) ((_,a2),b2) = compare a1 a2 `mappend` compare (basePos b1) (basePos b2)+                    grouper ((_,a1),b1) ((_,a2),b2) = a1==a2 && basePos b1 == basePos b2+                    orbitGroups = groupBy grouper . sortBy sorter . catMaybes $ mos+                mapM_ compressGroup orbitGroups+          mapM_ compressOrbit orbitTags++-- findTrans has to (part 1) decide, for each destination, "which" of+-- zero or more source NFA states will be the chosen source.  Then it+-- has to (part 2) perform the transition or spawn.  It keeps track of+-- the starting index while doing so, and compares the earliest start+-- with the stored winners.  (part 3) If some winners are ready to be+-- released then the future continuation of the search is placed in+-- "storeNext".  If no winners are ready to be released then the+-- computation continues immediately.++        findTrans s1 s2 did' dt' dtrans offset prev' input' =  {-# SCC "goNext.findTrans" #-} do+          -- findTrans part 0+          -- MAGIC TUNABLE CONSTANT 100 (and 100-1). TODO: (offset .&. 127 == 127) instead?+          when (not (null orbitTags) && (offset `rem` 100 == 99)) (compressOrbits s1 did' offset)+          -- findTrans part 1+          let findTransTo (destIndex,sources) | IMap.null sources =+                set which destIndex noSource+                                              | otherwise = do+                let prep (sourceIndex,(_dopa,instructions)) = {-# SCC "goNext.findTrans.prep" #-} do+                      pos <- maybe (err $ "findTrans,1 : "++show (sourceIndex,destIndex,did')) return+                               =<< m_pos s1 !! sourceIndex+                      orbit <- m_orbit s1 !! sourceIndex+                      let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)+                      return ((sourceIndex,instructions),pos,orbit')+                    challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.findTrans.challenge" #-} do+                      check <- comp offset x1 (newPos ins1) x2 (newPos ins2)+                      if check==LT then return x2 else return x1+                (first:rest) <- mapM prep (IMap.toList sources)+                set which destIndex =<< foldM challenge first rest+          let dl = IMap.toList dtrans+          mapM_ findTransTo dl+          -- findTrans part 2+          let performTransTo (destIndex,_sources) = {-# SCC "goNext.findTrans.performTransTo" #-} do+                x@((sourceIndex,_instructions),_pos,_orbit') <- which !! destIndex+                unless (sourceIndex == (-1)) $+                  (updateCopy doActions x offset s2 destIndex)+          mapM_ performTransTo dl+          -- findTrans part 3+          let offset' = succ offset in seq offset' $ next s2 s1 did' dt' offset' prev' input'++-- The "newWinnerThenProceed" can find both a new non-empty winner and+-- a new empty winner.  A new non-empty winner can cause some of the+-- NFA states that comprise the DFA state to be eliminated, and if the+-- startState is eliminated then it must then be respawned.  And+-- imperative flag setting and resetting style is used.+--+-- A non-empty winner from the startState might obscure a potential+-- empty winner (form the startState at the current offset).  This+-- winEmpty possibility is also checked for. (unit test pattern ".*")+-- (futher test "(.+|.+.)*" on "aa\n")++        {-# INLINE processWinner #-}+        processWinner s1 w offset = {-# SCC "goNext.newWinnerThenProceed" #-} do+          let prep x@(sourceIndex,instructions) = {-# SCC "goNext.newWinnerThenProceed.prep" #-} do+                pos <- maybe (err "newWinnerThenProceed,1") return =<< m_pos s1 !! sourceIndex+                startPos <- pos !! 0+                orbit <- m_orbit s1 !! sourceIndex+                let orbit' = maybe orbit (\ f -> f offset orbit) (newOrbits instructions)+                return (startPos,(x,pos,orbit'))+              challenge x1@((_si1,ins1),_p1,_o1) x2@((_si2,ins2),_p2,_o2) = {-# SCC "goNext.newWinnerThenProceed.challenge" #-} do+                check <- comp offset x1 (newPos ins1) x2 (newPos ins2)+                if check==LT then return x2 else return x1+          prep'd <- mapM prep (IMap.toList w)+          case map snd prep'd of+            [] -> return ()+            (first:rest) -> do+              best@((_sourceIndex,_instructions),bp,_orbit') <- foldM challenge first rest+              newWinner offset best++        newWinner preTag ((_sourceIndex,winInstructions),oldPos,_newOrbit) = {-# SCC "goNext.newWinner" #-} do+          newerPos <- newA_ b_tags+          copySTU oldPos newerPos+          doActions preTag newerPos (newPos winInstructions)+          putMQ (WScratch newerPos) winQ++        finalizeWinner = do+          mWinner <- readSTRef (mq_mWin winQ)+          case mWinner of+            Nothing -> return []+            Just winner -> resetMQ winQ >> mapM (tagsToGroupsST aGroups) [winner]++    -- goNext then ends with the next statement+    next s1In s2In didIn dtIn offsetIn prevIn inputIn++{-# INLINE doActions #-}+doActions :: Position -> STUArray s Tag Position -> [(Tag, Action)] -> ST s ()+doActions preTag pos ins = mapM_ doAction ins where+  postTag = succ preTag+  doAction (tag,SetPre) = set pos tag preTag+  doAction (tag,SetPost) = set pos tag postTag+  doAction (tag,SetVal v) = set pos tag v++----++{-# INLINE mkTest #-}+mkTest :: Uncons text => Bool -> WhichTest -> Index -> Char -> text -> Bool+mkTest isMultiline = if isMultiline then test_multiline else test_singleline+  where test_multiline Test_BOL _off prev _input = prev == '\n'+        test_multiline Test_EOL _off _prev input = case uncons input of+                                                     Nothing -> True+                                                     Just (next,_) -> next == '\n'+        test_singleline Test_BOL off _prev _input = off == 0+        test_singleline Test_EOL _off _prev input = case uncons input of+                                                      Nothing -> True+                                                      _ -> False++----++{- MUTABLE WINNER QUEUE -}++newtype MQ s = MQ { mq_mWin :: STRef s (Maybe (WScratch s)) }++newMQ :: S.ST s (MQ s)+newMQ = do+  mWin <- newSTRef Nothing+  return (MQ mWin)++resetMQ :: MQ s -> S.ST s ()+resetMQ (MQ {mq_mWin=mWin}) = do+  writeSTRef mWin Nothing++putMQ :: WScratch s -> MQ s -> S.ST s ()+putMQ ws (MQ {mq_mWin=mWin}) = do+  writeSTRef mWin (Just ws)++{- MUTABLE SCRATCH DATA STRUCTURES -}++data SScratch s = SScratch { _s_1 :: !(MScratch s)+                           , _s_2 :: !(MScratch s)+                           , _s_rest :: !( MQ s+                                        , BlankScratch s+                                        , STArray s Index ((Index,Instructions),STUArray s Tag Position,OrbitLog)+                                        )+                           }+data MScratch s = MScratch { m_pos :: !(STArray s Index (Maybe (STUArray s Tag Position)))+                           , m_orbit :: !(STArray s Index OrbitLog)+                           }+newtype BlankScratch s = BlankScratch { blank_pos :: (STUArray s Tag Position)+                                      }+newtype WScratch s = WScratch { w_pos :: (STUArray s Tag Position)+                              }++{- DEBUGGING HELPERS -}++{-+indent :: String -> String+indent xs = ' ':' ':xs++showMS :: MScratch s -> Index -> ST s String+showMS s i = do+  ma <- m_pos s !! i+  mc <- m_orbit s !! i+  a <- case ma of+        Nothing -> return "No pos"+        Just pos -> fmap show (getAssocs pos)+  let c = show mc+  return $ unlines [ "MScratch, index = "++show i+                   , indent a+                   , indent c]++showWS :: WScratch s -> ST s String+showWS (WScratch pos) = do+  a <- getAssocs pos+  return $ unlines [ "WScratch" +                   , indent (show a)]+-}+{- CREATING INITIAL MUTABLE SCRATCH DATA STRUCTURES -}++{-# INLINE newA #-}+newA :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> e -> S.ST s (STUArray s Tag e)+newA b_tags initial = newArray b_tags initial++{-# INLINE newA_ #-}+newA_ :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> S.ST s (STUArray s Tag e)+newA_ b_tags = newArray_ b_tags++newScratch :: (Index,Index) -> (Tag,Tag) -> S.ST s (SScratch s)+newScratch b_index b_tags = do+  s1 <- newMScratch b_index+  s2 <- newMScratch b_index+  winQ <- newMQ+  blank <- fmap BlankScratch (newA b_tags (-1))+  which <- (newArray b_index ((-1,err "newScratch which 1"),err "newScratch which 2",err "newScratch which 3"))+  return (SScratch s1 s2 (winQ,blank,which))++newMScratch :: (Index,Index) -> S.ST s (MScratch s)+newMScratch b_index = do+  pos's <- newArray b_index Nothing+  orbit's <- newArray b_index mempty+  return (MScratch pos's orbit's)++{- COMPOSE A FUNCTION CLOSURE TO COMPARE TAG VALUES -}++newtype F s = F ([F s] -> C s)+type C s = Position+	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)+	  -> [(Int, Action)]+	  -> ((Int, Instructions), STUArray s Tag Position, IntMap Orbits)+	  -> [(Int, Action)]+	  -> ST s Ordering++{-# INLINE orderOf #-}+orderOf :: Action -> Action -> Ordering+orderOf post1 post2 =+  case (post1,post2) of+    (SetPre,SetPre) -> EQ+    (SetPost,SetPost) -> EQ+    (SetPre,SetPost) -> LT+    (SetPost,SetPre) -> GT+    (SetVal v1,SetVal v2) -> compare v1 v2+    _ -> err $ "bestTrans.compareWith.choose sees incomparable "++show (post1,post2)++comp01 :: C s+comp01 preTag (_state1,pos1,_orbit1') np1 (_state2,pos2,_orbit2') np2 = do+  c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize+  case c of+    EQ -> challenge1+    answer -> return answer+ where+  challenge1 = do+    case np1 of+      ((t1,b1):_rest1) | t1==1 -> do+        let p1 = case b1 of SetPre -> preTag+                            SetPost -> succ preTag+                            SetVal v -> v+        case np2 of+          ((t2,b2):_rest2) | t2==1 -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! 1+            return (compare p1 p2)+      _ -> do+        p1 <- pos1 !! 1+        case np2 of+          ((t2,b2):_rest2) | t2==1 -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! 1+            return (compare p1 p2)++ditzyComp'3 :: forall s. Array Tag OP -> C s+ditzyComp'3 aTagOP = comp0 where+  (F comp1:compsRest) = allcomps 1++  comp0 :: C s+  comp0 preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 = do+    c <- liftM2 compare (pos2!!0) (pos1!!0) -- reversed since Minimize+    case c of+      EQ -> comp1 compsRest preTag x1 np1 x2 np2+      answer -> return answer++  allcomps :: Tag -> [F s]+  allcomps tag | tag > top = [F (\ _ _ _ _ _ _ -> return EQ)]+               | otherwise = +    case aTagOP ! tag of+      Orbit -> F (challenge_Orb tag) : allcomps (succ tag)+      Maximize -> F (challenge_Max tag) : allcomps (succ tag)+      Ignore -> F (challenge_Ignore tag) : allcomps (succ tag)+      Minimize -> err "allcomps Minimize"+   where top = snd (bounds aTagOP)++  challenge_Ignore !tag (F next:comps) preTag x1 np1 x2 np2 =+    case np1 of+      ((t1,_):rest1) | t1==tag ->+        case np2 of+          ((t2,_):rest2) | t2==tag -> next comps preTag x1 rest1 x2 rest2+          _ -> next comps preTag x1 rest1 x2 np2+      _ -> do+        case np2 of+          ((t2,_):rest2) | t2==tag -> next comps preTag x1 np1 x2 rest2+          _ ->  next comps preTag x1 np1 x2 np2+  challenge_Ignore _ [] _ _ _ _ _ = err "impossible 2347867"++  challenge_Max !tag (F next:comps) preTag x1@(_state1,pos1,_orbit1') np1 x2@(_state2,pos2,_orbit2') np2 =+    case np1 of+      ((t1,b1):rest1) | t1==tag ->+        case np2 of+          ((t2,b2):rest2) | t2==tag ->+            if b1==b2 then next comps preTag x1 rest1 x2 rest2+              else return (orderOf b1 b2)+          _ -> do+            p2 <- pos2 !! tag+            let p1 = case b1 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            if p1==p2 then next comps preTag x1 rest1 x2 np2+              else return (compare p1 p2)+      _ -> do+        p1 <- pos1 !! tag+        case np2 of+          ((t2,b2):rest2) | t2==tag -> do+            let p2 = case b2 of SetPre -> preTag+                                SetPost -> succ preTag+                                SetVal v -> v+            if p1==p2 then next comps preTag x1 np1 x2 rest2+              else return (compare p1 p2)+          _ -> do+            p2 <- pos2 !! tag+            if p1==p2 then next comps preTag x1 np1 x2 np2+              else return (compare p1 p2)+  challenge_Max _ [] _ _ _ _ _ = err "impossible 9384324"++  challenge_Orb !tag (F next:comps) preTag x1@(_state1,_pos1,orbit1') np1 x2@(_state2,_pos2,orbit2') np2 = +    let s1 = IMap.lookup tag orbit1'+        s2 = IMap.lookup tag orbit2'+    in case (s1,s2) of+         (Nothing,Nothing) -> next comps preTag x1 np1 x2 np2+         (Just o1,Just o2) | inOrbit o1 == inOrbit o2 ->+            case compare (ordinal o1) (ordinal o2) `mappend`+                 comparePos (viewl (getOrbits o1)) (viewl (getOrbits o2)) of+              EQ -> next comps preTag x1 np1 x2 np2+              answer -> return answer+         _ -> err $ unlines [ "challenge_Orb is too stupid to handle mismatched orbit data :"+                           , show(tag,preTag,np1,np2)+                           , show s1+                           , show s2+                           ]+  challenge_Orb _ [] _ _ _ _ _ = err "impossible 0298347"++comparePos :: (ViewL Position) -> (ViewL Position) -> Ordering+comparePos EmptyL EmptyL = EQ+comparePos EmptyL _      = GT+comparePos _      EmptyL = LT+comparePos (p1 :< ps1) (p2 :< ps2) = +  compare p1 p2 `mappend` comparePos (viewl ps1) (viewl ps2)++{- CONVERT WINNERS TO MATCHARRAY -}++tagsToGroup0ST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray+tagsToGroup0ST _aGroups (WScratch {w_pos=pos})= do+  ma <- newArray (0,0) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))+  startPos0 <- pos !! 0+  stopPos0 <- pos !! 1+  set ma 0 (startPos0,stopPos0-startPos0)+  unsafeFreeze ma++tagsToGroupsST :: forall s. Array GroupIndex [GroupInfo] -> WScratch s -> S.ST s MatchArray+tagsToGroupsST aGroups (WScratch {w_pos=pos})= do+  let b_max = snd (bounds (aGroups))+  ma <- newArray (0,b_max) (-1,0) :: ST s (STArray s Int (MatchOffset,MatchLength))+  startPos0 <- pos !! 0+  stopPos0 <- pos !! 1+  set ma 0 (startPos0,stopPos0-startPos0)+  let act _this_index [] = return ()+      act this_index ((GroupInfo _ parent start stop flagtag):gs) = do+        flagVal <- pos !! flagtag+        if (-1) == flagVal then act this_index gs+          else do+        startPos <- pos !! start+        stopPos <- pos !! stop+        (startParent,lengthParent) <- ma !! parent+        let ok = (0 <= startParent &&+                  0 <= lengthParent &&+                  startParent <= startPos &&+                  stopPos <= startPos + lengthParent)+        if not ok then act this_index gs+          else set ma this_index (startPos,stopPos-startPos)+  forM_ (range (1,b_max)) $ (\i -> act i (aGroups!i))+  unsafeFreeze ma++{- MUTABLE TAGGED TRANSITION (returning Tag-0 value) -}++{-# INLINE spawnAt #-}+-- Reset the entry at "Index", or allocate such an entry.+-- set tag 0 to the "Position"+spawnAt :: (Tag,Tag) -> BlankScratch s -> Index -> MScratch s -> Position -> S.ST s Position+spawnAt b_tags (BlankScratch blankPos) i s1 thisPos = do+  oldPos <- m_pos s1 !! i+  pos <- case oldPos of+           Nothing -> do+             pos' <- newA_ b_tags+             set (m_pos s1) i (Just pos')+             return pos'+           Just pos -> return pos+  copySTU blankPos pos+  set (m_orbit s1) i $! mempty+  set pos 0 thisPos+  return thisPos++{-# INLINE updateCopy #-}+updateCopy :: (Index -> STUArray s Tag Position -> [(Tag, Action)] -> ST s a)+           -> ((Index, Instructions), STUArray s Tag Position, OrbitLog)+           -> Index+           -> MScratch s+           -> Int+           -> ST s ()+updateCopy doActions ((_i1,instructions),oldPos,newOrbit) preTag s2 i2 = do+  b_tags <- getBounds oldPos+  newerPos <- maybe (do+    a <- newA_ b_tags+    set (m_pos s2) i2 (Just a)+    return a) return =<< m_pos s2 !! i2+  copySTU oldPos newerPos+  doActions preTag newerPos (newPos instructions)+  set (m_orbit s2) i2 $! newOrbit++{- USING memcpy TO COPY STUARRAY DATA -}++-- #ifdef __GLASGOW_HASKELL__+foreign import ccall unsafe "memcpy"+    memcpy :: MutableByteArray# RealWorld -> MutableByteArray# RealWorld -> Int# -> IO ()++{-+Prelude Data.Array.Base> :i STUArray+data STUArray s i e+  = STUArray !i !i !Int (GHC.Prim.MutableByteArray# s)+  	-- Defined in Data.Array.Base+-}+-- This has been updated for ghc 6.8.3 and still works with ghc 6.10.1+{-# INLINE copySTU #-}+copySTU :: (Show i,Ix i,MArray (STUArray s) e (S.ST s)) => STUArray s i e -> STUArray s i e -> S.ST s (STUArray s i e)+copySTU _souce@(STUArray _ _ _ msource) destination@(STUArray _ _ _ mdest) =+-- do b1 <- getBounds s1+--  b2 <- getBounds s2+--  when (b1/=b2) (error ("\n\nWTF copySTU: "++show (b1,b2)))+  ST $ \s1# ->+    case sizeofMutableByteArray# msource        of { n# ->+    case unsafeCoerce# memcpy mdest msource n# s1# of { (# s2#, () #) ->+    (# s2#, destination #) }}+{-+#else /* !__GLASGOW_HASKELL__ */++copySTU :: (MArray (STUArray s) e (S.ST s))=> STUArray s Tag e -> STUArray s Tag e -> S.ST s (STUArray s i e)+copySTU source destination = do+  b@(start,stop) <- getBounds source+  b' <- getBounds destination+  -- traceCopy ("> copySTArray "++show b) $ do+  when (b/=b') (fail $ "Text.Regex.TDFA.RunMutState copySTUArray bounds mismatch"++show (b,b'))+  forM_ (range b) $ \index ->+    set destination index =<< source !! index+  return destination+#endif /* !__GLASGOW_HASKELL__ */+-}
+ Text/Regex/TDFA/NewDFA/Engine_NC.hs view
@@ -0,0 +1,288 @@+-- | This is the non-capturing form of Text.Regex.TDFA.NewDFA.String+module Text.Regex.TDFA.NewDFA.Engine_NC(execMatch) where++import Control.Monad(when,forM,forM_,liftM2,foldM,join,MonadPlus(..),filterM)+import Data.Array.Base(unsafeRead,unsafeWrite,STUArray(..))+-- #ifdef __GLASGOW_HASKELL__+import GHC.Arr(STArray(..))+import GHC.ST(ST(..))+import GHC.Prim(MutableByteArray#,RealWorld,Int#,sizeofMutableByteArray#,unsafeCoerce#)+{-+-- #else+import Control.Monad.ST(ST)+import Data.Array.ST(STArray)+-- #endif+-}+import Prelude hiding ((!!))++import Data.Array.MArray(MArray(..),unsafeFreeze,getAssocs)+import Data.Array.IArray(Array,bounds,assocs)+--import qualified Data.Foldable as F+import qualified Data.IntMap.CharMap2 as CMap(lookup,findWithDefault)+import Data.IntMap(IntMap)+import qualified Data.IntMap as IMap(null,toList,lookup,insert,keys,member)+import Data.Ix(Ix,rangeSize,range)+import Data.Maybe(catMaybes,listToMaybe)+import Data.Monoid(Monoid(..))+--import Data.IntSet(IntSet)+import qualified Data.IntSet as ISet(toAscList,null)+import qualified Data.Array.ST+import Data.Array.IArray((!))+import qualified Data.Array.MArray as MA+import Data.List(partition,sort,foldl',sortBy,groupBy)+import Data.STRef+import qualified Control.Monad.ST.Lazy as L+import qualified Control.Monad.ST.Strict as S+import Data.Sequence(Seq,ViewL(..),viewl)+import qualified Data.Sequence as Seq+import qualified Data.ByteString.Char8 as SBS+import qualified Data.ByteString.Lazy.Char8 as LBS++import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)+import qualified Text.Regex.TDFA.IntArrTrieSet as Trie+import Text.Regex.TDFA.Common hiding (indent)+import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons))++-- import Debug.Trace++-- trace :: String -> a -> a+-- trace _ a = a++err :: String -> a+err s = common_error "Text.Regex.TDFA.NewDFA.Engine_NC"  s++{-# INLINE (!!) #-}+(!!) :: (MArray a e (S.ST s),Ix i) => a i e -> i -> S.ST s e+(!!) = MA.readArray -- unsafeRead+{-# INLINE set #-}+set :: (MArray a e (S.ST s),Ix i) => a i e -> i -> e -> S.ST s ()+set = MA.writeArray -- unsafeWrite++{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> ([] Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> (Seq Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> SBS.ByteString -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> LBS.ByteString -> [MatchArray] #-}+execMatch :: Uncons text => Regex -> Position -> Char -> text -> [MatchArray]+execMatch (Regex { regex_dfa = (DFA {d_id=didIn,d_dt=dtIn})+                 , regex_init = startState+                 , regex_b_index = b_index+                 , regex_b_tags = b_tags_all+                 , regex_trie = trie+                 , regex_tags = aTags+                 , regex_groups = aGroups+                 , regex_compOptions = CompOption { multiline = newline }+                 , regex_execOptions = ExecOption { captureGroups = capture+                                                  , testMatch = _checkMatch }})+          offsetIn prevIn inputIn = L.runST runCaptureGroup where++  !test = mkTest newline         ++  runCaptureGroup = {-# SCC "runCaptureGroup" #-} do+    obtainNext <- L.strictToLazyST constructNewEngine+    let loop = do vals <- L.strictToLazyST obtainNext+                  if null vals -- force vals before defining valsRest+                    then return []+                    else do valsRest <- loop+                            return (vals ++ valsRest)+    loop++  constructNewEngine :: S.ST s (S.ST s [MatchArray])+  constructNewEngine =  {-# SCC "constructNewEngine" #-} do+    storeNext <- newSTRef undefined+    writeSTRef storeNext (goNext storeNext)+    let obtainNext = join (readSTRef storeNext)+    return obtainNext++  goNext storeNext = {-# SCC "goNext" #-} do+    (SScratch s1In s2In winQ) <- newScratch b_index+    set s1In startState offsetIn+    writeSTRef storeNext (err "obtainNext called while goNext is running!")+    eliminatedStateFlag <- newSTRef False+    eliminatedRespawnFlag <- newSTRef False+    let next s1 s2 did dt offset prev input = {-# SCC "goNext.next" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset prev input+                then next s1 s2 did a offset prev input+                else next s1 s2 did b offset prev input+            Simple' {dt_win=w,dt_trans=t, dt_other=o}+              | IMap.null w ->+                  case uncons input of+                    Nothing -> finalizeWinners+                    Just (c,input') -> do+                      case CMap.findWithDefault o c t of+                        Transition {trans_many=DFA {d_id=did',d_dt=dt'},trans_how=dtrans} ->+                          findTrans s1 s2 did' dt' dtrans offset c input'+              | otherwise -> do+                  (did',dt') <- processWinner s1 did dt w offset+                  next' s1 s2 did' dt' offset prev input++        next' s1 s2 did dt offset prev input = {-# SCC "goNext'.next" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset prev input+                then next' s1 s2 did a offset prev input+                else next' s1 s2 did b offset prev input+            Simple' {dt_win=w,dt_trans=t, dt_other=o} ->+              case uncons input of+                Nothing -> finalizeWinners+                Just (c,input') -> do+                  case CMap.findWithDefault o c t of+                    Transition {trans_many=DFA {d_id=did',d_dt=dt'},trans_how=dtrans} ->+                      findTrans s1 s2 did' dt' dtrans offset c input'++        findTrans s1 s2 did' dt' dtrans offset prev' input' =  {-# SCC "goNext.findTrans" #-} do+          --+          let findTransTo (destIndex,sources) = do+                val <- if IMap.null sources then return (succ offset)+                         else return . minimum =<< mapM (s1 !!) (IMap.keys sources)+                set s2 destIndex val+                return val+          earlyStart <- fmap minimum $ mapM findTransTo (IMap.toList dtrans)+          --+          earlyWin <- readSTRef (mq_earliest winQ)+          if earlyWin < earlyStart+            then do+              winnersR <- getMQ earlyStart winQ+              writeSTRef storeNext (next s2 s1 did' dt' (succ offset) prev' input')+              mapM wsToGroup (reverse winnersR)+            else do+              let offset' = succ offset in seq offset' $ next s2 s1 did' dt' offset' prev' input'++        processWinner s1 did dt w offset = {-# SCC "goNext.newWinnerThenProceed" #-} do+          let getStart (sourceIndex,_) = s1 !! sourceIndex+          vals <- mapM getStart (IMap.toList w)+          let low = minimum vals   -- perhaps a non-empty winner+              high = maximum vals  -- perhaps an empty winner+          if low < offset+            then do+              putMQ (WScratch low offset) winQ+              when (high==offset || IMap.member startState w) $+                putMQ (WScratch offset offset) winQ+              let keepState i1 = do+                    startsAt <- s1 !! i1+                    let keep = (startsAt <= low) || (offset <= startsAt)+                    if keep+                      then return True+                      else if i1 == startState+                             then {- check for additional empty winner -}+                                  set s1 i1 (succ offset) >> return True+                             else writeSTRef eliminatedStateFlag True >> return False+              states' <- filterM keepState (ISet.toAscList did)+              flag <- readSTRef eliminatedStateFlag+              if flag+                then do+                  writeSTRef eliminatedStateFlag False+                  let DFA {d_id=did',d_dt=dt'} = Trie.lookupAsc trie states'+                  return (did',dt')+                else do+                  return (did,dt)+            else do+               -- offset == low == minimum vals == maximum vals == high; vals == [offset]+               putMQ (WScratch offset offset) winQ+               return (did,dt)++        finalizeWinners = do+          winnersR <- readSTRef (mq_list winQ)+          resetMQ winQ+          writeSTRef storeNext (return [])+          mapM wsToGroup (reverse winnersR)++    -- goNext then ends with the next statement+    next s1In s2In didIn dtIn offsetIn prevIn inputIn++----++{-# INLINE mkTest #-}+mkTest :: Uncons text => Bool -> WhichTest -> Index -> Char -> text -> Bool+mkTest isMultiline = if isMultiline then test_multiline else test_singleline+  where test_multiline Test_BOL _off prev _input = prev == '\n'+        test_multiline Test_EOL _off _prev input = case uncons input of+                                                     Nothing -> True+                                                     Just (next,_) -> next == '\n'+        test_singleline Test_BOL off _prev _input = off == 0+        test_singleline Test_EOL _off _prev input = case uncons input of+                                                      Nothing -> True+                                                      _ -> False++----++{- MUTABLE WINNER QUEUE -}++data MQ s = MQ { mq_earliest :: !(STRef s Position)+               , mq_list :: !(STRef s [WScratch])+               }++newMQ :: S.ST s (MQ s)+newMQ = do+  earliest <- newSTRef maxBound+  list <- newSTRef []+  return (MQ earliest list)++resetMQ :: MQ s -> S.ST s ()+resetMQ (MQ {mq_earliest=earliest,mq_list=list}) = do+  writeSTRef earliest maxBound+  writeSTRef list []++putMQ :: WScratch -> MQ s -> S.ST s ()+putMQ ws@(WScratch {ws_start=start,ws_stop=stop}) (MQ {mq_earliest=earliest,mq_list=list}) = do+  startE <- readSTRef earliest+  if start <= startE+    then writeSTRef earliest start >> writeSTRef list [ws]+    else do+      old <- readSTRef list+      let !rest = dropWhile (\ w -> start <= ws_start w) old +          !new = ws : rest+      writeSTRef list new++getMQ :: Position -> MQ s -> ST s [WScratch]+getMQ pos (MQ {mq_earliest=earliest,mq_list=list}) = do+  old <- readSTRef list+  case span (\ w -> pos <= ws_start w) old of+    ([],ans) -> do+      writeSTRef earliest maxBound+      writeSTRef list []+      return ans+    (new,ans) -> do+      writeSTRef earliest (ws_start (last new))+      writeSTRef list new+      return ans++{- MUTABLE SCRATCH DATA STRUCTURES -}++data SScratch s = SScratch { _s_1 :: !(MScratch s)+                           , _s_2 :: !(MScratch s)+                           , _s_mq :: !(MQ s)+                           }+type MScratch s = STUArray s Index Position+data WScratch = WScratch {ws_start,ws_stop :: !Position}+  deriving Show++{- DEBUGGING HELPERS -}+{- CREATING INITIAL MUTABLE SCRATCH DATA STRUCTURES -}++{-# INLINE newA #-}+newA :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> e -> S.ST s (STUArray s Tag e)+newA b_tags initial = newArray b_tags initial++{-# INLINE newA_ #-}+newA_ :: (MArray (STUArray s) e (ST s)) => (Tag,Tag) -> S.ST s (STUArray s Tag e)+newA_ b_tags = newArray_ b_tags++newScratch :: (Index,Index) -> S.ST s (SScratch s)+newScratch b_index = do+  s1 <- newMScratch b_index+  s2 <- newMScratch b_index+  winQ <- newMQ+  return (SScratch s1 s2 winQ)++newMScratch :: (Index,Index) -> S.ST s (MScratch s)+newMScratch b_index = newA b_index (-1)++{- CONVERT WINNERS TO MATCHARRAY -}++wsToGroup :: WScratch -> ST s MatchArray+wsToGroup (WScratch start stop) = do+  ma <- newArray (0,0) (start,stop-start)  :: ST s (STArray s Int (MatchOffset,MatchLength))+  unsafeFreeze ma+
+ Text/Regex/TDFA/NewDFA/Engine_NC_FA.hs view
@@ -0,0 +1,110 @@+-- | This is the non-capturing form of Text.Regex.TDFA.NewDFA.String+module Text.Regex.TDFA.NewDFA.Engine_NC_FA(execMatch) where++import Control.Monad(when,unless,forM,forM_,liftM2,foldM,join,MonadPlus(..),filterM)+import Data.Array.Base(unsafeRead,unsafeWrite,STUArray(..))+-- #ifdef __GLASGOW_HASKELL__+import GHC.Arr(STArray(..))+import GHC.ST(ST(..))+import GHC.Prim(MutableByteArray#,RealWorld,Int#,sizeofMutableByteArray#,unsafeCoerce#)+{-+-- #else+import Control.Monad.ST(ST)+import Data.Array.ST(STArray)+-- #endif+-}+import Prelude hiding ((!!))++import Data.Array.MArray(MArray(..),unsafeFreeze,getAssocs)+import Data.Array.IArray(Array,bounds,assocs)+import qualified Data.Foldable as F+import qualified Data.IntMap.CharMap2 as CMap(lookup,findWithDefault)+import Data.IntMap(IntMap)+import qualified Data.IntMap as IMap(null,toList,lookup,insert,keys,member)+import Data.Ix(Ix,rangeSize,range)+import Data.Maybe(catMaybes,listToMaybe)+import Data.Monoid(Monoid(..))+--import Data.IntSet(IntSet)+import qualified Data.IntSet as ISet(toAscList,null)+import qualified Data.Array.ST+import Data.Array.IArray((!))+import qualified Data.Array.MArray+import Data.List(partition,sort,foldl',sortBy,groupBy)+import Data.STRef+import qualified Control.Monad.ST.Lazy as L+import qualified Control.Monad.ST.Strict as S+import Data.Sequence(Seq,ViewL(..),viewl)+import qualified Data.Sequence as Seq+import qualified Data.ByteString.Char8 as SBS+import qualified Data.ByteString.Lazy.Char8 as LBS++import Text.Regex.Base(MatchArray,MatchOffset,MatchLength)+import qualified Text.Regex.TDFA.IntArrTrieSet as Trie+import Text.Regex.TDFA.Common hiding (indent)+import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons))++--import Debug.Trace++-- trace :: String -> a -> a+-- trace _ a = a++err :: String -> a+err s = common_error "Text.Regex.TDFA.NewDFA"  s++{-# INLINE (!!) #-}+(!!) :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> S.ST s e+(!!) = unsafeRead+{-# INLINE set #-}+set :: (MArray a e (S.ST s),Ix i) => a i e -> Int -> e -> S.ST s ()+set = unsafeWrite++{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> ([] Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> (Seq Char) -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> SBS.ByteString -> [MatchArray] #-}+{-# SPECIALIZE execMatch :: Regex -> Position -> Char -> LBS.ByteString -> [MatchArray] #-}+execMatch :: Uncons text => Regex -> Position -> Char -> text -> [MatchArray]+execMatch (Regex { regex_dfa = DFA {d_dt=dtIn} })+          offsetIn prevIn inputIn = S.runST goNext where++  test Test_BOL off _input = off == 0+  test Test_EOL _off input = case uncons input of+                               Nothing -> True+                               _ -> False++  goNext = {-# SCC "goNext" #-} do+    winQ <- newSTRef Nothing+    let next dt offset input = {-# SCC "goNext.next" #-}+          case dt of+            Testing' {dt_test=wt,dt_a=a,dt_b=b} ->+              if test wt offset input+                then next a offset input+                else next b offset input+            Simple' {dt_win=w,dt_trans=t, dt_other=o} -> do+              unless (IMap.null w) $+                writeSTRef winQ (Just offset)+              case uncons input of+                Nothing -> finalizeWinner+                Just (c,input') -> do+                  case CMap.findWithDefault o c t of+                    Transition {trans_single=DFA {d_id=did',d_dt=dt'}}+                      | ISet.null did' -> finalizeWinner+                      | otherwise ->+                          let offset' = succ offset+                          in seq offset' $ next dt' offset' input'++        finalizeWinner = do+          mWinner <- readSTRef winQ+          case mWinner of+            Nothing -> return []+            Just winner -> mapM (makeGroup offsetIn) [winner]++    next dtIn offsetIn inputIn++----++{- CONVERT WINNERS TO MATCHARRAY -}++makeGroup :: Position -> Position -> ST s MatchArray+makeGroup start stop = do+  ma <- newArray (0,0) (start,stop-start)  :: ST s (STArray s Int (MatchOffset,MatchLength))+  unsafeFreeze ma
+ Text/Regex/TDFA/NewDFA/Tester.hs view
@@ -0,0 +1,126 @@+-- | Like Engine, but merely checks to see whether any match at all is found.+-- +module Text.Regex.TDFA.NewDFA.Tester(matchTest) where++import Control.Monad(MonadPlus(..))+import qualified Data.IntMap.CharMap2 as CMap(findWithDefault)+import qualified Data.IntMap as IMap+import qualified Data.IntSet as ISet(null)++import Data.Sequence(Seq,ViewL(..),viewl)+import qualified Data.Sequence as Seq+import qualified Data.ByteString.Char8 as SBS+import qualified Data.ByteString.Lazy.Char8 as LBS++import Text.Regex.Base()+import Text.Regex.TDFA.Common hiding (indent)+import Text.Regex.TDFA.NewDFA.Uncons (Uncons(uncons))++{-# SPECIALIZE matchTest :: Regex -> ([] Char) -> Bool #-}+{-# SPECIALIZE matchTest :: Regex -> (Seq Char) -> Bool #-}+{-# SPECIALIZE matchTest :: Regex -> SBS.ByteString -> Bool #-}+{-# SPECIALIZE matchTest :: Regex -> LBS.ByteString -> Bool #-}+matchTest :: Uncons text => Regex -> text -> Bool+matchTest (Regex { regex_dfa = dfaIn+                 , regex_isFrontAnchored = ifa+                 , regex_compOptions = CompOption { multiline = newline } } )+          inputIn = ans where++  ans = case ifa of+          True -> single0 (d_dt dfaIn) inputIn+          False -> multi0 (d_dt dfaIn) inputIn++  {-# NOINLINE test0 #-}+  {-# NOINLINE test #-}+  !test0 = mkTest0 newline+  !test = mkTest newline         ++  multi0 (Testing' {dt_test=wt,dt_a=a,dt_b=b}) input =+    if test0 wt input+      then multi0 a input+      else multi0 b input+  multi0 (Simple' {dt_win=w,dt_trans=t, dt_other=o}) input+    | IMap.null w =+        case uncons input of+          Nothing -> False+          Just (c,input') ->+            case CMap.findWithDefault o c t of+              Transition {trans_many=DFA {d_dt=dt'}} -> multi dt' c input'+    | otherwise = True++  multi (Testing' {dt_test=wt,dt_a=a,dt_b=b}) prev input =+    if test wt prev input+      then multi a prev input+      else multi b prev input+  multi (Simple' {dt_win=w,dt_trans=t, dt_other=o}) _prev input+    | IMap.null w =+        case uncons input of+          Nothing -> False+          Just (c,input') ->+            case CMap.findWithDefault o c t of+              Transition {trans_many=DFA {d_dt=dt'}} -> multi dt' c input'+    | otherwise = True++  single0 (Testing' {dt_test=wt,dt_a=a,dt_b=b}) input =+    if testFA0 wt input+      then single0 a input+      else single0 b input+  single0 (Simple' {dt_win=w,dt_trans=t, dt_other=o}) input+    | IMap.null w =+        case uncons input of+             Nothing -> False+             Just (c,input') ->+               case CMap.findWithDefault o c t of+                 Transition {trans_single=DFA {d_id=did',d_dt=dt'}}+                   | ISet.null did' -> False+                   | otherwise -> single dt' input'+    | otherwise = True++  single (Testing' {dt_test=wt,dt_a=a,dt_b=b}) input =+    if testFA wt input+      then single a input+      else single b input+  single (Simple' {dt_win=w,dt_trans=t, dt_other=o}) input+    | IMap.null w =+        case uncons input of+             Nothing -> False+             Just (c,input') ->+               case CMap.findWithDefault o c t of+                 Transition {trans_single=DFA {d_id=did',d_dt=dt'}}+                   | ISet.null did' -> False+                   | otherwise -> single dt' input'+    | otherwise = True++testFA0,testFA :: Uncons text => WhichTest -> text -> Bool+testFA0 Test_BOL _input = True+testFA0 Test_EOL input = case uncons input of+                           Nothing -> True+                           _ -> False+testFA Test_BOL _input = False+testFA Test_EOL input = case uncons input of+                          Nothing -> True+                          _ -> False++{-# INLINE mkTest0 #-}+mkTest0 :: Uncons text => Bool -> WhichTest -> text -> Bool+mkTest0 isMultiline = if isMultiline then test_multiline else test_singleline+  where test_multiline Test_BOL _input = True+        test_multiline Test_EOL input = case uncons input of+                                          Nothing -> True+                                          Just (next,_) -> next == '\n'+        test_singleline Test_BOL _input = True+        test_singleline Test_EOL input = case uncons input of+                                           Nothing -> True+                                           _ -> False++{-# INLINE mkTest #-}+mkTest :: Uncons text => Bool -> WhichTest -> Char -> text -> Bool+mkTest isMultiline = if isMultiline then test_multiline else test_singleline+  where test_multiline Test_BOL prev _input = prev == '\n'+        test_multiline Test_EOL _prev input = case uncons input of+                                                Nothing -> True+                                                Just (next,_) -> next == '\n'+        test_singleline Test_BOL _prev _input = False+        test_singleline Test_EOL _prev input = case uncons input of+                                                Nothing -> True+                                                _ -> False
+ Text/Regex/TDFA/NewDFA/Uncons.hs view
@@ -0,0 +1,28 @@+module Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons)) where++import qualified Data.ByteString.Char8 as SBS(ByteString,uncons)+import qualified Data.ByteString.Lazy.Char8 as LBS(ByteString,uncons)+import Data.Sequence(Seq,viewl,ViewL(EmptyL,(:<)))++class Uncons a where+  {- INLINE uncons #-}+  uncons :: a -> Maybe (Char,a)++instance Uncons ([] Char) where+  {- INLINE uncons #-}+  uncons [] = Nothing+  uncons (x:xs) = Just (x,xs)++instance Uncons (Seq Char) where+  {- INLINE uncons #-}+  uncons s = case viewl s of+               EmptyL -> Nothing+               x :< xs -> Just (x,xs)++instance Uncons SBS.ByteString where+  {- INLINE uncons #-}+  uncons = SBS.uncons++instance Uncons LBS.ByteString where+  {- INLINE uncons #-}+  uncons = LBS.uncons
Text/Regex/TDFA/Pattern.hs view
@@ -161,6 +161,10 @@   unCapture' x = x -} +reGroup p@(PConcat xs) | 2 <= length xs = PGroup Nothing p+reGroup p@(POr xs)     | 2 <= length xs = PGroup Nothing p+reGroup p = p+ starTrans' :: Pattern -> Pattern starTrans' pIn =   case pIn of -- We know that "p" has been simplified in each of these cases:@@ -170,7 +174,7 @@    so set its mayFirstBeNull flag to False  -}     PPlus p | canOnlyMatchNull p -> p-            | otherwise -> asGroup $ PConcat [p,PStar False p]+            | otherwise -> asGroup $ PConcat [reGroup p,PStar False p]  {- "An ERE matching a single character repeated by an '*' , '?' , or    an interval expression shall not match a null expression unless@@ -258,7 +262,7 @@     PBound 0 (Just 1) p -> quest p -- Hard cases     PBound i Nothing  p | canOnlyMatchNull p -> p-                        | otherwise -> asGroup . PConcat $ apply (nc'p:) (pred i) [p,PStar False p]+                        | otherwise -> asGroup . PConcat $ apply (nc'p:) (pred i) [reGroup p,PStar False p]       where nc'p = nonCapture' p     PBound 0 (Just j) p | canOnlyMatchNull p -> quest p                         -- The first operation is quest NOT nonEmpty. This can be tested with@@ -278,9 +282,9 @@ -} {- 0.99.7 add -}     PBound i (Just j) p | canOnlyMatchNull p -> p-                        | i == j -> asGroup . PConcat $ apply (nc'p:) (pred i) [p]+                        | i == j -> asGroup . PConcat $ apply (nc'p:) (pred i) [reGroup p]                         | otherwise -> asGroup . PConcat $ apply (nc'p:) (pred i)-                                        [p,apply (nonEmpty' . (concat' p)) (j-i-1) (ne'p) ]+                                        [reGroup p,apply (nonEmpty' . (concat' p)) (j-i-1) (ne'p) ]       where nc'p = nonCapture' p             ne'p = nonEmpty' p {- 0.99.6@@ -308,7 +312,7 @@   where     quest = (\ p -> POr [p,PEmpty])  -- require p to have been simplified --    quest' = (\ p -> simplify' $ POr [p,PEmpty])  -- require p to have been simplified-    concat' a b = simplify' $ PConcat [a,b]      -- require a and b to have been simplified+    concat' a b = simplify' $ PConcat [reGroup a,reGroup b]      -- require a and b to have been simplified     nonEmpty' = (\ p -> simplify' $ POr [PEmpty,p]) -- 2009-01-19 : this was PNonEmpty     nonCapture' = PNonCapture     apply f n x = foldr ($) x (replicate n f) -- function f applied n times to x : f^n(x)
Text/Regex/TDFA/Sequence.hs view
@@ -17,17 +17,23 @@  ,regexec  ) where -import Data.Array((!),elems)-import Data.Sequence as S+import qualified Data.Sequence as S+import Data.Sequence (ViewL(EmptyL,(:<)))  import Text.Regex.Base(MatchArray,RegexContext(..),RegexMaker(..),RegexLike(..)) import Text.Regex.Base.Impl(polymatch,polymatchM)+import Text.Regex.TDFA.Common(common_error,Regex(..),CompOption,ExecOption(captureGroups)) import Text.Regex.TDFA.String() -- piggyback on RegexMaker for String import Text.Regex.TDFA.TDFA(patternToRegex)-import Text.Regex.TDFA.Wrap(Regex(..),CompOption,ExecOption)+import Text.Regex.TDFA.Wrap() import Text.Regex.TDFA.ReadRegex(parseRegex) import qualified Data.Foldable as F(toList) +import Data.Array.IArray((!),listArray,elems,bounds)+import Data.Maybe(listToMaybe)+import Text.Regex.TDFA.NewDFA.Engine(execMatch)+import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)+ {- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}  instance RegexContext Regex (S.Seq Char) (S.Seq Char) where@@ -38,10 +44,11 @@   makeRegexOptsM c e source = either fail return $ compile c e source  instance RegexLike Regex (S.Seq Char) where-  matchOnce r = matchOnce r . F.toList-  matchAll r = matchAll r . F.toList-  matchCount r = matchCount r . F.toList-  matchTest r = matchTest r . F.toList+  matchOnce r s = listToMaybe (matchAll r s)+  matchAll r s = execMatch r 0 '\n' s+  matchCount r s = length (matchAll r' s)+    where r' = r { regex_execOptions = (regex_execOptions r) {captureGroups = False} }+  matchTest = Tester.matchTest   matchOnceText regex source =      fmap (\ma -> let (o,l) = ma!0                  in (S.take o source
Text/Regex/TDFA/String.hs view
@@ -6,6 +6,7 @@ This exports instances of the high level API and the medium level API of 'compile','execute', and 'regexec'. -}+{- By Chris Kuklewicz, 2009. BSD License, see the LICENSE file. -} module Text.Regex.TDFA.String(   -- ** Types   Regex@@ -19,17 +20,19 @@  ,regexec  ) where -import Data.Array((!),elems)+import Data.Array.IArray((!),amap)  import Text.Regex.Base.Impl(polymatch,polymatchM) import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchOffset,MatchLength,MatchArray)-import Text.Regex.TDFA.Common(common_error)-import qualified Text.Regex.TDFA.NewDFA as N(matchAll,matchOnce,matchCount,matchTest)+import Text.Regex.TDFA.Common(common_error,Regex(..),CompOption,ExecOption(captureGroups)) import Text.Regex.TDFA.ReadRegex(parseRegex) import Text.Regex.TDFA.TDFA(patternToRegex)-import Text.Regex.TDFA.Wrap(Regex(..),CompOption,ExecOption)+import Text.Regex.TDFA.Wrap() -{- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}+import Data.Array.IArray((!),listArray,elems,bounds)+import Data.Maybe(listToMaybe)+import Text.Regex.TDFA.NewDFA.Engine(execMatch)+import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)  err :: String -> a err = common_error "Text.Regex.TDFA.String"@@ -54,7 +57,7 @@ execute :: Regex      -- ^ Compiled regular expression         -> String     -- ^ String to match against         -> Either String (Maybe MatchArray)-execute r s = Right (N.matchOnce r s)+execute r s = Right (matchOnce r s)  regexec :: Regex      -- ^ Compiled regular expression         -> String     -- ^ String to match against@@ -69,12 +72,20 @@  -- Minimal defintion for now instance RegexLike Regex String where-  matchOnce = N.matchOnce-  matchAll = N.matchAll-  matchCount = N.matchCount-  matchTest = N.matchTest--- matchOnceText--- matchTextAll+  matchOnce r s = listToMaybe (matchAll r s)+  matchAll r s = execMatch r 0 '\n' s+  matchCount r s = length (matchAll r' s)+    where r' = r { regex_execOptions = (regex_execOptions r) {captureGroups = False} }+  matchTest = Tester.matchTest+  -- matchOnceText+  matchAllText r s =+    let go i _ _ | i `seq` False = undefined+        go i t [] = []+        go i t (x:xs) = let (off0,len0) = x!0+                            trans pair@(off,len) = (take len (drop (off-i) t),pair)+                            t' = drop (off0+len0-i) t+                        in amap trans x : seq t' (go (i+off0+len0) t' xs)+    in go 0 s (matchAll r s)  instance RegexContext Regex String String where   match = polymatch
Text/Regex/TDFA/TDFA.hs view
@@ -3,8 +3,7 @@ -- of Index which are used to lookup the DFA state in a lazy Trie -- which holds all possible subsets of QNFA states. module Text.Regex.TDFA.TDFA(patternToRegex,DFA(..),DT(..)-                            ,examineDFA,isDFAFrontAnchored-                            ,nfaToDFA,dfaMap) where+                            ,examineDFA,nfaToDFA,dfaMap) where  --import Control.Arrow((***)) import Control.Monad.Instances()@@ -39,15 +38,8 @@ dlose = DFA { d_id = ISet.empty             , d_dt = Simple' { dt_win = IMap.empty                              , dt_trans = Map.empty-                             , dt_other = Nothing } }+                             , dt_other = Transition dlose dlose mempty } } -{---- Specilized utility-ungroupBy :: (a->x) -> ([a]->y) -> [[a]] -> [(x,y)]-ungroupBy f g = map helper where-  helper [] = (err "empty group passed to ungroupBy",g [])-  helper x@(x1:_) = (f x1,g x)--} -- dumb smart constructor for tracing construction (I wanted to monitor laziness) {-# INLINE makeDFA #-} makeDFA :: SetIndex -> DT -> DFA@@ -55,11 +47,13 @@  -- Note that no CompOption or ExecOption parameter is needed. nfaToDFA :: ((Index,Array Index QNFA),Array Tag OP,Array GroupIndex [GroupInfo])-         -> (CompOption -> ExecOption -> Regex)-nfaToDFA ((startIndex,aQNFA),aTagOp,aGroupInfo) = Regex dfa startIndex indexBounds tagBounds trie aTagOp aGroupInfo where+         -> CompOption -> ExecOption+         -> Regex+nfaToDFA ((startIndex,aQNFA),aTagOp,aGroupInfo) co eo = Regex dfa startIndex indexBounds tagBounds trie aTagOp aGroupInfo ifa co eo where   dfa = indexesToDFA [startIndex]   indexBounds = bounds aQNFA   tagBounds = bounds aTagOp+  ifa = (not (multiline co)) && isDFAFrontAnchored dfa    indexesToDFA = {-# SCC "nfaToDFA.indexesToDFA" #-} Trie.lookupAsc trie  -- Lookup in cache @@ -100,7 +94,7 @@         Simple' { dt_win = makeWinner                 , dt_trans = fmap qtransToDFA t --                , dt_other = if IMap.null o then Just (newTransition $ IMap.singleton startIndex mempty) else Just (qtransToDFA o)}-                , dt_other = Just (qtransToDFA o)}+                , dt_other = qtransToDFA o}         where           makeWinner :: IntMap {- Index -} Instructions --  (RunState ())           makeWinner | noWin w = IMap.empty@@ -127,9 +121,7 @@         where           w = w1 `mappend` w2           t = fuseDTrans -- t1 o1 t2 o2-          o = case (o1,o2) of-                (Just o1', Just o2') -> Just (mergeDTrans o1' o2')-                _                    -> o1 `mplus` o2+          o = mergeDTrans o1 o2           -- This is very much like mergeQTrans           mergeDTrans :: Transition -> Transition -> Transition           mergeDTrans (Transition {trans_how=dt1}) (Transition {trans_how=dt2}) = makeTransition dtrans@@ -140,17 +132,16 @@             where               l1 = IMap.toAscList (unCharMap t1)               l2 = IMap.toAscList (unCharMap t2)-              merge_o1 = case o1 of Nothing -> id-                                    Just o1' -> mergeDTrans o1'-              merge_o2 = case o2 of Nothing -> id-                                    Just o2' -> mergeDTrans o2'-              fuse [] y = if isJust o1 then mapSnd merge_o1 y else y-              fuse x [] = if isJust o2 then mapSnd merge_o2 x else x+              fuse :: [(IMap.Key, Transition)]+                   -> [(IMap.Key, Transition)]+                   -> [(IMap.Key, Transition)]+              fuse [] y = fmap (fmap (mergeDTrans o1)) y+              fuse x [] = fmap (fmap (mergeDTrans o2)) x               fuse x@((xc,xa):xs) y@((yc,ya):ys) =                  case compare xc yc of-                  LT -> (xc,merge_o2 xa) : fuse xs y+                  LT -> (xc,mergeDTrans o2 xa) : fuse xs y                   EQ -> (xc,mergeDTrans xa ya) : fuse xs ys-                  GT -> (yc,merge_o1 ya) : fuse x ys+                  GT -> (yc,mergeDTrans o1 ya) : fuse x ys       mergeDT dt1@(Testing' wt1 dopas1 a1 b1) dt2@(Testing' wt2 dopas2 a2 b2) =         case compare wt1 wt2 of           LT -> nestDT dt1 dt2@@ -177,7 +168,7 @@  -- Get all trans_many states flattenDT :: DT -> [DFA]-flattenDT (Simple' {dt_trans=(CharMap mt),dt_other=mo}) = concatMap (\d -> [trans_many d,trans_single d]) . maybe id (:) mo . IMap.elems $ mt+flattenDT (Simple' {dt_trans=(CharMap mt),dt_other=o}) = concatMap (\d -> [trans_many d {-,trans_single d-}]) . (:) o . IMap.elems $ mt flattenDT (Testing' {dt_a=a,dt_b=b}) = flattenDT a ++ flattenDT b  examineDFA :: Regex -> String@@ -301,30 +292,32 @@     cw xx [] = foldr (\x rest -> comp (Just x) Nothing  `mappend` rest) mempty xx     cw [] yy = foldr (\y rest -> comp Nothing  (Just y) `mappend` rest) mempty yy --- can DT never win or accept a character?-isDTLosing :: DT -> Bool-isDTLosing (Testing' {dt_a=a,dt_b=b}) = isDTLosing a && isDTLosing b-isDTLosing (Simple' {dt_win=w}) | not (IMap.null w) = False -- can win-isDTLosing (Simple' {dt_trans=CharMap mt,dt_other=mo}) =-  let ts = (maybe id (:) mo) (IMap.elems mt)-  in all transLoses ts--transLoses :: Transition -> Bool-transLoses t@(Transition {trans_single=dfa}) = isSpawning t || ISet.null (d_id dfa)-isSpawning :: Transition -> Bool-isSpawning t = case IMap.elems (trans_how t) of-                 [m] -> case IMap.keys m of-                         [] -> True-                         _ -> False-                 _ -> False                    --- Assumes that Test_BOL is the smallest (and therefore always first) test-isDTFrontAnchored :: DT -> Bool-isDTFrontAnchored (Testing' {dt_test=wt,dt_b=b}) | wt == Test_BOL = isDTLosing b-isDTFrontAnchored _ = False- isDFAFrontAnchored :: DFA -> Bool isDFAFrontAnchored = isDTFrontAnchored . d_dt+ where+  isDTFrontAnchored :: DT -> Bool+  isDTFrontAnchored (Simple' {}) = False+  isDTFrontAnchored (Testing' {dt_test=wt,dt_a=a,dt_b=b}) | wt == Test_BOL = isDTLosing b+                                                          | otherwise = isDTFrontAnchored a && isDTFrontAnchored b+   where+    -- can DT never win or accept a character (when following trans_single)?+    isDTLosing :: DT -> Bool+    isDTLosing (Testing' {dt_a=a,dt_b=b}) = isDTLosing a && isDTLosing b+    isDTLosing (Simple' {dt_win=w}) | not (IMap.null w) = False -- can win with 0 characters+    isDTLosing (Simple' {dt_trans=CharMap mt,dt_other=o}) =+      let ts = o : IMap.elems mt+      in all transLoses ts+     where+      transLoses :: Transition -> Bool+      transLoses (Transition {trans_single=dfa,trans_how=dtrans}) = isDTLose dfa || onlySpawns dtrans+       where+        isDTLose :: DFA -> Bool+        isDTLose dfa = ISet.null (d_id dfa)+        onlySpawns :: DTrans -> Bool+        onlySpawns t = case IMap.elems t of+                         [m] -> IMap.null m+                         _ -> False  {- toInstructions -} 
regex-tdfa.cabal view
@@ -1,5 +1,5 @@ Name:                   regex-tdfa-Version:                1.0.0+Version:                1.1.0 -- 0.99.4 tests pnonempty' = \ p -> POr [ PEmpty, p ] instead of PNonEmpty -- 0.99.5 remove PNonEmpty constructor -- 0.99.6 change to nested nonEmpty calls for PBound@@ -18,6 +18,25 @@ -- 0.99.19 try for pre-comparison of orbit-logs! -- 0.99.20 go to many vs single? -- 1.0.0+-- 1.0.1 add NewDFATest.hs+-- 1.0.2 arg, the prof is fast and the normal slow!+-- 1.0.3 try to alter matchTest to not have the Bool args? No+--  np2  comment out all Testing code? No+--  np3  !off the multi? No+--  np4  comment out all Single0 and Single code? No+--  np5  comment out all Multi0 code? No+--  np6  comment out ans check? No+--  np7  just return True? Fast+--  np8  np6 and NOINLINE endOff? No+--  np9  INLINE endOf? No+--  np10 Peel off CharMap/IntMap and DFA/DT with pattern matching? No+--  np11 break multi to not look at o and just return True? Yes !!!!+--  np12 expand o in the case where t lookup get Nothing? Yes--this is the fix!?+--  np13 try to improve readability with the "mm" combinator? Yes!+-- 1.0.4 try repaired NewDFATest_SBS+-- 1.0.5 use "uncons" on SBS+-- 1.0.6 try NewDFATest_SBS with uncons+-- 1.0.7 make NewDFA directory and String_NC License:                BSD3 License-File:           LICENSE Copyright:              Copyright (c) 2007, Christopher Kuklewicz@@ -43,24 +62,29 @@     Build-Depends:      base < 4.0    other-modules:          Paths_regex_tdfa-  Exposed-Modules:        Text.Regex.TDFA.Common+  Exposed-Modules:        Data.IntMap.CharMap2+                          Data.IntMap.EnumMap2+                          Data.IntSet.EnumSet2+                          Text.Regex.TDFA+                          Text.Regex.TDFA.ByteString+                          Text.Regex.TDFA.ByteString.Lazy+                          Text.Regex.TDFA.Common+                          Text.Regex.TDFA.CorePattern                           Text.Regex.TDFA.IntArrTrieSet-                          Text.Regex.TDFA.TNFA-                          Text.Regex.TDFA.TDFA+                          Text.Regex.TDFA.NewDFA.Engine+                          Text.Regex.TDFA.NewDFA.Engine_FA+                          Text.Regex.TDFA.NewDFA.Engine_NC+                          Text.Regex.TDFA.NewDFA.Engine_NC_FA+                          Text.Regex.TDFA.NewDFA.Tester+                          Text.Regex.TDFA.NewDFA.Uncons                           Text.Regex.TDFA.Pattern                           Text.Regex.TDFA.ReadRegex-                          Text.Regex.TDFA.CorePattern-                          Text.Regex.TDFA.NewDFA-                          Text.Regex.TDFA.String-                          Text.Regex.TDFA.ByteString-                          Text.Regex.TDFA.ByteString.Lazy                           Text.Regex.TDFA.Sequence+                          Text.Regex.TDFA.String+                          Text.Regex.TDFA.TDFA+                          Text.Regex.TDFA.TNFA                           Text.Regex.TDFA.Wrap-                          Text.Regex.TDFA-                          Data.IntSet.EnumSet2-                          Data.IntMap.EnumMap2-                          Data.IntMap.CharMap2   Buildable:              True-  Extensions:             MultiParamTypeClasses, FunctionalDependencies, BangPatterns, MagicHash, RecursiveDo, NoMonoPatBinds, ForeignFunctionInterface, UnboxedTuples, TypeOperators, FlexibleContexts, ExistentialQuantification, UnliftedFFITypes, TypeSynonymInstances+  Extensions:             MultiParamTypeClasses, FunctionalDependencies, BangPatterns, MagicHash, RecursiveDo, NoMonoPatBinds, ForeignFunctionInterface, UnboxedTuples, TypeOperators, FlexibleContexts, ExistentialQuantification, UnliftedFFITypes, TypeSynonymInstances, FlexibleInstances   GHC-Options:            -Wall -O2 -funbox-strict-fields   GHC-Prof-Options:       -auto-all