{-# LANGUAGE GADTs #-}
module Text.Regex.Applicative.Object
( ReObject
, compile
, emptyObject
, Thread
, threads
, failed
, isResult
, getResult
, results
, ThreadId
, threadId
, step
, stepThread
, fromThreads
, addThread
) where
import Text.Regex.Applicative.Types
import qualified Text.Regex.Applicative.StateQueue as SQ
import qualified Text.Regex.Applicative.Compile as Compile
import Data.Maybe
import Data.Foldable as F
import Control.Monad.Trans.State
import Control.Applicative hiding (empty)
newtype ReObject s r = ReObject (SQ.StateQueue (Thread s r))
threads :: ReObject s r -> [Thread s r]
threads (ReObject sq) = F.toList sq
fromThreads :: [Thread s r] -> ReObject s r
fromThreads ts = F.foldl' (flip addThread) emptyObject ts
isResult :: Thread s r -> Bool
isResult Accept {} = True
isResult _ = False
getResult :: Thread s r -> Maybe r
getResult (Accept r) = Just r
getResult _ = Nothing
failed :: ReObject s r -> Bool
failed obj = null $ threads obj
emptyObject :: ReObject s r
emptyObject = ReObject $ SQ.empty
results :: ReObject s r -> [r]
results obj =
mapMaybe getResult $ threads obj
step :: s -> ReObject s r -> ReObject s r
step s (ReObject sq) =
let accum q t =
case t of
Accept {} -> q
Thread _ c ->
F.foldl' (\q x -> addThread x q) q $ c s
newQueue = F.foldl' accum emptyObject sq
in newQueue
stepThread :: s -> Thread s r -> [Thread s r]
stepThread s t =
case t of
Thread _ c -> c s
Accept {} -> error "stepThread on a result"
addThread :: Thread s r -> ReObject s r -> ReObject s r
addThread t (ReObject q) =
case t of
Accept {} -> ReObject $ SQ.insert t q
Thread { threadId_ = ThreadId i } -> ReObject $ SQ.insertUnique i t q
compile :: RE s r -> ReObject s r
compile =
fromThreads .
flip Compile.compile (\x -> [Accept x]) .
renumber
renumber :: RE s a -> RE s a
renumber e = flip evalState (ThreadId 1) $ go e
where
go :: RE s a -> State ThreadId (RE s a)
go e =
case e of
Eps -> return Eps
Symbol _ p -> Symbol <$> fresh <*> pure p
Alt a1 a2 -> Alt <$> go a1 <*> go a2
App a1 a2 -> App <$> go a1 <*> go a2
Fail -> return Fail
Fmap f a -> Fmap f <$> go a
Rep g f b a -> Rep g f b <$> go a
Void a -> Void <$> go a
fresh :: State ThreadId ThreadId
fresh = do
t@(ThreadId i) <- get
put $! ThreadId (i+1)
return t