{-# LANGUAGE RecordWildCards, BangPatterns #-}
module Reactive.Banana.Prim.Evaluation (
step
) where
import qualified Control.Exception as Strict (evaluate)
import Control.Monad (foldM)
import Control.Monad (join)
import Control.Monad.IO.Class
import qualified Control.Monad.Trans.RWSIO as RWS
import qualified Control.Monad.Trans.ReaderWriterIO as RW
import Data.Functor
import Data.Maybe
import qualified Data.PQueue.Prio.Min as Q
import qualified Data.Vault.Lazy as Lazy
import System.Mem.Weak
import qualified Reactive.Banana.Prim.OrderedBag as OB
import Reactive.Banana.Prim.Plumbing
import Reactive.Banana.Prim.Types
import Reactive.Banana.Prim.Util
type Queue = Q.MinPQueue Level
step :: Inputs -> Step
step (inputs,pulses)
Network{ nTime = time1
, nOutputs = outputs1
, nAlwaysP = Just alwaysP
}
= {-# SCC step #-} do
((_, (latchUpdates, outputs)), topologyUpdates, os)
<- runBuildIO (time1, alwaysP)
$ runEvalP pulses
$ evaluatePulses inputs
doit latchUpdates
doit topologyUpdates
let actions :: [(Output, EvalO)]
actions = OB.inOrder outputs outputs1
state2 :: Network
state2 = Network
{ nTime = next time1
, nOutputs = OB.inserts outputs1 os
, nAlwaysP = Just alwaysP
}
return (runEvalOs $ map snd actions, state2)
runEvalOs :: [EvalO] -> IO ()
runEvalOs = sequence_ . map join
evaluatePulses :: [SomeNode] -> EvalP ()
evaluatePulses roots = wrapEvalP $ \r -> go r =<< insertNodes r roots Q.empty
where
go :: RWS.Tuple BuildR (EvalPW, BuildW) Lazy.Vault -> Queue SomeNode -> IO ()
go r q = {-# SCC go #-}
case ({-# SCC minView #-} Q.minView q) of
Nothing -> return ()
Just (node, q) -> do
children <- unwrapEvalP r (evaluateNode node)
q <- insertNodes r children q
go r q
evaluateNode :: SomeNode -> EvalP [SomeNode]
evaluateNode (P p) = {-# SCC evaluateNodeP #-} do
Pulse{..} <- readRef p
ma <- _evalP
writePulseP _keyP ma
case ma of
Nothing -> return []
Just _ -> liftIO $ deRefWeaks _childrenP
evaluateNode (L lw) = {-# SCC evaluateNodeL #-} do
time <- askTime
LatchWrite{..} <- readRef lw
mlatch <- liftIO $ deRefWeak _latchLW
case mlatch of
Nothing -> return ()
Just latch -> do
a <- _evalLW
rememberLatchUpdate $
modify' latch $ \l ->
a `seq` l { _seenL = time, _valueL = a }
return []
evaluateNode (O o) = {-# SCC evaluateNodeO #-} do
debug "evaluateNode O"
Output{..} <- readRef o
m <- _evalO
rememberOutput $ (o,m)
return []
insertNodes :: RWS.Tuple BuildR (EvalPW, BuildW) Lazy.Vault -> [SomeNode] -> Queue SomeNode -> IO (Queue SomeNode)
insertNodes (RWS.Tuple (time,_) _ _) = {-# SCC insertNodes #-} go
where
go :: [SomeNode] -> Queue SomeNode -> IO (Queue SomeNode)
go [] q = return q
go (node@(P p):xs) q = do
Pulse{..} <- readRef p
if time <= _seenP
then go xs q
else do
put p $! (let p = Pulse{..} in p { _seenP = time })
go xs (Q.insert _levelP node q)
go (node:xs) q = go xs (Q.insert ground node q)