-- | "Text.Regex.TDFA.TDFA" converts the QNFA from TNFA into the DFA.
-- A DFA state corresponds to a Set of QNFA states, repesented as list
-- 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,nfaToDFA,dfaMap) where

--import Control.Arrow((***))
import Data.Monoid as Mon(Monoid(..))
import Control.Monad.State(State,MonadState(..),execState)
import Data.Array.IArray(Array,(!),bounds,{-assocs-})
import Data.IntMap(IntMap)
import qualified Data.IntMap as IMap(empty,keys,delete,null,lookup,fromDistinctAscList
                                    ,member,unionWith,singleton,union
                                    ,toAscList,Key,elems,toList,insert
                                    ,insertWith,insertWithKey)
import Data.IntMap.CharMap2(CharMap(..))
import qualified Data.IntMap.CharMap2 as Map(empty)
--import Data.IntSet(IntSet)
import qualified Data.IntSet as ISet(empty,singleton,null)
import Data.List(foldl')
import qualified Data.Map (Map,empty,member,insert,elems)
import Data.Sequence as S((|>),{-viewl,ViewL(..)-})

import Text.Regex.TDFA.Common {- all -}
import Text.Regex.TDFA.IntArrTrieSet(TrieSet)
import qualified Text.Regex.TDFA.IntArrTrieSet as Trie(lookupAsc,fromSinglesMerge)
import Text.Regex.TDFA.Pattern(Pattern)
--import Text.Regex.TDFA.RunMutState(toInstructions)
import Text.Regex.TDFA.TNFA(patternToNFA)
--import Debug.Trace

{- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}

err :: String -> a
err :: String -> a
err s :: String
s = String -> String -> a
forall a. String -> String -> a
common_error "Text.Regex.TDFA.TDFA"  String
s

dlose :: DFA
dlose :: DFA
dlose = DFA :: SetIndex -> DT -> DFA
DFA { d_id :: SetIndex
d_id = SetIndex
ISet.empty
            , d_dt :: DT
d_dt = Simple' :: IntMap Instructions -> CharMap Transition -> Transition -> DT
Simple' { dt_win :: IntMap Instructions
dt_win = IntMap Instructions
forall a. IntMap a
IMap.empty
                             , dt_trans :: CharMap Transition
dt_trans = CharMap Transition
forall a. CharMap a
Map.empty
                             , dt_other :: Transition
dt_other = DFA -> DFA -> DTrans -> Transition
Transition DFA
dlose DFA
dlose DTrans
forall a. Monoid a => a
mempty } }

-- dumb smart constructor for tracing construction (I wanted to monitor laziness)
{-# INLINE makeDFA #-}
makeDFA :: SetIndex -> DT -> DFA
makeDFA :: SetIndex -> DT -> DFA
makeDFA i :: SetIndex
i dt :: DT
dt = SetIndex -> DT -> DFA
DFA SetIndex
i DT
dt

-- Note that no CompOption or ExecOption parameter is needed.
nfaToDFA :: ((Index,Array Index QNFA),Array Tag OP,Array GroupIndex [GroupInfo])
         -> CompOption -> ExecOption
         -> Regex
nfaToDFA :: ((Index, Array Index QNFA), Array Index OP,
 Array Index [GroupInfo])
-> CompOption -> ExecOption -> Regex
nfaToDFA ((startIndex :: Index
startIndex,aQNFA :: Array Index QNFA
aQNFA),aTagOp :: Array Index OP
aTagOp,aGroupInfo :: Array Index [GroupInfo]
aGroupInfo) co :: CompOption
co eo :: ExecOption
eo = DFA
-> Index
-> (Index, Index)
-> (Index, Index)
-> TrieSet DFA
-> Array Index OP
-> Array Index [GroupInfo]
-> Bool
-> CompOption
-> ExecOption
-> Regex
Regex DFA
dfa Index
startIndex (Index, Index)
indexBounds (Index, Index)
tagBounds TrieSet DFA
trie Array Index OP
aTagOp Array Index [GroupInfo]
aGroupInfo Bool
ifa CompOption
co ExecOption
eo where
  dfa :: DFA
dfa = [Index] -> DFA
indexesToDFA [Index
startIndex]
  indexBounds :: (Index, Index)
indexBounds = Array Index QNFA -> (Index, Index)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds Array Index QNFA
aQNFA
  tagBounds :: (Index, Index)
tagBounds = Array Index OP -> (Index, Index)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds Array Index OP
aTagOp
  ifa :: Bool
ifa = (Bool -> Bool
not (CompOption -> Bool
multiline CompOption
co)) Bool -> Bool -> Bool
&& DFA -> Bool
isDFAFrontAnchored DFA
dfa

  indexesToDFA :: [Index] -> DFA
indexesToDFA = {-# SCC "nfaToDFA.indexesToDFA" #-} TrieSet DFA -> [Index] -> DFA
forall v. TrieSet v -> [Index] -> v
Trie.lookupAsc TrieSet DFA
trie  -- Lookup in cache

  trie :: TrieSet DFA
  trie :: TrieSet DFA
trie = DFA
-> (DFA -> DFA -> DFA)
-> (Index, Index)
-> (Index -> DFA)
-> TrieSet DFA
forall v.
v -> (v -> v -> v) -> (Index, Index) -> (Index -> v) -> TrieSet v
Trie.fromSinglesMerge DFA
dlose DFA -> DFA -> DFA
mergeDFA (Array Index QNFA -> (Index, Index)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds Array Index QNFA
aQNFA) Index -> DFA
indexToDFA

  newTransition :: DTrans -> Transition
  newTransition :: DTrans -> Transition
newTransition dtrans :: DTrans
dtrans = Transition :: DFA -> DFA -> DTrans -> Transition
Transition { trans_many :: DFA
trans_many = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys DTrans
dtransWithSpawn)
                                    , trans_single :: DFA
trans_single = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys DTrans
dtrans)
                                    , trans_how :: DTrans
trans_how = DTrans
dtransWithSpawn }
    where dtransWithSpawn :: DTrans
dtransWithSpawn = DTrans -> DTrans
addSpawn DTrans
dtrans

  makeTransition :: DTrans -> Transition
  makeTransition :: DTrans -> Transition
makeTransition dtrans :: DTrans
dtrans | Bool
hasSpawn  = Transition :: DFA -> DFA -> DTrans -> Transition
Transition { trans_many :: DFA
trans_many = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys DTrans
dtrans)
                                                 , trans_single :: DFA
trans_single = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys (Index -> DTrans -> DTrans
forall a. Index -> IntMap a -> IntMap a
IMap.delete Index
startIndex DTrans
dtrans))
                                                 , trans_how :: DTrans
trans_how = DTrans
dtrans }
                        | Bool
otherwise = Transition :: DFA -> DFA -> DTrans -> Transition
Transition { trans_many :: DFA
trans_many = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys DTrans
dtrans)
                                                 , trans_single :: DFA
trans_single = [Index] -> DFA
indexesToDFA (DTrans -> [Index]
forall a. IntMap a -> [Index]
IMap.keys DTrans
dtrans)
                                                 , trans_how :: DTrans
trans_how = DTrans
dtrans }
    where hasSpawn :: Bool
hasSpawn = Bool
-> (IntMap (DoPa, Instructions) -> Bool)
-> Maybe (IntMap (DoPa, Instructions))
-> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False IntMap (DoPa, Instructions) -> Bool
forall a. IntMap a -> Bool
IMap.null (Index -> DTrans -> Maybe (IntMap (DoPa, Instructions))
forall a. Index -> IntMap a -> Maybe a
IMap.lookup Index
startIndex DTrans
dtrans)

  -- coming from (-1) means spawn a new starting item
  addSpawn :: DTrans -> DTrans
  addSpawn :: DTrans -> DTrans
addSpawn dtrans :: DTrans
dtrans | Index -> DTrans -> Bool
forall a. Index -> IntMap a -> Bool
IMap.member Index
startIndex DTrans
dtrans = DTrans
dtrans
                  | Bool
otherwise = Index -> IntMap (DoPa, Instructions) -> DTrans -> DTrans
forall a. Index -> a -> IntMap a -> IntMap a
IMap.insert Index
startIndex IntMap (DoPa, Instructions)
forall a. Monoid a => a
mempty DTrans
dtrans

  indexToDFA :: Index -> DFA  -- used to seed the Trie from the NFA
  indexToDFA :: Index -> DFA
indexToDFA i :: Index
i = {-# SCC "nfaToDFA.indexToDFA" #-} SetIndex -> DT -> DFA
makeDFA (Index -> SetIndex
ISet.singleton Index
source) (QT -> DT
qtToDT QT
qtIn)
    where
      (QNFA {q_id :: QNFA -> Index
q_id = Index
source,q_qt :: QNFA -> QT
q_qt = QT
qtIn}) = Array Index QNFA
aQNFAArray Index QNFA -> Index -> QNFA
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!Index
i
      qtToDT :: QT -> DT
      qtToDT :: QT -> DT
qtToDT (Testing {qt_test :: QT -> WhichTest
qt_test=WhichTest
wt, qt_dopas :: QT -> EnumSet DoPa
qt_dopas=EnumSet DoPa
dopas, qt_a :: QT -> QT
qt_a=QT
a, qt_b :: QT -> QT
qt_b=QT
b}) =
          Testing' :: WhichTest -> EnumSet DoPa -> DT -> DT -> DT
Testing' { dt_test :: WhichTest
dt_test = WhichTest
wt
                   , dt_dopas :: EnumSet DoPa
dt_dopas = EnumSet DoPa
dopas
                   , dt_a :: DT
dt_a = QT -> DT
qtToDT QT
a
                   , dt_b :: DT
dt_b = QT -> DT
qtToDT QT
b }
      qtToDT (Simple {qt_win :: QT -> WinTags
qt_win=WinTags
w, qt_trans :: QT -> CharMap QTrans
qt_trans=CharMap QTrans
t, qt_other :: QT -> QTrans
qt_other=QTrans
o}) =
        Simple' :: IntMap Instructions -> CharMap Transition -> Transition -> DT
Simple' { dt_win :: IntMap Instructions
dt_win = IntMap Instructions
makeWinner
                , dt_trans :: CharMap Transition
dt_trans = (QTrans -> Transition) -> CharMap QTrans -> CharMap Transition
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap QTrans -> Transition
qtransToDFA CharMap QTrans
t
--                , dt_other = if IMap.null o then Just (newTransition $ IMap.singleton startIndex mempty) else Just (qtransToDFA o)}
                , dt_other :: Transition
dt_other = QTrans -> Transition
qtransToDFA QTrans
o}
        where
          makeWinner :: IntMap {- Index -} Instructions --  (RunState ())
          makeWinner :: IntMap Instructions
makeWinner | WinTags -> Bool
noWin WinTags
w = IntMap Instructions
forall a. IntMap a
IMap.empty
                     | Bool
otherwise = Index -> Instructions -> IntMap Instructions
forall a. Index -> a -> IntMap a
IMap.singleton Index
source (WinTags -> Instructions
cleanWin WinTags
w)

          qtransToDFA :: QTrans -> Transition
          qtransToDFA :: QTrans -> Transition
qtransToDFA qtrans :: QTrans
qtrans = {-# SCC "nfaToDFA.indexToDFA.qtransToDFA" #-}
                               DTrans -> Transition
newTransition DTrans
dtrans
            where
              dtrans :: DTrans
              dtrans :: DTrans
dtrans =[(Index, IntMap (DoPa, Instructions))] -> DTrans
forall a. [(Index, a)] -> IntMap a
IMap.fromDistinctAscList ([(Index, IntMap (DoPa, Instructions))] -> DTrans)
-> ([(Index, (DoPa, Instructions))]
    -> [(Index, IntMap (DoPa, Instructions))])
-> [(Index, (DoPa, Instructions))]
-> DTrans
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((DoPa, Instructions) -> IntMap (DoPa, Instructions))
-> [(Index, (DoPa, Instructions))]
-> [(Index, IntMap (DoPa, Instructions))]
forall (f :: * -> *) t1 t2 t.
Functor f =>
(t1 -> t2) -> f (t, t1) -> f (t, t2)
mapSnd (Index -> (DoPa, Instructions) -> IntMap (DoPa, Instructions)
forall a. Index -> a -> IntMap a
IMap.singleton Index
source) ([(Index, (DoPa, Instructions))] -> DTrans)
-> [(Index, (DoPa, Instructions))] -> DTrans
forall a b. (a -> b) -> a -> b
$ [(Index, (DoPa, Instructions))]
best
              best :: [(Index {- Destination -} ,(DoPa,Instructions))]
              best :: [(Index, (DoPa, Instructions))]
best = Array Index OP -> QTrans -> [(Index, (DoPa, Instructions))]
pickQTrans Array Index OP
aTagOp (QTrans -> [(Index, (DoPa, Instructions))])
-> QTrans -> [(Index, (DoPa, Instructions))]
forall a b. (a -> b) -> a -> b
$ QTrans
qtrans

  -- The DFA states are built up by merging the singleton ones converted from the NFA.
  -- Thus the "source" indices in the DTrans should not collide.
  mergeDFA :: DFA -> DFA -> DFA
  mergeDFA :: DFA -> DFA -> DFA
mergeDFA d1 :: DFA
d1 d2 :: DFA
d2 = {-# SCC "nfaToDFA.mergeDFA" #-} SetIndex -> DT -> DFA
makeDFA SetIndex
i DT
dt
    where
      i :: SetIndex
i = DFA -> SetIndex
d_id DFA
d1 SetIndex -> SetIndex -> SetIndex
forall a. Monoid a => a -> a -> a
`mappend` DFA -> SetIndex
d_id DFA
d2
      dt :: DT
dt = DFA -> DT
d_dt DFA
d1 DT -> DT -> DT
`mergeDT` DFA -> DT
d_dt DFA
d2
      mergeDT,nestDT :: DT -> DT -> DT
      mergeDT :: DT -> DT -> DT
mergeDT (Simple' w1 :: IntMap Instructions
w1 t1 :: CharMap Transition
t1 o1 :: Transition
o1) (Simple' w2 :: IntMap Instructions
w2 t2 :: CharMap Transition
t2 o2 :: Transition
o2) = IntMap Instructions -> CharMap Transition -> Transition -> DT
Simple' IntMap Instructions
w CharMap Transition
t Transition
o
        where
          w :: IntMap Instructions
w = IntMap Instructions
w1 IntMap Instructions -> IntMap Instructions -> IntMap Instructions
forall a. Monoid a => a -> a -> a
`mappend` IntMap Instructions
w2
          t :: CharMap Transition
t = CharMap Transition
fuseDTrans -- t1 o1 t2 o2
          o :: Transition
o = Transition -> Transition -> Transition
mergeDTrans Transition
o1 Transition
o2
          -- This is very much like mergeQTrans
          mergeDTrans :: Transition -> Transition -> Transition
          mergeDTrans :: Transition -> Transition -> Transition
mergeDTrans (Transition {trans_how :: Transition -> DTrans
trans_how=DTrans
dt1}) (Transition {trans_how :: Transition -> DTrans
trans_how=DTrans
dt2}) = DTrans -> Transition
makeTransition DTrans
dtrans
            where dtrans :: DTrans
dtrans = (IntMap (DoPa, Instructions)
 -> IntMap (DoPa, Instructions) -> IntMap (DoPa, Instructions))
-> DTrans -> DTrans -> DTrans
forall a. (a -> a -> a) -> IntMap a -> IntMap a -> IntMap a
IMap.unionWith IntMap (DoPa, Instructions)
-> IntMap (DoPa, Instructions) -> IntMap (DoPa, Instructions)
forall a. IntMap a -> IntMap a -> IntMap a
IMap.union DTrans
dt1 DTrans
dt2
          -- This is very much like fuseQTrans
          fuseDTrans :: CharMap Transition
          fuseDTrans :: CharMap Transition
fuseDTrans = IntMap Transition -> CharMap Transition
forall a. IntMap a -> CharMap a
CharMap ([(Index, Transition)] -> IntMap Transition
forall a. [(Index, a)] -> IntMap a
IMap.fromDistinctAscList ([(Index, Transition)]
-> [(Index, Transition)] -> [(Index, Transition)]
fuse [(Index, Transition)]
l1 [(Index, Transition)]
l2))
            where
              l1 :: [(Index, Transition)]
l1 = IntMap Transition -> [(Index, Transition)]
forall a. IntMap a -> [(Index, a)]
IMap.toAscList (CharMap Transition -> IntMap Transition
forall a. CharMap a -> IntMap a
unCharMap CharMap Transition
t1)
              l2 :: [(Index, Transition)]
l2 = IntMap Transition -> [(Index, Transition)]
forall a. IntMap a -> [(Index, a)]
IMap.toAscList (CharMap Transition -> IntMap Transition
forall a. CharMap a -> IntMap a
unCharMap CharMap Transition
t2)
              fuse :: [(IMap.Key, Transition)]
                   -> [(IMap.Key, Transition)]
                   -> [(IMap.Key, Transition)]
              fuse :: [(Index, Transition)]
-> [(Index, Transition)] -> [(Index, Transition)]
fuse [] y :: [(Index, Transition)]
y = ((Index, Transition) -> (Index, Transition))
-> [(Index, Transition)] -> [(Index, Transition)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Transition -> Transition)
-> (Index, Transition) -> (Index, Transition)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Transition -> Transition -> Transition
mergeDTrans Transition
o1)) [(Index, Transition)]
y
              fuse x :: [(Index, Transition)]
x [] = ((Index, Transition) -> (Index, Transition))
-> [(Index, Transition)] -> [(Index, Transition)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Transition -> Transition)
-> (Index, Transition) -> (Index, Transition)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Transition -> Transition -> Transition
mergeDTrans Transition
o2)) [(Index, Transition)]
x
              fuse x :: [(Index, Transition)]
x@((xc :: Index
xc,xa :: Transition
xa):xs :: [(Index, Transition)]
xs) y :: [(Index, Transition)]
y@((yc :: Index
yc,ya :: Transition
ya):ys :: [(Index, Transition)]
ys) = 
                case Index -> Index -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Index
xc Index
yc of
                  LT -> (Index
xc,Transition -> Transition -> Transition
mergeDTrans Transition
o2 Transition
xa) (Index, Transition)
-> [(Index, Transition)] -> [(Index, Transition)]
forall a. a -> [a] -> [a]
: [(Index, Transition)]
-> [(Index, Transition)] -> [(Index, Transition)]
fuse [(Index, Transition)]
xs [(Index, Transition)]
y
                  EQ -> (Index
xc,Transition -> Transition -> Transition
mergeDTrans Transition
xa Transition
ya) (Index, Transition)
-> [(Index, Transition)] -> [(Index, Transition)]
forall a. a -> [a] -> [a]
: [(Index, Transition)]
-> [(Index, Transition)] -> [(Index, Transition)]
fuse [(Index, Transition)]
xs [(Index, Transition)]
ys
                  GT -> (Index
yc,Transition -> Transition -> Transition
mergeDTrans Transition
o1 Transition
ya) (Index, Transition)
-> [(Index, Transition)] -> [(Index, Transition)]
forall a. a -> [a] -> [a]
: [(Index, Transition)]
-> [(Index, Transition)] -> [(Index, Transition)]
fuse [(Index, Transition)]
x [(Index, Transition)]
ys
      mergeDT dt1 :: DT
dt1@(Testing' wt1 :: WhichTest
wt1 dopas1 :: EnumSet DoPa
dopas1 a1 :: DT
a1 b1 :: DT
b1) dt2 :: DT
dt2@(Testing' wt2 :: WhichTest
wt2 dopas2 :: EnumSet DoPa
dopas2 a2 :: DT
a2 b2 :: DT
b2) =
        case WhichTest -> WhichTest -> Ordering
forall a. Ord a => a -> a -> Ordering
compare WhichTest
wt1 WhichTest
wt2 of
          LT -> DT -> DT -> DT
nestDT DT
dt1 DT
dt2
          EQ -> Testing' :: WhichTest -> EnumSet DoPa -> DT -> DT -> DT
Testing' { dt_test :: WhichTest
dt_test = WhichTest
wt1
                         , dt_dopas :: EnumSet DoPa
dt_dopas = EnumSet DoPa
dopas1 EnumSet DoPa -> EnumSet DoPa -> EnumSet DoPa
forall a. Monoid a => a -> a -> a
`mappend` EnumSet DoPa
dopas2
                         , dt_a :: DT
dt_a = DT -> DT -> DT
mergeDT DT
a1 DT
a2
                         , dt_b :: DT
dt_b = DT -> DT -> DT
mergeDT DT
b1 DT
b2 }
          GT -> DT -> DT -> DT
nestDT DT
dt2 DT
dt1
      mergeDT dt1 :: DT
dt1@(Testing' {}) dt2 :: DT
dt2 = DT -> DT -> DT
nestDT DT
dt1 DT
dt2
      mergeDT dt1 :: DT
dt1 dt2 :: DT
dt2@(Testing' {}) = DT -> DT -> DT
nestDT DT
dt2 DT
dt1
      nestDT :: DT -> DT -> DT
nestDT dt1 :: DT
dt1@(Testing' {dt_a :: DT -> DT
dt_a=DT
a,dt_b :: DT -> DT
dt_b=DT
b}) dt2 :: DT
dt2 = DT
dt1 { dt_a :: DT
dt_a = DT -> DT -> DT
mergeDT DT
a DT
dt2, dt_b :: DT
dt_b = DT -> DT -> DT
mergeDT DT
b DT
dt2 }
      nestDT _ _ = String -> DT
forall a. String -> a
err "nestDT called on Simple -- cannot happen"

patternToRegex :: (Pattern,(GroupIndex, DoPa)) -> CompOption -> ExecOption -> Regex
patternToRegex :: (Pattern, (Index, DoPa)) -> CompOption -> ExecOption -> Regex
patternToRegex pattern :: (Pattern, (Index, DoPa))
pattern compOpt :: CompOption
compOpt execOpt :: ExecOption
execOpt = ((Index, Array Index QNFA), Array Index OP,
 Array Index [GroupInfo])
-> CompOption -> ExecOption -> Regex
nfaToDFA (CompOption
-> (Pattern, (Index, DoPa))
-> ((Index, Array Index QNFA), Array Index OP,
    Array Index [GroupInfo])
patternToNFA CompOption
compOpt (Pattern, (Index, DoPa))
pattern) CompOption
compOpt ExecOption
execOpt

dfaMap :: DFA -> Data.Map.Map SetIndex DFA
dfaMap :: DFA -> Map SetIndex DFA
dfaMap = Map SetIndex DFA -> DFA -> Map SetIndex DFA
seen (Map SetIndex DFA
forall k a. Map k a
Data.Map.empty) where
  seen :: Map SetIndex DFA -> DFA -> Map SetIndex DFA
seen old :: Map SetIndex DFA
old d :: DFA
d@(DFA {d_id :: DFA -> SetIndex
d_id=SetIndex
i,d_dt :: DFA -> DT
d_dt=DT
dt}) =
    if SetIndex
i SetIndex -> Map SetIndex DFA -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Data.Map.member` Map SetIndex DFA
old
      then Map SetIndex DFA
old
      else let new :: Map SetIndex DFA
new = SetIndex -> DFA -> Map SetIndex DFA -> Map SetIndex DFA
forall k a. Ord k => k -> a -> Map k a -> Map k a
Data.Map.insert SetIndex
i DFA
d Map SetIndex DFA
old
           in (Map SetIndex DFA -> DFA -> Map SetIndex DFA)
-> Map SetIndex DFA -> [DFA] -> Map SetIndex DFA
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Map SetIndex DFA -> DFA -> Map SetIndex DFA
seen Map SetIndex DFA
new (DT -> [DFA]
flattenDT DT
dt)

-- Get all trans_many states
flattenDT :: DT -> [DFA]
flattenDT :: DT -> [DFA]
flattenDT (Simple' {dt_trans :: DT -> CharMap Transition
dt_trans=(CharMap mt :: IntMap Transition
mt),dt_other :: DT -> Transition
dt_other=Transition
o}) = (Transition -> [DFA]) -> [Transition] -> [DFA]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\d :: Transition
d -> [Transition -> DFA
trans_many Transition
d {-,trans_single d-}]) ([Transition] -> [DFA])
-> (IntMap Transition -> [Transition])
-> IntMap Transition
-> [DFA]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:) Transition
o ([Transition] -> [Transition])
-> (IntMap Transition -> [Transition])
-> IntMap Transition
-> [Transition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntMap Transition -> [Transition]
forall a. IntMap a -> [a]
IMap.elems (IntMap Transition -> [DFA]) -> IntMap Transition -> [DFA]
forall a b. (a -> b) -> a -> b
$ IntMap Transition
mt
flattenDT (Testing' {dt_a :: DT -> DT
dt_a=DT
a,dt_b :: DT -> DT
dt_b=DT
b}) = DT -> [DFA]
flattenDT DT
a [DFA] -> [DFA] -> [DFA]
forall a. [a] -> [a] -> [a]
++ DT -> [DFA]
flattenDT DT
b

examineDFA :: Regex -> String
examineDFA :: Regex -> String
examineDFA (Regex {regex_dfa :: Regex -> DFA
regex_dfa=DFA
dfa}) = [String] -> String
unlines ([String] -> String) -> ([DFA] -> [String]) -> [DFA] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:) ("Number of reachable DFA states: "String -> String -> String
forall a. [a] -> [a] -> [a]
++Index -> String
forall a. Show a => a -> String
show ([DFA] -> Index
forall (t :: * -> *) a. Foldable t => t a -> Index
length [DFA]
dfas)) ([String] -> [String]) -> ([DFA] -> [String]) -> [DFA] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DFA -> String) -> [DFA] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map DFA -> String
forall a. Show a => a -> String
show ([DFA] -> String) -> [DFA] -> String
forall a b. (a -> b) -> a -> b
$ [DFA]
dfas
  where dfas :: [DFA]
dfas = Map SetIndex DFA -> [DFA]
forall k a. Map k a -> [a]
Data.Map.elems (Map SetIndex DFA -> [DFA]) -> Map SetIndex DFA -> [DFA]
forall a b. (a -> b) -> a -> b
$ DFA -> Map SetIndex DFA
dfaMap DFA
dfa

{-

fillMap :: Tag -> IntMap (Position,Bool)
fillMap tag = IMap.fromDistinctAscList [(t,(-1,True)) | t <- [0..tag] ]

diffMap :: IntMap (Position,Bool) -> IntMap (Position,Bool) -> [(Index,(Position,Bool))]
diffMap old new = IMap.toList (IMap.differenceWith (\a b -> if a==b then Nothing else Just b) old new)

examineDFA :: (DFA,Index,Array Tag OP,Array GroupIndex [GroupInfo]) -> String
examineDFA (dfa,_,aTags,_) = unlines $ map (examineDFA' (snd . bounds $ aTags)) (Map.elems $ dfaMap dfa)

examineDFA' :: Tag -> DFA -> String
examineDFA' maxTag = showDFA (fillMap maxTag)

{-
instance Show DFA where
  show (DFA {d_id=i,d_dt=dt}) = "DFA {d_id = "++show (ISet.toList i)
                            ++"\n    ,d_dt = "++ show dt
                            ++"\n}"
-}
-- instance Show DT where show = showDT

showDFA :: IntMap (Position,Bool) -> DFA -> String
showDFA m (DFA {d_id=i,d_dt=dt}) = "DFA {d_id = "++show (ISet.toList i)
                               ++"\n    ,d_dt = "++ showDT m dt
                               ++"\n}"
-}



-- pick QTrans can be told the unique source and knows all the
-- destinations (hmm...along with qt_win)!  So if in ascending destination order the last source
-- is free to mutatate the old state.  If the QTrans has only one
-- entry then all we need to do is mutate that entry when making a
-- transition.
-- 
pickQTrans :: Array Tag OP -> QTrans -> [({-Destination-}Index,(DoPa,Instructions))]
pickQTrans :: Array Index OP -> QTrans -> [(Index, (DoPa, Instructions))]
pickQTrans op :: Array Index OP
op tr :: QTrans
tr = ([TagCommand] -> (DoPa, Instructions))
-> [(Index, [TagCommand])] -> [(Index, (DoPa, Instructions))]
forall (f :: * -> *) t1 t2 t.
Functor f =>
(t1 -> t2) -> f (t, t1) -> f (t, t2)
mapSnd (Array Index OP -> [TagCommand] -> (DoPa, Instructions)
bestTrans Array Index OP
op) ([(Index, [TagCommand])] -> [(Index, (DoPa, Instructions))])
-> (QTrans -> [(Index, [TagCommand])])
-> QTrans
-> [(Index, (DoPa, Instructions))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QTrans -> [(Index, [TagCommand])]
forall a. IntMap a -> [(Index, a)]
IMap.toList (QTrans -> [(Index, (DoPa, Instructions))])
-> QTrans -> [(Index, (DoPa, Instructions))]
forall a b. (a -> b) -> a -> b
$ QTrans
tr

cleanWin :: WinTags -> Instructions
cleanWin :: WinTags -> Instructions
cleanWin = WinTags -> Instructions
toInstructions

bestTrans :: Array Tag OP -> [TagCommand] -> (DoPa,Instructions)
bestTrans :: Array Index OP -> [TagCommand] -> (DoPa, Instructions)
bestTrans _ [] = String -> (DoPa, Instructions)
forall a. String -> a
err "bestTrans : There were no transition choose from!"
bestTrans aTagOP :: Array Index OP
aTagOP (f :: TagCommand
f:fs :: [TagCommand]
fs) | [TagCommand] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TagCommand]
fs = TagCommand -> (DoPa, Instructions)
canonical TagCommand
f
                        | Bool
otherwise = (DoPa, Instructions)
answer -- if null toDisplay then answer else trace toDisplay answer
 where
  answer :: (DoPa, Instructions)
answer = ((DoPa, Instructions) -> TagCommand -> (DoPa, Instructions))
-> (DoPa, Instructions) -> [TagCommand] -> (DoPa, Instructions)
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (DoPa, Instructions) -> TagCommand -> (DoPa, Instructions)
pick (TagCommand -> (DoPa, Instructions)
canonical TagCommand
f) [TagCommand]
fs
  {- toDisplay | null fs = ""
               | otherwise = unlines $ "bestTrans" : show (answer) : "from among" : concatMap (\x -> [show x, show (toInstructions (snd x))]) (f:fs) -}
  canonical :: TagCommand -> (DoPa,Instructions)
  canonical :: TagCommand -> (DoPa, Instructions)
canonical (dopa :: DoPa
dopa,spec :: WinTags
spec) = (DoPa
dopa, WinTags -> Instructions
toInstructions WinTags
spec)
  pick :: (DoPa,Instructions) -> TagCommand -> (DoPa,Instructions)
  pick :: (DoPa, Instructions) -> TagCommand -> (DoPa, Instructions)
pick win :: (DoPa, Instructions)
win@(dopa1 :: DoPa
dopa1,winI :: Instructions
winI) (dopa2 :: DoPa
dopa2,spec :: WinTags
spec) =
    let nextI :: Instructions
nextI = WinTags -> Instructions
toInstructions WinTags
spec
--    in case compareWith choose winPos nextPos of -- XXX 2009: add in enterOrbit information
    in case (Maybe (Index, Action) -> Maybe (Index, Action) -> Ordering)
-> [(Index, Action)] -> [(Index, Action)] -> Ordering
forall x a b c.
(Ord x, Monoid a) =>
(Maybe (x, b) -> Maybe (x, c) -> a) -> [(x, b)] -> [(x, c)] -> a
compareWith Maybe (Index, Action) -> Maybe (Index, Action) -> Ordering
choose (Instructions -> [(Index, Action)]
toListing Instructions
winI) (Instructions -> [(Index, Action)]
toListing Instructions
nextI) of
         GT -> (DoPa, Instructions)
win
         LT -> (DoPa
dopa2,Instructions
nextI)
         EQ -> if DoPa
dopa1 DoPa -> DoPa -> Bool
forall a. Ord a => a -> a -> Bool
>= DoPa
dopa2 then (DoPa, Instructions)
win else (DoPa
dopa2,Instructions
nextI) -- no deep reason not to just pick win

  toListing :: Instructions -> [(Tag,Action)]
  toListing :: Instructions -> [(Index, Action)]
toListing (Instructions {newPos :: Instructions -> [(Index, Action)]
newPos = [(Index, Action)]
nextPos}) = ((Index, Action) -> Bool) -> [(Index, Action)] -> [(Index, Action)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Index, Action) -> Bool
forall a. (a, Action) -> Bool
notReset [(Index, Action)]
nextPos
    where notReset :: (a, Action) -> Bool
notReset (_,SetVal (-1)) = Bool
False
          notReset _ = Bool
True
{-
  toListing (Instructions {newPos = nextPos}) = mergeTagOrbit nextPos (filter snd nextFlags)

  mergeTagOrbit xx [] = xx
  mergeTagOrbit [] yy = yy
  mergeTagOrbit xx@(x:xs) yy@(y:ys) = 
    case compare (fst x) (fst y) of
      GT -> y : mergeTagOrbit xx ys
      LT -> x : mergeTagOrbit xs yy
      EQ -> x : mergeTagOrbit xs ys -- keep tag setting over orbit setting.
-}

  {-# INLINE choose #-}
  choose :: Maybe (Tag,Action) -> Maybe (Tag,Action) -> Ordering
  choose :: Maybe (Index, Action) -> Maybe (Index, Action) -> Ordering
choose Nothing Nothing = Ordering
EQ
  choose Nothing x :: Maybe (Index, Action)
x = Ordering -> Ordering
flipOrder (Maybe (Index, Action) -> Maybe (Index, Action) -> Ordering
choose Maybe (Index, Action)
x Maybe (Index, Action)
forall a. Maybe a
Nothing)
  choose (Just (tag :: Index
tag,_post :: Action
_post)) Nothing =
    case Array Index OP
aTagOPArray Index OP -> Index -> OP
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!Index
tag of
      Maximize -> Ordering
GT
      Minimize -> Ordering
LT -- needed to choose best path inside nested * operators,
                    -- this needs a leading Minimize tag inside at least the parent * operator
      Ignore -> Ordering
GT -- XXX this is a guess in analogy with Maximize for the end bit of a group
      Orbit -> Ordering
LT -- trace ("choose LT! Just "++show tag++" < Nothing") LT -- 2009 XXX : comment out next line and use the Orbit instead
--      Orbit -> err $ "bestTrans.choose : Very Unexpeted Orbit in Just Nothing: "++show (tag,post,aTagOP,f:fs)
  choose (Just (tag :: Index
tag,post1 :: Action
post1)) (Just (_,post2 :: Action
post2)) =
    case Array Index OP
aTagOPArray Index OP -> Index -> OP
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!Index
tag of
      Maximize -> Ordering
order
      Minimize -> Ordering -> Ordering
flipOrder Ordering
order
      Ignore -> Ordering
EQ
      Orbit -> Ordering
EQ
--      Orbit -> err $ "bestTrans.choose : Very Unexpeted Orbit in Just Just: "++show (tag,(post1,post2),aTagOP,f:fs)
   where order :: Ordering
order = case (Action
post1,Action
post2) of
                   (SetPre,SetPre) -> Ordering
EQ
                   (SetPost,SetPost) -> Ordering
EQ
                   (SetPre,SetPost) -> Ordering
LT
                   (SetPost,SetPre) -> Ordering
GT
                   (SetVal v1 :: Index
v1,SetVal v2 :: Index
v2) -> Index -> Index -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Index
v1 Index
v2
                   _ -> String -> Ordering
forall a. String -> a
err (String -> Ordering) -> String -> Ordering
forall a b. (a -> b) -> a -> b
$ "bestTrans.compareWith.choose sees incomparable "String -> String -> String
forall a. [a] -> [a] -> [a]
++(Index, Action, Action) -> String
forall a. Show a => a -> String
show (Index
tag,Action
post1,Action
post2)


  {-# INLINE compareWith #-}
  compareWith :: (Ord x,Monoid a) => (Maybe (x,b) -> Maybe (x,c) -> a) -> [(x,b)] -> [(x,c)] -> a
  compareWith :: (Maybe (x, b) -> Maybe (x, c) -> a) -> [(x, b)] -> [(x, c)] -> a
compareWith comp :: Maybe (x, b) -> Maybe (x, c) -> a
comp = [(x, b)] -> [(x, c)] -> a
cw where
    cw :: [(x, b)] -> [(x, c)] -> a
cw [] [] = Maybe (x, b) -> Maybe (x, c) -> a
comp Maybe (x, b)
forall a. Maybe a
Nothing Maybe (x, c)
forall a. Maybe a
Nothing
    cw xx :: [(x, b)]
xx@(x :: (x, b)
x:xs :: [(x, b)]
xs) yy :: [(x, c)]
yy@(y :: (x, c)
y:ys :: [(x, c)]
ys) =
      case x -> x -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((x, b) -> x
forall a b. (a, b) -> a
fst (x, b)
x) ((x, c) -> x
forall a b. (a, b) -> a
fst (x, c)
y) of
        GT -> Maybe (x, b) -> Maybe (x, c) -> a
comp Maybe (x, b)
forall a. Maybe a
Nothing  ((x, c) -> Maybe (x, c)
forall a. a -> Maybe a
Just (x, c)
y) a -> a -> a
forall a. Monoid a => a -> a -> a
`mappend` [(x, b)] -> [(x, c)] -> a
cw [(x, b)]
xx [(x, c)]
ys
        EQ -> Maybe (x, b) -> Maybe (x, c) -> a
comp ((x, b) -> Maybe (x, b)
forall a. a -> Maybe a
Just (x, b)
x) ((x, c) -> Maybe (x, c)
forall a. a -> Maybe a
Just (x, c)
y) a -> a -> a
forall a. Monoid a => a -> a -> a
`mappend` [(x, b)] -> [(x, c)] -> a
cw [(x, b)]
xs [(x, c)]
ys
        LT -> Maybe (x, b) -> Maybe (x, c) -> a
comp ((x, b) -> Maybe (x, b)
forall a. a -> Maybe a
Just (x, b)
x) Maybe (x, c)
forall a. Maybe a
Nothing  a -> a -> a
forall a. Monoid a => a -> a -> a
`mappend` [(x, b)] -> [(x, c)] -> a
cw [(x, b)]
xs [(x, c)]
yy
    cw xx :: [(x, b)]
xx [] = ((x, b) -> a -> a) -> a -> [(x, b)] -> a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\x :: (x, b)
x rest :: a
rest -> Maybe (x, b) -> Maybe (x, c) -> a
comp ((x, b) -> Maybe (x, b)
forall a. a -> Maybe a
Just (x, b)
x) Maybe (x, c)
forall a. Maybe a
Nothing  a -> a -> a
forall a. Monoid a => a -> a -> a
`mappend` a
rest) a
forall a. Monoid a => a
mempty [(x, b)]
xx
    cw [] yy :: [(x, c)]
yy = ((x, c) -> a -> a) -> a -> [(x, c)] -> a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\y :: (x, c)
y rest :: a
rest -> Maybe (x, b) -> Maybe (x, c) -> a
comp Maybe (x, b)
forall a. Maybe a
Nothing  ((x, c) -> Maybe (x, c)
forall a. a -> Maybe a
Just (x, c)
y) a -> a -> a
forall a. Monoid a => a -> a -> a
`mappend` a
rest) a
forall a. Monoid a => a
mempty [(x, c)]
yy

                   
isDFAFrontAnchored :: DFA -> Bool
isDFAFrontAnchored :: DFA -> Bool
isDFAFrontAnchored = DT -> Bool
isDTFrontAnchored (DT -> Bool) -> (DFA -> DT) -> DFA -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DFA -> DT
d_dt
 where
  isDTFrontAnchored :: DT -> Bool
  isDTFrontAnchored :: DT -> Bool
isDTFrontAnchored (Simple' {}) = Bool
False
  isDTFrontAnchored (Testing' {dt_test :: DT -> WhichTest
dt_test=WhichTest
wt,dt_a :: DT -> DT
dt_a=DT
a,dt_b :: DT -> DT
dt_b=DT
b}) | WhichTest
wt WhichTest -> WhichTest -> Bool
forall a. Eq a => a -> a -> Bool
== WhichTest
Test_BOL = DT -> Bool
isDTLosing DT
b
                                                          | Bool
otherwise = DT -> Bool
isDTFrontAnchored DT
a Bool -> Bool -> Bool
&& DT -> Bool
isDTFrontAnchored DT
b
   where
    -- can DT never win or accept a character (when following trans_single)?
    isDTLosing :: DT -> Bool
    isDTLosing :: DT -> Bool
isDTLosing (Testing' {dt_a :: DT -> DT
dt_a=DT
a',dt_b :: DT -> DT
dt_b=DT
b'}) = DT -> Bool
isDTLosing DT
a' Bool -> Bool -> Bool
&& DT -> Bool
isDTLosing DT
b'
    isDTLosing (Simple' {dt_win :: DT -> IntMap Instructions
dt_win=IntMap Instructions
w}) | Bool -> Bool
not (IntMap Instructions -> Bool
forall a. IntMap a -> Bool
IMap.null IntMap Instructions
w) = Bool
False -- can win with 0 characters
    isDTLosing (Simple' {dt_trans :: DT -> CharMap Transition
dt_trans=CharMap mt :: IntMap Transition
mt,dt_other :: DT -> Transition
dt_other=Transition
o}) =
      let ts :: [Transition]
ts = Transition
o Transition -> [Transition] -> [Transition]
forall a. a -> [a] -> [a]
: IntMap Transition -> [Transition]
forall a. IntMap a -> [a]
IMap.elems IntMap Transition
mt
      in (Transition -> Bool) -> [Transition] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Transition -> Bool
transLoses [Transition]
ts
     where
      transLoses :: Transition -> Bool
      transLoses :: Transition -> Bool
transLoses (Transition {trans_single :: Transition -> DFA
trans_single=DFA
dfa,trans_how :: Transition -> DTrans
trans_how=DTrans
dtrans}) = DFA -> Bool
isDTLose DFA
dfa Bool -> Bool -> Bool
|| DTrans -> Bool
onlySpawns DTrans
dtrans
       where
        isDTLose :: DFA -> Bool
        isDTLose :: DFA -> Bool
isDTLose dfa' :: DFA
dfa' = SetIndex -> Bool
ISet.null (DFA -> SetIndex
d_id DFA
dfa')
        onlySpawns :: DTrans -> Bool
        onlySpawns :: DTrans -> Bool
onlySpawns t :: DTrans
t = case DTrans -> [IntMap (DoPa, Instructions)]
forall a. IntMap a -> [a]
IMap.elems DTrans
t of
                         [m :: IntMap (DoPa, Instructions)
m] -> IntMap (DoPa, Instructions) -> Bool
forall a. IntMap a -> Bool
IMap.null IntMap (DoPa, Instructions)
m
                         _ -> Bool
False

{- toInstructions -}

toInstructions :: TagList -> Instructions
toInstructions :: WinTags -> Instructions
toInstructions spec :: WinTags
spec =
  let (p :: IntMap Action
p,o :: IntMap AlterOrbit
o) = State (IntMap Action, IntMap AlterOrbit) ()
-> (IntMap Action, IntMap AlterOrbit)
-> (IntMap Action, IntMap AlterOrbit)
forall s a. State s a -> s -> s
execState (WinTags -> State (IntMap Action, IntMap AlterOrbit) ()
assemble WinTags
spec) (IntMap Action
forall a. Monoid a => a
mempty,IntMap AlterOrbit
forall a. Monoid a => a
mempty)
  in $WInstructions :: [(Index, Action)]
-> Maybe (Index -> OrbitTransformer) -> Instructions
Instructions { newPos :: [(Index, Action)]
newPos = IntMap Action -> [(Index, Action)]
forall a. IntMap a -> [(Index, a)]
IMap.toList IntMap Action
p
                  , newOrbits :: Maybe (Index -> OrbitTransformer)
newOrbits = if IntMap AlterOrbit -> Bool
forall a. IntMap a -> Bool
IMap.null IntMap AlterOrbit
o then Maybe (Index -> OrbitTransformer)
forall a. Maybe a
Nothing
                                  else (Index -> OrbitTransformer) -> Maybe (Index -> OrbitTransformer)
forall a. a -> Maybe a
Just ((Index -> OrbitTransformer) -> Maybe (Index -> OrbitTransformer))
-> (Index -> OrbitTransformer) -> Maybe (Index -> OrbitTransformer)
forall a b. (a -> b) -> a -> b
$ [(Index, AlterOrbit)] -> Index -> OrbitTransformer
alterOrbits (IntMap AlterOrbit -> [(Index, AlterOrbit)]
forall a. IntMap a -> [(Index, a)]
IMap.toList IntMap AlterOrbit
o)
                  }

type CompileInstructions a = State
  ( IntMap Action -- 2009: change to SetPre | SetPost enum
  , IntMap AlterOrbit
  ) a

data AlterOrbit = AlterReset                        -- removing the Orbits record from the OrbitLog
                | AlterLeave                        -- set inOrbit to False
                | AlterModify { AlterOrbit -> Bool
newInOrbit :: Bool   -- set inOrbit to the newInOrbit value
                              , AlterOrbit -> Bool
freshOrbit :: Bool}  -- freshOrbit of True means to set getOrbits to mempty
                  deriving (Index -> AlterOrbit -> String -> String
[AlterOrbit] -> String -> String
AlterOrbit -> String
(Index -> AlterOrbit -> String -> String)
-> (AlterOrbit -> String)
-> ([AlterOrbit] -> String -> String)
-> Show AlterOrbit
forall a.
(Index -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [AlterOrbit] -> String -> String
$cshowList :: [AlterOrbit] -> String -> String
show :: AlterOrbit -> String
$cshow :: AlterOrbit -> String
showsPrec :: Index -> AlterOrbit -> String -> String
$cshowsPrec :: Index -> AlterOrbit -> String -> String
Show)                   -- freshOrbit of False means try appending position or else Seq.empty

assemble :: TagList -> CompileInstructions ()
assemble :: WinTags -> State (IntMap Action, IntMap AlterOrbit) ()
assemble = ((Index, TagUpdate) -> State (IntMap Action, IntMap AlterOrbit) ())
-> WinTags -> State (IntMap Action, IntMap AlterOrbit) ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Index, TagUpdate) -> State (IntMap Action, IntMap AlterOrbit) ()
oneInstruction where
  oneInstruction :: (Index, TagUpdate) -> State (IntMap Action, IntMap AlterOrbit) ()
oneInstruction (tag :: Index
tag,command :: TagUpdate
command) =
    case TagUpdate
command of
      PreUpdate TagTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
setPreTag Index
tag
      PreUpdate ResetGroupStopTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
resetGroupTag Index
tag
      PreUpdate SetGroupStopTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
setGroupTag Index
tag
      PreUpdate ResetOrbitTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
resetOrbit Index
tag
      PreUpdate EnterOrbitTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
enterOrbit Index
tag
      PreUpdate LeaveOrbitTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
leaveOrbit Index
tag
      PostUpdate TagTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
setPostTag Index
tag
      PostUpdate ResetGroupStopTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
resetGroupTag Index
tag
      PostUpdate SetGroupStopTask -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
setGroupTag Index
tag
      _ -> String -> State (IntMap Action, IntMap AlterOrbit) ()
forall a. String -> a
err ("assemble : Weird orbit command: "String -> String -> String
forall a. [a] -> [a] -> [a]
++(Index, TagUpdate) -> String
forall a. Show a => a -> String
show (Index
tag,TagUpdate
command))

setPreTag :: Tag -> CompileInstructions ()
setPreTag :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
setPreTag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos Action
SetPre

setPostTag :: Tag -> CompileInstructions ()
setPostTag :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
setPostTag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos Action
SetPost

resetGroupTag :: Tag -> CompileInstructions ()
resetGroupTag :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
resetGroupTag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos (Index -> Action
SetVal (-1))

setGroupTag :: Tag -> CompileInstructions ()
setGroupTag :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
setGroupTag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos (Index -> Action
SetVal 0)

-- The following is ten times more complicated than it ought to be.  Sorry, I was too new, and now
-- too busy to clean this up.

resetOrbit :: Tag -> CompileInstructions ()
resetOrbit :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
resetOrbit tag :: Index
tag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos (Index -> Action
SetVal (-1)) Index
tag State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (IntMap AlterOrbit -> IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
modifyOrbit (Index -> AlterOrbit -> IntMap AlterOrbit -> IntMap AlterOrbit
forall a. Index -> a -> IntMap a -> IntMap a
IMap.insert Index
tag AlterOrbit
AlterReset)

enterOrbit :: Tag -> CompileInstructions ()
enterOrbit :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
enterOrbit tag :: Index
tag = Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos (Index -> Action
SetVal 0) Index
tag State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (IntMap AlterOrbit -> IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
modifyOrbit IntMap AlterOrbit -> IntMap AlterOrbit
changeOrbit where
  changeOrbit :: IntMap AlterOrbit -> IntMap AlterOrbit
changeOrbit = (AlterOrbit -> AlterOrbit -> AlterOrbit)
-> Index -> AlterOrbit -> IntMap AlterOrbit -> IntMap AlterOrbit
forall a. (a -> a -> a) -> Index -> a -> IntMap a -> IntMap a
IMap.insertWith AlterOrbit -> AlterOrbit -> AlterOrbit
forall p. p -> AlterOrbit -> AlterOrbit
overwriteOrbit Index
tag AlterOrbit
appendNewOrbit

  appendNewOrbit :: AlterOrbit
appendNewOrbit = AlterModify :: Bool -> Bool -> AlterOrbit
AlterModify {newInOrbit :: Bool
newInOrbit = Bool
True, freshOrbit :: Bool
freshOrbit = Bool
False} -- try to append
  startNewOrbit :: AlterOrbit
startNewOrbit  = AlterModify :: Bool -> Bool -> AlterOrbit
AlterModify {newInOrbit :: Bool
newInOrbit = Bool
True, freshOrbit :: Bool
freshOrbit = Bool
True}  -- will start a new series

  overwriteOrbit :: p -> AlterOrbit -> AlterOrbit
overwriteOrbit _ AlterReset = AlterOrbit
startNewOrbit
  overwriteOrbit _ AlterLeave = AlterOrbit
startNewOrbit
  overwriteOrbit _ (AlterModify {newInOrbit :: AlterOrbit -> Bool
newInOrbit = Bool
False}) = AlterOrbit
startNewOrbit
  overwriteOrbit _ (AlterModify {newInOrbit :: AlterOrbit -> Bool
newInOrbit = Bool
True}) =
    String -> AlterOrbit
forall a. String -> a
err (String -> AlterOrbit) -> String -> AlterOrbit
forall a b. (a -> b) -> a -> b
$ "enterOrbit: Cannot enterOrbit twice in a row: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Index -> String
forall a. Show a => a -> String
show Index
tag

leaveOrbit :: Tag -> CompileInstructions ()
leaveOrbit :: Index -> State (IntMap Action, IntMap AlterOrbit) ()
leaveOrbit tag :: Index
tag = (IntMap AlterOrbit -> IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
modifyOrbit IntMap AlterOrbit -> IntMap AlterOrbit
escapeOrbit where
  escapeOrbit :: IntMap AlterOrbit -> IntMap AlterOrbit
escapeOrbit = (AlterOrbit -> AlterOrbit -> AlterOrbit)
-> Index -> AlterOrbit -> IntMap AlterOrbit -> IntMap AlterOrbit
forall a. (a -> a -> a) -> Index -> a -> IntMap a -> IntMap a
IMap.insertWith AlterOrbit -> AlterOrbit -> AlterOrbit
forall p. p -> AlterOrbit -> AlterOrbit
setInOrbitFalse Index
tag AlterOrbit
AlterLeave where
    setInOrbitFalse :: p -> AlterOrbit -> AlterOrbit
setInOrbitFalse _ x :: AlterOrbit
x@(AlterModify {}) = AlterOrbit
x {newInOrbit :: Bool
newInOrbit = Bool
False}
    setInOrbitFalse _ x :: AlterOrbit
x = AlterOrbit
x

modifyPos :: Action -> Tag -> CompileInstructions ()
modifyPos :: Action -> Index -> State (IntMap Action, IntMap AlterOrbit) ()
modifyPos todo :: Action
todo tag :: Index
tag = do
  (a :: IntMap Action
a,c :: IntMap AlterOrbit
c) <- StateT
  (IntMap Action, IntMap AlterOrbit)
  Identity
  (IntMap Action, IntMap AlterOrbit)
forall s (m :: * -> *). MonadState s m => m s
get
  let a' :: IntMap Action
a' = Index -> Action -> IntMap Action -> IntMap Action
forall a. Index -> a -> IntMap a -> IntMap a
IMap.insert Index
tag Action
todo IntMap Action
a
  IntMap Action
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall a b. a -> b -> b
seq IntMap Action
a' (State (IntMap Action, IntMap AlterOrbit) ()
 -> State (IntMap Action, IntMap AlterOrbit) ())
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall a b. (a -> b) -> a -> b
$ (IntMap Action, IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (IntMap Action
a',IntMap AlterOrbit
c)

modifyOrbit :: (IntMap AlterOrbit -> IntMap AlterOrbit) -> CompileInstructions ()
modifyOrbit :: (IntMap AlterOrbit -> IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
modifyOrbit f :: IntMap AlterOrbit -> IntMap AlterOrbit
f = do
  (a :: IntMap Action
a,c :: IntMap AlterOrbit
c) <- StateT
  (IntMap Action, IntMap AlterOrbit)
  Identity
  (IntMap Action, IntMap AlterOrbit)
forall s (m :: * -> *). MonadState s m => m s
get
  let c' :: IntMap AlterOrbit
c' = IntMap AlterOrbit -> IntMap AlterOrbit
f IntMap AlterOrbit
c
  IntMap AlterOrbit
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall a b. a -> b -> b
seq IntMap AlterOrbit
c' (State (IntMap Action, IntMap AlterOrbit) ()
 -> State (IntMap Action, IntMap AlterOrbit) ())
-> State (IntMap Action, IntMap AlterOrbit) ()
-> State (IntMap Action, IntMap AlterOrbit) ()
forall a b. (a -> b) -> a -> b
$ (IntMap Action, IntMap AlterOrbit)
-> State (IntMap Action, IntMap AlterOrbit) ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (IntMap Action
a,IntMap AlterOrbit
c')

----

alterOrbits :: [(Tag,AlterOrbit)] -> (Position -> OrbitTransformer)
alterOrbits :: [(Index, AlterOrbit)] -> Index -> OrbitTransformer
alterOrbits x :: [(Index, AlterOrbit)]
x = let items :: [Index -> OrbitTransformer]
items = ((Index, AlterOrbit) -> Index -> OrbitTransformer)
-> [(Index, AlterOrbit)] -> [Index -> OrbitTransformer]
forall a b. (a -> b) -> [a] -> [b]
map (Index, AlterOrbit) -> Index -> OrbitTransformer
alterOrbit [(Index, AlterOrbit)]
x
                in (\ pos :: Index
pos m :: OrbitLog
m -> (OrbitLog -> OrbitTransformer -> OrbitLog)
-> OrbitLog -> [OrbitTransformer] -> OrbitLog
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl ((OrbitTransformer -> OrbitTransformer)
-> OrbitLog -> OrbitTransformer -> OrbitLog
forall a b c. (a -> b -> c) -> b -> a -> c
flip OrbitTransformer -> OrbitTransformer
forall a b. (a -> b) -> a -> b
($)) OrbitLog
m (((Index -> OrbitTransformer) -> OrbitTransformer)
-> [Index -> OrbitTransformer] -> [OrbitTransformer]
forall a b. (a -> b) -> [a] -> [b]
map ((Index -> OrbitTransformer) -> Index -> OrbitTransformer
forall a b. (a -> b) -> a -> b
$ Index
pos) [Index -> OrbitTransformer]
items))

alterOrbit :: (Tag,AlterOrbit) -> (Position -> OrbitTransformer)

alterOrbit :: (Index, AlterOrbit) -> Index -> OrbitTransformer
alterOrbit (tag :: Index
tag,AlterModify {newInOrbit :: AlterOrbit -> Bool
newInOrbit = Bool
inOrbit',freshOrbit :: AlterOrbit -> Bool
freshOrbit = Bool
True}) =
  (\ pos :: Index
pos m :: OrbitLog
m -> Index -> Orbits -> OrbitTransformer
forall a. Index -> a -> IntMap a -> IntMap a
IMap.insert Index
tag ($WOrbits :: Bool -> Index -> Maybe Index -> Seq Index -> Orbits
Orbits { inOrbit :: Bool
inOrbit = Bool
inOrbit'
                                     , basePos :: Index
basePos = Index
pos
                                     , ordinal :: Maybe Index
ordinal = Maybe Index
forall a. Maybe a
Nothing
                                     , getOrbits :: Seq Index
getOrbits = Seq Index
forall a. Monoid a => a
mempty}) OrbitLog
m)

alterOrbit (tag :: Index
tag,AlterModify {newInOrbit :: AlterOrbit -> Bool
newInOrbit = Bool
inOrbit',freshOrbit :: AlterOrbit -> Bool
freshOrbit = Bool
False}) =
  (\ pos :: Index
pos m :: OrbitLog
m -> (Index -> Orbits -> Orbits -> Orbits)
-> Index -> Orbits -> OrbitTransformer
forall a.
(Index -> a -> a -> a) -> Index -> a -> IntMap a -> IntMap a
IMap.insertWithKey (Index -> Index -> Orbits -> Orbits -> Orbits
forall p. Index -> p -> Orbits -> Orbits -> Orbits
updateOrbit Index
pos) Index
tag (Index -> Orbits
newOrbit Index
pos) OrbitLog
m) where
  newOrbit :: Index -> Orbits
newOrbit pos :: Index
pos = $WOrbits :: Bool -> Index -> Maybe Index -> Seq Index -> Orbits
Orbits { inOrbit :: Bool
inOrbit = Bool
inOrbit'
                        , basePos :: Index
basePos = Index
pos
                        , ordinal :: Maybe Index
ordinal = Maybe Index
forall a. Maybe a
Nothing
                        , getOrbits :: Seq Index
getOrbits = Seq Index
forall a. Monoid a => a
Mon.mempty}
  updateOrbit :: Index -> p -> Orbits -> Orbits -> Orbits
updateOrbit pos :: Index
pos _tag :: p
_tag new :: Orbits
new old :: Orbits
old | Orbits -> Bool
inOrbit Orbits
old = Orbits
old { inOrbit :: Bool
inOrbit = Bool
inOrbit'
                                                   , getOrbits :: Seq Index
getOrbits = Orbits -> Seq Index
getOrbits Orbits
old Seq Index -> Index -> Seq Index
forall a. Seq a -> a -> Seq a
|> Index
pos }
                               | Bool
otherwise = Orbits
new

alterOrbit (tag :: Index
tag,AlterReset) = (\ _ m :: OrbitLog
m -> Index -> OrbitTransformer
forall a. Index -> IntMap a -> IntMap a
IMap.delete Index
tag OrbitLog
m)

alterOrbit (tag :: Index
tag,AlterLeave) = (\ _ m :: OrbitLog
m -> case Index -> OrbitLog -> Maybe Orbits
forall a. Index -> IntMap a -> Maybe a
IMap.lookup Index
tag OrbitLog
m of
                                         Nothing -> OrbitLog
m
                                         Just x :: Orbits
x -> Index -> Orbits -> OrbitTransformer
forall a. Index -> a -> IntMap a -> IntMap a
IMap.insert Index
tag (Orbits
x {inOrbit :: Bool
inOrbit=Bool
False}) OrbitLog
m)